1 | use crate::algorithm::Printer; |
2 | use crate::iter::IterDelimited; |
3 | use crate::INDENT; |
4 | use std::ptr; |
5 | use syn::{ |
6 | AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, Expr, GenericArgument, |
7 | ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf, |
8 | }; |
9 | |
10 | #[derive (Copy, Clone, PartialEq)] |
11 | pub enum PathKind { |
12 | // a::B |
13 | Simple, |
14 | // a::B<T> |
15 | Type, |
16 | // a::B::<T> |
17 | Expr, |
18 | } |
19 | |
20 | impl Printer { |
21 | pub fn path(&mut self, path: &Path, kind: PathKind) { |
22 | assert!(!path.segments.is_empty()); |
23 | for segment in path.segments.iter().delimited() { |
24 | if !segment.is_first || path.leading_colon.is_some() { |
25 | self.word("::" ); |
26 | } |
27 | self.path_segment(&segment, kind); |
28 | } |
29 | } |
30 | |
31 | pub fn path_segment(&mut self, segment: &PathSegment, kind: PathKind) { |
32 | self.ident(&segment.ident); |
33 | self.path_arguments(&segment.arguments, kind); |
34 | } |
35 | |
36 | fn path_arguments(&mut self, arguments: &PathArguments, kind: PathKind) { |
37 | match arguments { |
38 | PathArguments::None => {} |
39 | PathArguments::AngleBracketed(arguments) => { |
40 | self.angle_bracketed_generic_arguments(arguments, kind); |
41 | } |
42 | PathArguments::Parenthesized(arguments) => { |
43 | self.parenthesized_generic_arguments(arguments); |
44 | } |
45 | } |
46 | } |
47 | |
48 | fn generic_argument(&mut self, arg: &GenericArgument) { |
49 | match arg { |
50 | GenericArgument::Lifetime(lifetime) => self.lifetime(lifetime), |
51 | GenericArgument::Type(ty) => self.ty(ty), |
52 | GenericArgument::Const(expr) => { |
53 | match expr { |
54 | Expr::Lit(expr) => self.expr_lit(expr), |
55 | Expr::Block(expr) => self.expr_block(expr), |
56 | // ERROR CORRECTION: Add braces to make sure that the |
57 | // generated code is valid. |
58 | _ => { |
59 | self.word("{" ); |
60 | self.expr(expr); |
61 | self.word("}" ); |
62 | } |
63 | } |
64 | } |
65 | GenericArgument::AssocType(assoc) => self.assoc_type(assoc), |
66 | GenericArgument::AssocConst(assoc) => self.assoc_const(assoc), |
67 | GenericArgument::Constraint(constraint) => self.constraint(constraint), |
68 | #[cfg_attr (all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] |
69 | _ => unimplemented!("unknown GenericArgument" ), |
70 | } |
71 | } |
72 | |
73 | pub fn angle_bracketed_generic_arguments( |
74 | &mut self, |
75 | generic: &AngleBracketedGenericArguments, |
76 | path_kind: PathKind, |
77 | ) { |
78 | if generic.args.is_empty() || path_kind == PathKind::Simple { |
79 | return; |
80 | } |
81 | |
82 | if path_kind == PathKind::Expr { |
83 | self.word("::" ); |
84 | } |
85 | self.word("<" ); |
86 | self.cbox(INDENT); |
87 | self.zerobreak(); |
88 | |
89 | // Print lifetimes before types/consts/bindings, regardless of their |
90 | // order in self.args. |
91 | #[derive (Ord, PartialOrd, Eq, PartialEq)] |
92 | enum Group { |
93 | First, |
94 | Second, |
95 | } |
96 | fn group(arg: &GenericArgument) -> Group { |
97 | match arg { |
98 | GenericArgument::Lifetime(_) => Group::First, |
99 | GenericArgument::Type(_) |
100 | | GenericArgument::Const(_) |
101 | | GenericArgument::AssocType(_) |
102 | | GenericArgument::AssocConst(_) |
103 | | GenericArgument::Constraint(_) => Group::Second, |
104 | #[cfg_attr (all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] |
105 | _ => Group::Second, |
106 | } |
107 | } |
108 | let last = generic.args.iter().max_by_key(|param| group(param)); |
109 | for current_group in [Group::First, Group::Second] { |
110 | for arg in &generic.args { |
111 | if group(arg) == current_group { |
112 | self.generic_argument(arg); |
113 | self.trailing_comma(ptr::eq(arg, last.unwrap())); |
114 | } |
115 | } |
116 | } |
117 | |
118 | self.offset(-INDENT); |
119 | self.end(); |
120 | self.word(">" ); |
121 | } |
122 | |
123 | fn assoc_type(&mut self, assoc: &AssocType) { |
124 | self.ident(&assoc.ident); |
125 | if let Some(generics) = &assoc.generics { |
126 | self.angle_bracketed_generic_arguments(generics, PathKind::Type); |
127 | } |
128 | self.word(" = " ); |
129 | self.ty(&assoc.ty); |
130 | } |
131 | |
132 | fn assoc_const(&mut self, assoc: &AssocConst) { |
133 | self.ident(&assoc.ident); |
134 | if let Some(generics) = &assoc.generics { |
135 | self.angle_bracketed_generic_arguments(generics, PathKind::Type); |
136 | } |
137 | self.word(" = " ); |
138 | self.expr(&assoc.value); |
139 | } |
140 | |
141 | fn constraint(&mut self, constraint: &Constraint) { |
142 | self.ident(&constraint.ident); |
143 | if let Some(generics) = &constraint.generics { |
144 | self.angle_bracketed_generic_arguments(generics, PathKind::Type); |
145 | } |
146 | self.ibox(INDENT); |
147 | for bound in constraint.bounds.iter().delimited() { |
148 | if bound.is_first { |
149 | self.word(": " ); |
150 | } else { |
151 | self.space(); |
152 | self.word("+ " ); |
153 | } |
154 | self.type_param_bound(&bound); |
155 | } |
156 | self.end(); |
157 | } |
158 | |
159 | fn parenthesized_generic_arguments(&mut self, arguments: &ParenthesizedGenericArguments) { |
160 | self.cbox(INDENT); |
161 | self.word("(" ); |
162 | self.zerobreak(); |
163 | for ty in arguments.inputs.iter().delimited() { |
164 | self.ty(&ty); |
165 | self.trailing_comma(ty.is_last); |
166 | } |
167 | self.offset(-INDENT); |
168 | self.word(")" ); |
169 | self.return_type(&arguments.output); |
170 | self.end(); |
171 | } |
172 | |
173 | pub fn qpath(&mut self, qself: &Option<QSelf>, path: &Path, kind: PathKind) { |
174 | let qself = match qself { |
175 | Some(qself) => qself, |
176 | None => { |
177 | self.path(path, kind); |
178 | return; |
179 | } |
180 | }; |
181 | |
182 | assert!(qself.position < path.segments.len()); |
183 | |
184 | self.word("<" ); |
185 | self.ty(&qself.ty); |
186 | |
187 | let mut segments = path.segments.iter(); |
188 | if qself.position > 0 { |
189 | self.word(" as " ); |
190 | for segment in segments.by_ref().take(qself.position).delimited() { |
191 | if !segment.is_first || path.leading_colon.is_some() { |
192 | self.word("::" ); |
193 | } |
194 | self.path_segment(&segment, PathKind::Type); |
195 | if segment.is_last { |
196 | self.word(">" ); |
197 | } |
198 | } |
199 | } else { |
200 | self.word(">" ); |
201 | } |
202 | for segment in segments { |
203 | self.word("::" ); |
204 | self.path_segment(segment, kind); |
205 | } |
206 | } |
207 | } |
208 | |