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, 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 | #![cfg_attr (all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] |
51 | GenericArgument::Lifetime(lifetime) => self.lifetime(lifetime), |
52 | GenericArgument::Type(ty) => self.ty(ty), |
53 | GenericArgument::Const(expr) => self.const_argument(expr), |
54 | GenericArgument::AssocType(assoc) => self.assoc_type(assoc), |
55 | GenericArgument::AssocConst(assoc) => self.assoc_const(assoc), |
56 | GenericArgument::Constraint(constraint) => self.constraint(constraint), |
57 | _ => unimplemented!("unknown GenericArgument" ), |
58 | } |
59 | } |
60 | |
61 | pub fn angle_bracketed_generic_arguments( |
62 | &mut self, |
63 | generic: &AngleBracketedGenericArguments, |
64 | path_kind: PathKind, |
65 | ) { |
66 | if generic.args.is_empty() || path_kind == PathKind::Simple { |
67 | return; |
68 | } |
69 | |
70 | if path_kind == PathKind::Expr { |
71 | self.word("::" ); |
72 | } |
73 | self.word("<" ); |
74 | self.cbox(INDENT); |
75 | self.zerobreak(); |
76 | |
77 | // Print lifetimes before types/consts/bindings, regardless of their |
78 | // order in self.args. |
79 | #[derive (Ord, PartialOrd, Eq, PartialEq)] |
80 | enum Group { |
81 | First, |
82 | Second, |
83 | } |
84 | fn group(arg: &GenericArgument) -> Group { |
85 | match arg { |
86 | #![cfg_attr (all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] |
87 | GenericArgument::Lifetime(_) => Group::First, |
88 | GenericArgument::Type(_) |
89 | | GenericArgument::Const(_) |
90 | | GenericArgument::AssocType(_) |
91 | | GenericArgument::AssocConst(_) |
92 | | GenericArgument::Constraint(_) => Group::Second, |
93 | _ => Group::Second, |
94 | } |
95 | } |
96 | let last = generic.args.iter().max_by_key(|param| group(param)); |
97 | for current_group in [Group::First, Group::Second] { |
98 | for arg in &generic.args { |
99 | if group(arg) == current_group { |
100 | self.generic_argument(arg); |
101 | self.trailing_comma(ptr::eq(arg, last.unwrap())); |
102 | } |
103 | } |
104 | } |
105 | |
106 | self.offset(-INDENT); |
107 | self.end(); |
108 | self.word(">" ); |
109 | } |
110 | |
111 | fn assoc_type(&mut self, assoc: &AssocType) { |
112 | self.ident(&assoc.ident); |
113 | if let Some(generics) = &assoc.generics { |
114 | self.angle_bracketed_generic_arguments(generics, PathKind::Type); |
115 | } |
116 | self.word(" = " ); |
117 | self.ty(&assoc.ty); |
118 | } |
119 | |
120 | fn assoc_const(&mut self, assoc: &AssocConst) { |
121 | self.ident(&assoc.ident); |
122 | if let Some(generics) = &assoc.generics { |
123 | self.angle_bracketed_generic_arguments(generics, PathKind::Type); |
124 | } |
125 | self.word(" = " ); |
126 | self.const_argument(&assoc.value); |
127 | } |
128 | |
129 | fn constraint(&mut self, constraint: &Constraint) { |
130 | self.ident(&constraint.ident); |
131 | if let Some(generics) = &constraint.generics { |
132 | self.angle_bracketed_generic_arguments(generics, PathKind::Type); |
133 | } |
134 | self.ibox(INDENT); |
135 | for bound in constraint.bounds.iter().delimited() { |
136 | if bound.is_first { |
137 | self.word(": " ); |
138 | } else { |
139 | self.space(); |
140 | self.word("+ " ); |
141 | } |
142 | self.type_param_bound(&bound); |
143 | } |
144 | self.end(); |
145 | } |
146 | |
147 | fn parenthesized_generic_arguments(&mut self, arguments: &ParenthesizedGenericArguments) { |
148 | self.cbox(INDENT); |
149 | self.word("(" ); |
150 | self.zerobreak(); |
151 | for ty in arguments.inputs.iter().delimited() { |
152 | self.ty(&ty); |
153 | self.trailing_comma(ty.is_last); |
154 | } |
155 | self.offset(-INDENT); |
156 | self.word(")" ); |
157 | self.return_type(&arguments.output); |
158 | self.end(); |
159 | } |
160 | |
161 | pub fn qpath(&mut self, qself: &Option<QSelf>, path: &Path, kind: PathKind) { |
162 | let qself = if let Some(qself) = qself { |
163 | qself |
164 | } else { |
165 | self.path(path, kind); |
166 | return; |
167 | }; |
168 | |
169 | assert!(qself.position < path.segments.len()); |
170 | |
171 | self.word("<" ); |
172 | self.ty(&qself.ty); |
173 | |
174 | let mut segments = path.segments.iter(); |
175 | if qself.position > 0 { |
176 | self.word(" as " ); |
177 | for segment in segments.by_ref().take(qself.position).delimited() { |
178 | if !segment.is_first || path.leading_colon.is_some() { |
179 | self.word("::" ); |
180 | } |
181 | self.path_segment(&segment, PathKind::Type); |
182 | if segment.is_last { |
183 | self.word(">" ); |
184 | } |
185 | } |
186 | } else { |
187 | self.word(">" ); |
188 | } |
189 | for segment in segments { |
190 | self.word("::" ); |
191 | self.path_segment(segment, kind); |
192 | } |
193 | } |
194 | } |
195 | |