| 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, 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 { |
| 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) => self.const_argument(expr), |
| 54 | GenericArgument::AssocType(assoc) => self.assoc_type(assoc), |
| 55 | GenericArgument::AssocConst(assoc) => self.assoc_const(assoc), |
| 56 | GenericArgument::Constraint(constraint) => self.constraint(constraint), |
| 57 | _ => unimplemented!("unknown GenericArgument" ), |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | pub fn angle_bracketed_generic_arguments( |
| 62 | &mut self, |
| 63 | generic: &AngleBracketedGenericArguments, |
| 64 | path_kind: PathKind, |
| 65 | ) { |
| 66 | if generic.args.is_empty() || path_kind == PathKind::Simple { |
| 67 | return; |
| 68 | } |
| 69 | |
| 70 | if path_kind == PathKind::Expr { |
| 71 | self.word("::" ); |
| 72 | } |
| 73 | self.word("<" ); |
| 74 | self.cbox(INDENT); |
| 75 | self.zerobreak(); |
| 76 | |
| 77 | // Print lifetimes before types/consts/bindings, regardless of their |
| 78 | // order in self.args. |
| 79 | #[derive (Ord, PartialOrd, Eq, PartialEq)] |
| 80 | enum Group { |
| 81 | First, |
| 82 | Second, |
| 83 | } |
| 84 | fn group(arg: &GenericArgument) -> Group { |
| 85 | match arg { |
| 86 | #![cfg_attr (all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] |
| 87 | GenericArgument::Lifetime(_) => Group::First, |
| 88 | GenericArgument::Type(_) |
| 89 | | GenericArgument::Const(_) |
| 90 | | GenericArgument::AssocType(_) |
| 91 | | GenericArgument::AssocConst(_) |
| 92 | | GenericArgument::Constraint(_) => Group::Second, |
| 93 | _ => Group::Second, |
| 94 | } |
| 95 | } |
| 96 | let last = generic.args.iter().max_by_key(|param| group(param)); |
| 97 | for current_group in [Group::First, Group::Second] { |
| 98 | for arg in &generic.args { |
| 99 | if group(arg) == current_group { |
| 100 | self.generic_argument(arg); |
| 101 | self.trailing_comma(ptr::eq(arg, last.unwrap())); |
| 102 | } |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | self.offset(-INDENT); |
| 107 | self.end(); |
| 108 | self.word(">" ); |
| 109 | } |
| 110 | |
| 111 | fn assoc_type(&mut self, assoc: &AssocType) { |
| 112 | self.ident(&assoc.ident); |
| 113 | if let Some(generics) = &assoc.generics { |
| 114 | self.angle_bracketed_generic_arguments(generics, PathKind::Type); |
| 115 | } |
| 116 | self.word(" = " ); |
| 117 | self.ty(&assoc.ty); |
| 118 | } |
| 119 | |
| 120 | fn assoc_const(&mut self, assoc: &AssocConst) { |
| 121 | self.ident(&assoc.ident); |
| 122 | if let Some(generics) = &assoc.generics { |
| 123 | self.angle_bracketed_generic_arguments(generics, PathKind::Type); |
| 124 | } |
| 125 | self.word(" = " ); |
| 126 | self.const_argument(&assoc.value); |
| 127 | } |
| 128 | |
| 129 | fn constraint(&mut self, constraint: &Constraint) { |
| 130 | self.ident(&constraint.ident); |
| 131 | if let Some(generics) = &constraint.generics { |
| 132 | self.angle_bracketed_generic_arguments(generics, PathKind::Type); |
| 133 | } |
| 134 | self.ibox(INDENT); |
| 135 | for bound in constraint.bounds.iter().delimited() { |
| 136 | if bound.is_first { |
| 137 | self.word(": " ); |
| 138 | } else { |
| 139 | self.space(); |
| 140 | self.word("+ " ); |
| 141 | } |
| 142 | self.type_param_bound(&bound); |
| 143 | } |
| 144 | self.end(); |
| 145 | } |
| 146 | |
| 147 | fn parenthesized_generic_arguments(&mut self, arguments: &ParenthesizedGenericArguments) { |
| 148 | self.cbox(INDENT); |
| 149 | self.word("(" ); |
| 150 | self.zerobreak(); |
| 151 | for ty in arguments.inputs.iter().delimited() { |
| 152 | self.ty(&ty); |
| 153 | self.trailing_comma(ty.is_last); |
| 154 | } |
| 155 | self.offset(-INDENT); |
| 156 | self.word(")" ); |
| 157 | self.return_type(&arguments.output); |
| 158 | self.end(); |
| 159 | } |
| 160 | |
| 161 | pub fn qpath(&mut self, qself: &Option<QSelf>, path: &Path, kind: PathKind) { |
| 162 | let qself = if let Some(qself) = qself { |
| 163 | qself |
| 164 | } else { |
| 165 | self.path(path, kind); |
| 166 | return; |
| 167 | }; |
| 168 | |
| 169 | assert!(qself.position < path.segments.len()); |
| 170 | |
| 171 | self.word("<" ); |
| 172 | self.ty(&qself.ty); |
| 173 | |
| 174 | let mut segments = path.segments.iter(); |
| 175 | if qself.position > 0 { |
| 176 | self.word(" as " ); |
| 177 | for segment in segments.by_ref().take(qself.position).delimited() { |
| 178 | if !segment.is_first || path.leading_colon.is_some() { |
| 179 | self.word("::" ); |
| 180 | } |
| 181 | self.path_segment(&segment, PathKind::Type); |
| 182 | if segment.is_last { |
| 183 | self.word(">" ); |
| 184 | } |
| 185 | } |
| 186 | } else { |
| 187 | self.word(">" ); |
| 188 | } |
| 189 | for segment in segments { |
| 190 | self.word("::" ); |
| 191 | self.path_segment(segment, kind); |
| 192 | } |
| 193 | } |
| 194 | } |
| 195 | |