Skip to main content

winnow/macros/
seq.rs

1/// Initialize a struct or tuple out of a 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///# Example
12///
13/// ```
14/// # #[cfg(feature = "ascii")] {
15/// # use winnow::prelude::*;
16/// # use winnow::ascii::{alphanumeric1, dec_uint, space0};
17/// # use winnow::combinator::delimited;
18/// # use winnow::combinator::empty;
19/// # use winnow::error::ContextError;
20/// # use winnow::error::ErrMode;
21/// use winnow::combinator::seq;
22///
23/// #[derive(Default, Debug, PartialEq)]
24/// struct Field {
25///     namespace: u32,
26///     name: Vec<u8>,
27///     value: Vec<u8>,
28///     point: (u32, u32),
29///     metadata: Vec<u8>,
30/// }
31///
32/// // Parse into structs / tuple-structs
33/// fn field(input: &mut &[u8]) -> ModalResult<Field> {
34///     seq!{Field {
35///         namespace: empty.value(5),
36///         name: alphanumeric1.map(|s: &[u8]| s.to_owned()),
37///         // `_` fields are ignored when building the struct
38///         _: (space0, b':', space0),
39///         value: alphanumeric1.map(|s: &[u8]| s.to_owned()),
40///         _: (space0, b':', space0),
41///         point: point,
42///         // default initialization also works
43///         ..Default::default()
44///     }}.parse_next(input)
45/// }
46///
47/// // Or parse into tuples
48/// fn point(input: &mut &[u8]) -> ModalResult<(u32, u32)> {
49///     let mut num = dec_uint::<_, u32, ErrMode<ContextError>>;
50///     seq!(num, _: (space0, b',', space0), num).parse_next(input)
51/// }
52///
53/// assert_eq!(
54///     field.parse_peek(&b"test: data: 123 , 4"[..]),
55///     Ok((
56///         &b""[..],
57///         Field {
58///             namespace: 5,
59///             name: b"test"[..].to_owned(),
60///             value: b"data"[..].to_owned(),
61///             point: (123, 4),
62///             metadata: Default::default(),
63///         },
64///     )),
65/// );
66/// # }
67/// ```
68#[macro_export]
69#[doc(alias = "tuple")]
70#[doc(alias = "preceded")]
71#[doc(alias = "terminated")]
72#[doc(alias = "delimited")]
73#[doc(alias = "pair")]
74#[doc(alias = "separated_pair")]
75#[doc(alias = "struct_parser")]
76#[doc(hidden)] // forced to be visible in intended location
77macro_rules! seq {
78    ($($name: ident)::* { $($fields: tt)* }) => {
79        $crate::combinator::trace(stringify!($($name)::*), move |input: &mut _| {
80            $crate::seq_parse_struct_fields!(
81                ( $($fields)* );
82                ( _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20 );
83                input ;
84            );
85            Ok($crate::seq_init_struct_fields!(
86                ( $($fields)* );
87                $($name)::* ;
88            ))
89        })
90    };
91    ($($name: ident)::* ( $($fields: tt)* )) => {
92        $crate::combinator::trace(stringify!($($name)::*), move |input: &mut _| {
93            $crate::seq_parse_tuple_fields!(
94                ( $($fields)* );
95                ( _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20 );
96                input;
97            );
98            Ok($crate::seq_init_tuple_fields!(
99                ( $($fields)* );
100                ( _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20 );
101                $($name)::*;
102            ))
103        })
104    };
105    (( $($fields: tt)* )) => {
106        $crate::combinator::trace("tuple", move |input: &mut _| {
107            $crate::seq_parse_tuple_fields!(
108                ( $($fields)* );
109                ( _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20 );
110                input;
111            );
112            Ok($crate::seq_init_tuple_fields!(
113                ( $($fields)* );
114                ( _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20 );
115                ;
116            ))
117        })
118    };
119    ($($fields: tt)*) => {
120        $crate::seq!((
121            $($fields)*
122        ))
123    };
124}
125
126#[macro_export]
127#[doc(hidden)]
128macro_rules! seq_parse_struct_fields {
129    (
130        ( _ : $head_parser: expr, $($fields: tt)* );
131        ( $unnamed1: ident, $($unnamed: ident),* );
132        $input: ident ;
133    ) => {
134        let $unnamed1 = $crate::Parser::parse_next(&mut $head_parser, $input)?;
135        $crate::seq_parse_struct_fields!(
136            ( $($fields)* );
137            ( $($unnamed),* );
138            $input ;
139        )
140    };
141    (
142        ( _ : $head_parser: expr );
143        ( $unnamed1: ident, $($unnamed: ident),* );
144        $input: ident ;
145    ) => {
146        let $unnamed1 = $crate::Parser::parse_next(&mut $head_parser, $input)?;
147    };
148    (
149        ( $head_field: ident : $head_parser: expr, $($fields: tt)* );
150        ( $unnamed1: ident, $($unnamed: ident),* );
151        $input: ident ;
152    ) => {
153        let $head_field = $crate::Parser::parse_next(&mut $head_parser, $input)?;
154        $crate::seq_parse_struct_fields!(
155            ( $($fields)* );
156            ( $($unnamed),* );
157            $input ;
158        )
159    };
160    (
161        ( $head_field: ident : $head_parser: expr );
162        ( $unnamed1: ident, $($unnamed: ident),* );
163        $input: ident ;
164    ) => {
165        let $head_field = $crate::Parser::parse_next(&mut $head_parser, $input)?;
166    };
167    (
168        ( .. $update: expr );
169        ( $($unnamed: ident),* );
170        $input: expr ;
171    ) => {};
172    (
173        ( $(,)? );
174        ( $($unnamed: ident),* );
175        $input: expr ;
176    ) => {};
177}
178
179#[macro_export]
180#[doc(hidden)]
181macro_rules! seq_parse_tuple_fields {
182    (
183        ( $(_ :)? $head_parser: expr, $($fields: tt)* );
184        ( $unnamed1: ident, $($unnamed: ident),* );
185        $input: ident;
186    ) => {
187        let $unnamed1 = $crate::Parser::parse_next(&mut $head_parser, $input)?;
188        $crate::seq_parse_tuple_fields!(
189            ( $($fields)* );
190            ( $($unnamed),* );
191            $input ;
192        )
193    };
194    (
195        ( $(_ :)? $head_parser: expr );
196        ( $unnamed1: ident, $($unnamed: ident),* );
197        $input: ident;
198    ) => {
199        let $unnamed1 = $crate::Parser::parse_next(&mut $head_parser, $input)?;
200    };
201    (
202        ( $(,)? );
203        ( $($unnamed: ident),* );
204        $input: expr;
205    ) => {};
206}
207
208#[macro_export]
209#[doc(hidden)]
210macro_rules! seq_init_struct_fields {
211    (
212        ( _ : $head_parser: expr, $($fields: tt)* );
213        $($name: ident)::* ;
214        $($inits: tt)*
215    ) => {
216        $crate::seq_init_struct_fields!(
217            ( $($fields)* );
218            $($name)::* ;
219            $($inits)*
220        )
221    };
222    (
223        ( _ : $head_parser: expr );
224        $($name: ident)::* ;
225        $($inits: tt)*
226    ) => {
227        $crate::seq_init_struct_fields!(
228            ();
229            $($name)::* ;
230            $($inits)*
231        )
232    };
233    (
234        ( $head_field: ident : $head_parser: expr, $($fields: tt)* );
235        $($name: ident)::* ;
236        $($inits: tt)*
237    ) =>
238    {
239        $crate::seq_init_struct_fields!(
240            ( $($fields)* );
241            $($name)::* ;
242            $($inits)* $head_field,
243        )
244    };
245    (
246        ( $head_field: ident : $head_parser: expr );
247        $($name: ident)::* ;
248        $($inits: tt)*
249    ) => {
250        $crate::seq_init_struct_fields!(
251            ();
252            $($name)::* ;
253            $($inits)* $head_field,
254        )
255    };
256    (
257        ( .. $update: expr );
258        $($name: ident)::* ;
259        $($inits: tt)*
260    ) => {
261        $($name)::* { $($inits)* ..$update }
262    };
263    (
264        ( $(,)? );
265        $($name: ident)::* ;
266        $($inits: tt)*
267    ) => {
268        $($name)::* { $($inits)* }
269    };
270}
271
272#[macro_export]
273#[doc(hidden)]
274macro_rules! seq_init_tuple_fields {
275    (
276        ( _ : $head_parser: expr, $($fields: tt)* );
277        ( $unnamed1: ident, $($unnamed: ident),* );
278        $($name: ident)::*;
279        $($inits: tt)*
280    ) => {
281        $crate::seq_init_tuple_fields!(
282            ( $($fields)* );
283            ( $($unnamed),* );
284            $($name)::* ;
285            $($inits)*
286        )
287    };
288    (
289        ( _ : $head_parser: expr );
290        ( $unnamed1: ident, $($unnamed: ident),* );
291        $($name: ident)::*;
292        $($inits: tt)*
293    ) => {
294        $crate::seq_init_tuple_fields!(
295            ();
296            ( $($unnamed),* );
297            $($name)::* ;
298            $($inits)*
299        )
300    };
301    (
302        ( $head_parser: expr, $($fields: tt)* );
303        ( $unnamed1: ident, $($unnamed: ident),* );
304        $($name: ident)::*;
305        $($inits: tt)*
306    ) =>
307    {
308        $crate::seq_init_tuple_fields!(
309            ( $($fields)* );
310            ( $($unnamed),* );
311            $($name)::* ;
312            $($inits)* $unnamed1,
313        )
314    };
315    (
316        ( $head_parser: expr );
317        ( $unnamed1: ident, $($unnamed: ident),* );
318        $($name: ident)::*;
319        $($inits: tt)*
320    ) => {
321        $crate::seq_init_tuple_fields!(
322            ();
323            ( $($unnamed),* );
324            $($name)::* ;
325            $($inits)* $unnamed1,
326        )
327    };
328    (
329        ( $(,)? );
330        ( $unnamed1: ident, $($unnamed: ident),* );
331        $($name: ident)::*;
332        $($inits: tt)*
333    ) => {
334        $($name)::* ( $($inits)* )
335    };
336}