use crate::attributes::{FieldAttributes, FieldVisibility};
use crate::builder::{
builder_decl::BuilderDecl, builder_functions::BuilderFunctions, builder_impl::BuilderImpl,
};
use crate::field::Field;
use crate::struct_impl::StructImpl;
use core::str::FromStr;
use proc_macro2::{Ident, Span, TokenStream};
use quote::{ToTokens, TokenStreamExt};
use syn::{
parse::{Parse, ParseStream, Result},
AttrStyle, Attribute, Data, DeriveInput, Fields, GenericParam, Generics, Lifetime, Token,
VisPublic, Visibility,
};
pub struct StructInput {
pub vis: Visibility,
pub ident: Ident,
pub generics: Generics,
pub attrs: Vec<Attribute>,
pub required_fields: Vec<Field>,
pub optional_fields: Vec<Field>,
}
impl Parse for StructInput {
fn parse(input: ParseStream) -> Result<Self> {
let input: DeriveInput = input.parse()?;
let vis = input.vis;
let ident = input.ident;
let generics = input.generics;
let attrs = input.attrs;
let fields = if let Data::Struct(d) = input.data {
if let Fields::Named(f) = d.fields {
f
} else {
unimplemented!("Only named structures are supported!");
}
} else {
unimplemented!("Only structures are supported!");
};
let mut optional_fields: Vec<Field> = Vec::new();
let mut required_fields: Vec<Field> = Vec::new();
for f in fields.named.into_iter() {
let attrs: FieldAttributes = f.attrs.into();
let fields = if attrs.default.is_some() {
&mut optional_fields
} else {
&mut required_fields
};
fields.push(Field {
vis: if attrs.vis == FieldVisibility::Public {
let v = <Token![pub]>::default();
Visibility::Public(VisPublic { pub_token: v })
} else {
f.vis
},
ident: f
.ident
.unwrap_or_else(|| unimplemented!("Fields must have an identifier!")),
ty: f.ty,
attrs,
});
}
optional_fields.sort();
required_fields.sort();
Ok(StructInput {
vis,
ident,
generics,
attrs,
required_fields,
optional_fields,
})
}
}
impl ToTokens for StructInput {
fn to_tokens(&self, tokens: &mut TokenStream) {
let struct_impl = StructImpl::new(self);
struct_impl.to_tokens(tokens);
let builder_decl = BuilderDecl::new(self);
builder_decl.to_tokens(tokens);
let builder_impl = BuilderImpl::new(self);
builder_impl.to_tokens(tokens);
let builder_func = BuilderFunctions::new(self);
builder_func.to_tokens(tokens);
}
}
impl StructInput {
pub fn num_fields(&self) -> usize {
self.required_fields.len() + self.optional_fields.len()
}
pub fn builder_name(&self) -> Ident {
Ident::new(&format!("{}Builder", self.ident), Span::call_site())
}
pub fn fn_lifetime(&self) -> Lifetime {
Lifetime::new("'fn_lifetime", Span::call_site())
}
pub fn lifetimes(&self) -> Vec<TokenStream> {
self.generics
.lifetimes()
.map(|f| f.lifetime.to_token_stream())
.collect()
}
pub fn all_generics(&self) -> impl Iterator<Item = TokenStream> {
(0..(self.num_fields()))
.into_iter()
.map(|i| TokenStream::from_str(&format!("TyBuilderPattern{}", i + 1)).unwrap())
}
pub fn builder_fields<'a>(
&'a self,
fn_lifetime: &'a Lifetime,
) -> impl 'a + Iterator<Item = TokenStream> {
self.required_fields
.iter()
.chain(self.optional_fields.iter())
.map(move |f| {
let (ident, ty) = (&f.ident, &f.ty);
quote! {
#ident: Option<::builder_pattern::setter::Setter<#fn_lifetime, #ty>>
}
})
}
pub fn tokenize_types(&self) -> TokenStream {
let generics = &self.generics;
let mut tokens = TokenStream::new();
if generics.params.is_empty() {
return tokens;
}
let mut trailing_or_empty = true;
for param in generics.params.pairs() {
if let GenericParam::Lifetime(_) = *param.value() {
trailing_or_empty = param.punct().is_some();
}
}
for param in generics.params.pairs() {
if let GenericParam::Lifetime(_) = **param.value() {
continue;
}
if !trailing_or_empty {
<Token![,]>::default().to_tokens(&mut tokens);
trailing_or_empty = true;
}
match *param.value() {
GenericParam::Lifetime(_) => unreachable!(),
GenericParam::Type(param) => {
param.ident.to_tokens(&mut tokens);
}
GenericParam::Const(param) => {
param.ident.to_tokens(&mut tokens);
}
}
param.punct().to_tokens(&mut tokens);
}
<Token![,]>::default().to_tokens(&mut tokens);
tokens
}
pub fn tokenize_impl(&self) -> TokenStream {
let mut tokens = TokenStream::new();
let generics = &self.generics;
let mut trailing_or_empty = true;
for param in generics.params.pairs() {
if let GenericParam::Lifetime(_) = **param.value() {
param.to_tokens(&mut tokens);
trailing_or_empty = param.punct().is_some();
}
}
for param in generics.params.pairs() {
if let GenericParam::Lifetime(_) = **param.value() {
continue;
}
if !trailing_or_empty {
<Token![,]>::default().to_tokens(&mut tokens);
trailing_or_empty = true;
}
match *param.value() {
GenericParam::Lifetime(_) => unreachable!(),
GenericParam::Type(param) => {
tokens.append_all(param.attrs.iter().filter(|attr| match attr.style {
AttrStyle::Outer => true,
AttrStyle::Inner(_) => false,
}));
param.ident.to_tokens(&mut tokens);
if !param.bounds.is_empty() {
if let Some(t) = ¶m.colon_token {
t.to_tokens(&mut tokens)
}
param.bounds.to_tokens(&mut tokens);
}
}
GenericParam::Const(param) => {
tokens.append_all(param.attrs.iter().filter(|attr| match attr.style {
AttrStyle::Outer => true,
AttrStyle::Inner(_) => false,
}));
param.const_token.to_tokens(&mut tokens);
param.ident.to_tokens(&mut tokens);
param.colon_token.to_tokens(&mut tokens);
param.ty.to_tokens(&mut tokens);
}
}
param.punct().to_tokens(&mut tokens);
}
if !tokens.is_empty() {
<Token![,]>::default().to_tokens(&mut tokens);
}
tokens
}
}