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
use alloc::vec::Vec;
use crate::error::InvalidFormatDescription;
use crate::format_description::component::{Component, NakedComponent};
use crate::format_description::{helper, modifier, FormatItem};
#[derive(Debug)]
pub(crate) struct ParsedItem<'a> {
pub(crate) item: FormatItem<'a>,
pub(crate) remaining: &'a [u8],
}
fn parse_component(mut s: &[u8], index: &mut usize) -> Result<Component, InvalidFormatDescription> {
s = helper::consume_whitespace(s, index);
let component_index = *index;
let whitespace_loc = s
.iter()
.position(u8::is_ascii_whitespace)
.unwrap_or(s.len());
*index += whitespace_loc;
let component_name = &s[..whitespace_loc];
s = &s[whitespace_loc..];
s = helper::consume_whitespace(s, index);
Ok(NakedComponent::parse(component_name, component_index)?
.attach_modifiers(&modifier::Modifiers::parse(component_name, s, index)?))
}
fn parse_literal<'a>(s: &'a [u8], index: &mut usize) -> ParsedItem<'a> {
let loc = s.iter().position(|&c| c == b'[').unwrap_or(s.len());
*index += loc;
ParsedItem {
item: FormatItem::Literal(&s[..loc]),
remaining: &s[loc..],
}
}
fn parse_item<'a>(
s: &'a [u8],
index: &mut usize,
) -> Result<ParsedItem<'a>, InvalidFormatDescription> {
if let [b'[', b'[', remaining @ ..] = s {
*index += 2;
return Ok(ParsedItem {
item: FormatItem::Literal(&[b'[']),
remaining,
});
};
if s.starts_with(&[b'[']) {
if let Some(bracket_index) = s.iter().position(|&c| c == b']') {
*index += 1;
let ret_val = ParsedItem {
item: FormatItem::Component(parse_component(&s[1..bracket_index], index)?),
remaining: &s[bracket_index + 1..],
};
*index += 1;
Ok(ret_val)
} else {
Err(InvalidFormatDescription::UnclosedOpeningBracket { index: *index })
}
} else {
Ok(parse_literal(s, index))
}
}
#[cfg_attr(__time_03_docs, doc(cfg(feature = "alloc")))]
pub fn parse(s: &str) -> Result<Vec<FormatItem<'_>>, InvalidFormatDescription> {
let mut compound = Vec::new();
let mut loc = 0;
let mut s = s.as_bytes();
while !s.is_empty() {
let ParsedItem { item, remaining } = parse_item(s, &mut loc)?;
s = remaining;
compound.push(item);
}
Ok(compound)
}