1 use crate::algorithm::Printer;
2 use crate::iter::IterDelimited;
3 use crate::path::PathKind;
4 use crate::INDENT;
5 use proc_macro2::TokenStream;
6 use syn::{
7     FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct, PatTuple,
8     PatTupleStruct, PatType, PatWild,
9 };
10 
11 impl Printer {
pat(&mut self, pat: &Pat)12     pub fn pat(&mut self, pat: &Pat) {
13         match pat {
14             #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
15             Pat::Const(pat) => self.expr_const(pat),
16             Pat::Ident(pat) => self.pat_ident(pat),
17             Pat::Lit(pat) => self.expr_lit(pat),
18             Pat::Macro(pat) => self.expr_macro(pat),
19             Pat::Or(pat) => self.pat_or(pat),
20             Pat::Paren(pat) => self.pat_paren(pat),
21             Pat::Path(pat) => self.expr_path(pat),
22             Pat::Range(pat) => self.expr_range(pat),
23             Pat::Reference(pat) => self.pat_reference(pat),
24             Pat::Rest(pat) => self.pat_rest(pat),
25             Pat::Slice(pat) => self.pat_slice(pat),
26             Pat::Struct(pat) => self.pat_struct(pat),
27             Pat::Tuple(pat) => self.pat_tuple(pat),
28             Pat::TupleStruct(pat) => self.pat_tuple_struct(pat),
29             Pat::Type(pat) => self.pat_type(pat),
30             Pat::Verbatim(pat) => self.pat_verbatim(pat),
31             Pat::Wild(pat) => self.pat_wild(pat),
32             _ => unimplemented!("unknown Pat"),
33         }
34     }
35 
pat_ident(&mut self, pat: &PatIdent)36     fn pat_ident(&mut self, pat: &PatIdent) {
37         self.outer_attrs(&pat.attrs);
38         if pat.by_ref.is_some() {
39             self.word("ref ");
40         }
41         if pat.mutability.is_some() {
42             self.word("mut ");
43         }
44         self.ident(&pat.ident);
45         if let Some((_at_token, subpat)) = &pat.subpat {
46             self.word(" @ ");
47             self.pat(subpat);
48         }
49     }
50 
pat_or(&mut self, pat: &PatOr)51     fn pat_or(&mut self, pat: &PatOr) {
52         self.outer_attrs(&pat.attrs);
53         let mut consistent_break = false;
54         for case in &pat.cases {
55             match case {
56                 Pat::Lit(_) | Pat::Wild(_) => {}
57                 _ => {
58                     consistent_break = true;
59                     break;
60                 }
61             }
62         }
63         if consistent_break {
64             self.cbox(0);
65         } else {
66             self.ibox(0);
67         }
68         for case in pat.cases.iter().delimited() {
69             if !case.is_first {
70                 self.space();
71                 self.word("| ");
72             }
73             self.pat(&case);
74         }
75         self.end();
76     }
77 
pat_paren(&mut self, pat: &PatParen)78     fn pat_paren(&mut self, pat: &PatParen) {
79         self.outer_attrs(&pat.attrs);
80         self.word("(");
81         self.pat(&pat.pat);
82         self.word(")");
83     }
84 
pat_reference(&mut self, pat: &PatReference)85     fn pat_reference(&mut self, pat: &PatReference) {
86         self.outer_attrs(&pat.attrs);
87         self.word("&");
88         if pat.mutability.is_some() {
89             self.word("mut ");
90         }
91         self.pat(&pat.pat);
92     }
93 
pat_rest(&mut self, pat: &PatRest)94     fn pat_rest(&mut self, pat: &PatRest) {
95         self.outer_attrs(&pat.attrs);
96         self.word("..");
97     }
98 
pat_slice(&mut self, pat: &PatSlice)99     fn pat_slice(&mut self, pat: &PatSlice) {
100         self.outer_attrs(&pat.attrs);
101         self.word("[");
102         for elem in pat.elems.iter().delimited() {
103             self.pat(&elem);
104             self.trailing_comma(elem.is_last);
105         }
106         self.word("]");
107     }
108 
pat_struct(&mut self, pat: &PatStruct)109     fn pat_struct(&mut self, pat: &PatStruct) {
110         self.outer_attrs(&pat.attrs);
111         self.cbox(INDENT);
112         self.path(&pat.path, PathKind::Expr);
113         self.word(" {");
114         self.space_if_nonempty();
115         for field in pat.fields.iter().delimited() {
116             self.field_pat(&field);
117             self.trailing_comma_or_space(field.is_last && pat.rest.is_none());
118         }
119         if let Some(rest) = &pat.rest {
120             self.pat_rest(rest);
121             self.space();
122         }
123         self.offset(-INDENT);
124         self.end();
125         self.word("}");
126     }
127 
pat_tuple(&mut self, pat: &PatTuple)128     fn pat_tuple(&mut self, pat: &PatTuple) {
129         self.outer_attrs(&pat.attrs);
130         self.word("(");
131         self.cbox(INDENT);
132         self.zerobreak();
133         for elem in pat.elems.iter().delimited() {
134             self.pat(&elem);
135             if pat.elems.len() == 1 {
136                 if pat.elems.trailing_punct() {
137                     self.word(",");
138                 }
139                 self.zerobreak();
140             } else {
141                 self.trailing_comma(elem.is_last);
142             }
143         }
144         self.offset(-INDENT);
145         self.end();
146         self.word(")");
147     }
148 
pat_tuple_struct(&mut self, pat: &PatTupleStruct)149     fn pat_tuple_struct(&mut self, pat: &PatTupleStruct) {
150         self.outer_attrs(&pat.attrs);
151         self.path(&pat.path, PathKind::Expr);
152         self.word("(");
153         self.cbox(INDENT);
154         self.zerobreak();
155         for elem in pat.elems.iter().delimited() {
156             self.pat(&elem);
157             self.trailing_comma(elem.is_last);
158         }
159         self.offset(-INDENT);
160         self.end();
161         self.word(")");
162     }
163 
pat_type(&mut self, pat: &PatType)164     pub fn pat_type(&mut self, pat: &PatType) {
165         self.outer_attrs(&pat.attrs);
166         self.pat(&pat.pat);
167         self.word(": ");
168         self.ty(&pat.ty);
169     }
170 
171     #[cfg(not(feature = "verbatim"))]
pat_verbatim(&mut self, pat: &TokenStream)172     fn pat_verbatim(&mut self, pat: &TokenStream) {
173         unimplemented!("Pat::Verbatim `{}`", pat);
174     }
175 
176     #[cfg(feature = "verbatim")]
pat_verbatim(&mut self, tokens: &TokenStream)177     fn pat_verbatim(&mut self, tokens: &TokenStream) {
178         use syn::parse::{Parse, ParseStream, Result};
179         use syn::{braced, Attribute, Block, Token};
180 
181         enum PatVerbatim {
182             Ellipsis,
183             Box(Pat),
184             Const(PatConst),
185         }
186 
187         struct PatConst {
188             attrs: Vec<Attribute>,
189             block: Block,
190         }
191 
192         impl Parse for PatVerbatim {
193             fn parse(input: ParseStream) -> Result<Self> {
194                 let lookahead = input.lookahead1();
195                 if lookahead.peek(Token![box]) {
196                     input.parse::<Token![box]>()?;
197                     let inner = Pat::parse_single(input)?;
198                     Ok(PatVerbatim::Box(inner))
199                 } else if lookahead.peek(Token![const]) {
200                     input.parse::<Token![const]>()?;
201                     let content;
202                     let brace_token = braced!(content in input);
203                     let attrs = content.call(Attribute::parse_inner)?;
204                     let stmts = content.call(Block::parse_within)?;
205                     Ok(PatVerbatim::Const(PatConst {
206                         attrs,
207                         block: Block { brace_token, stmts },
208                     }))
209                 } else if lookahead.peek(Token![...]) {
210                     input.parse::<Token![...]>()?;
211                     Ok(PatVerbatim::Ellipsis)
212                 } else {
213                     Err(lookahead.error())
214                 }
215             }
216         }
217 
218         let pat: PatVerbatim = match syn::parse2(tokens.clone()) {
219             Ok(pat) => pat,
220             Err(_) => unimplemented!("Pat::Verbatim `{}`", tokens),
221         };
222 
223         match pat {
224             PatVerbatim::Ellipsis => {
225                 self.word("...");
226             }
227             PatVerbatim::Box(pat) => {
228                 self.word("box ");
229                 self.pat(&pat);
230             }
231             PatVerbatim::Const(pat) => {
232                 self.word("const ");
233                 self.cbox(INDENT);
234                 self.small_block(&pat.block, &pat.attrs);
235                 self.end();
236             }
237         }
238     }
239 
pat_wild(&mut self, pat: &PatWild)240     fn pat_wild(&mut self, pat: &PatWild) {
241         self.outer_attrs(&pat.attrs);
242         self.word("_");
243     }
244 
field_pat(&mut self, field_pat: &FieldPat)245     fn field_pat(&mut self, field_pat: &FieldPat) {
246         self.outer_attrs(&field_pat.attrs);
247         if field_pat.colon_token.is_some() {
248             self.member(&field_pat.member);
249             self.word(": ");
250         }
251         self.pat(&field_pat.pat);
252     }
253 }
254