hefty/
tuple.rs

1use typle::typle;
2
3use crate::byte_stream::ByteStream;
4use crate::iterable::OutputToByteStream;
5use crate::repeatable::Repeatable;
6use crate::{Extract, ParseResult};
7
8#[typle(Tuple for 1..=12)]
9pub struct TupleAny<T> {
10    tuple: T,
11}
12
13#[typle(Tuple for 1..=12)]
14impl<T> Extract for TupleAny<T>
15where
16    T: Tuple,
17    T<_>: Extract<Output = ByteStream>,
18{
19    // For each component the state begins as `Some(None)`. After a call to `extract` the state
20    // becomes`Some(Some(inner_state))`. If the component does not match, the state becomes `None`.
21    type State = typle_for!(i in .. => Option<Option<T<{i}>::State>>);
22    type Output = ByteStream;
23
24    fn extract(
25        &self,
26        input: ByteStream,
27        state: Option<Self::State>,
28        last: bool,
29    ) -> ParseResult<Self::State, Self::Output> {
30        let mut exhausted = true;
31        let mut state = state.unwrap_or(typle_for!(.. => Some(None)));
32        for typle_index!(i) in 0..T::LEN {
33            if let Some(inner_state) = &mut state[[i]] {
34                let input = input.clone();
35                match self.tuple[[i]].extract(input, inner_state.take(), last) {
36                    ParseResult::NoMatch(_) => {
37                        state[[i]] = None;
38                    }
39                    ParseResult::Partial(new_state) => {
40                        *inner_state = Some(new_state);
41                        if !last {
42                            exhausted = false;
43                        }
44                    }
45                    ParseResult::Match(output, input) => {
46                        return ParseResult::Match(output, input);
47                    }
48                }
49            }
50        }
51        if exhausted {
52            ParseResult::NoMatch(input.position())
53        } else {
54            ParseResult::Partial(state)
55        }
56    }
57}
58
59#[typle(Tuple for 1..=12)]
60impl<T> Repeatable for TupleAny<T>
61where
62    T: Tuple,
63    T<_>: Extract<Output = ByteStream>,
64{
65}
66
67#[typle(Tuple for 1..=12)]
68impl<T> OutputToByteStream for TupleAny<T>
69where
70    T: Tuple,
71    T<_>: Extract<Output = ByteStream>,
72{
73    fn output_to_bytestream(output: Self::Output) -> ByteStream {
74        output
75    }
76}
77
78pub struct TupleFirst<T> {
79    tuple: T,
80}
81
82#[typle(Tuple for 1..=12)]
83impl<T> Extract for TupleFirst<T>
84where
85    T: Tuple,
86    T<_>: Extract<Output = ByteStream>,
87{
88    // For each component the state begins as `None`. After a call to `extract` the returned
89    // `ParseResult` is kept in the state.
90    type State = typle_for!(i in .. => Option<ParseResult<T<{i}>::State, ByteStream>>);
91    type Output = ByteStream;
92
93    fn extract(
94        &self,
95        input: ByteStream,
96        state: Option<Self::State>,
97        last: bool,
98    ) -> ParseResult<Self::State, Self::Output> {
99        let mut first = true;
100        let mut state = state.unwrap_or(typle_for!(.. => None));
101        for typle_index!(i) in 0..T::LEN {
102            state[[i]] = match state[[i]].take() {
103                Some(ParseResult::NoMatch(position)) => Some(ParseResult::NoMatch(position)),
104                Some(ParseResult::Partial(inner_state)) => {
105                    let res = self.tuple[[i]].extract(input.clone(), Some(inner_state), last);
106                    match res {
107                        ParseResult::NoMatch(position) => Some(ParseResult::NoMatch(position)),
108                        ParseResult::Partial(state) => {
109                            if !last {
110                                first = false;
111                            }
112                            Some(ParseResult::Partial(state))
113                        }
114                        ParseResult::Match(output, input) => {
115                            if first {
116                                return ParseResult::Match(output, input);
117                            }
118                            Some(ParseResult::Match(output, input))
119                        }
120                    }
121                }
122                Some(ParseResult::Match(output, input)) => {
123                    if first {
124                        return ParseResult::Match(output, input);
125                    }
126                    Some(ParseResult::Match(output, input))
127                }
128                None => {
129                    let res = self.tuple[[i]].extract(input.clone(), None, last);
130                    match res {
131                        ParseResult::NoMatch(position) => Some(ParseResult::NoMatch(position)),
132                        ParseResult::Partial(state) => {
133                            if !last {
134                                first = false;
135                            }
136                            Some(ParseResult::Partial(state))
137                        }
138                        ParseResult::Match(output, input) => {
139                            if first {
140                                return ParseResult::Match(output, input);
141                            }
142                            Some(ParseResult::Match(output, input))
143                        }
144                    }
145                }
146            };
147        }
148        if first {
149            ParseResult::NoMatch(input.position())
150        } else {
151            ParseResult::Partial(state)
152        }
153    }
154}
155
156#[typle(Tuple for 1..=12)]
157impl<T> Repeatable for TupleFirst<T>
158where
159    T: Tuple,
160    T<_>: Extract<Output = ByteStream>,
161{
162}
163
164#[typle(Tuple for 1..=12)]
165impl<T> OutputToByteStream for TupleFirst<T>
166where
167    T: Tuple,
168    T<_>: Extract<Output = ByteStream>,
169{
170    fn output_to_bytestream(output: Self::Output) -> ByteStream {
171        output
172    }
173}
174
175#[typle(Tuple for 1..=12)]
176pub enum TupleSequenceState<T>
177where
178    T: Tuple,
179    T<_>: Extract,
180{
181    S = typle_variant!(i in ..T::MAX =>
182        typle_for!(j in ..i => T::<{j}>::Output), Option<T<{i}>::State>
183    ),
184}
185
186pub struct TupleSequence<T> {
187    tuple: T,
188}
189
190#[typle(Tuple for 1..=12, never=std::convert::Infallible)]
191impl<T> Extract for TupleSequence<T>
192where
193    T: Tuple,
194    T<_>: Extract,
195{
196    // The state contains the output from all previous components and the state
197    // of the current component.
198    type State = TupleSequenceState<T<{ ..T::MAX }>>;
199    type Output = typle_for!(i in .. => <T<{i}> as Extract>::Output);
200
201    fn extract(
202        &self,
203        mut input: ByteStream,
204        state: Option<Self::State>,
205        last: bool,
206    ) -> ParseResult<Self::State, Self::Output> {
207        let default_position = input.position();
208        #[typle_attr_if(T::LEN == 1, allow(unused_mut))]
209        let mut state = state.unwrap_or(Self::State::S::<typle_ident!(0)>((), None));
210        for typle_index!(i) in 0..T::LEN {
211            if let Self::State::S::<typle_ident!(i)>(output, inner_state) = state {
212                match self.tuple[[i]].extract(input, inner_state, last) {
213                    ParseResult::NoMatch(position) => {
214                        return ParseResult::NoMatch(position);
215                    }
216                    ParseResult::Partial(inner_state) => {
217                        if last {
218                            return ParseResult::NoMatch(default_position);
219                        } else {
220                            return ParseResult::Partial(Self::State::S::<typle_ident!(i)>(
221                                output,
222                                Some(inner_state),
223                            ));
224                        }
225                    }
226                    ParseResult::Match(matched, remain) => {
227                        // Make an output (i+1)-tuple from the existing output i-tuple and `matched`
228                        let output = (output[[..i]], matched);
229                        input = remain;
230                        if typle_const!(i + 1 == T::LEN) {
231                            return ParseResult::Match(output, input);
232                        } else {
233                            state = Self::State::S::<typle_ident!(i + 1)>(output, None);
234                        }
235                    }
236                }
237            }
238        }
239        unreachable!();
240    }
241}
242
243#[typle(Tuple for 1..=12)]
244impl<T> Repeatable for TupleSequence<T>
245where
246    T: Tuple,
247    T<_>: Extract,
248{
249}
250
251#[typle(Tuple for 1..=12)]
252impl<T> OutputToByteStream for TupleSequence<T>
253where
254    T: Tuple,
255    T<_>: OutputToByteStream,
256{
257    fn output_to_bytestream(output: Self::Output) -> ByteStream {
258        #[typle_attr_if(T::LEN == 1, allow(unused_mut))]
259        let mut byte_stream = T::<0>::output_to_bytestream(output.0);
260        for typle_index!(i) in 1..T::LEN {
261            byte_stream.merge(T::<{ i }>::output_to_bytestream(output[[i]]));
262        }
263        byte_stream
264    }
265}
266
267pub trait ExtractTuple {
268    type TupleAny;
269    type TupleFirst;
270    type TupleSequence;
271
272    fn any(self) -> Self::TupleAny;
273
274    fn first(self) -> Self::TupleFirst;
275
276    fn seq(self) -> Self::TupleSequence;
277}
278
279#[typle(Tuple for 1..=12)]
280impl<T> ExtractTuple for T
281where
282    T: Tuple,
283    T<_>: Extract,
284{
285    type TupleAny = TupleAny<T>;
286    type TupleFirst = TupleFirst<T>;
287    type TupleSequence = TupleSequence<T>;
288
289    fn any(self) -> Self::TupleAny {
290        TupleAny { tuple: self }
291    }
292
293    fn first(self) -> Self::TupleFirst {
294        TupleFirst { tuple: self }
295    }
296
297    fn seq(self) -> Self::TupleSequence {
298        TupleSequence { tuple: self }
299    }
300}
301
302#[cfg(test)]
303mod tests {
304    use crate::byte_stream::ByteStream;
305    use crate::repeatable::Repeatable;
306    use crate::{Extract, ExtractTuple, ParseResult, ParseWhen};
307
308    #[test]
309    fn test_sequence() {
310        let input = ByteStream::from("hello3a");
311        let ParseResult::Match((out1, out2, out3), input) = (
312            "hello",
313            char::when(|c: char| c.is_ascii_digit()),
314            char::when(char::is_alphabetic),
315        )
316            .seq()
317            .extract(input, None, true)
318        else {
319            panic!()
320        };
321        assert_eq!(out1.to_string(), "hello");
322        assert_eq!(out2.to_string(), "3");
323        assert_eq!(out3.to_string(), "a");
324        assert!(input.is_empty());
325
326        let mut buffer = ByteStream::from("hello3a");
327        let input = buffer.take_before(3);
328        let ParseResult::Partial(state) = ("hello", char::when(char::is_alphabetic))
329            .seq()
330            .extract(input, None, false)
331        else {
332            panic!()
333        };
334        let ParseResult::NoMatch(5) =
335            ("hello", char::when(char::is_alphabetic))
336                .seq()
337                .extract(buffer, Some(state), false)
338        else {
339            panic!()
340        };
341    }
342
343    #[test]
344    fn test_optional_sequence() {
345        let input = ByteStream::from("hello, world!");
346        let ParseResult::Match((out1, out2), input) =
347            ("hello", char::when(|c: char| c.is_ascii_digit()))
348                .seq()
349                .optional()
350                .extract(input, None, true)
351        else {
352            panic!()
353        };
354        assert!(out1.is_empty());
355        assert!(out2.is_empty());
356        assert_eq!(input.to_string(), "hello, world!");
357
358        let ParseResult::Match((out1, out2), input) = ("hello, ", "world!")
359            .seq()
360            .optional()
361            .extract(input, None, true)
362        else {
363            panic!()
364        };
365        assert_eq!(out1.to_string(), "hello, ");
366        assert_eq!(out2.to_string(), "world!");
367        assert!(input.is_empty());
368    }
369
370    #[test]
371    fn test_any() {
372        let input = ByteStream::from("hello3a");
373        let ParseResult::Match(output, input) = ("hello", char::when(|c: char| c.is_ascii_digit()))
374            .any()
375            .extract(input, None, false)
376        else {
377            panic!()
378        };
379        assert_eq!(output.to_string(), "hello");
380        let ParseResult::Match(output, input) = ("hello", char::when(|c: char| c.is_ascii_digit()))
381            .any()
382            .extract(input, None, true)
383        else {
384            panic!()
385        };
386        assert_eq!(output.to_string(), "3");
387        assert_eq!(input.to_string(), "a");
388    }
389
390    #[test]
391    fn test_first() {
392        let input = ByteStream::from("hello3a");
393        let ParseResult::Match(output, input) = ("hello", char::when(|c: char| c.is_ascii_digit()))
394            .first()
395            .extract(input, None, false)
396        else {
397            panic!()
398        };
399        assert_eq!(output.to_string(), "hello");
400        let ParseResult::Match(output, input) = ("hello", char::when(|c: char| c.is_ascii_digit()))
401            .first()
402            .extract(input, None, true)
403        else {
404            panic!()
405        };
406        assert_eq!(output.to_string(), "3");
407        assert_eq!(input.to_string(), "a");
408    }
409
410    // any() finds the matching alphabetic character, even though "hello" might
411    // eventually match.
412    #[test]
413    fn test_precedence_any() {
414        let mut buffer = ByteStream::from("hello3a");
415        let input = buffer.take_before(3);
416        let ParseResult::Match(output, input) = ("hello", char::when(char::is_alphabetic))
417            .any()
418            .extract(input, None, false)
419        else {
420            panic!()
421        };
422        assert_eq!(output.to_string(), "h");
423        assert_eq!(input.to_string(), "el");
424    }
425
426    // first() finds "hello" because it is first in the tuple even though the alphabetic character
427    // pattern matches earlier.
428    #[test]
429    fn test_precedence_first() {
430        let mut buffer = ByteStream::from("hello3a");
431        let input = buffer.take_before(3);
432        let ParseResult::Partial(state) = ("hello", char::when(char::is_alphabetic))
433            .first()
434            .extract(input, None, false)
435        else {
436            panic!()
437        };
438        let ParseResult::Match(output, input) = ("hello", char::when(char::is_alphabetic))
439            .first()
440            .extract(buffer, Some(state), false)
441        else {
442            panic!()
443        };
444        assert_eq!(output.to_string(), "hello");
445        assert_eq!(input.to_string(), "3a");
446    }
447}