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