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            #![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                    // ERROR CORRECTION: Add braces to make sure that the
59                    // generated code is valid.
60                    _ => {
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        // Print lifetimes before types/consts/bindings, regardless of their
91        // order in self.args.
92        #[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}