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
use core::iter::Peekable;
pub use super::errors::ParserError;
use crate::parser::get_subtag_iterator;
use crate::subtags;
use crate::LanguageIdentifier;
use alloc::vec::Vec;
#[derive(PartialEq, Clone, Copy)]
pub enum ParserMode {
LanguageIdentifier,
Locale,
Partial,
}
#[derive(PartialEq, Clone, Copy)]
enum ParserPosition {
Script,
Region,
Variant,
}
pub fn parse_language_identifier_from_iter<'a>(
iter: &mut Peekable<impl Iterator<Item = &'a [u8]>>,
mode: ParserMode,
) -> Result<LanguageIdentifier, ParserError> {
let language;
let mut script = None;
let mut region = None;
let mut variants = Vec::new();
if let Some(subtag) = iter.next() {
language = subtags::Language::from_bytes(subtag)?;
} else {
return Err(ParserError::InvalidLanguage);
}
let mut position = ParserPosition::Script;
while let Some(subtag) = iter.peek() {
if mode != ParserMode::LanguageIdentifier && subtag.len() == 1 {
break;
}
if position == ParserPosition::Script {
if let Ok(s) = subtags::Script::from_bytes(subtag) {
script = Some(s);
position = ParserPosition::Region;
} else if let Ok(s) = subtags::Region::from_bytes(subtag) {
region = Some(s);
position = ParserPosition::Variant;
} else if let Ok(v) = subtags::Variant::from_bytes(subtag) {
if let Err(idx) = variants.binary_search(&v) {
variants.insert(idx, v);
}
position = ParserPosition::Variant;
} else if mode == ParserMode::Partial {
break;
} else {
return Err(ParserError::InvalidSubtag);
}
} else if position == ParserPosition::Region {
if let Ok(s) = subtags::Region::from_bytes(subtag) {
region = Some(s);
position = ParserPosition::Variant;
} else if let Ok(v) = subtags::Variant::from_bytes(subtag) {
if let Err(idx) = variants.binary_search(&v) {
variants.insert(idx, v);
}
position = ParserPosition::Variant;
} else if mode == ParserMode::Partial {
break;
} else {
return Err(ParserError::InvalidSubtag);
}
} else if let Ok(v) = subtags::Variant::from_bytes(subtag) {
if let Err(idx) = variants.binary_search(&v) {
variants.insert(idx, v);
}
} else if mode == ParserMode::Partial {
break;
} else {
return Err(ParserError::InvalidSubtag);
}
iter.next();
}
Ok(LanguageIdentifier {
language,
script,
region,
variants: subtags::Variants::from_vec_unchecked(variants),
})
}
pub fn parse_language_identifier(
t: &[u8],
mode: ParserMode,
) -> Result<LanguageIdentifier, ParserError> {
let mut iter = get_subtag_iterator(t).peekable();
parse_language_identifier_from_iter(&mut iter, mode)
}