use super::super::Tag;
use super::internal::{at::*, *};
use super::util::*;
#[derive(Copy, Clone)]
pub struct Script<'a> {
data: Bytes<'a>,
gsub: u32,
gpos: u32,
gsub_offset: u32,
gpos_offset: u32,
tag: Tag,
}
impl<'a> Script<'a> {
pub fn languages(&self) -> Languages<'a> {
Languages::new(
self.data,
self.gsub,
self.gpos,
self.gsub_offset,
self.gpos_offset,
)
}
}
#[derive(Copy, Clone)]
pub struct Scripts<'a> {
data: Bytes<'a>,
gsub: u32,
gpos: u32,
in_gsub: bool,
len: u16,
cur: u16,
done: bool,
}
impl<'a> Scripts<'a> {
pub fn new(data: Bytes<'a>, gsub: u32, gpos: u32) -> Self {
Self {
data,
gsub,
gpos,
in_gsub: true,
len: script_count(&data, gsub),
cur: 0,
done: false,
}
}
fn get_next(&mut self) -> Option<Script<'a>> {
if self.in_gsub {
if self.cur < self.len {
let index = self.cur;
self.cur += 1;
let (tag, offset) = script_at(&self.data, self.gsub, index)?;
let gpos_offset = script_by_tag(&self.data, self.gpos, tag).unwrap_or(0);
return Some(Script {
data: self.data,
gsub: self.gsub,
gpos: self.gpos,
gsub_offset: offset,
gpos_offset,
tag,
});
} else {
self.in_gsub = false;
self.cur = 0;
self.len = script_count(&self.data, self.gpos);
}
} else if self.cur < self.len {
let index = self.cur;
self.cur += 1;
let (tag, offset) = script_at(&self.data, self.gpos, index)?;
if script_by_tag(&self.data, self.gsub, tag).is_some() {
return None;
}
return Some(Script {
data: self.data,
gsub: self.gsub,
gpos: self.gpos,
gsub_offset: 0,
gpos_offset: offset,
tag,
});
} else {
self.done = true;
}
None
}
}
impl<'a> Iterator for Scripts<'a> {
type Item = Script<'a>;
fn next(&mut self) -> Option<Self::Item> {
while !self.done {
let item = self.get_next();
if item.is_some() {
return item;
}
}
None
}
}
#[derive(Copy, Clone)]
pub struct Language<'a> {
data: Bytes<'a>,
gsub: u32,
gpos: u32,
gsub_offset: u32,
gpos_offset: u32,
tag: Tag,
}
#[derive(Copy, Clone)]
pub struct Languages<'a> {
data: Bytes<'a>,
gsub: u32,
gpos: u32,
gsub_script: u32,
gpos_script: u32,
in_gsub: bool,
len: u16,
cur: u16,
done: bool,
}
impl<'a> Languages<'a> {
fn new(data: Bytes<'a>, gsub: u32, gpos: u32, gsub_script: u32, gpos_script: u32) -> Self {
Self {
data,
gsub,
gpos,
gsub_script,
gpos_script,
in_gsub: true,
len: script_language_count(&data, gsub_script),
cur: 0,
done: false,
}
}
fn get_next(&mut self) -> Option<Language<'a>> {
if self.in_gsub {
if self.cur < self.len {
let index = self.cur;
self.cur += 1;
let (tag, offset) = script_language_at(&self.data, self.gsub_script, index)?;
let gsub_default = tag == DFLT;
let (gpos_offset, _) = if gsub_default {
(
script_default_language(&self.data, self.gpos_script).unwrap_or(0),
true,
)
} else {
script_language_by_tag(&self.data, self.gpos_script, Some(tag))
.unwrap_or((0, false))
};
return Some(Language {
data: self.data,
gsub: self.gsub,
gpos: self.gpos,
gsub_offset: offset,
gpos_offset,
tag,
});
} else {
self.in_gsub = false;
self.cur = 0;
self.len = script_language_count(&self.data, self.gpos_script);
}
} else if self.cur < self.len {
let index = self.cur;
self.cur += 1;
let (tag, offset) = script_language_at(&self.data, self.gpos_script, index)?;
if script_language_by_tag(&self.data, self.gsub_script, Some(tag)).is_some() {
return None;
}
return Some(Language {
data: self.data,
gsub: self.gsub,
gpos: self.gpos,
gsub_offset: 0,
gpos_offset: offset,
tag,
});
} else {
self.done = true;
}
None
}
}
impl<'a> Iterator for Languages<'a> {
type Item = Language<'a>;
fn next(&mut self) -> Option<Self::Item> {
while !self.done {
let item = self.get_next();
if item.is_some() {
return item;
}
}
None
}
}
#[derive(Copy, Clone)]
pub struct WritingSystem<'a> {
lang: Language<'a>,
script_tag: Tag,
}
impl<'a> WritingSystem<'a> {
pub fn script_tag(&self) -> Tag {
self.script_tag
}
pub fn language_tag(&self) -> Tag {
self.lang.tag
}
pub fn features(&self) -> Features<'a> {
Features::new(&self.lang)
}
}
#[derive(Copy, Clone)]
pub struct WritingSystems<'a> {
scripts: Scripts<'a>,
langs: Option<Languages<'a>>,
script_tag: Tag,
}
impl<'a> WritingSystems<'a> {
pub fn new(scripts: Scripts<'a>) -> Self {
Self {
scripts,
langs: None,
script_tag: 0,
}
}
}
impl<'a> Iterator for WritingSystems<'a> {
type Item = WritingSystem<'a>;
fn next(&mut self) -> Option<Self::Item> {
loop {
if self.langs.is_none() {
let script = self.scripts.next()?;
self.script_tag = script.tag;
self.langs = Some(script.languages());
}
if let Some(lang) = self.langs.as_mut().unwrap().next() {
return Some(WritingSystem {
lang,
script_tag: self.script_tag,
});
} else {
self.langs = None;
}
}
}
}
#[derive(Copy, Clone)]
pub struct Feature {
pub stage: u8,
pub tag: Tag,
}
#[derive(Copy, Clone)]
pub struct Features<'a> {
data: Bytes<'a>,
gsub: u32,
gpos: u32,
gsub_language: u32,
gpos_language: u32,
stage: u8,
len: u16,
cur: u16,
done: bool,
}
impl<'a> Features<'a> {
fn new(language: &Language<'a>) -> Self {
Self {
data: language.data,
gsub: language.gsub,
gpos: language.gpos,
gsub_language: language.gsub_offset,
gpos_language: language.gpos_offset,
stage: 0,
len: language_feature_count(&language.data, language.gsub_offset),
cur: 0,
done: false,
}
}
fn get_next(&mut self) -> Option<Feature> {
let (gsubgpos, language) = match self.stage {
0 => (self.gsub, self.gsub_language),
_ => (self.gpos, self.gpos_language),
};
if self.cur < self.len {
let index = self.cur;
self.cur += 1;
let feature = language_feature_at(&self.data, language, index)?;
let (tag, _offset) = feature_at(&self.data, gsubgpos, feature)?;
return Some(Feature {
stage: self.stage,
tag,
});
} else if self.stage == 0 {
self.stage = 1;
self.len = language_feature_count(&self.data, self.gpos_language);
self.cur = 0;
} else {
self.done = true;
}
None
}
}
impl<'a> Iterator for Features<'a> {
type Item = Feature;
fn next(&mut self) -> Option<Self::Item> {
while !self.done {
let item = self.get_next();
if item.is_some() {
return item;
}
}
None
}
}
#[derive(Copy, Clone)]
pub struct AllFeatures<'a> {
data: Bytes<'a>,
seen: SeenFeatures,
table: u32,
next_table: u32,
stage: u8,
len: u16,
cur: u16,
}
impl<'a> AllFeatures<'a> {
pub fn new(data: Bytes<'a>, gsub: u32, gpos: u32) -> Self {
let len = feature_count(&data, gsub);
Self {
data,
seen: SeenFeatures::new(),
table: gsub,
next_table: gpos,
stage: 0,
len,
cur: 0,
}
}
}
impl<'a> Iterator for AllFeatures<'a> {
type Item = (u8, Tag);
fn next(&mut self) -> Option<Self::Item> {
loop {
if self.cur >= self.len {
if self.next_table == 0 {
return None;
}
self.table = self.next_table;
self.next_table = 0;
self.stage = 1;
self.cur = 0;
self.len = feature_count(&self.data, self.table);
if self.len == 0 {
return None;
}
}
let index = self.cur;
self.cur += 1;
if let Some((tag, _)) = feature_at(&self.data, self.table, index) {
match FEATURES.binary_search_by(|pair| pair.0.cmp(&tag)) {
Ok(index) => {
if self.seen.mark(index) {
return Some((self.stage, tag));
}
}
_ => continue,
}
}
}
}
}