ixdtf/parsers/
annotations.rs1use crate::{
8 assert_syntax,
9 encoding::EncodingType,
10 parsers::{
11 grammar::{
12 is_a_key_char, is_a_key_leading_char, is_annotation_close,
13 is_annotation_key_value_separator, is_annotation_open, is_annotation_value_component,
14 is_critical_flag, is_hyphen,
15 },
16 timezone, Cursor,
17 },
18 records::{Annotation, TimeZoneAnnotation},
19 ParseError, ParserResult,
20};
21
22pub(crate) struct AnnotationSet<'a, T: EncodingType> {
24 pub(crate) tz: Option<TimeZoneAnnotation<'a, T>>,
25 pub(crate) calendar: Option<&'a [T::CodeUnit]>,
26}
27
28pub(crate) fn parse_annotation_set<'a, T: EncodingType>(
30 cursor: &mut Cursor<'a, T>,
31 handler: impl FnMut(Annotation<'a, T>) -> Option<Annotation<'a, T>>,
32) -> ParserResult<AnnotationSet<'a, T>> {
33 let tz_annotation = timezone::parse_ambiguous_tz_annotation(cursor)?;
35
36 let annotations = cursor.check_or(false, is_annotation_open)?;
38
39 if annotations {
40 let calendar = parse_annotations(cursor, handler)?;
41 return Ok(AnnotationSet {
42 tz: tz_annotation,
43 calendar,
44 });
45 }
46
47 Ok(AnnotationSet {
48 tz: tz_annotation,
49 calendar: None,
50 })
51}
52
53pub(crate) fn parse_annotations<'a, T: EncodingType>(
55 cursor: &mut Cursor<'a, T>,
56 mut handler: impl FnMut(Annotation<'a, T>) -> Option<Annotation<'a, T>>,
57) -> ParserResult<Option<&'a [T::CodeUnit]>> {
58 let mut calendar: Option<Annotation<'a, T>> = None;
59
60 while cursor.check_or(false, is_annotation_open)? {
61 let annotation = handler(parse_kv_annotation(cursor)?);
62
63 match annotation {
64 Some(kv) if T::check_calendar_key(kv.key) => {
66 match calendar {
68 Some(calendar)
69 if calendar.value != kv.value && (calendar.critical || kv.critical) =>
71 {
72 return Err(ParseError::CriticalDuplicateCalendar)
73 }
74 None => {
76 calendar = Some(kv);
77 }
78 _ => {}
79 }
80 }
81 Some(unknown_kv) if unknown_kv.critical => {
82 return Err(ParseError::UnrecognizedCritical);
84 }
85 _ => {}
86 }
87 }
88
89 Ok(calendar.map(|a| a.value))
90}
91
92fn parse_kv_annotation<'a, T: EncodingType>(
94 cursor: &mut Cursor<'a, T>,
95) -> ParserResult<Annotation<'a, T>> {
96 assert_syntax!(
97 is_annotation_open(cursor.next_or(ParseError::AnnotationOpen)?),
98 AnnotationOpen
99 );
100
101 let critical = cursor.check_or(false, is_critical_flag)?;
102 cursor.advance_if(critical);
103
104 let annotation_key = parse_annotation_key(cursor)?;
106 assert_syntax!(
107 is_annotation_key_value_separator(cursor.next_or(ParseError::AnnotationKeyValueSeparator)?),
108 AnnotationKeyValueSeparator,
109 );
110
111 let annotation_value = parse_annotation_value(cursor)?;
113 assert_syntax!(
114 is_annotation_close(cursor.next_or(ParseError::AnnotationClose)?),
115 AnnotationClose
116 );
117
118 Ok(Annotation {
119 critical,
120 key: annotation_key,
121 value: annotation_value,
122 })
123}
124
125fn parse_annotation_key<'a, T: EncodingType>(
127 cursor: &mut Cursor<'a, T>,
128) -> ParserResult<&'a [T::CodeUnit]> {
129 let key_start = cursor.pos();
130 assert_syntax!(
131 is_a_key_leading_char(cursor.next_or(ParseError::AnnotationKeyLeadingChar)?),
132 AnnotationKeyLeadingChar,
133 );
134
135 while let Some(potential_key_char) = cursor.next()? {
136 if cursor.check_or(false, is_annotation_key_value_separator)? {
138 return cursor
140 .slice(key_start, cursor.pos())
141 .ok_or(ParseError::ImplAssert);
142 }
143
144 assert_syntax!(is_a_key_char(potential_key_char), AnnotationKeyChar);
145 }
146
147 Err(ParseError::AnnotationChar)
148}
149
150fn parse_annotation_value<'a, T: EncodingType>(
152 cursor: &mut Cursor<'a, T>,
153) -> ParserResult<&'a [T::CodeUnit]> {
154 let value_start = cursor.pos();
155 cursor.advance();
156 while let Some(potential_value_char) = cursor.next()? {
157 if cursor.check_or(false, is_annotation_close)? {
158 return cursor
160 .slice(value_start, cursor.pos())
161 .ok_or(ParseError::ImplAssert);
162 }
163
164 if is_hyphen(potential_value_char) {
165 assert_syntax!(
166 cursor.peek()?.is_some_and(is_annotation_value_component),
167 AnnotationValueCharPostHyphen,
168 );
169 cursor.advance();
170 continue;
171 }
172
173 assert_syntax!(
174 is_annotation_value_component(potential_value_char),
175 AnnotationValueChar,
176 );
177 }
178
179 Err(ParseError::AnnotationValueChar)
180}