prettyplease/
path.rs
1use crate::algorithm::Printer;
2use crate::iter::IterDelimited;
3use crate::INDENT;
4use std::ptr;
5use syn::{
6 AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, 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) => 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 #[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}