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 #![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 angle_bracketed_generic_arguments( &mut self, generic: &AngleBracketedGenericArguments, path_kind: PathKind, )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 assoc_type(&mut self, assoc: &AssocType)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 assoc_const(&mut self, assoc: &AssocConst)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 constraint(&mut self, constraint: &Constraint)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 parenthesized_generic_arguments(&mut self, arguments: &ParenthesizedGenericArguments)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 qpath(&mut self, qself: &Option<QSelf>, path: &Path, kind: PathKind)174 pub fn qpath(&mut self, qself: &Option<QSelf>, path: &Path, kind: PathKind) { 175 let qself = match qself { 176 Some(qself) => qself, 177 None => { 178 self.path(path, kind); 179 return; 180 } 181 }; 182 183 assert!(qself.position < path.segments.len()); 184 185 self.word("<"); 186 self.ty(&qself.ty); 187 188 let mut segments = path.segments.iter(); 189 if qself.position > 0 { 190 self.word(" as "); 191 for segment in segments.by_ref().take(qself.position).delimited() { 192 if !segment.is_first || path.leading_colon.is_some() { 193 self.word("::"); 194 } 195 self.path_segment(&segment, PathKind::Type); 196 if segment.is_last { 197 self.word(">"); 198 } 199 } 200 } else { 201 self.word(">"); 202 } 203 for segment in segments { 204 self.word("::"); 205 self.path_segment(segment, kind); 206 } 207 } 208 } 209