use crate::util::{atomic::AtomicCounter, string::SmallString};
use super::types::{FamilyKey, GenericFamily};
#[derive(Clone, Debug)]
pub struct FamilyList {
names: SmallString,
key: u64,
}
pub(crate) static FONT_FAMILY_KEYS: AtomicCounter = AtomicCounter::new();
impl FamilyList {
pub fn new(names: &str) -> Self {
Self {
names: SmallString::new(names),
key: FONT_FAMILY_KEYS.next(),
}
}
pub fn names(&self) -> &str {
self.names.as_str()
}
pub fn families<'a>(&'a self) -> impl Iterator<Item = FamilyKey<'a>> + Clone + 'a {
parse_families(self.names())
}
pub fn key(&self) -> u64 {
self.key
}
}
impl Default for FamilyList {
fn default() -> Self {
Self {
names: SmallString::new(""),
key: !0,
}
}
}
impl PartialEq for FamilyList {
fn eq(&self, other: &Self) -> bool {
self.names == other.names
}
}
impl Eq for FamilyList {}
impl From<&str> for FamilyList {
fn from(s: &str) -> Self {
Self::new(s)
}
}
pub fn parse_families<'a>(families: &'a str) -> impl Iterator<Item = FamilyKey<'a>> + Clone {
FamilyParser {
source: families.as_bytes(),
cur: 0,
len: families.len(),
}
}
#[derive(Clone)]
struct FamilyParser<'a> {
source: &'a [u8],
cur: usize,
len: usize,
}
impl<'a> Iterator for FamilyParser<'a> {
type Item = FamilyKey<'a>;
fn next(&mut self) -> Option<Self::Item> {
let mut quote = None;
let mut cur = self.cur;
while cur < self.len && {
let ch = self.source[cur];
ch.is_ascii_whitespace() || ch == b','
} {
cur += 1;
}
self.cur = cur;
if cur >= self.len {
return None;
}
let first = self.source[cur];
let mut start = cur;
match first {
b'"' | b'\'' => {
quote = Some(first);
cur += 1;
start += 1;
}
_ => {}
}
if let Some(quote) = quote {
while cur < self.len {
if self.source[cur] == quote {
self.cur = cur + 1;
return Some(FamilyKey::Name(
core::str::from_utf8(self.source.get(start..cur)?)
.ok()?
.trim(),
));
}
cur += 1;
}
self.cur = cur;
return Some(FamilyKey::Name(
core::str::from_utf8(self.source.get(start..cur)?)
.ok()?
.trim(),
));
}
let mut end = start;
while cur < self.len {
if self.source[cur] == b',' {
cur += 1;
break;
}
cur += 1;
end += 1;
}
self.cur = cur;
let name = core::str::from_utf8(self.source.get(start..end)?)
.ok()?
.trim();
Some(match GenericFamily::parse(name) {
Some(family) => FamilyKey::Generic(family),
_ => FamilyKey::Name(name),
})
}
}