1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
mod private; mod transform; mod unicode; pub use private::PrivateExtensionList; pub use transform::TransformExtensionList; pub use unicode::UnicodeExtensionList; use std::collections::BTreeMap; use std::fmt::Write; use std::iter::Peekable; use std::str::FromStr; use tinystr::TinyStr8; use crate::parser::ParserError; #[derive(PartialEq, Eq, Debug, Clone, Copy)] pub enum ExtensionType { Unicode, Transform, Other(char), Private, } impl ExtensionType { pub fn from_char(key: char) -> Result<Self, ParserError> { match key { 'u' => Ok(ExtensionType::Unicode), 't' => Ok(ExtensionType::Transform), 'x' => Ok(ExtensionType::Private), sign if sign.is_ascii_alphanumeric() => { Ok(ExtensionType::Other(sign.to_ascii_lowercase())) } _ => Err(ParserError::InvalidExtension), } } } impl std::fmt::Display for ExtensionType { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let ch = match self { ExtensionType::Unicode => 'u', ExtensionType::Transform => 't', ExtensionType::Other(n) => *n, ExtensionType::Private => 'x', }; f.write_char(ch) } } #[derive(Debug, Default, PartialEq, Eq, Clone)] pub struct ExtensionsMap { pub unicode: UnicodeExtensionList, pub transform: TransformExtensionList, pub other: BTreeMap<char, Vec<TinyStr8>>, pub private: PrivateExtensionList, } impl ExtensionsMap { pub fn try_from_iter<'a>( iter: &mut Peekable<impl Iterator<Item = &'a str>>, ) -> Result<Self, ParserError> { let mut result = ExtensionsMap::default(); let mut st = iter.next(); while let Some(subtag) = st { let subtag = subtag.to_ascii_lowercase(); match subtag.as_str() { "" => break, "u" => { result.unicode = UnicodeExtensionList::try_from_iter(iter)?; } "t" => { result.transform = TransformExtensionList::try_from_iter(iter)?; } "x" => { result.private = PrivateExtensionList::try_from_iter(iter)?; } _ => unimplemented!(), } st = iter.next(); } Ok(result) } pub fn is_empty(&self) -> bool { self.unicode.is_empty() && self.transform.is_empty() && self.private.is_empty() } } static SEPARATORS: &[char] = &['-', '_']; impl FromStr for ExtensionsMap { type Err = ParserError; fn from_str(source: &str) -> Result<Self, Self::Err> { let mut iterator = source.split(|c| SEPARATORS.contains(&c)).peekable(); Self::try_from_iter(&mut iterator) } } impl std::fmt::Display for ExtensionsMap { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}{}{}", self.unicode, self.transform, self.private)?; Ok(()) } }