Skip to main content

eure_document/parse/
tuple.rs

1//! TupleParser for parsing tuple types from Eure documents.
2
3extern 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/// Helper for parsing tuple types from Eure documents.
13///
14/// Provides both sequential access via `next()` and random access via `get()`.
15/// Use `finish()` to verify all elements were consumed.
16///
17/// # Example
18///
19/// ```ignore
20/// let mut tuple = ctx.parse_tuple()?;
21/// let first: String = tuple.next()?;
22/// let second: i32 = tuple.next()?;
23/// tuple.finish()?; // Ensures no extra elements
24/// ```
25#[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    /// Create a new TupleParser for the given context.
36    pub(crate) fn new(ctx: &ParseContext<'doc>) -> Result<Self, ParseError> {
37        Self::from_doc_and_node(ctx.doc(), ctx.node_id())
38    }
39
40    /// Create a new TupleParser from document and node ID directly.
41    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    /// Get the node ID being parsed.
68    pub fn node_id(&self) -> NodeId {
69        self.node_id
70    }
71
72    /// Get the next element, advancing the position.
73    ///
74    /// Returns `ParseErrorKind::MissingField` if no more elements.
75    #[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    /// Get the next element using a custom parser, advancing the position.
85    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    /// Get the next element using a marker type, advancing the position.
101    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    /// Get the element at a specific index without advancing position.
110    ///
111    /// Returns `ParseErrorKind::MissingField` if the index is out of bounds.
112    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    /// Get the element at a specific index using a custom parser.
121    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    /// Get the element at a specific index using a marker type.
135    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    /// Get the number of remaining elements.
144    pub fn remaining(&self) -> usize {
145        self.tuple.len().saturating_sub(self.position)
146    }
147
148    /// Verify all elements were consumed.
149    ///
150    /// Returns `ParseErrorKind::UnexpectedTupleLength` if elements remain.
151    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    /// Verify the tuple has the expected length.
165    ///
166    /// Returns `ParseErrorKind::UnexpectedTupleLength` if length doesn't match.
167    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    /// Get the total number of elements in the tuple.
181    pub fn len(&self) -> usize {
182        self.tuple.len()
183    }
184
185    /// Check if the tuple is empty.
186    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        // Only consumed 1 of 2 elements
292        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}