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