#![deny(missing_docs)]
use proc_macro::TokenStream;
struct DefaultValue {
#[allow(unused)]
equal_sign: syn::Token![=],
value: syn::Expr,
}
struct CustomField {
field: syn::Field,
default_value: Option<DefaultValue>,
}
impl syn::parse::Parse for DefaultValue {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let equal_sign: syn::Token![=] = input.parse()?;
let value: syn::Expr = input.parse()?;
Ok(Self { equal_sign, value })
}
}
impl CustomField {
fn parse_named(input: syn::parse::ParseStream) -> syn::Result<Self> {
let field = syn::Field::parse_named(input)?;
let default_value = if !input.peek(syn::Token![,]) {
Some(input.parse()?)
} else {
None
};
Ok(CustomField {
field,
default_value,
})
}
fn parse_unnamed(input: syn::parse::ParseStream) -> syn::Result<Self> {
let field = syn::Field::parse_unnamed(input)?;
let default_value = if !input.peek(syn::Token![,]) {
Some(input.parse()?)
} else {
None
};
Ok(CustomField {
field,
default_value,
})
}
}
struct CustomFieldsNamed {
brace_token: syn::token::Brace,
named: syn::punctuated::Punctuated<CustomField, syn::Token![,]>,
}
impl CustomFieldsNamed {
fn to_formatted_defaults(&self) -> Vec<proc_macro2::TokenStream> {
self.named
.iter()
.map(
|CustomField {
field,
default_value,
}| {
let ty = &field.ty;
let ident = &field.ident;
let value = match &default_value {
Some(DefaultValue {
equal_sign: _,
value,
}) => quote::quote!(#value),
None => quote::quote!(<#ty as core::default::Default>::default()),
};
quote::quote!(#ident: #value)
},
)
.collect()
}
}
impl syn::parse::Parse for CustomFieldsNamed {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let content;
Ok(Self {
brace_token: syn::braced!(content in input),
named: content.parse_terminated(CustomField::parse_named, syn::Token![,])?,
})
}
}
struct CustomFieldsUnnamed {
paren_token: syn::token::Paren,
unnamed: syn::punctuated::Punctuated<CustomField, syn::Token![,]>,
}
impl CustomFieldsUnnamed {
fn to_formatted_defaults(&self) -> Vec<proc_macro2::TokenStream> {
self.unnamed
.iter()
.map(|field| {
let ty = &field.field.ty;
let value = match &field.default_value {
Some(DefaultValue {
equal_sign: _,
value,
}) => quote::quote!(#value),
None => quote::quote!(<#ty as core::default::Default>::default()),
};
quote::quote!(#value)
})
.collect()
}
}
impl syn::parse::Parse for CustomFieldsUnnamed {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let content;
Ok(Self {
paren_token: syn::parenthesized!(content in input),
unnamed: content.parse_terminated(CustomField::parse_unnamed, syn::Token![,])?,
})
}
}
enum CustomFields {
Named(CustomFieldsNamed),
Unnamed(CustomFieldsUnnamed),
Unit,
}
struct Parsed {
attrs: Vec<syn::Attribute>,
vis: syn::Visibility,
struct_token: syn::Token![struct],
ident: syn::Ident,
generics: syn::Generics,
fields: CustomFields,
semi_token: Option<syn::Token![;]>,
}
impl Parsed {
fn into_item_struct(self) -> syn::ItemStruct {
let Self {
attrs,
vis,
struct_token,
ident,
generics,
fields,
semi_token,
} = self;
let fields = match fields {
CustomFields::Named(CustomFieldsNamed { brace_token, named }) => {
syn::Fields::Named(syn::FieldsNamed {
brace_token,
named: syn::punctuated::Punctuated::from_iter(
named.into_iter().map(|x| x.field),
),
})
}
CustomFields::Unnamed(CustomFieldsUnnamed {
paren_token,
unnamed,
}) => syn::Fields::Unnamed(syn::FieldsUnnamed {
paren_token,
unnamed: syn::punctuated::Punctuated::from_iter(
unnamed.into_iter().map(|x| x.field),
),
}),
CustomFields::Unit => syn::Fields::Unit,
};
syn::ItemStruct {
attrs,
vis,
struct_token,
ident,
generics,
fields,
semi_token,
}
}
fn impl_default(&self) -> proc_macro2::TokenStream {
#[allow(unused)]
let Self {
attrs,
vis,
struct_token,
ident,
generics,
fields,
semi_token,
} = &self;
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let fields = match fields {
CustomFields::Named(cfn) => {
let entries = cfn.to_formatted_defaults();
quote::quote!(
Self {
#(#entries),*
}
)
}
CustomFields::Unnamed(cfu) => {
let entries = cfu.to_formatted_defaults();
quote::quote!(
Self (#(#entries),*)
)
}
CustomFields::Unit => quote::quote!(Self),
};
quote::quote!(
impl #impl_generics core::default::Default for #ident #ty_generics #where_clause {
fn default() -> Self { #fields }
}
)
}
}
fn data_struct(
input: syn::parse::ParseStream,
) -> syn::Result<(
Option<syn::WhereClause>,
CustomFields,
Option<syn::Token![;]>,
)> {
let mut lookahead = input.lookahead1();
let mut where_clause = None;
if lookahead.peek(syn::Token![where]) {
where_clause = Some(input.parse()?);
lookahead = input.lookahead1();
}
if where_clause.is_none() && lookahead.peek(syn::token::Paren) {
let fields = input.parse()?;
lookahead = input.lookahead1();
if lookahead.peek(syn::Token![where]) {
where_clause = Some(input.parse()?);
lookahead = input.lookahead1();
}
if lookahead.peek(syn::Token![;]) {
let semi = input.parse()?;
Ok((where_clause, CustomFields::Unnamed(fields), Some(semi)))
} else {
Err(lookahead.error())
}
} else if lookahead.peek(syn::token::Brace) {
let fields = input.parse()?;
Ok((where_clause, CustomFields::Named(fields), None))
} else if lookahead.peek(syn::Token![;]) {
let semi = input.parse()?;
Ok((where_clause, CustomFields::Unit, Some(semi)))
} else {
Err(lookahead.error())
}
}
impl syn::parse::Parse for Parsed {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let attrs = input.call(syn::Attribute::parse_outer)?;
let vis = input.parse::<syn::Visibility>()?;
let struct_token = input.parse::<syn::Token![struct]>()?;
let ident = input.parse::<syn::Ident>()?;
let generics = input.parse::<syn::Generics>()?;
let (where_clause, fields, semi_token) = data_struct(input)?;
Ok(Parsed {
attrs,
vis,
struct_token,
ident,
generics: syn::Generics {
where_clause,
..generics
},
fields,
semi_token,
})
}
}
#[proc_macro]
pub fn default(tokenstream: TokenStream) -> TokenStream {
let parsed: Parsed = syn::parse_macro_input!(tokenstream);
let default_impl = parsed.impl_default();
let item_struct = parsed.into_item_struct();
quote::quote!(
#item_struct
const _: () = {
#default_impl
};
)
.into()
}