1use crate::attr::Attribute;
2use crate::expr::Member;
3use crate::ident::Ident;
4use crate::path::{Path, QSelf};
5use crate::punctuated::Punctuated;
6use crate::token;
7use crate::ty::Type;
8use proc_macro2::TokenStream;
9
10pub use crate::expr::{
11 ExprConst as PatConst, ExprLit as PatLit, ExprMacro as PatMacro, ExprPath as PatPath,
12 ExprRange as PatRange,
13};
14
15ast_enum_of_structs! {
16 #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
25 #[non_exhaustive]
26 pub enum Pat {
27 Const(PatConst),
29
30 Ident(PatIdent),
32
33 Lit(PatLit),
35
36 Macro(PatMacro),
38
39 Or(PatOr),
41
42 Paren(PatParen),
44
45 Path(PatPath),
53
54 Range(PatRange),
56
57 Reference(PatReference),
59
60 Rest(PatRest),
62
63 Slice(PatSlice),
65
66 Struct(PatStruct),
68
69 Tuple(PatTuple),
71
72 TupleStruct(PatTupleStruct),
74
75 Type(PatType),
77
78 Verbatim(TokenStream),
80
81 Wild(PatWild),
83
84 }
102}
103
104ast_struct! {
105 #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
110 pub struct PatIdent {
111 pub attrs: Vec<Attribute>,
112 pub by_ref: Option<Token![ref]>,
113 pub mutability: Option<Token![mut]>,
114 pub ident: Ident,
115 pub subpat: Option<(Token![@], Box<Pat>)>,
116 }
117}
118
119ast_struct! {
120 #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
122 pub struct PatOr {
123 pub attrs: Vec<Attribute>,
124 pub leading_vert: Option<Token![|]>,
125 pub cases: Punctuated<Pat, Token![|]>,
126 }
127}
128
129ast_struct! {
130 #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
132 pub struct PatParen {
133 pub attrs: Vec<Attribute>,
134 pub paren_token: token::Paren,
135 pub pat: Box<Pat>,
136 }
137}
138
139ast_struct! {
140 #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
142 pub struct PatReference {
143 pub attrs: Vec<Attribute>,
144 pub and_token: Token![&],
145 pub mutability: Option<Token![mut]>,
146 pub pat: Box<Pat>,
147 }
148}
149
150ast_struct! {
151 #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
153 pub struct PatRest {
154 pub attrs: Vec<Attribute>,
155 pub dot2_token: Token![..],
156 }
157}
158
159ast_struct! {
160 #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
162 pub struct PatSlice {
163 pub attrs: Vec<Attribute>,
164 pub bracket_token: token::Bracket,
165 pub elems: Punctuated<Pat, Token![,]>,
166 }
167}
168
169ast_struct! {
170 #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
172 pub struct PatStruct {
173 pub attrs: Vec<Attribute>,
174 pub qself: Option<QSelf>,
175 pub path: Path,
176 pub brace_token: token::Brace,
177 pub fields: Punctuated<FieldPat, Token![,]>,
178 pub rest: Option<PatRest>,
179 }
180}
181
182ast_struct! {
183 #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
185 pub struct PatTuple {
186 pub attrs: Vec<Attribute>,
187 pub paren_token: token::Paren,
188 pub elems: Punctuated<Pat, Token![,]>,
189 }
190}
191
192ast_struct! {
193 #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
195 pub struct PatTupleStruct {
196 pub attrs: Vec<Attribute>,
197 pub qself: Option<QSelf>,
198 pub path: Path,
199 pub paren_token: token::Paren,
200 pub elems: Punctuated<Pat, Token![,]>,
201 }
202}
203
204ast_struct! {
205 #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
207 pub struct PatType {
208 pub attrs: Vec<Attribute>,
209 pub pat: Box<Pat>,
210 pub colon_token: Token![:],
211 pub ty: Box<Type>,
212 }
213}
214
215ast_struct! {
216 #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
218 pub struct PatWild {
219 pub attrs: Vec<Attribute>,
220 pub underscore_token: Token![_],
221 }
222}
223
224ast_struct! {
225 #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
230 pub struct FieldPat {
231 pub attrs: Vec<Attribute>,
232 pub member: Member,
233 pub colon_token: Option<Token![:]>,
234 pub pat: Box<Pat>,
235 }
236}
237
238#[cfg(feature = "parsing")]
239pub(crate) mod parsing {
240 use crate::attr::Attribute;
241 use crate::error::{self, Result};
242 use crate::expr::{
243 Expr, ExprConst, ExprLit, ExprMacro, ExprPath, ExprRange, Member, RangeLimits,
244 };
245 use crate::ext::IdentExt as _;
246 use crate::ident::Ident;
247 use crate::lit::Lit;
248 use crate::mac::{self, Macro};
249 use crate::parse::{Parse, ParseBuffer, ParseStream};
250 use crate::pat::{
251 FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct,
252 PatTuple, PatTupleStruct, PatType, PatWild,
253 };
254 use crate::path::{self, Path, QSelf};
255 use crate::punctuated::Punctuated;
256 use crate::stmt::Block;
257 use crate::token;
258 use crate::verbatim;
259 use proc_macro2::TokenStream;
260
261 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
262 impl Pat {
263 pub fn parse_single(input: ParseStream) -> Result<Self> {
288 let begin = input.fork();
289 let lookahead = input.lookahead1();
290 if lookahead.peek(Ident)
291 && (input.peek2(Token![::])
292 || input.peek2(Token![!])
293 || input.peek2(token::Brace)
294 || input.peek2(token::Paren)
295 || input.peek2(Token![..]))
296 || input.peek(Token![self]) && input.peek2(Token![::])
297 || lookahead.peek(Token![::])
298 || lookahead.peek(Token![<])
299 || input.peek(Token![Self])
300 || input.peek(Token![super])
301 || input.peek(Token![crate])
302 {
303 pat_path_or_macro_or_struct_or_range(input)
304 } else if lookahead.peek(Token![_]) {
305 input.call(pat_wild).map(Pat::Wild)
306 } else if input.peek(Token![box]) {
307 pat_box(begin, input)
308 } else if input.peek(Token![-]) || lookahead.peek(Lit) || lookahead.peek(Token![const])
309 {
310 pat_lit_or_range(input)
311 } else if lookahead.peek(Token![ref])
312 || lookahead.peek(Token![mut])
313 || input.peek(Token![self])
314 || input.peek(Ident)
315 {
316 input.call(pat_ident).map(Pat::Ident)
317 } else if lookahead.peek(Token![&]) {
318 input.call(pat_reference).map(Pat::Reference)
319 } else if lookahead.peek(token::Paren) {
320 input.call(pat_paren_or_tuple)
321 } else if lookahead.peek(token::Bracket) {
322 input.call(pat_slice).map(Pat::Slice)
323 } else if lookahead.peek(Token![..]) && !input.peek(Token![...]) {
324 pat_range_half_open(input)
325 } else if lookahead.peek(Token![const]) {
326 input.call(pat_const).map(Pat::Verbatim)
327 } else {
328 Err(lookahead.error())
329 }
330 }
331
332 pub fn parse_multi(input: ParseStream) -> Result<Self> {
334 multi_pat_impl(input, None)
335 }
336
337 pub fn parse_multi_with_leading_vert(input: ParseStream) -> Result<Self> {
380 let leading_vert: Option<Token![|]> = input.parse()?;
381 multi_pat_impl(input, leading_vert)
382 }
383 }
384
385 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
386 impl Parse for PatType {
387 fn parse(input: ParseStream) -> Result<Self> {
388 Ok(PatType {
389 attrs: Vec::new(),
390 pat: Box::new(Pat::parse_single(input)?),
391 colon_token: input.parse()?,
392 ty: input.parse()?,
393 })
394 }
395 }
396
397 fn multi_pat_impl(input: ParseStream, leading_vert: Option<Token![|]>) -> Result<Pat> {
398 let mut pat = Pat::parse_single(input)?;
399 if leading_vert.is_some()
400 || input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=])
401 {
402 let mut cases = Punctuated::new();
403 cases.push_value(pat);
404 while input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=]) {
405 let punct = input.parse()?;
406 cases.push_punct(punct);
407 let pat = Pat::parse_single(input)?;
408 cases.push_value(pat);
409 }
410 pat = Pat::Or(PatOr {
411 attrs: Vec::new(),
412 leading_vert,
413 cases,
414 });
415 }
416 Ok(pat)
417 }
418
419 fn pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat> {
420 let expr_style = true;
421 let (qself, path) = path::parsing::qpath(input, expr_style)?;
422
423 if qself.is_none()
424 && input.peek(Token![!])
425 && !input.peek(Token![!=])
426 && path.is_mod_style()
427 {
428 let bang_token: Token![!] = input.parse()?;
429 let (delimiter, tokens) = mac::parse_delimiter(input)?;
430 return Ok(Pat::Macro(ExprMacro {
431 attrs: Vec::new(),
432 mac: Macro {
433 path,
434 bang_token,
435 delimiter,
436 tokens,
437 },
438 }));
439 }
440
441 if input.peek(token::Brace) {
442 pat_struct(input, qself, path).map(Pat::Struct)
443 } else if input.peek(token::Paren) {
444 pat_tuple_struct(input, qself, path).map(Pat::TupleStruct)
445 } else if input.peek(Token![..]) {
446 pat_range(input, qself, path)
447 } else {
448 Ok(Pat::Path(ExprPath {
449 attrs: Vec::new(),
450 qself,
451 path,
452 }))
453 }
454 }
455
456 fn pat_wild(input: ParseStream) -> Result<PatWild> {
457 Ok(PatWild {
458 attrs: Vec::new(),
459 underscore_token: input.parse()?,
460 })
461 }
462
463 fn pat_box(begin: ParseBuffer, input: ParseStream) -> Result<Pat> {
464 input.parse::<Token![box]>()?;
465 Pat::parse_single(input)?;
466 Ok(Pat::Verbatim(verbatim::between(&begin, input)))
467 }
468
469 fn pat_ident(input: ParseStream) -> Result<PatIdent> {
470 Ok(PatIdent {
471 attrs: Vec::new(),
472 by_ref: input.parse()?,
473 mutability: input.parse()?,
474 ident: {
475 if input.peek(Token![self]) {
476 input.call(Ident::parse_any)?
477 } else {
478 input.parse()?
479 }
480 },
481 subpat: {
482 if input.peek(Token![@]) {
483 let at_token: Token![@] = input.parse()?;
484 let subpat = Pat::parse_single(input)?;
485 Some((at_token, Box::new(subpat)))
486 } else {
487 None
488 }
489 },
490 })
491 }
492
493 fn pat_tuple_struct(
494 input: ParseStream,
495 qself: Option<QSelf>,
496 path: Path,
497 ) -> Result<PatTupleStruct> {
498 let content;
499 let paren_token = parenthesized!(content in input);
500
501 let mut elems = Punctuated::new();
502 while !content.is_empty() {
503 let value = Pat::parse_multi_with_leading_vert(&content)?;
504 elems.push_value(value);
505 if content.is_empty() {
506 break;
507 }
508 let punct = content.parse()?;
509 elems.push_punct(punct);
510 }
511
512 Ok(PatTupleStruct {
513 attrs: Vec::new(),
514 qself,
515 path,
516 paren_token,
517 elems,
518 })
519 }
520
521 fn pat_struct(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<PatStruct> {
522 let content;
523 let brace_token = braced!(content in input);
524
525 let mut fields = Punctuated::new();
526 let mut rest = None;
527 while !content.is_empty() {
528 let attrs = content.call(Attribute::parse_outer)?;
529 if content.peek(Token![..]) {
530 rest = Some(PatRest {
531 attrs,
532 dot2_token: content.parse()?,
533 });
534 break;
535 }
536 let mut value = content.call(field_pat)?;
537 value.attrs = attrs;
538 fields.push_value(value);
539 if content.is_empty() {
540 break;
541 }
542 let punct: Token![,] = content.parse()?;
543 fields.push_punct(punct);
544 }
545
546 Ok(PatStruct {
547 attrs: Vec::new(),
548 qself,
549 path,
550 brace_token,
551 fields,
552 rest,
553 })
554 }
555
556 fn field_pat(input: ParseStream) -> Result<FieldPat> {
557 let begin = input.fork();
558 let boxed: Option<Token![box]> = input.parse()?;
559 let by_ref: Option<Token![ref]> = input.parse()?;
560 let mutability: Option<Token![mut]> = input.parse()?;
561
562 let member = if boxed.is_some() || by_ref.is_some() || mutability.is_some() {
563 input.parse().map(Member::Named)
564 } else {
565 input.parse()
566 }?;
567
568 if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:])
569 || !member.is_named()
570 {
571 return Ok(FieldPat {
572 attrs: Vec::new(),
573 member,
574 colon_token: Some(input.parse()?),
575 pat: Box::new(Pat::parse_multi_with_leading_vert(input)?),
576 });
577 }
578
579 let ident = match member {
580 Member::Named(ident) => ident,
581 Member::Unnamed(_) => unreachable!(),
582 };
583
584 let pat = if boxed.is_some() {
585 Pat::Verbatim(verbatim::between(&begin, input))
586 } else {
587 Pat::Ident(PatIdent {
588 attrs: Vec::new(),
589 by_ref,
590 mutability,
591 ident: ident.clone(),
592 subpat: None,
593 })
594 };
595
596 Ok(FieldPat {
597 attrs: Vec::new(),
598 member: Member::Named(ident),
599 colon_token: None,
600 pat: Box::new(pat),
601 })
602 }
603
604 fn pat_range(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<Pat> {
605 let limits = RangeLimits::parse_obsolete(input)?;
606 let end = input.call(pat_range_bound)?;
607 if let (RangeLimits::Closed(_), None) = (&limits, &end) {
608 return Err(input.error("expected range upper bound"));
609 }
610 Ok(Pat::Range(ExprRange {
611 attrs: Vec::new(),
612 start: Some(Box::new(Expr::Path(ExprPath {
613 attrs: Vec::new(),
614 qself,
615 path,
616 }))),
617 limits,
618 end: end.map(PatRangeBound::into_expr),
619 }))
620 }
621
622 fn pat_range_half_open(input: ParseStream) -> Result<Pat> {
623 let limits: RangeLimits = input.parse()?;
624 let end = input.call(pat_range_bound)?;
625 if end.is_some() {
626 Ok(Pat::Range(ExprRange {
627 attrs: Vec::new(),
628 start: None,
629 limits,
630 end: end.map(PatRangeBound::into_expr),
631 }))
632 } else {
633 match limits {
634 RangeLimits::HalfOpen(dot2_token) => Ok(Pat::Rest(PatRest {
635 attrs: Vec::new(),
636 dot2_token,
637 })),
638 RangeLimits::Closed(_) => Err(input.error("expected range upper bound")),
639 }
640 }
641 }
642
643 fn pat_paren_or_tuple(input: ParseStream) -> Result<Pat> {
644 let content;
645 let paren_token = parenthesized!(content in input);
646
647 let mut elems = Punctuated::new();
648 while !content.is_empty() {
649 let value = Pat::parse_multi_with_leading_vert(&content)?;
650 if content.is_empty() {
651 if elems.is_empty() && !matches!(value, Pat::Rest(_)) {
652 return Ok(Pat::Paren(PatParen {
653 attrs: Vec::new(),
654 paren_token,
655 pat: Box::new(value),
656 }));
657 }
658 elems.push_value(value);
659 break;
660 }
661 elems.push_value(value);
662 let punct = content.parse()?;
663 elems.push_punct(punct);
664 }
665
666 Ok(Pat::Tuple(PatTuple {
667 attrs: Vec::new(),
668 paren_token,
669 elems,
670 }))
671 }
672
673 fn pat_reference(input: ParseStream) -> Result<PatReference> {
674 Ok(PatReference {
675 attrs: Vec::new(),
676 and_token: input.parse()?,
677 mutability: input.parse()?,
678 pat: Box::new(Pat::parse_single(input)?),
679 })
680 }
681
682 fn pat_lit_or_range(input: ParseStream) -> Result<Pat> {
683 let start = input.call(pat_range_bound)?.unwrap();
684 if input.peek(Token![..]) {
685 let limits = RangeLimits::parse_obsolete(input)?;
686 let end = input.call(pat_range_bound)?;
687 if let (RangeLimits::Closed(_), None) = (&limits, &end) {
688 return Err(input.error("expected range upper bound"));
689 }
690 Ok(Pat::Range(ExprRange {
691 attrs: Vec::new(),
692 start: Some(start.into_expr()),
693 limits,
694 end: end.map(PatRangeBound::into_expr),
695 }))
696 } else {
697 Ok(start.into_pat())
698 }
699 }
700
701 enum PatRangeBound {
703 Const(ExprConst),
704 Lit(ExprLit),
705 Path(ExprPath),
706 }
707
708 impl PatRangeBound {
709 fn into_expr(self) -> Box<Expr> {
710 Box::new(match self {
711 PatRangeBound::Const(pat) => Expr::Const(pat),
712 PatRangeBound::Lit(pat) => Expr::Lit(pat),
713 PatRangeBound::Path(pat) => Expr::Path(pat),
714 })
715 }
716
717 fn into_pat(self) -> Pat {
718 match self {
719 PatRangeBound::Const(pat) => Pat::Const(pat),
720 PatRangeBound::Lit(pat) => Pat::Lit(pat),
721 PatRangeBound::Path(pat) => Pat::Path(pat),
722 }
723 }
724 }
725
726 fn pat_range_bound(input: ParseStream) -> Result<Option<PatRangeBound>> {
727 if input.is_empty()
728 || input.peek(Token![|])
729 || input.peek(Token![=])
730 || input.peek(Token![:]) && !input.peek(Token![::])
731 || input.peek(Token![,])
732 || input.peek(Token![;])
733 || input.peek(Token![if])
734 {
735 return Ok(None);
736 }
737
738 let lookahead = input.lookahead1();
739 let expr = if lookahead.peek(Lit) {
740 PatRangeBound::Lit(input.parse()?)
741 } else if lookahead.peek(Ident)
742 || lookahead.peek(Token![::])
743 || lookahead.peek(Token![<])
744 || lookahead.peek(Token![self])
745 || lookahead.peek(Token![Self])
746 || lookahead.peek(Token![super])
747 || lookahead.peek(Token![crate])
748 {
749 PatRangeBound::Path(input.parse()?)
750 } else if lookahead.peek(Token![const]) {
751 PatRangeBound::Const(input.parse()?)
752 } else {
753 return Err(lookahead.error());
754 };
755
756 Ok(Some(expr))
757 }
758
759 fn pat_slice(input: ParseStream) -> Result<PatSlice> {
760 let content;
761 let bracket_token = bracketed!(content in input);
762
763 let mut elems = Punctuated::new();
764 while !content.is_empty() {
765 let value = Pat::parse_multi_with_leading_vert(&content)?;
766 match value {
767 Pat::Range(pat) if pat.start.is_none() || pat.end.is_none() => {
768 let (start, end) = match pat.limits {
769 RangeLimits::HalfOpen(dot_dot) => (dot_dot.spans[0], dot_dot.spans[1]),
770 RangeLimits::Closed(dot_dot_eq) => {
771 (dot_dot_eq.spans[0], dot_dot_eq.spans[2])
772 }
773 };
774 let msg = "range pattern is not allowed unparenthesized inside slice pattern";
775 return Err(error::new2(start, end, msg));
776 }
777 _ => {}
778 }
779 elems.push_value(value);
780 if content.is_empty() {
781 break;
782 }
783 let punct = content.parse()?;
784 elems.push_punct(punct);
785 }
786
787 Ok(PatSlice {
788 attrs: Vec::new(),
789 bracket_token,
790 elems,
791 })
792 }
793
794 fn pat_const(input: ParseStream) -> Result<TokenStream> {
795 let begin = input.fork();
796 input.parse::<Token![const]>()?;
797
798 let content;
799 braced!(content in input);
800 content.call(Attribute::parse_inner)?;
801 content.call(Block::parse_within)?;
802
803 Ok(verbatim::between(&begin, input))
804 }
805}
806
807#[cfg(feature = "printing")]
808mod printing {
809 use crate::attr::FilterAttrs;
810 use crate::pat::{
811 FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct,
812 PatTuple, PatTupleStruct, PatType, PatWild,
813 };
814 use crate::path;
815 use crate::path::printing::PathStyle;
816 use proc_macro2::TokenStream;
817 use quote::{ToTokens, TokenStreamExt};
818
819 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
820 impl ToTokens for PatIdent {
821 fn to_tokens(&self, tokens: &mut TokenStream) {
822 tokens.append_all(self.attrs.outer());
823 self.by_ref.to_tokens(tokens);
824 self.mutability.to_tokens(tokens);
825 self.ident.to_tokens(tokens);
826 if let Some((at_token, subpat)) = &self.subpat {
827 at_token.to_tokens(tokens);
828 subpat.to_tokens(tokens);
829 }
830 }
831 }
832
833 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
834 impl ToTokens for PatOr {
835 fn to_tokens(&self, tokens: &mut TokenStream) {
836 tokens.append_all(self.attrs.outer());
837 self.leading_vert.to_tokens(tokens);
838 self.cases.to_tokens(tokens);
839 }
840 }
841
842 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
843 impl ToTokens for PatParen {
844 fn to_tokens(&self, tokens: &mut TokenStream) {
845 tokens.append_all(self.attrs.outer());
846 self.paren_token.surround(tokens, |tokens| {
847 self.pat.to_tokens(tokens);
848 });
849 }
850 }
851
852 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
853 impl ToTokens for PatReference {
854 fn to_tokens(&self, tokens: &mut TokenStream) {
855 tokens.append_all(self.attrs.outer());
856 self.and_token.to_tokens(tokens);
857 self.mutability.to_tokens(tokens);
858 self.pat.to_tokens(tokens);
859 }
860 }
861
862 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
863 impl ToTokens for PatRest {
864 fn to_tokens(&self, tokens: &mut TokenStream) {
865 tokens.append_all(self.attrs.outer());
866 self.dot2_token.to_tokens(tokens);
867 }
868 }
869
870 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
871 impl ToTokens for PatSlice {
872 fn to_tokens(&self, tokens: &mut TokenStream) {
873 tokens.append_all(self.attrs.outer());
874 self.bracket_token.surround(tokens, |tokens| {
875 self.elems.to_tokens(tokens);
876 });
877 }
878 }
879
880 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
881 impl ToTokens for PatStruct {
882 fn to_tokens(&self, tokens: &mut TokenStream) {
883 tokens.append_all(self.attrs.outer());
884 path::printing::print_qpath(tokens, &self.qself, &self.path, PathStyle::Expr);
885 self.brace_token.surround(tokens, |tokens| {
886 self.fields.to_tokens(tokens);
887 if !self.fields.empty_or_trailing() && self.rest.is_some() {
889 <Token![,]>::default().to_tokens(tokens);
890 }
891 self.rest.to_tokens(tokens);
892 });
893 }
894 }
895
896 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
897 impl ToTokens for PatTuple {
898 fn to_tokens(&self, tokens: &mut TokenStream) {
899 tokens.append_all(self.attrs.outer());
900 self.paren_token.surround(tokens, |tokens| {
901 self.elems.to_tokens(tokens);
902 if self.elems.len() == 1
906 && !self.elems.trailing_punct()
907 && !matches!(self.elems[0], Pat::Rest { .. })
908 {
909 <Token![,]>::default().to_tokens(tokens);
910 }
911 });
912 }
913 }
914
915 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
916 impl ToTokens for PatTupleStruct {
917 fn to_tokens(&self, tokens: &mut TokenStream) {
918 tokens.append_all(self.attrs.outer());
919 path::printing::print_qpath(tokens, &self.qself, &self.path, PathStyle::Expr);
920 self.paren_token.surround(tokens, |tokens| {
921 self.elems.to_tokens(tokens);
922 });
923 }
924 }
925
926 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
927 impl ToTokens for PatType {
928 fn to_tokens(&self, tokens: &mut TokenStream) {
929 tokens.append_all(self.attrs.outer());
930 self.pat.to_tokens(tokens);
931 self.colon_token.to_tokens(tokens);
932 self.ty.to_tokens(tokens);
933 }
934 }
935
936 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
937 impl ToTokens for PatWild {
938 fn to_tokens(&self, tokens: &mut TokenStream) {
939 tokens.append_all(self.attrs.outer());
940 self.underscore_token.to_tokens(tokens);
941 }
942 }
943
944 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
945 impl ToTokens for FieldPat {
946 fn to_tokens(&self, tokens: &mut TokenStream) {
947 tokens.append_all(self.attrs.outer());
948 if let Some(colon_token) = &self.colon_token {
949 self.member.to_tokens(tokens);
950 colon_token.to_tokens(tokens);
951 }
952 self.pat.to_tokens(tokens);
953 }
954 }
955}