• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
path(&mut self, path: &Path, kind: PathKind)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 
path_segment(&mut self, segment: &PathSegment, kind: PathKind)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 
path_arguments(&mut self, arguments: &PathArguments, kind: PathKind)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 
generic_argument(&mut self, arg: &GenericArgument)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 
angle_bracketed_generic_arguments( &mut self, generic: &AngleBracketedGenericArguments, path_kind: PathKind, )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 
assoc_type(&mut self, assoc: &AssocType)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 
assoc_const(&mut self, assoc: &AssocConst)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 
constraint(&mut self, constraint: &Constraint)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 
parenthesized_generic_arguments(&mut self, arguments: &ParenthesizedGenericArguments)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 
qpath(&mut self, qself: &Option<QSelf>, path: &Path, kind: PathKind)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