• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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             Pat::Const(pat) => self.expr_const(pat),
15             Pat::Ident(pat) => self.pat_ident(pat),
16             Pat::Lit(pat) => self.expr_lit(pat),
17             Pat::Macro(pat) => self.expr_macro(pat),
18             Pat::Or(pat) => self.pat_or(pat),
19             Pat::Paren(pat) => self.pat_paren(pat),
20             Pat::Path(pat) => self.expr_path(pat),
21             Pat::Range(pat) => self.expr_range(pat),
22             Pat::Reference(pat) => self.pat_reference(pat),
23             Pat::Rest(pat) => self.pat_rest(pat),
24             Pat::Slice(pat) => self.pat_slice(pat),
25             Pat::Struct(pat) => self.pat_struct(pat),
26             Pat::Tuple(pat) => self.pat_tuple(pat),
27             Pat::TupleStruct(pat) => self.pat_tuple_struct(pat),
28             Pat::Type(pat) => self.pat_type(pat),
29             Pat::Verbatim(pat) => self.pat_verbatim(pat),
30             Pat::Wild(pat) => self.pat_wild(pat),
31             #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
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             Box(Pat),
183             Const(PatConst),
184         }
185 
186         struct PatConst {
187             attrs: Vec<Attribute>,
188             block: Block,
189         }
190 
191         impl Parse for PatVerbatim {
192             fn parse(input: ParseStream) -> Result<Self> {
193                 let lookahead = input.lookahead1();
194                 if lookahead.peek(Token![box]) {
195                     input.parse::<Token![box]>()?;
196                     let inner = Pat::parse_single(input)?;
197                     Ok(PatVerbatim::Box(inner))
198                 } else if lookahead.peek(Token![const]) {
199                     input.parse::<Token![const]>()?;
200                     let content;
201                     let brace_token = braced!(content in input);
202                     let attrs = content.call(Attribute::parse_inner)?;
203                     let stmts = content.call(Block::parse_within)?;
204                     Ok(PatVerbatim::Const(PatConst {
205                         attrs,
206                         block: Block { brace_token, stmts },
207                     }))
208                 } else {
209                     Err(lookahead.error())
210                 }
211             }
212         }
213 
214         let pat: PatVerbatim = match syn::parse2(tokens.clone()) {
215             Ok(pat) => pat,
216             Err(_) => unimplemented!("Pat::Verbatim `{}`", tokens),
217         };
218 
219         match pat {
220             PatVerbatim::Box(pat) => {
221                 self.word("box ");
222                 self.pat(&pat);
223             }
224             PatVerbatim::Const(pat) => {
225                 self.word("const ");
226                 self.cbox(INDENT);
227                 self.small_block(&pat.block, &pat.attrs);
228                 self.end();
229             }
230         }
231     }
232 
pat_wild(&mut self, pat: &PatWild)233     fn pat_wild(&mut self, pat: &PatWild) {
234         self.outer_attrs(&pat.attrs);
235         self.word("_");
236     }
237 
field_pat(&mut self, field_pat: &FieldPat)238     fn field_pat(&mut self, field_pat: &FieldPat) {
239         self.outer_attrs(&field_pat.attrs);
240         if field_pat.colon_token.is_some() {
241             self.member(&field_pat.member);
242             self.word(": ");
243         }
244         self.pat(&field_pat.pat);
245     }
246 }
247