1use crate::algorithm::Printer;
2use crate::iter::IterDelimited;
3use crate::path::PathKind;
4use crate::INDENT;
5use proc_macro2::TokenStream;
6use syn::{
7 FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct, PatTuple,
8 PatTupleStruct, PatType, PatWild,
9};
10
11impl Printer {
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
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
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
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
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
94 fn pat_rest(&mut self, pat: &PatRest) {
95 self.outer_attrs(&pat.attrs);
96 self.word("..");
97 }
98
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
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
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
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
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"))]
172 fn pat_verbatim(&mut self, pat: &TokenStream) {
173 unimplemented!("Pat::Verbatim `{}`", pat);
174 }
175
176 #[cfg(feature = "verbatim")]
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
240 fn pat_wild(&mut self, pat: &PatWild) {
241 self.outer_attrs(&pat.attrs);
242 self.word("_");
243 }
244
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