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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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, Hash)]
pub enum ExtensionType {
Unicode,
Transform,
Other(char),
Private,
}
impl ExtensionType {
pub fn from_byte(key: u8) -> Result<Self, ParserError> {
let key = key.to_ascii_lowercase();
match key {
b'u' => Ok(ExtensionType::Unicode),
b't' => Ok(ExtensionType::Transform),
b'x' => Ok(ExtensionType::Private),
sign if sign.is_ascii_alphanumeric() => Ok(ExtensionType::Other(char::from(sign))),
_ => 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, Hash)]
pub struct ExtensionsMap {
pub unicode: UnicodeExtensionList,
pub transform: TransformExtensionList,
pub other: BTreeMap<char, Vec<TinyStr8>>,
pub private: PrivateExtensionList,
}
impl ExtensionsMap {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, ParserError> {
let mut iterator = bytes.split(|c| *c == b'-' || *c == b'_').peekable();
Self::try_from_iter(&mut iterator)
}
pub(crate) fn try_from_iter<'a>(
iter: &mut Peekable<impl Iterator<Item = &'a [u8]>>,
) -> Result<Self, ParserError> {
let mut result = ExtensionsMap::default();
let mut st = iter.next();
while let Some(subtag) = st {
if subtag.is_empty() {
break;
}
match ExtensionType::from_byte(subtag[0]) {
Ok(ExtensionType::Unicode) => {
result.unicode = UnicodeExtensionList::try_from_iter(iter)?;
}
Ok(ExtensionType::Transform) => {
result.transform = TransformExtensionList::try_from_iter(iter)?;
}
Ok(ExtensionType::Private) => {
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()
}
}
impl FromStr for ExtensionsMap {
type Err = ParserError;
fn from_str(source: &str) -> Result<Self, Self::Err> {
Self::from_bytes(source.as_bytes())
}
}
impl std::fmt::Display for ExtensionsMap {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}{}{}", self.transform, self.unicode, self.private)?;
Ok(())
}
}