diff options
Diffstat (limited to 'vendor/prettyplease/src/generics.rs')
| -rw-r--r-- | vendor/prettyplease/src/generics.rs | 383 |
1 files changed, 383 insertions, 0 deletions
diff --git a/vendor/prettyplease/src/generics.rs b/vendor/prettyplease/src/generics.rs new file mode 100644 index 00000000..3f225b88 --- /dev/null +++ b/vendor/prettyplease/src/generics.rs @@ -0,0 +1,383 @@ +use crate::algorithm::Printer; +use crate::iter::IterDelimited; +use crate::path::PathKind; +use crate::INDENT; +use proc_macro2::TokenStream; +use std::ptr; +use syn::{ + BoundLifetimes, CapturedParam, ConstParam, Expr, GenericParam, Generics, LifetimeParam, + PreciseCapture, PredicateLifetime, PredicateType, TraitBound, TraitBoundModifier, TypeParam, + TypeParamBound, WhereClause, WherePredicate, +}; + +impl Printer { + pub fn generics(&mut self, generics: &Generics) { + if generics.params.is_empty() { + return; + } + + self.word("<"); + self.cbox(0); + self.zerobreak(); + + // Print lifetimes before types and consts, regardless of their + // order in self.params. + #[derive(Ord, PartialOrd, Eq, PartialEq)] + enum Group { + First, + Second, + } + fn group(param: &GenericParam) -> Group { + match param { + GenericParam::Lifetime(_) => Group::First, + GenericParam::Type(_) | GenericParam::Const(_) => Group::Second, + } + } + let last = generics.params.iter().max_by_key(|param| group(param)); + for current_group in [Group::First, Group::Second] { + for param in &generics.params { + if group(param) == current_group { + self.generic_param(param); + self.trailing_comma(ptr::eq(param, last.unwrap())); + } + } + } + + self.offset(-INDENT); + self.end(); + self.word(">"); + } + + fn generic_param(&mut self, generic_param: &GenericParam) { + match generic_param { + GenericParam::Type(type_param) => self.type_param(type_param), + GenericParam::Lifetime(lifetime_param) => self.lifetime_param(lifetime_param), + GenericParam::Const(const_param) => self.const_param(const_param), + } + } + + pub fn bound_lifetimes(&mut self, bound_lifetimes: &BoundLifetimes) { + self.word("for<"); + for param in bound_lifetimes.lifetimes.iter().delimited() { + self.generic_param(¶m); + if !param.is_last { + self.word(", "); + } + } + self.word("> "); + } + + fn lifetime_param(&mut self, lifetime_param: &LifetimeParam) { + self.outer_attrs(&lifetime_param.attrs); + self.lifetime(&lifetime_param.lifetime); + for lifetime in lifetime_param.bounds.iter().delimited() { + if lifetime.is_first { + self.word(": "); + } else { + self.word(" + "); + } + self.lifetime(&lifetime); + } + } + + fn type_param(&mut self, type_param: &TypeParam) { + self.outer_attrs(&type_param.attrs); + self.ident(&type_param.ident); + self.ibox(INDENT); + for type_param_bound in type_param.bounds.iter().delimited() { + if type_param_bound.is_first { + self.word(": "); + } else { + self.space(); + self.word("+ "); + } + self.type_param_bound(&type_param_bound); + } + if let Some(default) = &type_param.default { + self.space(); + self.word("= "); + self.ty(default); + } + self.end(); + } + + pub fn type_param_bound(&mut self, type_param_bound: &TypeParamBound) { + match type_param_bound { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + TypeParamBound::Trait(trait_bound) => { + let tilde_const = false; + self.trait_bound(trait_bound, tilde_const); + } + TypeParamBound::Lifetime(lifetime) => self.lifetime(lifetime), + TypeParamBound::PreciseCapture(precise_capture) => { + self.precise_capture(precise_capture); + } + TypeParamBound::Verbatim(bound) => self.type_param_bound_verbatim(bound), + _ => unimplemented!("unknown TypeParamBound"), + } + } + + fn trait_bound(&mut self, trait_bound: &TraitBound, tilde_const: bool) { + if trait_bound.paren_token.is_some() { + self.word("("); + } + if tilde_const { + self.word("~const "); + } + self.trait_bound_modifier(&trait_bound.modifier); + if let Some(bound_lifetimes) = &trait_bound.lifetimes { + self.bound_lifetimes(bound_lifetimes); + } + for segment in trait_bound.path.segments.iter().delimited() { + if !segment.is_first || trait_bound.path.leading_colon.is_some() { + self.word("::"); + } + self.path_segment(&segment, PathKind::Type); + } + if trait_bound.paren_token.is_some() { + self.word(")"); + } + } + + fn trait_bound_modifier(&mut self, trait_bound_modifier: &TraitBoundModifier) { + match trait_bound_modifier { + TraitBoundModifier::None => {} + TraitBoundModifier::Maybe(_question_mark) => self.word("?"), + } + } + + #[cfg(not(feature = "verbatim"))] + fn type_param_bound_verbatim(&mut self, bound: &TokenStream) { + unimplemented!("TypeParamBound::Verbatim `{}`", bound); + } + + #[cfg(feature = "verbatim")] + fn type_param_bound_verbatim(&mut self, tokens: &TokenStream) { + use syn::parse::{Parse, ParseStream, Result}; + use syn::{parenthesized, token, Token}; + + enum TypeParamBoundVerbatim { + Ellipsis, + TildeConst(TraitBound), + } + + impl Parse for TypeParamBoundVerbatim { + fn parse(input: ParseStream) -> Result<Self> { + let content; + let (paren_token, content) = if input.peek(token::Paren) { + (Some(parenthesized!(content in input)), &content) + } else { + (None, input) + }; + let lookahead = content.lookahead1(); + if lookahead.peek(Token![~]) { + content.parse::<Token![~]>()?; + content.parse::<Token![const]>()?; + let mut bound: TraitBound = content.parse()?; + bound.paren_token = paren_token; + Ok(TypeParamBoundVerbatim::TildeConst(bound)) + } else if lookahead.peek(Token![...]) { + content.parse::<Token![...]>()?; + Ok(TypeParamBoundVerbatim::Ellipsis) + } else { + Err(lookahead.error()) + } + } + } + + let bound: TypeParamBoundVerbatim = match syn::parse2(tokens.clone()) { + Ok(bound) => bound, + Err(_) => unimplemented!("TypeParamBound::Verbatim `{}`", tokens), + }; + + match bound { + TypeParamBoundVerbatim::Ellipsis => { + self.word("..."); + } + TypeParamBoundVerbatim::TildeConst(trait_bound) => { + let tilde_const = true; + self.trait_bound(&trait_bound, tilde_const); + } + } + } + + fn const_param(&mut self, const_param: &ConstParam) { + self.outer_attrs(&const_param.attrs); + self.word("const "); + self.ident(&const_param.ident); + self.word(": "); + self.ty(&const_param.ty); + if let Some(default) = &const_param.default { + self.word(" = "); + self.const_argument(default); + } + } + + pub fn where_clause_for_body(&mut self, where_clause: &Option<WhereClause>) { + let hardbreaks = true; + let semi = false; + self.where_clause_impl(where_clause, hardbreaks, semi); + } + + pub fn where_clause_semi(&mut self, where_clause: &Option<WhereClause>) { + let hardbreaks = true; + let semi = true; + self.where_clause_impl(where_clause, hardbreaks, semi); + } + + pub fn where_clause_oneline(&mut self, where_clause: &Option<WhereClause>) { + let hardbreaks = false; + let semi = false; + self.where_clause_impl(where_clause, hardbreaks, semi); + } + + pub fn where_clause_oneline_semi(&mut self, where_clause: &Option<WhereClause>) { + let hardbreaks = false; + let semi = true; + self.where_clause_impl(where_clause, hardbreaks, semi); + } + + fn where_clause_impl( + &mut self, + where_clause: &Option<WhereClause>, + hardbreaks: bool, + semi: bool, + ) { + let where_clause = match where_clause { + Some(where_clause) if !where_clause.predicates.is_empty() => where_clause, + _ => { + if semi { + self.word(";"); + } else { + self.nbsp(); + } + return; + } + }; + if hardbreaks { + self.hardbreak(); + self.offset(-INDENT); + self.word("where"); + self.hardbreak(); + for predicate in where_clause.predicates.iter().delimited() { + self.where_predicate(&predicate); + if predicate.is_last && semi { + self.word(";"); + } else { + self.word(","); + self.hardbreak(); + } + } + if !semi { + self.offset(-INDENT); + } + } else { + self.space(); + self.offset(-INDENT); + self.word("where"); + self.space(); + for predicate in where_clause.predicates.iter().delimited() { + self.where_predicate(&predicate); + if predicate.is_last && semi { + self.word(";"); + } else { + self.trailing_comma_or_space(predicate.is_last); + } + } + if !semi { + self.offset(-INDENT); + } + } + } + + fn where_predicate(&mut self, predicate: &WherePredicate) { + match predicate { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + WherePredicate::Type(predicate) => self.predicate_type(predicate), + WherePredicate::Lifetime(predicate) => self.predicate_lifetime(predicate), + _ => unimplemented!("unknown WherePredicate"), + } + } + + fn predicate_type(&mut self, predicate: &PredicateType) { + if let Some(bound_lifetimes) = &predicate.lifetimes { + self.bound_lifetimes(bound_lifetimes); + } + self.ty(&predicate.bounded_ty); + self.word(":"); + if predicate.bounds.len() == 1 { + self.ibox(0); + } else { + self.ibox(INDENT); + } + for type_param_bound in predicate.bounds.iter().delimited() { + if type_param_bound.is_first { + self.nbsp(); + } else { + self.space(); + self.word("+ "); + } + self.type_param_bound(&type_param_bound); + } + self.end(); + } + + fn predicate_lifetime(&mut self, predicate: &PredicateLifetime) { + self.lifetime(&predicate.lifetime); + self.word(":"); + self.ibox(INDENT); + for lifetime in predicate.bounds.iter().delimited() { + if lifetime.is_first { + self.nbsp(); + } else { + self.space(); + self.word("+ "); + } + self.lifetime(&lifetime); + } + self.end(); + } + + fn precise_capture(&mut self, precise_capture: &PreciseCapture) { + self.word("use<"); + for capture in precise_capture.params.iter().delimited() { + self.captured_param(&capture); + if !capture.is_last { + self.word(", "); + } + } + self.word(">"); + } + + fn captured_param(&mut self, capture: &CapturedParam) { + match capture { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + CapturedParam::Lifetime(lifetime) => self.lifetime(lifetime), + CapturedParam::Ident(ident) => self.ident(ident), + _ => unimplemented!("unknown CapturedParam"), + } + } + + pub fn const_argument(&mut self, expr: &Expr) { + match expr { + #![cfg_attr(all(test, exhaustive), allow(non_exhaustive_omitted_patterns))] + Expr::Lit(expr) => self.expr_lit(expr), + + Expr::Path(expr) + if expr.attrs.is_empty() + && expr.qself.is_none() + && expr.path.get_ident().is_some() => + { + self.expr_path(expr); + } + + Expr::Block(expr) => self.expr_block(expr), + + _ => { + self.cbox(INDENT); + self.expr_as_small_block(expr, 0); + self.end(); + } + } + } +} |
