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