prettyplease/
path.rs

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}