use proc_macro2::Span;
use syn::{
parenthesized,
parse::{Parse, ParseStream, Result},
punctuated::Punctuated,
token, BoundLifetimes, Lifetime, ParenthesizedGenericArguments, PathArguments, Token,
TraitBoundModifier,
};
use super::*;
impl Parse for WhereClause {
fn parse(input: ParseStream) -> Result<Self> {
let where_token: token::Where = if input.peek(token::Impl) {
let _: token::Impl = input.parse()?;
token::Where(Span::call_site())
} else if input.peek(token::For) {
let _: token::For = input.parse()?;
token::Where(Span::call_site())
} else {
input.parse()?
};
Ok(WhereClause {
where_token,
predicates: {
let mut predicates = Punctuated::new();
loop {
if input.is_empty()
|| input.peek(token::Brace)
|| input.peek(Token![,])
|| input.peek(Token![;])
|| input.peek(Token![:]) && !input.peek(Token![::])
|| input.peek(Token![=])
{
break;
}
let value = input.parse()?;
predicates.push_value(value);
if !input.peek(Token![,]) {
break;
}
let punct = input.parse()?;
predicates.push_punct(punct);
}
predicates
},
})
}
}
impl Parse for WherePredicate {
fn parse(input: ParseStream) -> Result<Self> {
if input.peek(Lifetime) && input.peek2(Token![:]) {
Ok(WherePredicate::Lifetime(PredicateLifetime {
lifetime: input.parse()?,
colon_token: input.parse()?,
bounds: {
let mut bounds = Punctuated::new();
loop {
if input.is_empty()
|| input.peek(token::Brace)
|| input.peek(Token![,])
|| input.peek(Token![;])
|| input.peek(Token![:])
|| input.peek(Token![=])
{
break;
}
let value = input.parse()?;
bounds.push_value(value);
if !input.peek(Token![+]) {
break;
}
let punct = input.parse()?;
bounds.push_punct(punct);
}
bounds
},
}))
} else {
Ok(WherePredicate::Type(PredicateType {
lifetimes: input.parse()?,
bounded_ty: input.parse()?,
colon_token: input.parse()?,
bounds: {
let mut bounds = Punctuated::new();
loop {
if input.is_empty()
|| input.peek(token::Brace)
|| input.peek(Token![,])
|| input.peek(Token![;])
|| input.peek(Token![:]) && !input.peek(Token![::])
|| input.peek(Token![=])
{
break;
}
let value = input.parse()?;
bounds.push_value(value);
if !input.peek(Token![+]) {
break;
}
let punct = input.parse()?;
bounds.push_punct(punct);
}
bounds
},
}))
}
}
}
impl Parse for TypeParamBound {
fn parse(input: ParseStream) -> Result<Self> {
if input.peek(Lifetime) {
return input.parse().map(TypeParamBound::Lifetime);
}
if input.peek(token::Paren) {
let content;
let paren_token = parenthesized!(content in input);
let mut bound: TraitBound = content.parse()?;
bound.paren_token = Some(paren_token);
return Ok(TypeParamBound::Trait(bound));
}
input.parse().map(TypeParamBound::Trait)
}
}
impl Parse for TraitBound {
fn parse(input: ParseStream) -> Result<Self> {
let dispatch = if input.peek(Token![^]) {
let token: Token![^] = input.parse()?;
Some(token)
} else {
None
};
let modifier: TraitBoundModifier = input.parse()?;
let lifetimes: Option<BoundLifetimes> = input.parse()?;
let mut ty: Type = input.parse()?;
if let Type::Path(ref mut path) = ty {
if path.path.segments.last().unwrap().arguments.is_empty()
&& (input.peek(token::Paren) || input.peek(Token![::]) && input.peek3(token::Paren))
{
input.parse::<Option<Token![::]>>()?;
let args: ParenthesizedGenericArguments = input.parse()?;
let parenthesized = PathArguments::Parenthesized(args);
path.path.segments.last_mut().unwrap().arguments = parenthesized;
}
}
Ok(TraitBound {
paren_token: None,
dispatch,
modifier,
lifetimes,
ty,
})
}
}