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