typed-builder 0.1.0

Compile-time type-checked builder derive
Documentation
use syn;
use quote::Tokens;

use util::{make_identifier, map_only_one};

pub struct FieldInfo<'a> {
    pub ordinal: usize,
    pub name: &'a syn::Ident,
    pub generic_ident: syn::Ident,
    pub ty: &'a syn::Ty,
    pub default: Option<Tokens>,
}

impl<'a> FieldInfo<'a> {
    pub fn new(ordinal: usize, field: &syn::Field) -> FieldInfo {
        if let Some(ref name) = field.ident {
            FieldInfo {
                ordinal: ordinal,
                name: &name,
                generic_ident: make_identifier("genericType", name),
                ty: &field.ty,
                default: Self::find_field_default(field).unwrap_or_else(|f| panic!("Field {}: {}", name, f)),
            }
        } else {
            panic!("Nameless field in struct");
        }
    }

    fn find_field_default(field: &syn::Field) -> Result<Option<Tokens>, String> {
        map_only_one(&field.attrs, |attr| {
            match attr.value {
                syn::MetaItem::Word(ref name) if name == "default" => {
                    Ok(Some(quote!(::std::default::Default::default())))
                },
                syn::MetaItem::List(ref name, _) if name == "default" => {
                    Err("default can not be a list style attribute".into())
                }
                syn::MetaItem::NameValue(ref name, syn::Lit::Str(ref lit, _)) if name == "default" => {
                    let field_value = syn::parse_token_trees(lit)?;
                    Ok(Some(quote!(#( #field_value )*)))
                },
                _ => Ok(None)
            }
        })
    }

    pub fn generic_ty_param(&self) -> syn::TyParam {
        syn::TyParam::from(self.generic_ident.clone())
    }

    pub fn tuplized_type_ty_param(&self) -> syn :: TyParam {
        let ref ty = self.ty;
        let quoted = quote!((#ty,));
        syn::TyParam::from(syn::Ident::from(quoted.into_string()))
    }

    pub fn empty_ty_param() -> syn::TyParam {
        syn::TyParam::from(syn::Ident::from("()"))
    }
}