ff_macro 0.2.2

TryFrom impl HashMap<String,String> -> Struct
Documentation
use syn::{Data, DataStruct, DeriveInput, Field, Ident, Type};

pub fn preamble(input: DeriveInput) -> (DeriveInput, Ident, DataStruct) {
    let name = input.clone().ident;
    let data = match input.clone().data {
        Data::Struct(data) => data,
        _ => panic!("FromForm can only be implemented for structs"),
    };

    (input, name, data)
}

pub fn get_inner_type(t: Type) -> Type {
    match t {
        Type::Path(p) => {
            let ty = match p.path.segments.first().unwrap().arguments.clone() {
                syn::PathArguments::AngleBracketed(t) => t,
                _ => panic!("Unexpected path arguments"),
            }
            .args;

            let ty = match ty.first().unwrap() {
                syn::GenericArgument::Type(t) => t,
                _ => panic!("Unexpected non-type generic argument"),
            };

            ty.clone()
        }
        _ => panic!("Cant get inner type of non-path"),
    }
}

pub fn filter_opts(
    f: impl Iterator<Item = Field>,
    use_opts: bool,
    use_str: bool,
) -> impl Iterator<Item = Field> {
    f.filter(move |f| match f.ty.clone() {
        Type::Path(p) => match p.path.segments.first().map(|p| p.ident.clone()) {
            Some(p) => match use_opts {
                true => p.to_string() == "Option".to_string(),
                false => p.to_string() != "Option".to_string(),
            },
            None => !use_opts,
        },
        _ => !use_opts,
    })
    .filter(
        move |f| match f.attrs.iter().find(|a| a.path().is_ident("from_str")).is_some() {
            true => use_str,
            false => !use_str,
        },
    )
}

pub fn collect(f: impl Iterator<Item = Field>) -> (Vec<Option<Ident>>, Vec<String>, Vec<Type>) {
    let f = f.map(|f| {
        let form_name = f
            .attrs
            .iter()
            .find(|a| a.path().is_ident("rename"))
            .and_then(|attr| attr.parse_args::<syn::LitStr>().ok().map(|lit| lit.value()))
            .unwrap_or_else(|| f.ident.clone().unwrap().to_string());

        let field_type = f.ty.clone();

        (f.ident.clone(), (form_name, field_type))
    });

    let (ident, r): (Vec<_>, (Vec<_>, Vec<_>)) = f.unzip();
    let (name, ty) = r;

    (ident, name, ty)
}