unic_locale_impl/extensions/
mod.rs1mod private;
11mod transform;
12mod unicode;
13
14pub use private::PrivateExtensionList;
15pub use transform::TransformExtensionList;
16pub use unicode::UnicodeExtensionList;
17
18use std::collections::BTreeMap;
19use std::fmt::Write;
20use std::iter::Peekable;
21use std::str::FromStr;
22
23use tinystr::TinyStr8;
24
25use crate::parser::ParserError;
26
27#[derive(PartialEq, Eq, Debug, Clone, Copy, Hash, PartialOrd, Ord)]
29pub enum ExtensionType {
30 Transform,
32 Unicode,
34 Private,
36 Other(char),
38}
39
40impl ExtensionType {
41 pub fn from_byte(key: u8) -> Result<Self, ParserError> {
42 let key = key.to_ascii_lowercase();
43 match key {
44 b'u' => Ok(ExtensionType::Unicode),
45 b't' => Ok(ExtensionType::Transform),
46 b'x' => Ok(ExtensionType::Private),
47 sign if sign.is_ascii_alphanumeric() => Ok(ExtensionType::Other(char::from(sign))),
48 _ => Err(ParserError::InvalidExtension),
49 }
50 }
51}
52
53impl std::fmt::Display for ExtensionType {
54 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
55 let ch = match self {
56 ExtensionType::Unicode => 'u',
57 ExtensionType::Transform => 't',
58 ExtensionType::Other(n) => *n,
59 ExtensionType::Private => 'x',
60 };
61 f.write_char(ch)
62 }
63}
64
65#[derive(Debug, Default, PartialEq, Eq, Clone, Hash, PartialOrd, Ord)]
67pub struct ExtensionsMap {
68 pub unicode: UnicodeExtensionList,
69 pub transform: TransformExtensionList,
70 pub other: BTreeMap<char, Vec<TinyStr8>>,
71 pub private: PrivateExtensionList,
72}
73
74impl ExtensionsMap {
75 pub fn from_bytes(bytes: &[u8]) -> Result<Self, ParserError> {
76 let mut iterator = bytes.split(|c| *c == b'-' || *c == b'_').peekable();
77 Self::try_from_iter(&mut iterator)
78 }
79
80 pub(crate) fn try_from_iter<'a>(
81 iter: &mut Peekable<impl Iterator<Item = &'a [u8]>>,
82 ) -> Result<Self, ParserError> {
83 let mut result = ExtensionsMap::default();
84
85 let mut st = iter.next();
86 while let Some(subtag) = st {
87 match subtag.first().map(|b| ExtensionType::from_byte(*b)) {
88 Some(Ok(ExtensionType::Unicode)) => {
89 result.unicode = UnicodeExtensionList::try_from_iter(iter)?;
90 }
91 Some(Ok(ExtensionType::Transform)) => {
92 result.transform = TransformExtensionList::try_from_iter(iter)?;
93 }
94 Some(Ok(ExtensionType::Private)) => {
95 result.private = PrivateExtensionList::try_from_iter(iter)?;
96 }
97 None => {}
98 _ => unimplemented!(),
99 }
100
101 st = iter.next();
102 }
103
104 Ok(result)
105 }
106
107 pub fn is_empty(&self) -> bool {
108 self.unicode.is_empty() && self.transform.is_empty() && self.private.is_empty()
109 }
110}
111
112impl FromStr for ExtensionsMap {
113 type Err = ParserError;
114
115 fn from_str(source: &str) -> Result<Self, Self::Err> {
116 Self::from_bytes(source.as_bytes())
117 }
118}
119
120impl std::fmt::Display for ExtensionsMap {
121 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
122 write!(f, "{}{}{}", self.transform, self.unicode, self.private)?;
124
125 Ok(())
126 }
127}