use super::*;
use proc_macro2::TokenStream;
use punctuated::Punctuated;
#[cfg(feature = "extra-traits")]
use std::hash::{Hash, Hasher};
#[cfg(feature = "extra-traits")]
use tt::TokenStreamHelper;
ast_enum_of_structs! {
pub enum Type {
pub Slice(TypeSlice {
pub bracket_token: token::Bracket,
pub elem: Box<Type>,
}),
pub Array(TypeArray {
pub bracket_token: token::Bracket,
pub elem: Box<Type>,
pub semi_token: Token![;],
pub len: Expr,
}),
pub Ptr(TypePtr {
pub star_token: Token![*],
pub const_token: Option<Token![const]>,
pub mutability: Option<Token![mut]>,
pub elem: Box<Type>,
}),
pub Reference(TypeReference {
pub and_token: Token![&],
pub lifetime: Option<Lifetime>,
pub mutability: Option<Token![mut]>,
pub elem: Box<Type>,
}),
pub BareFn(TypeBareFn {
pub lifetimes: Option<BoundLifetimes>,
pub unsafety: Option<Token![unsafe]>,
pub abi: Option<Abi>,
pub fn_token: Token![fn],
pub paren_token: token::Paren,
pub inputs: Punctuated<BareFnArg, Token![,]>,
pub variadic: Option<Token![...]>,
pub output: ReturnType,
}),
pub Never(TypeNever {
pub bang_token: Token![!],
}),
pub Tuple(TypeTuple {
pub paren_token: token::Paren,
pub elems: Punctuated<Type, Token![,]>,
}),
pub Path(TypePath {
pub qself: Option<QSelf>,
pub path: Path,
}),
pub TraitObject(TypeTraitObject {
pub dyn_token: Option<Token![dyn]>,
pub bounds: Punctuated<TypeParamBound, Token![+]>,
}),
pub ImplTrait(TypeImplTrait {
pub impl_token: Token![impl],
pub bounds: Punctuated<TypeParamBound, Token![+]>,
}),
pub Paren(TypeParen {
pub paren_token: token::Paren,
pub elem: Box<Type>,
}),
pub Group(TypeGroup {
pub group_token: token::Group,
pub elem: Box<Type>,
}),
pub Infer(TypeInfer {
pub underscore_token: Token![_],
}),
pub Macro(TypeMacro {
pub mac: Macro,
}),
pub Verbatim(TypeVerbatim #manual_extra_traits {
pub tts: TokenStream,
}),
}
}
#[cfg(feature = "extra-traits")]
impl Eq for TypeVerbatim {}
#[cfg(feature = "extra-traits")]
impl PartialEq for TypeVerbatim {
fn eq(&self, other: &Self) -> bool {
TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts)
}
}
#[cfg(feature = "extra-traits")]
impl Hash for TypeVerbatim {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
TokenStreamHelper(&self.tts).hash(state);
}
}
ast_struct! {
pub struct Abi {
pub extern_token: Token![extern],
pub name: Option<LitStr>,
}
}
ast_struct! {
pub struct BareFnArg {
pub name: Option<(BareFnArgName, Token![:])>,
pub ty: Type,
}
}
ast_enum! {
pub enum BareFnArgName {
Named(Ident),
Wild(Token![_]),
}
}
ast_enum! {
pub enum ReturnType {
Default,
Type(Token![->], Box<Type>),
}
}
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
use parse::{Parse, ParseStream, Result};
use path;
impl Parse for Type {
fn parse(input: ParseStream) -> Result<Self> {
ambig_ty(input, true)
}
}
impl Type {
pub fn without_plus(input: ParseStream) -> Result<Self> {
ambig_ty(input, false)
}
}
fn ambig_ty(input: ParseStream, allow_plus: bool) -> Result<Type> {
if input.peek(token::Group) {
return input.parse().map(Type::Group);
}
let mut lifetimes = None::<BoundLifetimes>;
let mut lookahead = input.lookahead1();
if lookahead.peek(Token![for]) {
lifetimes = input.parse()?;
lookahead = input.lookahead1();
if !lookahead.peek(Ident)
&& !lookahead.peek(Token![fn])
&& !lookahead.peek(Token![unsafe])
&& !lookahead.peek(Token![extern])
&& !lookahead.peek(Token![super])
&& !lookahead.peek(Token![self])
&& !lookahead.peek(Token![Self])
&& !lookahead.peek(Token![crate])
{
return Err(lookahead.error());
}
}
if lookahead.peek(token::Paren) {
let content;
let paren_token = parenthesized!(content in input);
if content.is_empty() {
return Ok(Type::Tuple(TypeTuple {
paren_token: paren_token,
elems: Punctuated::new(),
}));
}
if content.peek(Lifetime) {
return Ok(Type::Paren(TypeParen {
paren_token: paren_token,
elem: Box::new(Type::TraitObject(content.parse()?)),
}));
}
if content.peek(Token![?]) {
return Ok(Type::TraitObject(TypeTraitObject {
dyn_token: None,
bounds: {
let mut bounds = Punctuated::new();
bounds.push_value(TypeParamBound::Trait(TraitBound {
paren_token: Some(paren_token),
..content.parse()?
}));
while let Some(plus) = input.parse()? {
bounds.push_punct(plus);
bounds.push_value(input.parse()?);
}
bounds
},
}));
}
let first: Type = content.parse()?;
if content.peek(Token![,]) {
return Ok(Type::Tuple(TypeTuple {
paren_token: paren_token,
elems: {
let mut elems = Punctuated::new();
elems.push_value(first);
elems.push_punct(content.parse()?);
let rest: Punctuated<Type, Token![,]> =
content.parse_terminated(Parse::parse)?;
elems.extend(rest);
elems
},
}));
}
if allow_plus && input.peek(Token![+]) {
loop {
let first = match first {
Type::Path(TypePath { qself: None, path }) => {
TypeParamBound::Trait(TraitBound {
paren_token: Some(paren_token),
modifier: TraitBoundModifier::None,
lifetimes: None,
path: path,
})
}
Type::TraitObject(TypeTraitObject {
dyn_token: None,
ref bounds,
}) => {
if bounds.len() > 1 || bounds.trailing_punct() {
break;
}
match first {
Type::TraitObject(TypeTraitObject { bounds, .. }) => {
match bounds.into_iter().next().unwrap() {
TypeParamBound::Trait(trait_bound) => {
TypeParamBound::Trait(TraitBound {
paren_token: Some(paren_token),
..trait_bound
})
}
other => other,
}
}
_ => unreachable!(),
}
}
_ => break,
};
return Ok(Type::TraitObject(TypeTraitObject {
dyn_token: None,
bounds: {
let mut bounds = Punctuated::new();
bounds.push_value(first);
while let Some(plus) = input.parse()? {
bounds.push_punct(plus);
bounds.push_value(input.parse()?);
}
bounds
},
}));
}
}
Ok(Type::Paren(TypeParen {
paren_token: paren_token,
elem: Box::new(first),
}))
} else if lookahead.peek(Token![fn])
|| lookahead.peek(Token![unsafe])
|| lookahead.peek(Token![extern]) && !input.peek2(Token![::])
{
let mut bare_fn: TypeBareFn = input.parse()?;
bare_fn.lifetimes = lifetimes;
Ok(Type::BareFn(bare_fn))
} else if lookahead.peek(Ident)
|| input.peek(Token![super])
|| input.peek(Token![self])
|| input.peek(Token![Self])
|| input.peek(Token![crate])
|| input.peek(Token![extern])
|| lookahead.peek(Token![::])
|| lookahead.peek(Token![<])
{
if input.peek(Token![dyn]) {
let mut trait_object: TypeTraitObject = input.parse()?;
if lifetimes.is_some() {
match *trait_object.bounds.iter_mut().next().unwrap() {
TypeParamBound::Trait(ref mut trait_bound) => {
trait_bound.lifetimes = lifetimes;
}
TypeParamBound::Lifetime(_) => unreachable!(),
}
}
return Ok(Type::TraitObject(trait_object));
}
let ty: TypePath = input.parse()?;
if ty.qself.is_some() {
return Ok(Type::Path(ty));
}
if input.peek(Token![!]) && !input.peek(Token![!=]) {
let mut contains_arguments = false;
for segment in &ty.path.segments {
match segment.arguments {
PathArguments::None => {}
PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => {
contains_arguments = true;
}
}
}
if !contains_arguments {
let bang_token: Token![!] = input.parse()?;
let (delimiter, tts) = mac::parse_delimiter(input)?;
return Ok(Type::Macro(TypeMacro {
mac: Macro {
path: ty.path,
bang_token: bang_token,
delimiter: delimiter,
tts: tts,
},
}));
}
}
if lifetimes.is_some() || allow_plus && input.peek(Token![+]) {
let mut bounds = Punctuated::new();
bounds.push_value(TypeParamBound::Trait(TraitBound {
paren_token: None,
modifier: TraitBoundModifier::None,
lifetimes: lifetimes,
path: ty.path,
}));
if allow_plus {
while input.peek(Token![+]) {
bounds.push_punct(input.parse()?);
if input.peek(Token![>]) {
break;
}
bounds.push_value(input.parse()?);
}
}
return Ok(Type::TraitObject(TypeTraitObject {
dyn_token: None,
bounds: bounds,
}));
}
Ok(Type::Path(ty))
} else if lookahead.peek(token::Bracket) {
let content;
let bracket_token = bracketed!(content in input);
let elem: Type = content.parse()?;
if content.peek(Token![;]) {
Ok(Type::Array(TypeArray {
bracket_token: bracket_token,
elem: Box::new(elem),
semi_token: content.parse()?,
len: content.parse()?,
}))
} else {
Ok(Type::Slice(TypeSlice {
bracket_token: bracket_token,
elem: Box::new(elem),
}))
}
} else if lookahead.peek(Token![*]) {
input.parse().map(Type::Ptr)
} else if lookahead.peek(Token![&]) {
input.parse().map(Type::Reference)
} else if lookahead.peek(Token![!]) && !input.peek(Token![=]) {
input.parse().map(Type::Never)
} else if lookahead.peek(Token![impl]) {
input.parse().map(Type::ImplTrait)
} else if lookahead.peek(Token![_]) {
input.parse().map(Type::Infer)
} else if lookahead.peek(Lifetime) {
input.parse().map(Type::TraitObject)
} else {
Err(lookahead.error())
}
}
impl Parse for TypeSlice {
fn parse(input: ParseStream) -> Result<Self> {
let content;
Ok(TypeSlice {
bracket_token: bracketed!(content in input),
elem: content.parse()?,
})
}
}
impl Parse for TypeArray {
fn parse(input: ParseStream) -> Result<Self> {
let content;
Ok(TypeArray {
bracket_token: bracketed!(content in input),
elem: content.parse()?,
semi_token: content.parse()?,
len: content.parse()?,
})
}
}
impl Parse for TypePtr {
fn parse(input: ParseStream) -> Result<Self> {
let star_token: Token![*] = input.parse()?;
let lookahead = input.lookahead1();
let (const_token, mutability) = if lookahead.peek(Token![const]) {
(Some(input.parse()?), None)
} else if lookahead.peek(Token![mut]) {
(None, Some(input.parse()?))
} else {
return Err(lookahead.error());
};
Ok(TypePtr {
star_token: star_token,
const_token: const_token,
mutability: mutability,
elem: Box::new(input.call(Type::without_plus)?),
})
}
}
impl Parse for TypeReference {
fn parse(input: ParseStream) -> Result<Self> {
Ok(TypeReference {
and_token: input.parse()?,
lifetime: input.parse()?,
mutability: input.parse()?,
elem: Box::new(input.call(Type::without_plus)?),
})
}
}
impl Parse for TypeBareFn {
fn parse(input: ParseStream) -> Result<Self> {
let args;
let allow_variadic;
Ok(TypeBareFn {
lifetimes: input.parse()?,
unsafety: input.parse()?,
abi: input.parse()?,
fn_token: input.parse()?,
paren_token: parenthesized!(args in input),
inputs: {
let mut inputs = Punctuated::new();
while !args.is_empty() && !args.peek(Token![...]) {
inputs.push_value(args.parse()?);
if args.is_empty() {
break;
}
inputs.push_punct(args.parse()?);
}
allow_variadic = inputs.empty_or_trailing();
inputs
},
variadic: {
if allow_variadic && args.peek(Token![...]) {
Some(args.parse()?)
} else {
None
}
},
output: input.call(ReturnType::without_plus)?,
})
}
}
impl Parse for TypeNever {
fn parse(input: ParseStream) -> Result<Self> {
Ok(TypeNever {
bang_token: input.parse()?,
})
}
}
impl Parse for TypeInfer {
fn parse(input: ParseStream) -> Result<Self> {
Ok(TypeInfer {
underscore_token: input.parse()?,
})
}
}
impl Parse for TypeTuple {
fn parse(input: ParseStream) -> Result<Self> {
let content;
Ok(TypeTuple {
paren_token: parenthesized!(content in input),
elems: content.parse_terminated(Type::parse)?,
})
}
}
impl Parse for TypeMacro {
fn parse(input: ParseStream) -> Result<Self> {
Ok(TypeMacro {
mac: input.parse()?,
})
}
}
impl Parse for TypePath {
fn parse(input: ParseStream) -> Result<Self> {
let (qself, mut path) = path::parsing::qpath(input, false)?;
if path.segments.last().unwrap().value().arguments.is_empty()
&& input.peek(token::Paren)
{
let args: ParenthesizedGenericArguments = input.parse()?;
let parenthesized = PathArguments::Parenthesized(args);
path.segments.last_mut().unwrap().value_mut().arguments = parenthesized;
}
Ok(TypePath {
qself: qself,
path: path,
})
}
}
impl ReturnType {
pub fn without_plus(input: ParseStream) -> Result<Self> {
Self::parse(input, false)
}
pub fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> {
if input.peek(Token![->]) {
let arrow = input.parse()?;
let ty = ambig_ty(input, allow_plus)?;
Ok(ReturnType::Type(arrow, Box::new(ty)))
} else {
Ok(ReturnType::Default)
}
}
}
impl Parse for ReturnType {
fn parse(input: ParseStream) -> Result<Self> {
Self::parse(input, true)
}
}
impl Parse for TypeTraitObject {
fn parse(input: ParseStream) -> Result<Self> {
Self::parse(input, true)
}
}
fn at_least_one_type(bounds: &Punctuated<TypeParamBound, Token![+]>) -> bool {
for bound in bounds {
if let TypeParamBound::Trait(_) = *bound {
return true;
}
}
false
}
impl TypeTraitObject {
pub fn without_plus(input: ParseStream) -> Result<Self> {
Self::parse(input, false)
}
pub fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> {
Ok(TypeTraitObject {
dyn_token: input.parse()?,
bounds: {
let mut bounds = Punctuated::new();
if allow_plus {
loop {
bounds.push_value(input.parse()?);
if !input.peek(Token![+]) {
break;
}
bounds.push_punct(input.parse()?);
if input.peek(Token![>]) {
break;
}
}
} else {
bounds.push_value(input.parse()?);
}
if !at_least_one_type(&bounds) {
return Err(input.error("expected at least one type"));
}
bounds
},
})
}
}
impl Parse for TypeImplTrait {
fn parse(input: ParseStream) -> Result<Self> {
Ok(TypeImplTrait {
impl_token: input.parse()?,
bounds: {
let mut bounds = Punctuated::new();
loop {
bounds.push_value(input.parse()?);
if !input.peek(Token![+]) {
break;
}
bounds.push_punct(input.parse()?);
}
bounds
},
})
}
}
impl Parse for TypeGroup {
fn parse(input: ParseStream) -> Result<Self> {
let group = private::parse_group(input)?;
Ok(TypeGroup {
group_token: group.token,
elem: group.content.parse()?,
})
}
}
impl Parse for TypeParen {
fn parse(input: ParseStream) -> Result<Self> {
Self::parse(input, false)
}
}
impl TypeParen {
fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> {
let content;
Ok(TypeParen {
paren_token: parenthesized!(content in input),
elem: Box::new(ambig_ty(&content, allow_plus)?),
})
}
}
impl Parse for BareFnArg {
fn parse(input: ParseStream) -> Result<Self> {
Ok(BareFnArg {
name: {
if (input.peek(Ident) || input.peek(Token![_]))
&& !input.peek2(Token![::])
&& input.peek2(Token![:])
{
let name: BareFnArgName = input.parse()?;
let colon: Token![:] = input.parse()?;
Some((name, colon))
} else {
None
}
},
ty: input.parse()?,
})
}
}
impl Parse for BareFnArgName {
fn parse(input: ParseStream) -> Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(Ident) {
input.parse().map(BareFnArgName::Named)
} else if lookahead.peek(Token![_]) {
input.parse().map(BareFnArgName::Wild)
} else {
Err(lookahead.error())
}
}
}
impl Parse for Abi {
fn parse(input: ParseStream) -> Result<Self> {
Ok(Abi {
extern_token: input.parse()?,
name: input.parse()?,
})
}
}
impl Parse for Option<Abi> {
fn parse(input: ParseStream) -> Result<Self> {
if input.peek(Token![extern]) {
input.parse().map(Some)
} else {
Ok(None)
}
}
}
}
#[cfg(feature = "printing")]
mod printing {
use super::*;
use proc_macro2::TokenStream;
use quote::ToTokens;
use print::TokensOrDefault;
impl ToTokens for TypeSlice {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.bracket_token.surround(tokens, |tokens| {
self.elem.to_tokens(tokens);
});
}
}
impl ToTokens for TypeArray {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.bracket_token.surround(tokens, |tokens| {
self.elem.to_tokens(tokens);
self.semi_token.to_tokens(tokens);
self.len.to_tokens(tokens);
});
}
}
impl ToTokens for TypePtr {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.star_token.to_tokens(tokens);
match self.mutability {
Some(ref tok) => tok.to_tokens(tokens),
None => {
TokensOrDefault(&self.const_token).to_tokens(tokens);
}
}
self.elem.to_tokens(tokens);
}
}
impl ToTokens for TypeReference {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.and_token.to_tokens(tokens);
self.lifetime.to_tokens(tokens);
self.mutability.to_tokens(tokens);
self.elem.to_tokens(tokens);
}
}
impl ToTokens for TypeBareFn {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.lifetimes.to_tokens(tokens);
self.unsafety.to_tokens(tokens);
self.abi.to_tokens(tokens);
self.fn_token.to_tokens(tokens);
self.paren_token.surround(tokens, |tokens| {
self.inputs.to_tokens(tokens);
if let Some(ref variadic) = self.variadic {
if !self.inputs.empty_or_trailing() {
let span = variadic.spans[0];
Token![,](span).to_tokens(tokens);
}
variadic.to_tokens(tokens);
}
});
self.output.to_tokens(tokens);
}
}
impl ToTokens for TypeNever {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.bang_token.to_tokens(tokens);
}
}
impl ToTokens for TypeTuple {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.paren_token.surround(tokens, |tokens| {
self.elems.to_tokens(tokens);
});
}
}
impl ToTokens for TypePath {
fn to_tokens(&self, tokens: &mut TokenStream) {
private::print_path(tokens, &self.qself, &self.path);
}
}
impl ToTokens for TypeTraitObject {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.dyn_token.to_tokens(tokens);
self.bounds.to_tokens(tokens);
}
}
impl ToTokens for TypeImplTrait {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.impl_token.to_tokens(tokens);
self.bounds.to_tokens(tokens);
}
}
impl ToTokens for TypeGroup {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.group_token.surround(tokens, |tokens| {
self.elem.to_tokens(tokens);
});
}
}
impl ToTokens for TypeParen {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.paren_token.surround(tokens, |tokens| {
self.elem.to_tokens(tokens);
});
}
}
impl ToTokens for TypeInfer {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.underscore_token.to_tokens(tokens);
}
}
impl ToTokens for TypeMacro {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.mac.to_tokens(tokens);
}
}
impl ToTokens for TypeVerbatim {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.tts.to_tokens(tokens);
}
}
impl ToTokens for ReturnType {
fn to_tokens(&self, tokens: &mut TokenStream) {
match *self {
ReturnType::Default => {}
ReturnType::Type(ref arrow, ref ty) => {
arrow.to_tokens(tokens);
ty.to_tokens(tokens);
}
}
}
}
impl ToTokens for BareFnArg {
fn to_tokens(&self, tokens: &mut TokenStream) {
if let Some((ref name, ref colon)) = self.name {
name.to_tokens(tokens);
colon.to_tokens(tokens);
}
self.ty.to_tokens(tokens);
}
}
impl ToTokens for BareFnArgName {
fn to_tokens(&self, tokens: &mut TokenStream) {
match *self {
BareFnArgName::Named(ref t) => t.to_tokens(tokens),
BareFnArgName::Wild(ref t) => t.to_tokens(tokens),
}
}
}
impl ToTokens for Abi {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.extern_token.to_tokens(tokens);
self.name.to_tokens(tokens);
}
}
}