use super::*;
use crate::derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput};
use crate::punctuated::Punctuated;
use proc_macro2::TokenStream;
#[cfg(feature = "parsing")]
use std::mem;
ast_enum_of_structs! {
/// Things that can appear directly inside of a module or scope.
///
/// # Syntax tree enum
///
/// This type is a [syntax tree enum].
///
/// [syntax tree enum]: Expr#syntax-tree-enums
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
#[non_exhaustive]
pub enum Item {
/// A constant item: `const MAX: u16 = 65535`.
Const(ItemConst),
/// An enum definition: `enum Foo { A(A), B(B) }`.
Enum(ItemEnum),
/// An `extern crate` item: `extern crate serde`.
ExternCrate(ItemExternCrate),
/// A free-standing function: `fn process(n: usize) -> Result<()> { ...
/// }`.
Fn(ItemFn),
/// A block of foreign items: `extern "C" { ... }`.
ForeignMod(ItemForeignMod),
/// An impl block providing trait or associated items: `impl Trait
/// for Data { ... }`.
Impl(ItemImpl),
/// A macro invocation, which includes `macro_rules!` definitions.
Macro(ItemMacro),
/// A module or module declaration: `mod m` or `mod m { ... }`.
Mod(ItemMod),
/// A static item: `static BIKE: Shed = Shed(42)`.
Static(ItemStatic),
/// A struct definition: `struct Foo { x: A }`.
Struct(ItemStruct),
/// A trait definition: `pub trait Iterator { ... }`.
Trait(ItemTrait),
/// A trait alias: `pub trait SharableIterator = Iterator + Sync`.
TraitAlias(ItemTraitAlias),
/// A type alias: `type Result = std::result::Result`.
Type(ItemType),
/// A union definition: `union Foo { x: A, y: B }`.
Union(ItemUnion),
/// A use declaration: `use std::collections::HashMap`.
Use(ItemUse),
/// Tokens forming an item not interpreted by Syn.
Verbatim(TokenStream),
// For testing exhaustiveness in downstream code, use the following idiom:
//
// match item {
// Item::Const(item) => {...}
// Item::Enum(item) => {...}
// ...
// Item::Verbatim(item) => {...}
//
// #[cfg_attr(test, deny(non_exhaustive_omitted_patterns))]
// _ => { /* some sane fallback */ }
// }
//
// This way we fail your tests but don't break your library when adding
// a variant. You will be notified by a test failure when a variant is
// added, so that you can add code to handle it, but your library will
// continue to compile and work for downstream users in the interim.
}
}
ast_struct! {
/// A constant item: `const MAX: u16 = 65535`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ItemConst {
pub attrs: Vec,
pub vis: Visibility,
pub const_token: Token![const],
pub ident: Ident,
pub generics: Generics,
pub colon_token: Token![:],
pub ty: Box,
pub eq_token: Token![=],
pub expr: Box,
pub semi_token: Token![;],
}
}
ast_struct! {
/// An enum definition: `enum Foo { A(A), B(B) }`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ItemEnum {
pub attrs: Vec,
pub vis: Visibility,
pub enum_token: Token![enum],
pub ident: Ident,
pub generics: Generics,
pub brace_token: token::Brace,
pub variants: Punctuated,
}
}
ast_struct! {
/// An `extern crate` item: `extern crate serde`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ItemExternCrate {
pub attrs: Vec,
pub vis: Visibility,
pub extern_token: Token![extern],
pub crate_token: Token![crate],
pub ident: Ident,
pub rename: Option<(Token![as], Ident)>,
pub semi_token: Token![;],
}
}
ast_struct! {
/// A free-standing function: `fn process(n: usize) -> Result<()> { ... }`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ItemFn {
pub attrs: Vec,
pub vis: Visibility,
pub sig: Signature,
pub block: Box,
}
}
ast_struct! {
/// A block of foreign items: `extern "C" { ... }`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ItemForeignMod {
pub attrs: Vec,
pub unsafety: Option,
pub abi: Abi,
pub brace_token: token::Brace,
pub items: Vec,
}
}
ast_struct! {
/// An impl block providing trait or associated items: `impl Trait
/// for Data { ... }`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ItemImpl {
pub attrs: Vec,
pub defaultness: Option,
pub unsafety: Option,
pub impl_token: Token![impl],
pub generics: Generics,
/// Trait this impl implements.
pub trait_: Option<(Option, Path, Token![for])>,
/// The Self type of the impl.
pub self_ty: Box,
pub brace_token: token::Brace,
pub items: Vec,
}
}
ast_struct! {
/// A macro invocation, which includes `macro_rules!` definitions.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ItemMacro {
pub attrs: Vec,
/// The `example` in `macro_rules! example { ... }`.
pub ident: Option,
pub mac: Macro,
pub semi_token: Option,
}
}
ast_struct! {
/// A module or module declaration: `mod m` or `mod m { ... }`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ItemMod {
pub attrs: Vec,
pub vis: Visibility,
pub unsafety: Option,
pub mod_token: Token![mod],
pub ident: Ident,
pub content: Option<(token::Brace, Vec- )>,
pub semi: Option,
}
}
ast_struct! {
/// A static item: `static BIKE: Shed = Shed(42)`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ItemStatic {
pub attrs: Vec,
pub vis: Visibility,
pub static_token: Token![static],
pub mutability: StaticMutability,
pub ident: Ident,
pub colon_token: Token![:],
pub ty: Box,
pub eq_token: Token![=],
pub expr: Box,
pub semi_token: Token![;],
}
}
ast_struct! {
/// A struct definition: `struct Foo { x: A }`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ItemStruct {
pub attrs: Vec,
pub vis: Visibility,
pub struct_token: Token![struct],
pub ident: Ident,
pub generics: Generics,
pub fields: Fields,
pub semi_token: Option,
}
}
ast_struct! {
/// A trait definition: `pub trait Iterator { ... }`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ItemTrait {
pub attrs: Vec,
pub vis: Visibility,
pub unsafety: Option,
pub auto_token: Option,
pub restriction: Option,
pub trait_token: Token![trait],
pub ident: Ident,
pub generics: Generics,
pub colon_token: Option,
pub supertraits: Punctuated,
pub brace_token: token::Brace,
pub items: Vec,
}
}
ast_struct! {
/// A trait alias: `pub trait SharableIterator = Iterator + Sync`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ItemTraitAlias {
pub attrs: Vec,
pub vis: Visibility,
pub trait_token: Token![trait],
pub ident: Ident,
pub generics: Generics,
pub eq_token: Token![=],
pub bounds: Punctuated,
pub semi_token: Token![;],
}
}
ast_struct! {
/// A type alias: `type Result = std::result::Result`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ItemType {
pub attrs: Vec,
pub vis: Visibility,
pub type_token: Token![type],
pub ident: Ident,
pub generics: Generics,
pub eq_token: Token![=],
pub ty: Box,
pub semi_token: Token![;],
}
}
ast_struct! {
/// A union definition: `union Foo { x: A, y: B }`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ItemUnion {
pub attrs: Vec,
pub vis: Visibility,
pub union_token: Token![union],
pub ident: Ident,
pub generics: Generics,
pub fields: FieldsNamed,
}
}
ast_struct! {
/// A use declaration: `use std::collections::HashMap`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ItemUse {
pub attrs: Vec,
pub vis: Visibility,
pub use_token: Token![use],
pub leading_colon: Option,
pub tree: UseTree,
pub semi_token: Token![;],
}
}
impl Item {
#[cfg(feature = "parsing")]
pub(crate) fn replace_attrs(&mut self, new: Vec) -> Vec {
match self {
Item::Const(ItemConst { attrs, .. })
| Item::Enum(ItemEnum { attrs, .. })
| Item::ExternCrate(ItemExternCrate { attrs, .. })
| Item::Fn(ItemFn { attrs, .. })
| Item::ForeignMod(ItemForeignMod { attrs, .. })
| Item::Impl(ItemImpl { attrs, .. })
| Item::Macro(ItemMacro { attrs, .. })
| Item::Mod(ItemMod { attrs, .. })
| Item::Static(ItemStatic { attrs, .. })
| Item::Struct(ItemStruct { attrs, .. })
| Item::Trait(ItemTrait { attrs, .. })
| Item::TraitAlias(ItemTraitAlias { attrs, .. })
| Item::Type(ItemType { attrs, .. })
| Item::Union(ItemUnion { attrs, .. })
| Item::Use(ItemUse { attrs, .. }) => mem::replace(attrs, new),
Item::Verbatim(_) => Vec::new(),
}
}
}
impl From for Item {
fn from(input: DeriveInput) -> Item {
match input.data {
Data::Struct(data) => Item::Struct(ItemStruct {
attrs: input.attrs,
vis: input.vis,
struct_token: data.struct_token,
ident: input.ident,
generics: input.generics,
fields: data.fields,
semi_token: data.semi_token,
}),
Data::Enum(data) => Item::Enum(ItemEnum {
attrs: input.attrs,
vis: input.vis,
enum_token: data.enum_token,
ident: input.ident,
generics: input.generics,
brace_token: data.brace_token,
variants: data.variants,
}),
Data::Union(data) => Item::Union(ItemUnion {
attrs: input.attrs,
vis: input.vis,
union_token: data.union_token,
ident: input.ident,
generics: input.generics,
fields: data.fields,
}),
}
}
}
impl From for DeriveInput {
fn from(input: ItemStruct) -> DeriveInput {
DeriveInput {
attrs: input.attrs,
vis: input.vis,
ident: input.ident,
generics: input.generics,
data: Data::Struct(DataStruct {
struct_token: input.struct_token,
fields: input.fields,
semi_token: input.semi_token,
}),
}
}
}
impl From for DeriveInput {
fn from(input: ItemEnum) -> DeriveInput {
DeriveInput {
attrs: input.attrs,
vis: input.vis,
ident: input.ident,
generics: input.generics,
data: Data::Enum(DataEnum {
enum_token: input.enum_token,
brace_token: input.brace_token,
variants: input.variants,
}),
}
}
}
impl From for DeriveInput {
fn from(input: ItemUnion) -> DeriveInput {
DeriveInput {
attrs: input.attrs,
vis: input.vis,
ident: input.ident,
generics: input.generics,
data: Data::Union(DataUnion {
union_token: input.union_token,
fields: input.fields,
}),
}
}
}
ast_enum_of_structs! {
/// A suffix of an import tree in a `use` item: `Type as Renamed` or `*`.
///
/// # Syntax tree enum
///
/// This type is a [syntax tree enum].
///
/// [syntax tree enum]: Expr#syntax-tree-enums
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub enum UseTree {
/// A path prefix of imports in a `use` item: `std::...`.
Path(UsePath),
/// An identifier imported by a `use` item: `HashMap`.
Name(UseName),
/// An renamed identifier imported by a `use` item: `HashMap as Map`.
Rename(UseRename),
/// A glob import in a `use` item: `*`.
Glob(UseGlob),
/// A braced group of imports in a `use` item: `{A, B, C}`.
Group(UseGroup),
}
}
ast_struct! {
/// A path prefix of imports in a `use` item: `std::...`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct UsePath {
pub ident: Ident,
pub colon2_token: Token![::],
pub tree: Box,
}
}
ast_struct! {
/// An identifier imported by a `use` item: `HashMap`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct UseName {
pub ident: Ident,
}
}
ast_struct! {
/// An renamed identifier imported by a `use` item: `HashMap as Map`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct UseRename {
pub ident: Ident,
pub as_token: Token![as],
pub rename: Ident,
}
}
ast_struct! {
/// A glob import in a `use` item: `*`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct UseGlob {
pub star_token: Token![*],
}
}
ast_struct! {
/// A braced group of imports in a `use` item: `{A, B, C}`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct UseGroup {
pub brace_token: token::Brace,
pub items: Punctuated,
}
}
ast_enum_of_structs! {
/// An item within an `extern` block.
///
/// # Syntax tree enum
///
/// This type is a [syntax tree enum].
///
/// [syntax tree enum]: Expr#syntax-tree-enums
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
#[non_exhaustive]
pub enum ForeignItem {
/// A foreign function in an `extern` block.
Fn(ForeignItemFn),
/// A foreign static item in an `extern` block: `static ext: u8`.
Static(ForeignItemStatic),
/// A foreign type in an `extern` block: `type void`.
Type(ForeignItemType),
/// A macro invocation within an extern block.
Macro(ForeignItemMacro),
/// Tokens in an `extern` block not interpreted by Syn.
Verbatim(TokenStream),
// For testing exhaustiveness in downstream code, use the following idiom:
//
// match item {
// ForeignItem::Fn(item) => {...}
// ForeignItem::Static(item) => {...}
// ...
// ForeignItem::Verbatim(item) => {...}
//
// #[cfg_attr(test, deny(non_exhaustive_omitted_patterns))]
// _ => { /* some sane fallback */ }
// }
//
// This way we fail your tests but don't break your library when adding
// a variant. You will be notified by a test failure when a variant is
// added, so that you can add code to handle it, but your library will
// continue to compile and work for downstream users in the interim.
}
}
ast_struct! {
/// A foreign function in an `extern` block.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ForeignItemFn {
pub attrs: Vec,
pub vis: Visibility,
pub sig: Signature,
pub semi_token: Token![;],
}
}
ast_struct! {
/// A foreign static item in an `extern` block: `static ext: u8`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ForeignItemStatic {
pub attrs: Vec,
pub vis: Visibility,
pub static_token: Token![static],
pub mutability: StaticMutability,
pub ident: Ident,
pub colon_token: Token![:],
pub ty: Box,
pub semi_token: Token![;],
}
}
ast_struct! {
/// A foreign type in an `extern` block: `type void`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ForeignItemType {
pub attrs: Vec,
pub vis: Visibility,
pub type_token: Token![type],
pub ident: Ident,
pub generics: Generics,
pub semi_token: Token![;],
}
}
ast_struct! {
/// A macro invocation within an extern block.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ForeignItemMacro {
pub attrs: Vec,
pub mac: Macro,
pub semi_token: Option,
}
}
ast_enum_of_structs! {
/// An item declaration within the definition of a trait.
///
/// # Syntax tree enum
///
/// This type is a [syntax tree enum].
///
/// [syntax tree enum]: Expr#syntax-tree-enums
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
#[non_exhaustive]
pub enum TraitItem {
/// An associated constant within the definition of a trait.
Const(TraitItemConst),
/// An associated function within the definition of a trait.
Fn(TraitItemFn),
/// An associated type within the definition of a trait.
Type(TraitItemType),
/// A macro invocation within the definition of a trait.
Macro(TraitItemMacro),
/// Tokens within the definition of a trait not interpreted by Syn.
Verbatim(TokenStream),
// For testing exhaustiveness in downstream code, use the following idiom:
//
// match item {
// TraitItem::Const(item) => {...}
// TraitItem::Fn(item) => {...}
// ...
// TraitItem::Verbatim(item) => {...}
//
// #[cfg_attr(test, deny(non_exhaustive_omitted_patterns))]
// _ => { /* some sane fallback */ }
// }
//
// This way we fail your tests but don't break your library when adding
// a variant. You will be notified by a test failure when a variant is
// added, so that you can add code to handle it, but your library will
// continue to compile and work for downstream users in the interim.
}
}
ast_struct! {
/// An associated constant within the definition of a trait.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct TraitItemConst {
pub attrs: Vec,
pub const_token: Token![const],
pub ident: Ident,
pub generics: Generics,
pub colon_token: Token![:],
pub ty: Type,
pub default: Option<(Token![=], Expr)>,
pub semi_token: Token![;],
}
}
ast_struct! {
/// An associated function within the definition of a trait.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct TraitItemFn {
pub attrs: Vec,
pub sig: Signature,
pub default: Option,
pub semi_token: Option,
}
}
ast_struct! {
/// An associated type within the definition of a trait.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct TraitItemType {
pub attrs: Vec,
pub type_token: Token![type],
pub ident: Ident,
pub generics: Generics,
pub colon_token: Option,
pub bounds: Punctuated,
pub default: Option<(Token![=], Type)>,
pub semi_token: Token![;],
}
}
ast_struct! {
/// A macro invocation within the definition of a trait.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct TraitItemMacro {
pub attrs: Vec,
pub mac: Macro,
pub semi_token: Option,
}
}
ast_enum_of_structs! {
/// An item within an impl block.
///
/// # Syntax tree enum
///
/// This type is a [syntax tree enum].
///
/// [syntax tree enum]: Expr#syntax-tree-enums
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
#[non_exhaustive]
pub enum ImplItem {
/// An associated constant within an impl block.
Const(ImplItemConst),
/// An associated function within an impl block.
Fn(ImplItemFn),
/// An associated type within an impl block.
Type(ImplItemType),
/// A macro invocation within an impl block.
Macro(ImplItemMacro),
/// Tokens within an impl block not interpreted by Syn.
Verbatim(TokenStream),
// For testing exhaustiveness in downstream code, use the following idiom:
//
// match item {
// ImplItem::Const(item) => {...}
// ImplItem::Fn(item) => {...}
// ...
// ImplItem::Verbatim(item) => {...}
//
// #[cfg_attr(test, deny(non_exhaustive_omitted_patterns))]
// _ => { /* some sane fallback */ }
// }
//
// This way we fail your tests but don't break your library when adding
// a variant. You will be notified by a test failure when a variant is
// added, so that you can add code to handle it, but your library will
// continue to compile and work for downstream users in the interim.
}
}
ast_struct! {
/// An associated constant within an impl block.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ImplItemConst {
pub attrs: Vec,
pub vis: Visibility,
pub defaultness: Option,
pub const_token: Token![const],
pub ident: Ident,
pub generics: Generics,
pub colon_token: Token![:],
pub ty: Type,
pub eq_token: Token![=],
pub expr: Expr,
pub semi_token: Token![;],
}
}
ast_struct! {
/// An associated function within an impl block.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ImplItemFn {
pub attrs: Vec,
pub vis: Visibility,
pub defaultness: Option,
pub sig: Signature,
pub block: Block,
}
}
ast_struct! {
/// An associated type within an impl block.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ImplItemType {
pub attrs: Vec,
pub vis: Visibility,
pub defaultness: Option,
pub type_token: Token![type],
pub ident: Ident,
pub generics: Generics,
pub eq_token: Token![=],
pub ty: Type,
pub semi_token: Token![;],
}
}
ast_struct! {
/// A macro invocation within an impl block.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct ImplItemMacro {
pub attrs: Vec,
pub mac: Macro,
pub semi_token: Option,
}
}
ast_struct! {
/// A function signature in a trait or implementation: `unsafe fn
/// initialize(&self)`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct Signature {
pub constness: Option,
pub asyncness: Option,
pub unsafety: Option,
pub abi: Option,
pub fn_token: Token![fn],
pub ident: Ident,
pub generics: Generics,
pub paren_token: token::Paren,
pub inputs: Punctuated,
pub variadic: Option,
pub output: ReturnType,
}
}
impl Signature {
/// A method's `self` receiver, such as `&self` or `self: Box`.
pub fn receiver(&self) -> Option<&Receiver> {
let arg = self.inputs.first()?;
match arg {
FnArg::Receiver(receiver) => Some(receiver),
FnArg::Typed(_) => None,
}
}
}
ast_enum_of_structs! {
/// An argument in a function signature: the `n: usize` in `fn f(n: usize)`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub enum FnArg {
/// The `self` argument of an associated method.
Receiver(Receiver),
/// A function argument accepted by pattern and type.
Typed(PatType),
}
}
ast_struct! {
/// The `self` argument of an associated method.
///
/// If `colon_token` is present, the receiver is written with an explicit
/// type such as `self: Box`. If `colon_token` is absent, the receiver
/// is written in shorthand such as `self` or `&self` or `&mut self`. In the
/// shorthand case, the type in `ty` is reconstructed as one of `Self`,
/// `&Self`, or `&mut Self`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct Receiver {
pub attrs: Vec,
pub reference: Option<(Token![&], Option)>,
pub mutability: Option,
pub self_token: Token![self],
pub colon_token: Option,
pub ty: Box,
}
}
impl Receiver {
pub fn lifetime(&self) -> Option<&Lifetime> {
self.reference.as_ref()?.1.as_ref()
}
}
ast_struct! {
/// The variadic argument of a foreign function.
///
/// ```rust
/// # struct c_char;
/// # struct c_int;
/// #
/// extern "C" {
/// fn printf(format: *const c_char, ...) -> c_int;
/// // ^^^
/// }
/// ```
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
pub struct Variadic {
pub attrs: Vec,
pub pat: Option<(Box, Token![:])>,
pub dots: Token![...],
pub comma: Option,
}
}
ast_enum! {
/// The mutability of an `Item::Static` or `ForeignItem::Static`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
#[non_exhaustive]
pub enum StaticMutability {
Mut(Token![mut]),
None,
}
}
ast_enum! {
/// Unused, but reserved for RFC 3323 restrictions.
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
#[non_exhaustive]
pub enum ImplRestriction {}
// TODO: https://rust-lang.github.io/rfcs/3323-restrictions.html
//
// pub struct ImplRestriction {
// pub impl_token: Token![impl],
// pub paren_token: token::Paren,
// pub in_token: Option,
// pub path: Box,
// }
}
#[cfg(feature = "parsing")]
pub(crate) mod parsing {
use super::*;
use crate::ext::IdentExt;
use crate::parse::discouraged::Speculative;
use crate::parse::{Parse, ParseBuffer, ParseStream, Result};
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
impl Parse for Item {
fn parse(input: ParseStream) -> Result {
let begin = input.fork();
let mut attrs = input.call(Attribute::parse_outer)?;
let ahead = input.fork();
let vis: Visibility = ahead.parse()?;
let lookahead = ahead.lookahead1();
let mut item = if lookahead.peek(Token![fn]) || peek_signature(&ahead) {
let vis: Visibility = input.parse()?;
let sig: Signature = input.parse()?;
if input.peek(Token![;]) {
input.parse::()?;
Ok(Item::Verbatim(verbatim::between(begin, input)))
} else {
parse_rest_of_fn(input, Vec::new(), vis, sig).map(Item::Fn)
}
} else if lookahead.peek(Token![extern]) {
ahead.parse::()?;
let lookahead = ahead.lookahead1();
if lookahead.peek(Token![crate]) {
input.parse().map(Item::ExternCrate)
} else if lookahead.peek(token::Brace) {
input.parse().map(Item::ForeignMod)
} else if lookahead.peek(LitStr) {
ahead.parse::()?;
let lookahead = ahead.lookahead1();
if lookahead.peek(token::Brace) {
input.parse().map(Item::ForeignMod)
} else {
Err(lookahead.error())
}
} else {
Err(lookahead.error())
}
} else if lookahead.peek(Token![use]) {
let allow_crate_root_in_path = true;
match parse_item_use(input, allow_crate_root_in_path)? {
Some(item_use) => Ok(Item::Use(item_use)),
None => Ok(Item::Verbatim(verbatim::between(begin, input))),
}
} else if lookahead.peek(Token![static]) {
let vis = input.parse()?;
let static_token = input.parse()?;
let mutability = input.parse()?;
let ident = input.parse()?;
if input.peek(Token![=]) {
input.parse::()?;
input.parse::()?;
input.parse::()?;
Ok(Item::Verbatim(verbatim::between(begin, input)))
} else {
let colon_token = input.parse()?;
let ty = input.parse()?;
if input.peek(Token![;]) {
input.parse::()?;
Ok(Item::Verbatim(verbatim::between(begin, input)))
} else {
Ok(Item::Static(ItemStatic {
attrs: Vec::new(),
vis,
static_token,
mutability,
ident,
colon_token,
ty,
eq_token: input.parse()?,
expr: input.parse()?,
semi_token: input.parse()?,
}))
}
}
} else if lookahead.peek(Token![const]) {
let vis = input.parse()?;
let const_token: Token![const] = input.parse()?;
let lookahead = input.lookahead1();
let ident = if lookahead.peek(Ident) || lookahead.peek(Token![_]) {
input.call(Ident::parse_any)?
} else {
return Err(lookahead.error());
};
let colon_token = input.parse()?;
let ty = input.parse()?;
if input.peek(Token![;]) {
input.parse::()?;
Ok(Item::Verbatim(verbatim::between(begin, input)))
} else {
Ok(Item::Const(ItemConst {
attrs: Vec::new(),
vis,
const_token,
ident,
generics: Generics::default(),
colon_token,
ty,
eq_token: input.parse()?,
expr: input.parse()?,
semi_token: input.parse()?,
}))
}
} else if lookahead.peek(Token![unsafe]) {
ahead.parse::()?;
let lookahead = ahead.lookahead1();
if lookahead.peek(Token![trait])
|| lookahead.peek(Token![auto]) && ahead.peek2(Token![trait])
{
input.parse().map(Item::Trait)
} else if lookahead.peek(Token![impl]) {
let allow_verbatim_impl = true;
if let Some(item) = parse_impl(input, allow_verbatim_impl)? {
Ok(Item::Impl(item))
} else {
Ok(Item::Verbatim(verbatim::between(begin, input)))
}
} else if lookahead.peek(Token![extern]) {
input.parse().map(Item::ForeignMod)
} else if lookahead.peek(Token![mod]) {
input.parse().map(Item::Mod)
} else {
Err(lookahead.error())
}
} else if lookahead.peek(Token![mod]) {
input.parse().map(Item::Mod)
} else if lookahead.peek(Token![type]) {
parse_item_type(begin, input)
} else if lookahead.peek(Token![struct]) {
input.parse().map(Item::Struct)
} else if lookahead.peek(Token![enum]) {
input.parse().map(Item::Enum)
} else if lookahead.peek(Token![union]) && ahead.peek2(Ident) {
input.parse().map(Item::Union)
} else if lookahead.peek(Token![trait]) {
input.call(parse_trait_or_trait_alias)
} else if lookahead.peek(Token![auto]) && ahead.peek2(Token![trait]) {
input.parse().map(Item::Trait)
} else if lookahead.peek(Token![impl])
|| lookahead.peek(Token![default]) && !ahead.peek2(Token![!])
{
let allow_verbatim_impl = true;
if let Some(item) = parse_impl(input, allow_verbatim_impl)? {
Ok(Item::Impl(item))
} else {
Ok(Item::Verbatim(verbatim::between(begin, input)))
}
} else if lookahead.peek(Token![macro]) {
input.advance_to(&ahead);
parse_macro2(begin, vis, input)
} else if vis.is_inherited()
&& (lookahead.peek(Ident)
|| lookahead.peek(Token![self])
|| lookahead.peek(Token![super])
|| lookahead.peek(Token![crate])
|| lookahead.peek(Token![::]))
{
input.parse().map(Item::Macro)
} else {
Err(lookahead.error())
}?;
attrs.extend(item.replace_attrs(Vec::new()));
item.replace_attrs(attrs);
Ok(item)
}
}
struct FlexibleItemType {
vis: Visibility,
defaultness: Option,
type_token: Token![type],
ident: Ident,
generics: Generics,
colon_token: Option,
bounds: Punctuated,
ty: Option<(Token![=], Type)>,
semi_token: Token![;],
}
enum TypeDefaultness {
Optional,
Disallowed,
}
enum WhereClauseLocation {
// type Ty where T: 'static = T;
BeforeEq,
// type Ty = T where T: 'static;
AfterEq,
// TODO: goes away once the migration period on rust-lang/rust#89122 is over
Both,
}
impl FlexibleItemType {
fn parse(
input: ParseStream,
allow_defaultness: TypeDefaultness,
where_clause_location: WhereClauseLocation,
) -> Result {
let vis: Visibility = input.parse()?;
let defaultness: Option = match allow_defaultness {
TypeDefaultness::Optional => input.parse()?,
TypeDefaultness::Disallowed => None,
};
let type_token: Token![type] = input.parse()?;
let ident: Ident = input.parse()?;
let mut generics: Generics = input.parse()?;
let (colon_token, bounds) = Self::parse_optional_bounds(input)?;
match where_clause_location {
WhereClauseLocation::BeforeEq | WhereClauseLocation::Both => {
generics.where_clause = input.parse()?;
}
WhereClauseLocation::AfterEq => {}
}
let ty = Self::parse_optional_definition(input)?;
match where_clause_location {
WhereClauseLocation::AfterEq | WhereClauseLocation::Both
if generics.where_clause.is_none() =>
{
generics.where_clause = input.parse()?;
}
_ => {}
}
let semi_token: Token![;] = input.parse()?;
Ok(FlexibleItemType {
vis,
defaultness,
type_token,
ident,
generics,
colon_token,
bounds,
ty,
semi_token,
})
}
fn parse_optional_bounds(
input: ParseStream,
) -> Result<(Option, Punctuated)> {
let colon_token: Option = input.parse()?;
let mut bounds = Punctuated::new();
if colon_token.is_some() {
loop {
if input.peek(Token![where]) || input.peek(Token![=]) || input.peek(Token![;]) {
break;
}
bounds.push_value(input.parse::()?);
if input.peek(Token![where]) || input.peek(Token![=]) || input.peek(Token![;]) {
break;
}
bounds.push_punct(input.parse::()?);
}
}
Ok((colon_token, bounds))
}
fn parse_optional_definition(input: ParseStream) -> Result