1extern crate alloc;
4
5use alloc::format;
6
7use crate::document::node::NodeTuple;
8use crate::prelude_internal::*;
9
10use super::{DocumentParser, FromEure, ParseContext, 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 _ => Err(ParseError {
58 node_id,
59 kind: ParseErrorKind::TypeMismatch {
60 expected: crate::value::ValueKind::Tuple,
61 actual: node.content.value_kind(),
62 },
63 }),
64 }
65 }
66
67 pub fn node_id(&self) -> NodeId {
69 self.node_id
70 }
71
72 #[allow(clippy::should_implement_trait)]
76 pub fn next<T>(&mut self) -> Result<T, T::Error>
77 where
78 T: FromEure<'doc>,
79 T::Error: From<ParseError>,
80 {
81 self.next_with(T::parse)
82 }
83
84 pub fn next_with<T>(&mut self, mut parser: T) -> Result<T::Output, T::Error>
86 where
87 T: DocumentParser<'doc>,
88 T::Error: From<ParseError>,
89 {
90 let index = self.position;
91 let element_node_id = self.tuple.get(index).ok_or_else(|| ParseError {
92 node_id: self.node_id,
93 kind: ParseErrorKind::MissingField(format!("#{}", index)),
94 })?;
95 self.position += 1;
96 let ctx = ParseContext::new(self.doc, element_node_id);
97 parser.parse(&ctx)
98 }
99
100 pub fn next_via<M, T>(&mut self) -> Result<T, M::Error>
102 where
103 M: FromEure<'doc, T>,
104 M::Error: From<ParseError>,
105 {
106 self.next_with(M::parse)
107 }
108
109 pub fn get<T>(&self, index: usize) -> Result<T, T::Error>
113 where
114 T: FromEure<'doc>,
115 T::Error: From<ParseError>,
116 {
117 self.get_with(index, T::parse)
118 }
119
120 pub fn get_with<T>(&self, index: usize, mut parser: T) -> Result<T::Output, T::Error>
122 where
123 T: DocumentParser<'doc>,
124 T::Error: From<ParseError>,
125 {
126 let element_node_id = self.tuple.get(index).ok_or_else(|| ParseError {
127 node_id: self.node_id,
128 kind: ParseErrorKind::MissingField(format!("#{}", index)),
129 })?;
130 let ctx = ParseContext::new(self.doc, element_node_id);
131 parser.parse(&ctx)
132 }
133
134 pub fn get_via<M, T>(&self, index: usize) -> Result<T, M::Error>
136 where
137 M: FromEure<'doc, T>,
138 M::Error: From<ParseError>,
139 {
140 self.get_with(index, M::parse)
141 }
142
143 pub fn remaining(&self) -> usize {
145 self.tuple.len().saturating_sub(self.position)
146 }
147
148 pub fn finish(self) -> Result<(), ParseError> {
152 if self.position != self.tuple.len() {
153 return Err(ParseError {
154 node_id: self.node_id,
155 kind: ParseErrorKind::UnexpectedTupleLength {
156 expected: self.position,
157 actual: self.tuple.len(),
158 },
159 });
160 }
161 Ok(())
162 }
163
164 pub fn expect_len(&self, expected: usize) -> Result<(), ParseError> {
168 if self.tuple.len() != expected {
169 return Err(ParseError {
170 node_id: self.node_id,
171 kind: ParseErrorKind::UnexpectedTupleLength {
172 expected,
173 actual: self.tuple.len(),
174 },
175 });
176 }
177 Ok(())
178 }
179
180 pub fn len(&self) -> usize {
182 self.tuple.len()
183 }
184
185 pub fn is_empty(&self) -> bool {
187 self.tuple.is_empty()
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 use super::*;
194 use crate::document::constructor::DocumentConstructor;
195 use crate::path::PathSegment;
196 use crate::value::PrimitiveValue;
197
198 fn create_tuple_doc(elements: Vec<PrimitiveValue>) -> EureDocument {
199 let mut c = DocumentConstructor::new();
200 c.bind_empty_tuple().unwrap();
201 for (i, elem) in elements.into_iter().enumerate() {
202 let scope = c.begin_scope();
203 c.navigate(PathSegment::TupleIndex(i as u8)).unwrap();
204 c.bind_primitive(elem).unwrap();
205 c.end_scope(scope).unwrap();
206 }
207 c.finish()
208 }
209
210 #[test]
211 fn test_next_sequential() {
212 let doc = create_tuple_doc(vec![
213 PrimitiveValue::Integer(1.into()),
214 PrimitiveValue::Integer(2.into()),
215 PrimitiveValue::Integer(3.into()),
216 ]);
217
218 let mut tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
219 assert_eq!(tuple.next::<i32>().unwrap(), 1);
220 assert_eq!(tuple.next::<i32>().unwrap(), 2);
221 assert_eq!(tuple.next::<i32>().unwrap(), 3);
222 tuple.finish().unwrap();
223 }
224
225 #[test]
226 fn test_next_past_end() {
227 let doc = create_tuple_doc(vec![PrimitiveValue::Integer(1.into())]);
228
229 let mut tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
230 tuple.next::<i32>().unwrap();
231 let result = tuple.next::<i32>();
232 assert!(matches!(
233 result.unwrap_err().kind,
234 ParseErrorKind::MissingField(_)
235 ));
236 }
237
238 #[test]
239 fn test_get_random_access() {
240 let doc = create_tuple_doc(vec![
241 PrimitiveValue::Integer(10.into()),
242 PrimitiveValue::Integer(20.into()),
243 PrimitiveValue::Integer(30.into()),
244 ]);
245
246 let tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
247 assert_eq!(tuple.get::<i32>(2).unwrap(), 30);
248 assert_eq!(tuple.get::<i32>(0).unwrap(), 10);
249 assert_eq!(tuple.get::<i32>(1).unwrap(), 20);
250 }
251
252 #[test]
253 fn test_get_out_of_bounds() {
254 let doc = create_tuple_doc(vec![PrimitiveValue::Integer(1.into())]);
255
256 let tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
257 let result = tuple.get::<i32>(5);
258 assert!(matches!(
259 result.unwrap_err().kind,
260 ParseErrorKind::MissingField(_)
261 ));
262 }
263
264 #[test]
265 fn test_remaining() {
266 let doc = create_tuple_doc(vec![
267 PrimitiveValue::Integer(1.into()),
268 PrimitiveValue::Integer(2.into()),
269 PrimitiveValue::Integer(3.into()),
270 ]);
271
272 let mut tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
273 assert_eq!(tuple.remaining(), 3);
274 tuple.next::<i32>().unwrap();
275 assert_eq!(tuple.remaining(), 2);
276 tuple.next::<i32>().unwrap();
277 assert_eq!(tuple.remaining(), 1);
278 tuple.next::<i32>().unwrap();
279 assert_eq!(tuple.remaining(), 0);
280 }
281
282 #[test]
283 fn test_finish_with_remaining_elements() {
284 let doc = create_tuple_doc(vec![
285 PrimitiveValue::Integer(1.into()),
286 PrimitiveValue::Integer(2.into()),
287 ]);
288
289 let mut tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
290 tuple.next::<i32>().unwrap();
291 let result = tuple.finish();
293 assert!(matches!(
294 result.unwrap_err().kind,
295 ParseErrorKind::UnexpectedTupleLength {
296 expected: 1,
297 actual: 2
298 }
299 ));
300 }
301
302 #[test]
303 fn test_expect_len_correct() {
304 let doc = create_tuple_doc(vec![
305 PrimitiveValue::Integer(1.into()),
306 PrimitiveValue::Integer(2.into()),
307 ]);
308
309 let tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
310 tuple.expect_len(2).unwrap();
311 }
312
313 #[test]
314 fn test_expect_len_incorrect() {
315 let doc = create_tuple_doc(vec![PrimitiveValue::Integer(1.into())]);
316
317 let tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
318 let result = tuple.expect_len(3);
319 assert!(matches!(
320 result.unwrap_err().kind,
321 ParseErrorKind::UnexpectedTupleLength {
322 expected: 3,
323 actual: 1
324 }
325 ));
326 }
327
328 #[test]
329 fn test_empty_tuple() {
330 let doc = create_tuple_doc(vec![]);
331
332 let tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
333 assert!(tuple.is_empty());
334 assert_eq!(tuple.len(), 0);
335 assert_eq!(tuple.remaining(), 0);
336 tuple.finish().unwrap();
337 }
338
339 #[test]
340 fn test_len_and_is_empty() {
341 let doc = create_tuple_doc(vec![
342 PrimitiveValue::Integer(1.into()),
343 PrimitiveValue::Integer(2.into()),
344 ]);
345
346 let tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
347 assert!(!tuple.is_empty());
348 assert_eq!(tuple.len(), 2);
349 }
350
351 #[test]
352 fn test_parse_non_tuple_fails() {
353 let mut c = DocumentConstructor::new();
354 c.bind_empty_array().unwrap();
355 let doc = c.finish();
356
357 let result = doc.parse_tuple(doc.get_root_id());
358 assert!(matches!(
359 result.unwrap_err().kind,
360 ParseErrorKind::TypeMismatch { .. }
361 ));
362 }
363}