• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
74 macro_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)]
112 macro_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)]
151 macro_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)]
186 macro_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)]
234 macro_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 }
276