Skip to main content

winnow/macros/
unordered_seq.rs

1/// Initialize a struct or tuple out of an unordered sequences of parsers
2///
3/// Unlike normal struct initialization syntax:
4/// - `_` fields can exist to run a parser but ignore the result
5/// - Parse results for a field can later be referenced using the field name
6///
7/// Unlike normal tuple initialization syntax:
8/// - Struct-style initialization (`{ 0: _, 1: _}`) is not supported
9/// - `_: <parser>` fields can exist to run a parser but ignore the result
10///
11/// To stop on an error, rather than trying further permutations, see
12/// [`cut_err`][crate::combinator::cut_err] ([example][crate::_tutorial::chapter_7]).
13///
14/// # Example
15///
16/// ```rust
17/// # #[cfg(feature = "ascii")] {
18/// # use winnow::{error::ErrMode, error::Needed};
19/// # use winnow::prelude::*;
20/// use winnow::ascii::{alpha1, digit1};
21/// use winnow::combinator::unordered_seq;
22/// fn parser<'i>(input: &mut &'i str) -> ModalResult<(&'i str, &'i str)> {
23///   unordered_seq!((alpha1, digit1)).parse_next(input)
24/// }
25///
26/// // permutation takes alphabetic characters then digit
27/// assert_eq!(parser.parse_peek("abc123"), Ok(("", ("abc", "123"))));
28///
29/// // but also in inverse order
30/// assert_eq!(parser.parse_peek("123abc"), Ok(("", ("abc", "123"))));
31///
32/// // it will fail if one of the parsers failed
33/// assert!(parser.parse_peek("abc;").is_err());
34/// # }
35/// ```
36///
37/// The parsers are applied greedily: if there are multiple unapplied parsers
38/// that could parse the next slice of input, the first one is used.
39/// ```rust
40/// # #[cfg(feature = "parser")] {
41/// # use winnow::error::ErrMode;
42/// # use winnow::prelude::*;
43/// use winnow::combinator::unordered_seq;
44/// use winnow::token::any;
45///
46/// fn parser(input: &mut &str) -> ModalResult<(char, char)> {
47///   unordered_seq!((any, 'a')).parse_next(input)
48/// }
49///
50/// // any parses 'b', then char('a') parses 'a'
51/// assert_eq!(parser.parse_peek("ba"), Ok(("", ('b', 'a'))));
52///
53/// // any parses 'a', then char('a') fails on 'b',
54/// // even though char('a') followed by any would succeed
55/// assert!(parser.parse_peek("ab").is_err());
56/// # }
57/// ```
58#[macro_export]
59#[doc(alias = "permutation")]
60#[doc(hidden)] // forced to be visible in intended location
61macro_rules! unordered_seq {
62    ($($name: ident)::* { $($fields: tt)* }) => {
63        $crate::combinator::trace(stringify!($($name)::*), move |input: &mut _| {
64            $crate::unordered_seq_parse_struct_body!(
65                ( $($name)::* );
66                ( $($fields)* );
67                ( _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20 );
68                ( input );
69            )
70        })
71    };
72    (( $($fields: tt)* )) => {
73        $crate::combinator::trace("tuple", move |input: &mut _| {
74            $crate::unordered_seq_parse_tuple_body!(
75                ( );
76                ( $($fields)* );
77                ( _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20 );
78                ( input );
79            )
80        })
81    };
82    ($($name: ident)::* ( $($fields: tt)* )) => {
83        $crate::combinator::trace(stringify!($($name)::*), move |input: &mut _| {
84            $crate::unordered_seq_parse_tuple_body!(
85                ( $($name)::* );
86                ( $($fields)* );
87                ( _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20 );
88                ( input );
89            )
90        })
91    };
92    ($($fields: tt)*) => {
93        $crate::unordered_seq!((
94            $($fields)*
95        ))
96    };
97}
98
99#[macro_export]
100#[doc(hidden)]
101macro_rules! unordered_seq_parse_struct_body {
102    (
103        ( $($name: ident)::* );
104        ( $($fields: tt)* );
105        ( $($unnamed: ident),* );
106        ( $input: expr );
107    ) => {{
108        // Workaround a type inference issue by hinting to the compiler `I` within `ParserError` calls
109        fn recover_err<I, E>(_input: &I, curr: E, acc: &mut Option<E>) -> Option<E>
110        where
111            I: $crate::stream::Stream,
112            E: $crate::error::ParserError<I>,
113        {
114            if $crate::error::ParserError::is_backtrack(&curr) {
115                *acc = Some(match acc.take() {
116                    Some(err) => $crate::error::ParserError::or(err, curr),
117                    None => curr,
118                });
119                None
120            } else {
121                Some(curr)
122            }
123        }
124
125        $crate::unordered_seq_parse_struct_init!(
126            ( $($fields)* );
127            ( $($unnamed),* );
128        );
129
130        loop {
131            let mut err = ::core::option::Option::None;
132            let start = $crate::stream::Stream::checkpoint($input);
133
134            $crate::unordered_seq_parse_struct_each!(
135                ( $($fields)* );
136                ( $($unnamed),* );
137                ( $input );
138                ( start );
139                ( err );
140            );
141
142            // If we reach here, every iterator has either been applied before,
143            // or errored on the remaining input
144            if let ::core::option::Option::Some(err) = err {
145                // There are remaining parsers, and all errored on the remaining input
146                break Err($crate::error::ParserError::append(err, $input, &start));
147            }
148
149            // All parsers were applied
150            break Ok(
151                $crate::unordered_seq_parse_struct_collect!(
152                    ( $($fields)* );
153                    ( $($unnamed),* );
154                    ( $($name)::* );
155                )
156            );
157        }
158    }}
159}
160
161#[macro_export]
162#[doc(hidden)]
163macro_rules! unordered_seq_parse_struct_init {
164    (
165        ( _ : $head_parser: expr, $($fields: tt)* );
166        ( $unnamed1: ident, $($unnamed: ident),* );
167    ) => {
168        let mut $unnamed1 = ::core::option::Option::None;
169        $crate::unordered_seq_parse_struct_init!(
170            ( $($fields)* );
171            ( $($unnamed),* );
172        );
173    };
174    (
175        ( $named: ident : $head_parser: expr, $($fields: tt)* );
176        ( $unnamed1: ident, $($unnamed: ident),* );
177    ) => {
178        let mut $named = ::core::option::Option::None;
179        $crate::unordered_seq_parse_struct_init!(
180            ( $($fields)* );
181            ( $($unnamed),* );
182        );
183    };
184    (
185        ( _ : $head_parser: expr );
186        ( $unnamed1: ident, $($unnamed: ident),* );
187    ) => {
188        let mut $unnamed1 = ::core::option::Option::None;
189    };
190    (
191        ( $named: ident : $head_parser: expr );
192        ( $unnamed1: ident, $($unnamed: ident),* );
193    ) => {
194        let mut $named = ::core::option::Option::None;
195    };
196    (
197        ( .. $update: expr  $(,)? );
198        ( $($unnamed: ident),* );
199    ) => {
200    };
201    (
202        ( $(,)? );
203        ( $($unnamed: ident),* );
204    ) => {
205    };
206}
207
208#[macro_export]
209#[doc(hidden)]
210macro_rules! unordered_seq_parse_struct_collect {
211    (
212        ( $(,)? );
213        ( $($unnamed: ident),* );
214        ( $($name: ident)::* );
215        $($inits: tt)*
216    ) => {
217        $($name)::* { $($inits)* }
218    };
219    (
220        ( .. $update: expr $(,)? );
221        ( $unnamed1: ident, $($unnamed: ident),* );
222        ( $($name: ident)::* );
223        $($inits: tt)*
224    ) => {
225       $crate::unordered_seq_parse_struct_collect!(
226            ( , );
227            ( $($unnamed),* );
228            ( $($name)::* );
229            $($inits)* .. $update
230        )
231    };
232    (
233        ( _ : $head_parser: expr );
234        ( $unnamed1: ident, $($unnamed: ident),* );
235        ( $($name: ident)::* );
236        $($inits: tt)*
237    ) => {
238        $crate::unordered_seq_parse_struct_collect!(
239            ( , );
240            ( $($unnamed),* );
241            ( $($name)::* );
242            $($inits)*
243        )
244    };
245    (
246        ( _ : $head_parser: expr, $($fields: tt)* );
247        ( $unnamed1: ident, $($unnamed: ident),* );
248        ( $($name: ident)::* );
249        $($inits: tt)*
250    ) => {
251        $crate::unordered_seq_parse_struct_collect!(
252            ( $($fields)* );
253            ( $($unnamed),* );
254            ( $($name)::* );
255            $($inits)*
256        )
257    };
258    (
259        ( $named: ident : $head_parser: expr );
260        ( $unnamed1: ident, $($unnamed: ident),* );
261        ( $($name: ident)::* );
262        $($inits: tt)*
263    ) => {
264        $crate::unordered_seq_parse_struct_collect!(
265            ( , );
266            ( $($unnamed),* );
267            ( $($name)::* );
268            $($inits)* $named: $named.unwrap(),
269        )
270    };
271    (
272        ( $named: ident : $head_parser: expr, $($fields: tt)* );
273        ( $unnamed1: ident, $($unnamed: ident),* );
274        ( $($name: ident)::* );
275        $($inits: tt)*
276    ) => {
277        $crate::unordered_seq_parse_struct_collect!(
278            ( $($fields)* );
279            ( $($unnamed),* );
280            ( $($name)::* );
281            $($inits)* $named: $named.unwrap(),
282        )
283    };
284}
285
286#[macro_export]
287#[doc(hidden)]
288macro_rules! unordered_seq_parse_struct_each(
289    (
290        ( _ : $head_parser: expr $(,)? );
291        ( $unnamed1: ident, $($unnamed: ident),* );
292        ( $input: expr );
293        ( $start: expr );
294        ( $err: expr );
295    ) => (
296        $crate::unordered_seq_parse_next!(
297            ( $head_parser );
298            ( $unnamed1 );
299            ( $input );
300            ( $start );
301            ( $err );
302        );
303    );
304    (
305        ( $named: ident : $head_parser: expr $(,)? );
306        ( $unnamed1: ident, $($unnamed: ident),* );
307        ( $input: expr );
308        ( $start: expr );
309        ( $err: expr );
310    ) => (
311        $crate::unordered_seq_parse_next!(
312            ( $head_parser );
313            ( $named );
314            ( $input );
315            ( $start );
316            ( $err );
317        );
318    );
319    (
320        ( _ : $head_parser: expr, $($fields: tt)* );
321        ( $unnamed1: ident, $($unnamed: ident),* );
322        ( $input: expr );
323        ( $start: expr );
324        ( $err: expr );
325    ) => (
326        $crate::unordered_seq_parse_next!(
327            ( $head_parser );
328            ( $unnamed1 );
329            ( $input );
330            ( $start );
331            ( $err );
332        );
333        $crate::unordered_seq_parse_struct_each!(
334            ( $($fields)* );
335            ( $($unnamed),* );
336            ( $input );
337            ( $start );
338            ( $err );
339        );
340    );
341    (
342        ( $named: ident : $head_parser: expr, $($fields: tt)* );
343        ( $unnamed1: ident, $($unnamed: ident),* );
344        ( $input: expr );
345        ( $start: expr );
346        ( $err: expr );
347    ) => (
348        $crate::unordered_seq_parse_next!(
349            ( $head_parser );
350            ( $named );
351            ( $input );
352            ( $start );
353            ( $err );
354        );
355        $crate::unordered_seq_parse_struct_each!(
356            ( $($fields)* );
357            ( $($unnamed),* );
358            ( $input );
359            ( $start );
360            ( $err );
361        );
362    );
363    (
364        ( .. $update: expr $(,)? );
365        ( $unnamed1: ident, $($unnamed: ident),* );
366        ( $input: expr );
367        ( $start: expr );
368        ( $err: expr );
369    ) => (
370    );
371);
372
373#[macro_export]
374#[doc(hidden)]
375macro_rules! unordered_seq_parse_tuple_body {
376    (
377        ( $($name: ident)::* );
378        ( $($fields: tt)* );
379        ( $($unnamed: ident),* );
380        ( $input: expr );
381    ) => {{
382        // Workaround a type inference issue by hinting to the compiler `I` within `ParserError` calls
383        fn recover_err<I, E>(_input: &I, curr: E, acc: &mut Option<E>) -> Option<E>
384        where
385            I: $crate::stream::Stream,
386            E: $crate::error::ParserError<I>,
387        {
388            if $crate::error::ParserError::is_backtrack(&curr) {
389                *acc = Some(match acc.take() {
390                    Some(err) => $crate::error::ParserError::or(err, curr),
391                    None => curr,
392                });
393                None
394            } else {
395                Some(curr)
396            }
397        }
398
399        $crate::unordered_seq_parse_tuple_init!(
400            ( $($fields)* );
401            ( $($unnamed),* );
402        );
403
404        loop {
405            let mut err = ::core::option::Option::None;
406            let start = $crate::stream::Stream::checkpoint($input);
407
408            $crate::unordered_seq_parse_tuple_each!(
409                ( $($fields)* );
410                ( $($unnamed),* );
411                ( $input );
412                ( start );
413                ( err );
414            );
415
416            // If we reach here, every iterator has either been applied before,
417            // or errored on the remaining input
418            if let ::core::option::Option::Some(err) = err {
419                // There are remaining parsers, and all errored on the remaining input
420                break Err($crate::error::ParserError::append(err, $input, &start));
421            }
422
423            // All parsers were applied
424            break Ok(
425                $crate::unordered_seq_parse_tuple_collect!(
426                    ( $($fields)* );
427                    ( $($unnamed),* );
428                    ( $($name)::* );
429                )
430            );
431        }
432    }}
433}
434
435#[macro_export]
436#[doc(hidden)]
437macro_rules! unordered_seq_parse_tuple_init {
438    (
439        ( $(_ :)? $head_parser: expr, $($fields: tt)* );
440        ( $unnamed1: ident, $($unnamed: ident),* );
441    ) => {
442        let mut $unnamed1 = ::core::option::Option::None;
443        $crate::unordered_seq_parse_tuple_init!(
444            ( $($fields)* );
445            ( $($unnamed),* );
446        );
447    };
448    (
449        ( $(_ :)? $head_parser: expr );
450        ( $unnamed1: ident, $($unnamed: ident),* );
451    ) => {
452        let mut $unnamed1 = ::core::option::Option::None;
453    };
454    (
455        ( $(,)? );
456        ( $($unnamed: ident),* );
457    ) => {
458    };
459}
460
461#[macro_export]
462#[doc(hidden)]
463macro_rules! unordered_seq_parse_tuple_collect {
464    (
465        ( $(,)? );
466        ( $($unnamed: ident),* );
467        ( $($name: ident)::* );
468        $($inits: tt)*
469    ) => {
470        $($name)::* ( $($inits)* )
471    };
472    (
473        ( _ : $head_parser: expr );
474        ( $unnamed1: ident, $($unnamed: ident),* );
475        ( $($name: ident)::* );
476        $($inits: tt)*
477    ) => {
478        $crate::unordered_seq_parse_tuple_collect!(
479            ( , );
480            ( $($unnamed),* );
481            ( $($name)::* );
482            $($inits)*
483        )
484    };
485    (
486        ( _ : $head_parser: expr, $($fields: tt)* );
487        ( $unnamed1: ident, $($unnamed: ident),* );
488        ( $($name: ident)::* );
489        $($inits: tt)*
490    ) => {
491        $crate::unordered_seq_parse_tuple_collect!(
492            ( $($fields)* );
493            ( $($unnamed),* );
494            ( $($name)::* );
495            $($inits)*
496        )
497    };
498    (
499        ( $head_parser: expr );
500        ( $unnamed1: ident, $($unnamed: ident),* );
501        ( $($name: ident)::* );
502        $($inits: tt)*
503    ) => {
504        $crate::unordered_seq_parse_tuple_collect!(
505            ( , );
506            ( $($unnamed),* );
507            ( $($name)::* );
508            $($inits)* $unnamed1.unwrap(),
509        )
510    };
511    (
512        ( $head_parser: expr, $($fields: tt)* );
513        ( $unnamed1: ident, $($unnamed: ident),* );
514        ( $($name: ident)::* );
515        $($inits: tt)*
516    ) => {
517        $crate::unordered_seq_parse_tuple_collect!(
518            ( $($fields)* );
519            ( $($unnamed),* );
520            ( $($name)::* );
521            $($inits)* $unnamed1.unwrap(),
522        )
523    };
524}
525
526#[macro_export]
527#[doc(hidden)]
528macro_rules! unordered_seq_parse_tuple_each(
529    (
530        ( $(_ :)? $head_parser: expr $(,)? );
531        ( $unnamed1: ident, $($unnamed: ident),* );
532        ( $input: expr );
533        ( $start: expr );
534        ( $err: expr );
535    ) => (
536        $crate::unordered_seq_parse_next!(
537            ( $head_parser );
538            ( $unnamed1 );
539            ( $input );
540            ( $start );
541            ( $err );
542        );
543    );
544    (
545        ( $(_ :)? $head_parser: expr, $($fields: tt)* );
546        ( $unnamed1: ident, $($unnamed: ident),* );
547        ( $input: expr );
548        ( $start: expr );
549        ( $err: expr );
550    ) => (
551        $crate::unordered_seq_parse_next!(
552            ( $head_parser );
553            ( $unnamed1 );
554            ( $input );
555            ( $start );
556            ( $err );
557        );
558        $crate::unordered_seq_parse_tuple_each!(
559            ( $($fields)* );
560            ( $($unnamed),* );
561            ( $input );
562            ( $start );
563            ( $err );
564        );
565    );
566);
567
568#[macro_export]
569#[doc(hidden)]
570macro_rules! unordered_seq_parse_next(
571    (
572        ( $field: tt );
573        ( $unnamed: ident );
574        ( $input: expr );
575        ( $start: expr );
576        ( $err: expr );
577    ) => (
578        if $unnamed.is_none() {
579            $crate::stream::Stream::reset($input, &$start);
580
581            match $crate::Parser::parse_next(&mut $field, $input) {
582                Ok(o) => {
583                    $unnamed = Some(o);
584                    continue;
585                }
586                Err(e) => {
587                    if let Some(cut) = recover_err($input, e, &mut $err) {
588                        return Err(cut);
589                    }
590                }
591            };
592        }
593    );
594);