dotenvy-derive 0.15.8

Proc macro to derive compile-time struct initialization from .env files via dotenvy_macro.
Documentation
use syn::{DeriveInput, Error, Field, Fields, LitStr, Result};

pub struct FieldBinding {
    pub ident: syn::Ident,
    pub env_key: String,
}

pub fn parse_derive_input(input: &DeriveInput) -> Result<Vec<FieldBinding>> {
    let fields = match &input.data {
        syn::Data::Struct(s) => match &s.fields {
            Fields::Named(named) => &named.named,
            _ => {
                return Err(Error::new_spanned(
                    &input.ident,
                    "Bind: only named-field structs are supported",
                ));
            }
        },
        _ => {
            return Err(Error::new_spanned(
                &input.ident,
                "Bind: only structs are supported",
            ));
        }
    };

    fields.iter().map(parse_field).collect()
}

fn parse_field(field: &Field) -> Result<FieldBinding> {
    let ident = field
        .ident
        .clone()
        .ok_or_else(|| Error::new_spanned(field, "Bind: unnamed fields not supported"))?;

    let env_attr = field
        .attrs
        .iter()
        .find(|a| a.path().is_ident("env"))
        .ok_or_else(|| {
            Error::new_spanned(
                &ident,
                format!("Bind: field `{}` missing #[env(\"VAR\")] attribute", ident),
            )
        })?;

    let lit: LitStr = env_attr.parse_args().map_err(|_| {
        Error::new_spanned(
            env_attr,
            "Bind: #[env(...)] expects a string literal, e.g. #[env(\"VAR_NAME\")]",
        )
    })?;

    Ok(FieldBinding {
        ident,
        env_key: lit.value(),
    })
}