1extern crate alloc;
4
5use alloc::format;
6
7use crate::document::node::NodeTuple;
8use crate::prelude_internal::*;
9
10use super::{ParseContext, ParseDocument, ParseError, ParseErrorKind};
11
12#[derive(Debug)]
26#[must_use]
27pub struct TupleParser<'doc> {
28 doc: &'doc EureDocument,
29 node_id: NodeId,
30 tuple: &'doc NodeTuple,
31 position: usize,
32}
33
34impl<'doc> TupleParser<'doc> {
35 pub(crate) fn new(ctx: &ParseContext<'doc>) -> Result<Self, ParseError> {
37 Self::from_doc_and_node(ctx.doc(), ctx.node_id())
38 }
39
40 pub(crate) fn from_doc_and_node(
42 doc: &'doc EureDocument,
43 node_id: NodeId,
44 ) -> Result<Self, ParseError> {
45 let node = doc.node(node_id);
46 match &node.content {
47 NodeValue::Tuple(tuple) => Ok(Self {
48 doc,
49 node_id,
50 tuple,
51 position: 0,
52 }),
53 NodeValue::Hole(_) => Err(ParseError {
54 node_id,
55 kind: ParseErrorKind::UnexpectedHole,
56 }),
57 value => Err(ParseError {
58 node_id,
59 kind: value
60 .value_kind()
61 .map(|actual| ParseErrorKind::TypeMismatch {
62 expected: crate::value::ValueKind::Tuple,
63 actual,
64 })
65 .unwrap_or(ParseErrorKind::UnexpectedHole),
66 }),
67 }
68 }
69
70 pub fn node_id(&self) -> NodeId {
72 self.node_id
73 }
74
75 #[allow(clippy::should_implement_trait)]
79 pub fn next<T>(&mut self) -> Result<T, T::Error>
80 where
81 T: ParseDocument<'doc>,
82 T::Error: From<ParseError>,
83 {
84 let index = self.position;
85 let element_node_id = self.tuple.get(index).ok_or_else(|| ParseError {
86 node_id: self.node_id,
87 kind: ParseErrorKind::MissingField(format!("#{}", index)),
88 })?;
89 self.position += 1;
90 let ctx = ParseContext::new(self.doc, element_node_id);
91 T::parse(&ctx)
92 }
93
94 pub fn get<T>(&self, index: usize) -> Result<T, T::Error>
98 where
99 T: ParseDocument<'doc>,
100 T::Error: From<ParseError>,
101 {
102 let element_node_id = self.tuple.get(index).ok_or_else(|| ParseError {
103 node_id: self.node_id,
104 kind: ParseErrorKind::MissingField(format!("#{}", index)),
105 })?;
106 let ctx = ParseContext::new(self.doc, element_node_id);
107 T::parse(&ctx)
108 }
109
110 pub fn remaining(&self) -> usize {
112 self.tuple.len().saturating_sub(self.position)
113 }
114
115 pub fn finish(self) -> Result<(), ParseError> {
119 if self.position != self.tuple.len() {
120 return Err(ParseError {
121 node_id: self.node_id,
122 kind: ParseErrorKind::UnexpectedTupleLength {
123 expected: self.position,
124 actual: self.tuple.len(),
125 },
126 });
127 }
128 Ok(())
129 }
130
131 pub fn expect_len(&self, expected: usize) -> Result<(), ParseError> {
135 if self.tuple.len() != expected {
136 return Err(ParseError {
137 node_id: self.node_id,
138 kind: ParseErrorKind::UnexpectedTupleLength {
139 expected,
140 actual: self.tuple.len(),
141 },
142 });
143 }
144 Ok(())
145 }
146
147 pub fn len(&self) -> usize {
149 self.tuple.len()
150 }
151
152 pub fn is_empty(&self) -> bool {
154 self.tuple.is_empty()
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161 use crate::document::constructor::DocumentConstructor;
162 use crate::path::PathSegment;
163 use crate::value::PrimitiveValue;
164
165 fn create_tuple_doc(elements: Vec<PrimitiveValue>) -> EureDocument {
166 let mut c = DocumentConstructor::new();
167 c.bind_empty_tuple().unwrap();
168 for (i, elem) in elements.into_iter().enumerate() {
169 let scope = c.begin_scope();
170 c.navigate(PathSegment::TupleIndex(i as u8)).unwrap();
171 c.bind_primitive(elem).unwrap();
172 c.end_scope(scope).unwrap();
173 }
174 c.finish()
175 }
176
177 #[test]
178 fn test_next_sequential() {
179 let doc = create_tuple_doc(vec![
180 PrimitiveValue::Integer(1.into()),
181 PrimitiveValue::Integer(2.into()),
182 PrimitiveValue::Integer(3.into()),
183 ]);
184
185 let mut tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
186 assert_eq!(tuple.next::<i32>().unwrap(), 1);
187 assert_eq!(tuple.next::<i32>().unwrap(), 2);
188 assert_eq!(tuple.next::<i32>().unwrap(), 3);
189 tuple.finish().unwrap();
190 }
191
192 #[test]
193 fn test_next_past_end() {
194 let doc = create_tuple_doc(vec![PrimitiveValue::Integer(1.into())]);
195
196 let mut tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
197 tuple.next::<i32>().unwrap();
198 let result = tuple.next::<i32>();
199 assert!(matches!(
200 result.unwrap_err().kind,
201 ParseErrorKind::MissingField(_)
202 ));
203 }
204
205 #[test]
206 fn test_get_random_access() {
207 let doc = create_tuple_doc(vec![
208 PrimitiveValue::Integer(10.into()),
209 PrimitiveValue::Integer(20.into()),
210 PrimitiveValue::Integer(30.into()),
211 ]);
212
213 let tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
214 assert_eq!(tuple.get::<i32>(2).unwrap(), 30);
215 assert_eq!(tuple.get::<i32>(0).unwrap(), 10);
216 assert_eq!(tuple.get::<i32>(1).unwrap(), 20);
217 }
218
219 #[test]
220 fn test_get_out_of_bounds() {
221 let doc = create_tuple_doc(vec![PrimitiveValue::Integer(1.into())]);
222
223 let tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
224 let result = tuple.get::<i32>(5);
225 assert!(matches!(
226 result.unwrap_err().kind,
227 ParseErrorKind::MissingField(_)
228 ));
229 }
230
231 #[test]
232 fn test_remaining() {
233 let doc = create_tuple_doc(vec![
234 PrimitiveValue::Integer(1.into()),
235 PrimitiveValue::Integer(2.into()),
236 PrimitiveValue::Integer(3.into()),
237 ]);
238
239 let mut tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
240 assert_eq!(tuple.remaining(), 3);
241 tuple.next::<i32>().unwrap();
242 assert_eq!(tuple.remaining(), 2);
243 tuple.next::<i32>().unwrap();
244 assert_eq!(tuple.remaining(), 1);
245 tuple.next::<i32>().unwrap();
246 assert_eq!(tuple.remaining(), 0);
247 }
248
249 #[test]
250 fn test_finish_with_remaining_elements() {
251 let doc = create_tuple_doc(vec![
252 PrimitiveValue::Integer(1.into()),
253 PrimitiveValue::Integer(2.into()),
254 ]);
255
256 let mut tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
257 tuple.next::<i32>().unwrap();
258 let result = tuple.finish();
260 assert!(matches!(
261 result.unwrap_err().kind,
262 ParseErrorKind::UnexpectedTupleLength {
263 expected: 1,
264 actual: 2
265 }
266 ));
267 }
268
269 #[test]
270 fn test_expect_len_correct() {
271 let doc = create_tuple_doc(vec![
272 PrimitiveValue::Integer(1.into()),
273 PrimitiveValue::Integer(2.into()),
274 ]);
275
276 let tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
277 tuple.expect_len(2).unwrap();
278 }
279
280 #[test]
281 fn test_expect_len_incorrect() {
282 let doc = create_tuple_doc(vec![PrimitiveValue::Integer(1.into())]);
283
284 let tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
285 let result = tuple.expect_len(3);
286 assert!(matches!(
287 result.unwrap_err().kind,
288 ParseErrorKind::UnexpectedTupleLength {
289 expected: 3,
290 actual: 1
291 }
292 ));
293 }
294
295 #[test]
296 fn test_empty_tuple() {
297 let doc = create_tuple_doc(vec![]);
298
299 let tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
300 assert!(tuple.is_empty());
301 assert_eq!(tuple.len(), 0);
302 assert_eq!(tuple.remaining(), 0);
303 tuple.finish().unwrap();
304 }
305
306 #[test]
307 fn test_len_and_is_empty() {
308 let doc = create_tuple_doc(vec![
309 PrimitiveValue::Integer(1.into()),
310 PrimitiveValue::Integer(2.into()),
311 ]);
312
313 let tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
314 assert!(!tuple.is_empty());
315 assert_eq!(tuple.len(), 2);
316 }
317
318 #[test]
319 fn test_parse_non_tuple_fails() {
320 let mut c = DocumentConstructor::new();
321 c.bind_empty_array().unwrap();
322 let doc = c.finish();
323
324 let result = doc.parse_tuple(doc.get_root_id());
325 assert!(matches!(
326 result.unwrap_err().kind,
327 ParseErrorKind::TypeMismatch { .. }
328 ));
329 }
330}