winnow/macros/
seq.rs

1/// Initialize a struct or tuple out of a sequences of parsers
2///
3///# Example
4///
5/// ```
6/// # use winnow::prelude::*;
7/// # use winnow::ascii::{alphanumeric1, dec_uint, space0};
8/// # use winnow::combinator::delimited;
9/// # use winnow::combinator::empty;
10/// # use winnow::error::ContextError;
11/// use winnow::combinator::seq;
12///
13/// #[derive(Default, Debug, PartialEq)]
14/// struct Field {
15///     namespace: u32,
16///     name: Vec<u8>,
17///     value: Vec<u8>,
18///     point: (u32, u32),
19///     metadata: Vec<u8>,
20/// }
21///
22/// // Parse into structs / tuple-structs
23/// fn field(input: &mut &[u8]) -> PResult<Field> {
24///     seq!{Field {
25///         namespace: empty.value(5),
26///         name: alphanumeric1.map(|s: &[u8]| s.to_owned()),
27///         // `_` fields are ignored when building the struct
28///         _: (space0, b':', space0),
29///         value: alphanumeric1.map(|s: &[u8]| s.to_owned()),
30///         _: (space0, b':', space0),
31///         point: point,
32///         // default initialization also works
33///         ..Default::default()
34///     }}.parse_next(input)
35/// }
36///
37/// // Or parse into tuples
38/// fn point(input: &mut &[u8]) -> PResult<(u32, u32)> {
39///     let num = dec_uint::<_, u32, ContextError>;
40///     seq!(num, _: (space0, b',', space0), num).parse_next(input)
41/// }
42///
43/// assert_eq!(
44///     field.parse_peek(&b"test: data: 123 , 4"[..]),
45///     Ok((
46///         &b""[..],
47///         Field {
48///             namespace: 5,
49///             name: b"test"[..].to_owned(),
50///             value: b"data"[..].to_owned(),
51///             point: (123, 4),
52///             metadata: Default::default(),
53///         },
54///     )),
55/// );
56/// ```
57#[macro_export]
58#[doc(alias = "tuple")]
59#[doc(alias = "preceded")]
60#[doc(alias = "terminated")]
61#[doc(alias = "delimited")]
62#[doc(alias = "pair")]
63#[doc(alias = "separated_pair")]
64#[doc(alias = "struct_parser")]
65macro_rules! seq {
66    ($name: ident { $($fields: tt)* }) => {
67        $crate::combinator::trace(stringify!($name), move |input: &mut _| {
68            use $crate::Parser;
69            $crate::seq_parse_struct_fields!(input; $($fields)*);
70            #[allow(clippy::redundant_field_names)]
71            Ok($crate::seq_init_struct_fields!( ($($fields)*); $name;))
72        })
73    };
74    ($name: ident ( $($elements: tt)* )) => {
75        $crate::combinator::trace(stringify!($name), move |input: &mut _| {
76            use $crate::Parser;
77            $crate::seq_parse_tuple_fields!( ($($elements)*) ; ).map(|t| {
78                $crate::seq_init_tuple_fields!(
79                    ($($elements)*);
80                    (t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16, t.17, t.18, t.19, t.20);
81                    $name;
82                )
83            }).parse_next(input)
84        })
85    };
86    (( $($elements: tt)* )) => {
87        $crate::combinator::trace("tuple", move |input: &mut _| {
88            use $crate::Parser;
89            $crate::seq_parse_tuple_fields!( ($($elements)*) ; ).map(|t| {
90                $crate::seq_init_tuple_fields!(
91                    ($($elements)*);
92                    (t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16, t.17, t.18, t.19, t.20);
93                    ;
94                )
95            }).parse_next(input)
96        })
97    };
98    ($($elements: tt)*) => {
99        $crate::seq!(($($elements)*))
100    };
101}
102
103#[macro_export]
104#[doc(hidden)]
105macro_rules! seq_parse_struct_fields {
106    (
107        $input: ident;
108        _ : $head_parser: expr, $($fields: tt)*
109    ) => {
110        let _ = $head_parser.parse_next($input)?;
111        $crate::seq_parse_struct_fields!($input; $($fields)*)
112    };
113    (
114        $input: ident;
115        _ : $head_parser: expr
116    ) => {
117        let _ = $head_parser.parse_next($input)?;
118    };
119    (
120        $input: ident;
121        $head_field: ident : $head_parser: expr, $($fields: tt)*
122    ) => {
123        let $head_field = $head_parser.parse_next($input)?;
124        $crate::seq_parse_struct_fields!($input; $($fields)*)
125    };
126    (
127        $input: ident;
128        $head_field: ident : $head_parser: expr
129    ) => {
130        let $head_field = $head_parser.parse_next($input)?;
131    };
132    (
133        $input: expr;
134        .. $update: expr
135    ) => {};
136    (
137        $input: expr;
138        $(,)?
139    ) => {};
140}
141
142#[macro_export]
143#[doc(hidden)]
144macro_rules! seq_parse_tuple_fields {
145    (
146        (_ : $head_parser: expr, $($fields: tt)* );
147        $($sequenced: tt)*
148    ) => {
149        $crate::seq_parse_tuple_fields!( ( $($fields)* ) ; $($sequenced)* $head_parser.void(), )
150    };
151    (
152        (_ : $head_parser: expr);
153        $($sequenced: tt)*
154    ) => {
155        $crate::seq_parse_tuple_fields!((); $($sequenced)* $head_parser.void(), )
156    };
157    (
158        ($head_parser: expr, $($fields: tt)*);
159        $($sequenced: tt)*
160    ) => {
161        $crate::seq_parse_tuple_fields!( ( $($fields)* ) ; $($sequenced)* $head_parser, )
162    };
163    (
164        ($head_parser: expr);
165        $($sequenced: tt)*
166    )=> {
167        $crate::seq_parse_tuple_fields!((); $($sequenced)* $head_parser, )
168    };
169    (
170        ();
171        $($sequenced: tt)*
172    ) => {
173        ($($sequenced)*)
174    };
175}
176
177#[macro_export]
178#[doc(hidden)]
179macro_rules! seq_init_struct_fields {
180    (
181        (_ : $head_parser: expr, $($fields: tt)*);
182        $name: ident;
183        $($inits: tt)*
184    ) => {
185        $crate::seq_init_struct_fields!( ( $($fields)* ) ; $name ; $($inits)* )
186    };
187    (
188        (_ : $head_parser: expr);
189        $name: ident;
190        $($inits: tt)*
191    ) => {
192        $crate::seq_init_struct_fields!( (); $name ; $($inits)* )
193    };
194    (
195        ($head_field: ident : $head_parser: expr, $($fields: tt)*);
196        $name: ident;
197        $($inits: tt)*
198    ) =>
199    {
200        $crate::seq_init_struct_fields!( ( $($fields)* ) ; $name ; $($inits)* $head_field: $head_field, )
201    };
202    (
203        ($head_field: ident : $head_parser: expr);
204        $name: ident;
205        $($inits: tt)*
206    ) => {
207        $crate::seq_init_struct_fields!( (); $name ; $($inits)* $head_field: $head_field,)
208    };
209    (
210        (.. $update: expr);
211        $name: ident;
212        $($inits: tt)*
213    ) => {
214        $name { $($inits)* ..$update }
215    };
216    (
217        ($(,)?);
218        $name: ident;
219        $($inits: tt)*
220    ) => {
221        $name { $($inits)* }
222    };
223}
224
225#[macro_export]
226#[doc(hidden)]
227macro_rules! seq_init_tuple_fields {
228    (
229        (_ : $head_parser: expr, $($fields: tt)*);
230        ($head_arg: expr, $($args: expr),*);
231        $($name: ident)?;
232        $($inits: tt)*
233    ) => {
234        $crate::seq_init_tuple_fields!( ( $($fields)* ); ( $($args),* ) ; $($name)? ; $($inits)* )
235    };
236    (
237        (_ : $head_parser: expr);
238        ($head_arg: expr, $($args: expr),*);
239        $($name: ident)?;
240        $($inits: tt)*
241    ) => {
242        $crate::seq_init_tuple_fields!((); ( $($args),* ); $($name)? ; $($inits)*)
243    };
244    (
245        ($head_parser: expr, $($fields: tt)*);
246        ($head_arg: expr, $($args: expr),*);
247        $($name: ident)?;
248        $($inits: tt)*
249    ) => {
250        $crate::seq_init_tuple_fields!( ( $($fields)* ) ; ( $($args),* ) ; $($name)? ; $($inits)* $head_arg, )
251    };
252    (
253        ($head_parser: expr);
254        ($head_arg: expr, $($args: expr),*);
255        $($name: ident)?;
256        $($inits: tt)*
257    ) => {
258        $crate::seq_init_tuple_fields!((); ( $($args),* ); $($name)? ; $($inits)* $head_arg)
259    };
260    (
261        ();
262        ($($args: expr),*);
263        $($name: ident)?;
264        $($inits: expr),* $(,)?
265    ) => {
266        $($name)?( $($inits,)* )
267    };
268}