confroid-derive 0.0.4

Derive macro for confroid.
Documentation
use quote::quote;
use syn::DeriveInput;

pub(crate) fn expand(input: &DeriveInput) -> proc_macro2::TokenStream {
    let ident = &input.ident;
    let (_, original_ty_generics, _) = input.generics.split_for_impl();

    let mut from_env_generics = input.generics.clone();
    let from_env_where = from_env_generics.make_where_clause();
    from_env_where.predicates.push(syn::parse_quote! {
        #ident #original_ty_generics: ::core::str::FromStr
    });
    from_env_where.predicates.push(syn::parse_quote! {
        <#ident #original_ty_generics as ::core::str::FromStr>::Err:
            ::std::error::Error + ::core::marker::Send + ::core::marker::Sync + 'static
    });
    let (from_env_impl_generics, from_env_ty_generics, from_env_where_clause) =
        from_env_generics.split_for_impl();

    let documented_impl = if cfg!(feature = "docs") {
        let mut documented_generics = input.generics.clone();
        documented_generics
            .make_where_clause()
            .predicates
            .push(syn::parse_quote! {
                #ident #original_ty_generics: ::core::fmt::Display
            });
        let (documented_impl_generics, documented_ty_generics, documented_where_clause) =
            documented_generics.split_for_impl();
        quote! {
            #[automatically_derived]
            impl #documented_impl_generics ::confroid::Documented
                for #ident #documented_ty_generics #documented_where_clause
            {
                fn doc_fields() -> ::core::option::Option<
                    ::std::vec::Vec<::confroid::FieldDoc>
                > {
                    ::core::option::Option::None
                }
            }
        }
    } else {
        quote! {}
    };

    quote! {
        #[automatically_derived]
        impl #from_env_impl_generics ::confroid::FromEnv
            for #ident #from_env_ty_generics #from_env_where_clause
        {
            fn from_env(
                ctx: &::confroid::Ctx,
                env: &::confroid::Env,
            ) -> ::confroid::Result<Self> {
                match env.get(&ctx.var) {
                    ::core::option::Option::None =>
                        ::core::result::Result::Err(
                            ::confroid::ConfroidError::EnvVarNotFound {
                                var_name: ctx.var.clone(),
                                field: ctx.path.clone(),
                            }
                        ),
                    ::core::option::Option::Some(__raw) =>
                        __raw.parse::<Self>().map_err(|__error| {
                            ::confroid::ConfroidError::EnvVarInvalid {
                                var_name: ctx.var.clone(),
                                field: ctx.path.clone(),
                                value: __raw.to_string(),
                                parser_error: ::std::boxed::Box::new(__error),
                            }
                        }),
                }
            }

            fn is_present(ctx: &::confroid::Ctx, env: &::confroid::Env) -> bool {
                env.get(&ctx.var).is_some()
            }
        }

        #documented_impl
    }
}