1use alloc::{boxed::Box, vec::Vec};
6
7use syn::{Attribute, Ident, Member, Path, Token, Type, punctuated::Punctuated, token};
8
9use super::PatPath;
10
11ast_enum_of_structs! {
12 #[non_exhaustive]
15 pub enum Pat {
16 Ident(PatIdent),
18
19 Path(PatPath),
21
22 Reference(PatReference),
24
25 Struct(PatStruct),
27
28 Tuple(PatTuple),
30
31 TupleStruct(PatTupleStruct),
33
34 Type(PatType),
36
37 Wild(PatWild),
39 }
40}
41
42ast_struct! {
43 pub struct PatIdent {
45 pub attrs: Vec<Attribute>,
46 pub by_ref: Option<Token![ref]>,
47 pub mutability: Option<Token![mut]>,
48 pub ident: Ident,
49 }
50}
51
52ast_struct! {
53 pub struct PatReference {
55 pub attrs: Vec<Attribute>,
56 pub and_token: Token![&],
57 pub mutability: Option<Token![mut]>,
58 pub pat: Box<Pat>,
59 }
60}
61
62ast_struct! {
63 pub struct PatRest {
65 pub attrs: Vec<Attribute>,
66 pub dot2_token: Token![..],
67 }
68}
69
70ast_struct! {
71 pub struct PatStruct {
73 pub attrs: Vec<Attribute>,
74 pub path: Path,
75 pub brace_token: token::Brace,
76 pub fields: Punctuated<FieldPat, Token![,]>,
77 pub rest: Option<PatRest>,
78 }
79}
80
81ast_struct! {
82 pub struct PatTuple {
84 pub attrs: Vec<Attribute>,
85 pub paren_token: token::Paren,
86 pub elems: Punctuated<Pat, Token![,]>,
87 }
88}
89
90ast_struct! {
91 pub struct PatTupleStruct {
93 pub attrs: Vec<Attribute>,
94 pub path: Path,
95 pub paren_token: token::Paren,
96 pub elems: Punctuated<Pat, Token![,]>,
97 }
98}
99
100ast_struct! {
101 pub struct PatType {
103 pub attrs: Vec<Attribute>,
104 pub pat: Box<Pat>,
105 pub colon_token: Token![:],
106 pub ty: Box<Type>,
107 }
108}
109
110ast_struct! {
111 pub struct PatWild {
113 pub attrs: Vec<Attribute>,
114 pub underscore_token: Token![_],
115 }
116}
117
118ast_struct! {
119 pub struct FieldPat {
124 pub attrs: Vec<Attribute>,
125 pub member: Member,
126 pub colon_token: Option<Token![:]>,
127 pub pat: Box<Pat>,
128 }
129}
130
131mod parsing {
132 use alloc::{boxed::Box, vec};
133
134 use syn::{
135 Attribute, ExprPath, Ident, Member, Path, Token, braced,
136 ext::IdentExt as _,
137 parenthesized,
138 parse::{ParseStream, Result},
139 punctuated::Punctuated,
140 token,
141 };
142
143 use super::{
144 FieldPat, Pat, PatIdent, PatReference, PatRest, PatStruct, PatTuple, PatTupleStruct,
145 PatWild,
146 };
147 use crate::path;
148
149 impl Pat {
150 pub fn parse_single(input: ParseStream<'_>) -> Result<Self> {
152 let lookahead = input.lookahead1();
153 if lookahead.peek(Ident)
154 && (input.peek2(Token![::])
155 || input.peek2(Token![!])
156 || input.peek2(token::Brace)
157 || input.peek2(token::Paren)
158 || input.peek2(Token![..]))
159 || input.peek(Token![self]) && input.peek2(Token![::])
160 || lookahead.peek(Token![::])
161 || lookahead.peek(Token![<])
162 || input.peek(Token![Self])
163 || input.peek(Token![super])
164 || input.peek(Token![crate])
165 {
166 pat_path_or_struct(input)
167 } else if lookahead.peek(Token![_]) {
168 input.call(pat_wild).map(Pat::Wild)
169 } else if lookahead.peek(Token![ref])
170 || lookahead.peek(Token![mut])
171 || input.peek(Token![self])
172 || input.peek(Ident)
173 {
174 input.call(pat_ident).map(Pat::Ident)
175 } else if lookahead.peek(Token![&]) {
176 input.call(pat_reference).map(Pat::Reference)
177 } else if lookahead.peek(token::Paren) {
178 input.call(pat_paren_or_tuple)
179 } else {
180 Err(lookahead.error())
181 }
182 }
183 }
184
185 fn pat_path_or_struct(input: ParseStream<'_>) -> Result<Pat> {
186 let path = path::parse_path(input)?;
187
188 if input.peek(token::Brace) {
189 pat_struct(input, path).map(Pat::Struct)
190 } else if input.peek(token::Paren) {
191 pat_tuple_struct(input, path).map(Pat::TupleStruct)
192 } else {
193 Ok(Pat::Path(ExprPath { attrs: vec![], qself: None, path }))
194 }
195 }
196
197 fn pat_wild(input: ParseStream<'_>) -> Result<PatWild> {
198 Ok(PatWild { attrs: vec![], underscore_token: input.parse()? })
199 }
200
201 fn pat_ident(input: ParseStream<'_>) -> Result<PatIdent> {
202 Ok(PatIdent {
203 attrs: vec![],
204 by_ref: input.parse()?,
205 mutability: input.parse()?,
206 ident: input.call(Ident::parse_any)?,
207 })
208 }
209
210 fn pat_tuple_struct(input: ParseStream<'_>, path: Path) -> Result<PatTupleStruct> {
211 let content;
212 let paren_token = parenthesized!(content in input);
213
214 let mut elems = Punctuated::new();
215 while !content.is_empty() {
216 let value = Pat::parse_single(&content)?;
217 elems.push_value(value);
218 if content.is_empty() {
219 break;
220 }
221 let punct = content.parse()?;
222 elems.push_punct(punct);
223 }
224
225 Ok(PatTupleStruct { attrs: vec![], path, paren_token, elems })
226 }
227
228 fn pat_struct(input: ParseStream<'_>, path: Path) -> Result<PatStruct> {
229 let content;
230 let brace_token = braced!(content in input);
231
232 let mut fields = Punctuated::new();
233 let mut rest = None;
234 while !content.is_empty() {
235 let attrs = content.call(Attribute::parse_outer)?;
236 if content.peek(Token![..]) {
237 rest = Some(PatRest { attrs, dot2_token: content.parse()? });
238 break;
239 }
240 let mut value = content.call(field_pat)?;
241 value.attrs = attrs;
242 fields.push_value(value);
243 if content.is_empty() {
244 break;
245 }
246 let punct: Token![,] = content.parse()?;
247 fields.push_punct(punct);
248 }
249
250 Ok(PatStruct { attrs: vec![], path, brace_token, fields, rest })
251 }
252
253 fn field_pat(input: ParseStream<'_>) -> Result<FieldPat> {
254 let boxed: Option<Token![box]> = input.parse()?;
255 let by_ref: Option<Token![ref]> = input.parse()?;
256 let mutability: Option<Token![mut]> = input.parse()?;
257
258 let member = if boxed.is_some() || by_ref.is_some() || mutability.is_some() {
259 input.parse().map(Member::Named)
260 } else {
261 input.parse()
262 }?;
263
264 if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:])
265 || is_unnamed(&member)
266 {
267 return Ok(FieldPat {
268 attrs: vec![],
269 member,
270 colon_token: Some(input.parse()?),
271 pat: Box::new(Pat::parse_single(input)?),
272 });
273 }
274
275 let ident = match member {
276 Member::Named(ident) => ident,
277 Member::Unnamed(_) => unreachable!(),
278 };
279
280 let pat = Pat::Ident(PatIdent { attrs: vec![], by_ref, mutability, ident: ident.clone() });
281
282 Ok(FieldPat {
283 attrs: vec![],
284 member: Member::Named(ident),
285 colon_token: None,
286 pat: Box::new(pat),
287 })
288 }
289
290 fn pat_paren_or_tuple(input: ParseStream<'_>) -> Result<Pat> {
291 let content;
292 let paren_token = parenthesized!(content in input);
293
294 let mut elems = Punctuated::new();
295 while !content.is_empty() {
296 let value = Pat::parse_single(&content)?;
297 if content.is_empty() {
298 elems.push_value(value);
299 break;
300 }
301 elems.push_value(value);
302 let punct = content.parse()?;
303 elems.push_punct(punct);
304 }
305
306 Ok(Pat::Tuple(PatTuple { attrs: vec![], paren_token, elems }))
307 }
308
309 fn pat_reference(input: ParseStream<'_>) -> Result<PatReference> {
310 Ok(PatReference {
311 attrs: vec![],
312 and_token: input.parse()?,
313 mutability: input.parse()?,
314 pat: Box::new(Pat::parse_single(input)?),
315 })
316 }
317
318 fn is_unnamed(member: &Member) -> bool {
319 match member {
320 Member::Named(_) => false,
321 Member::Unnamed(_) => true,
322 }
323 }
324}
325
326mod printing {
327 use proc_macro2::TokenStream;
328 use quote::{ToTokens, TokenStreamExt as _};
329 use syn::Token;
330
331 use super::{
332 FieldPat, PatIdent, PatReference, PatRest, PatStruct, PatTuple, PatTupleStruct, PatType,
333 PatWild,
334 };
335
336 impl ToTokens for PatIdent {
337 fn to_tokens(&self, tokens: &mut TokenStream) {
338 tokens.append_all(&self.attrs);
339 self.by_ref.to_tokens(tokens);
340 self.mutability.to_tokens(tokens);
341 self.ident.to_tokens(tokens);
342 }
343 }
344
345 impl ToTokens for PatReference {
346 fn to_tokens(&self, tokens: &mut TokenStream) {
347 tokens.append_all(&self.attrs);
348 self.and_token.to_tokens(tokens);
349 self.mutability.to_tokens(tokens);
350 self.pat.to_tokens(tokens);
351 }
352 }
353
354 impl ToTokens for PatRest {
355 fn to_tokens(&self, tokens: &mut TokenStream) {
356 tokens.append_all(&self.attrs);
357 self.dot2_token.to_tokens(tokens);
358 }
359 }
360
361 impl ToTokens for PatStruct {
362 fn to_tokens(&self, tokens: &mut TokenStream) {
363 tokens.append_all(&self.attrs);
364 self.path.to_tokens(tokens);
365 self.brace_token.surround(tokens, |tokens| {
366 self.fields.to_tokens(tokens);
367 if !self.fields.empty_or_trailing() && self.rest.is_some() {
369 <Token![,]>::default().to_tokens(tokens);
370 }
371 self.rest.to_tokens(tokens);
372 });
373 }
374 }
375
376 impl ToTokens for PatTuple {
377 fn to_tokens(&self, tokens: &mut TokenStream) {
378 tokens.append_all(&self.attrs);
379 self.paren_token.surround(tokens, |tokens| {
380 self.elems.to_tokens(tokens);
381 });
382 }
383 }
384
385 impl ToTokens for PatTupleStruct {
386 fn to_tokens(&self, tokens: &mut TokenStream) {
387 tokens.append_all(&self.attrs);
388 self.path.to_tokens(tokens);
389 self.paren_token.surround(tokens, |tokens| {
390 self.elems.to_tokens(tokens);
391 });
392 }
393 }
394
395 impl ToTokens for PatType {
396 fn to_tokens(&self, tokens: &mut TokenStream) {
397 tokens.append_all(&self.attrs);
398 self.pat.to_tokens(tokens);
399 self.colon_token.to_tokens(tokens);
400 self.ty.to_tokens(tokens);
401 }
402 }
403
404 impl ToTokens for PatWild {
405 fn to_tokens(&self, tokens: &mut TokenStream) {
406 tokens.append_all(&self.attrs);
407 self.underscore_token.to_tokens(tokens);
408 }
409 }
410
411 impl ToTokens for FieldPat {
412 fn to_tokens(&self, tokens: &mut TokenStream) {
413 tokens.append_all(&self.attrs);
414 if let Some(colon_token) = &self.colon_token {
415 self.member.to_tokens(tokens);
416 colon_token.to_tokens(tokens);
417 }
418 self.pat.to_tokens(tokens);
419 }
420 }
421}