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