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" )] |
65 | macro_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)] |
105 | macro_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)] |
144 | macro_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)] |
179 | macro_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)] |
227 | macro_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 | } |
269 | |