1use crate::algorithm::Printer;
2use crate::iter::IterDelimited;
3use crate::INDENT;
4use std::ptr;
5use syn::{
6 AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, Expr, GenericArgument,
7 ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
8};
9
10#[derive(Copy, Clone, PartialEq)]
11pub enum PathKind {
12 // a::B
13 Simple,
14 // a::B<T>
15 Type,
16 // a::B::<T>
17 Expr,
18}
19
20impl 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