| // SPDX-License-Identifier: Apache-2.0 OR MIT | |
| use crate::attr::Attribute; | |
| use crate::data::{Fields, FieldsNamed, Variant}; | |
| use crate::generics::Generics; | |
| use crate::ident::Ident; | |
| use crate::punctuated::Punctuated; | |
| use crate::restriction::Visibility; | |
| use crate::token; | |
| ast_struct! { | |
| /// Data structure sent to a `proc_macro_derive` macro. | |
| #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] | |
| pub struct DeriveInput { | |
| pub attrs: Vec<Attribute>, | |
| pub vis: Visibility, | |
| pub ident: Ident, | |
| pub generics: Generics, | |
| pub data: Data, | |
| } | |
| } | |
| ast_enum! { | |
| /// The storage of a struct, enum or union data structure. | |
| /// | |
| /// # Syntax tree enum | |
| /// | |
| /// This type is a [syntax tree enum]. | |
| /// | |
| /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums | |
| #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] | |
| pub enum Data { | |
| Struct(DataStruct), | |
| Enum(DataEnum), | |
| Union(DataUnion), | |
| } | |
| } | |
| ast_struct! { | |
| /// A struct input to a `proc_macro_derive` macro. | |
| #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] | |
| pub struct DataStruct { | |
| pub struct_token: Token![struct], | |
| pub fields: Fields, | |
| pub semi_token: Option<Token![;]>, | |
| } | |
| } | |
| ast_struct! { | |
| /// An enum input to a `proc_macro_derive` macro. | |
| #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] | |
| pub struct DataEnum { | |
| pub enum_token: Token![enum], | |
| pub brace_token: token::Brace, | |
| pub variants: Punctuated<Variant, Token![,]>, | |
| } | |
| } | |
| ast_struct! { | |
| /// An untagged union input to a `proc_macro_derive` macro. | |
| #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] | |
| pub struct DataUnion { | |
| pub union_token: Token![union], | |
| pub fields: FieldsNamed, | |
| } | |
| } | |
| #[cfg(feature = "parsing")] | |
| pub(crate) mod parsing { | |
| use crate::attr::Attribute; | |
| use crate::data::{Fields, FieldsNamed, Variant}; | |
| use crate::derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput}; | |
| use crate::error::Result; | |
| use crate::generics::{Generics, WhereClause}; | |
| use crate::ident::Ident; | |
| use crate::parse::{Parse, ParseStream}; | |
| use crate::punctuated::Punctuated; | |
| use crate::restriction::Visibility; | |
| use crate::token; | |
| #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] | |
| impl Parse for DeriveInput { | |
| fn parse(input: ParseStream) -> Result<Self> { | |
| let attrs = input.call(Attribute::parse_outer)?; | |
| let vis = input.parse::<Visibility>()?; | |
| let lookahead = input.lookahead1(); | |
| if lookahead.peek(Token![struct]) { | |
| let struct_token = input.parse::<Token![struct]>()?; | |
| let ident = input.parse::<Ident>()?; | |
| let generics = input.parse::<Generics>()?; | |
| let (where_clause, fields, semi) = data_struct(input)?; | |
| Ok(DeriveInput { | |
| attrs, | |
| vis, | |
| ident, | |
| generics: Generics { | |
| where_clause, | |
| ..generics | |
| }, | |
| data: Data::Struct(DataStruct { | |
| struct_token, | |
| fields, | |
| semi_token: semi, | |
| }), | |
| }) | |
| } else if lookahead.peek(Token![enum]) { | |
| let enum_token = input.parse::<Token![enum]>()?; | |
| let ident = input.parse::<Ident>()?; | |
| let generics = input.parse::<Generics>()?; | |
| let (where_clause, brace, variants) = data_enum(input)?; | |
| Ok(DeriveInput { | |
| attrs, | |
| vis, | |
| ident, | |
| generics: Generics { | |
| where_clause, | |
| ..generics | |
| }, | |
| data: Data::Enum(DataEnum { | |
| enum_token, | |
| brace_token: brace, | |
| variants, | |
| }), | |
| }) | |
| } else if lookahead.peek(Token![union]) { | |
| let union_token = input.parse::<Token![union]>()?; | |
| let ident = input.parse::<Ident>()?; | |
| let generics = input.parse::<Generics>()?; | |
| let (where_clause, fields) = data_union(input)?; | |
| Ok(DeriveInput { | |
| attrs, | |
| vis, | |
| ident, | |
| generics: Generics { | |
| where_clause, | |
| ..generics | |
| }, | |
| data: Data::Union(DataUnion { | |
| union_token, | |
| fields, | |
| }), | |
| }) | |
| } else { | |
| Err(lookahead.error()) | |
| } | |
| } | |
| } | |
| pub(crate) fn data_struct( | |
| input: ParseStream, | |
| ) -> Result<(Option<WhereClause>, Fields, Option<Token![;]>)> { | |
| let mut lookahead = input.lookahead1(); | |
| let mut where_clause = None; | |
| if lookahead.peek(Token![where]) { | |
| where_clause = Some(input.parse()?); | |
| lookahead = input.lookahead1(); | |
| } | |
| if where_clause.is_none() && lookahead.peek(token::Paren) { | |
| let fields = input.parse()?; | |
| lookahead = input.lookahead1(); | |
| if lookahead.peek(Token![where]) { | |
| where_clause = Some(input.parse()?); | |
| lookahead = input.lookahead1(); | |
| } | |
| if lookahead.peek(Token![;]) { | |
| let semi = input.parse()?; | |
| Ok((where_clause, Fields::Unnamed(fields), Some(semi))) | |
| } else { | |
| Err(lookahead.error()) | |
| } | |
| } else if lookahead.peek(token::Brace) { | |
| let fields = input.parse()?; | |
| Ok((where_clause, Fields::Named(fields), None)) | |
| } else if lookahead.peek(Token![;]) { | |
| let semi = input.parse()?; | |
| Ok((where_clause, Fields::Unit, Some(semi))) | |
| } else { | |
| Err(lookahead.error()) | |
| } | |
| } | |
| pub(crate) fn data_enum( | |
| input: ParseStream, | |
| ) -> Result<( | |
| Option<WhereClause>, | |
| token::Brace, | |
| Punctuated<Variant, Token![,]>, | |
| )> { | |
| let where_clause = input.parse()?; | |
| let content; | |
| let brace = braced!(content in input); | |
| let variants = content.parse_terminated(Variant::parse, Token![,])?; | |
| Ok((where_clause, brace, variants)) | |
| } | |
| pub(crate) fn data_union(input: ParseStream) -> Result<(Option<WhereClause>, FieldsNamed)> { | |
| let where_clause = input.parse()?; | |
| let fields = input.parse()?; | |
| Ok((where_clause, fields)) | |
| } | |
| } | |
| #[cfg(feature = "printing")] | |
| mod printing { | |
| use crate::attr::FilterAttrs; | |
| use crate::data::Fields; | |
| use crate::derive::{Data, DeriveInput}; | |
| use crate::print::TokensOrDefault; | |
| use proc_macro2::TokenStream; | |
| use quote::ToTokens; | |
| #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] | |
| impl ToTokens for DeriveInput { | |
| fn to_tokens(&self, tokens: &mut TokenStream) { | |
| for attr in self.attrs.outer() { | |
| attr.to_tokens(tokens); | |
| } | |
| self.vis.to_tokens(tokens); | |
| match &self.data { | |
| Data::Struct(d) => d.struct_token.to_tokens(tokens), | |
| Data::Enum(d) => d.enum_token.to_tokens(tokens), | |
| Data::Union(d) => d.union_token.to_tokens(tokens), | |
| } | |
| self.ident.to_tokens(tokens); | |
| self.generics.to_tokens(tokens); | |
| match &self.data { | |
| Data::Struct(data) => match &data.fields { | |
| Fields::Named(fields) => { | |
| self.generics.where_clause.to_tokens(tokens); | |
| fields.to_tokens(tokens); | |
| } | |
| Fields::Unnamed(fields) => { | |
| fields.to_tokens(tokens); | |
| self.generics.where_clause.to_tokens(tokens); | |
| TokensOrDefault(&data.semi_token).to_tokens(tokens); | |
| } | |
| Fields::Unit => { | |
| self.generics.where_clause.to_tokens(tokens); | |
| TokensOrDefault(&data.semi_token).to_tokens(tokens); | |
| } | |
| }, | |
| Data::Enum(data) => { | |
| self.generics.where_clause.to_tokens(tokens); | |
| data.brace_token.surround(tokens, |tokens| { | |
| data.variants.to_tokens(tokens); | |
| }); | |
| } | |
| Data::Union(data) => { | |
| self.generics.where_clause.to_tokens(tokens); | |
| data.fields.to_tokens(tokens); | |
| } | |
| } | |
| } | |
| } | |
| } |