delta-pack-derive 0.3.0

Proc-macro derive for delta-pack
Documentation
use syn::spanned::Spanned;

#[derive(Default, Debug)]
pub struct FieldAttrs {
    pub min: Option<i64>,
    pub max: Option<i64>,
    pub precision: Option<f32>,
}

pub fn parse_field_attrs(attrs: &[syn::Attribute]) -> syn::Result<FieldAttrs> {
    let mut out = FieldAttrs::default();
    for attr in attrs {
        if !attr.path().is_ident("delta_pack") {
            continue;
        }
        attr.parse_nested_meta(|meta| {
            if meta.path.is_ident("range") {
                meta.parse_nested_meta(|range_meta| {
                    if range_meta.path.is_ident("min") {
                        let lit: syn::LitInt = range_meta.value()?.parse()?;
                        out.min = Some(lit.base10_parse()?);
                    } else if range_meta.path.is_ident("max") {
                        let lit: syn::LitInt = range_meta.value()?.parse()?;
                        out.max = Some(lit.base10_parse()?);
                    } else {
                        return Err(range_meta.error("expected `min` or `max`"));
                    }
                    Ok(())
                })?;
            } else if meta.path.is_ident("precision") {
                let value = meta.value()?;
                let lit: syn::LitFloat = value.parse()?;
                out.precision = Some(lit.base10_parse()?);
            } else {
                return Err(meta.error("unknown delta_pack attribute"));
            }
            Ok(())
        })?;
    }
    if let (Some(min), Some(max)) = (out.min, out.max) {
        if min > max {
            return Err(syn::Error::new(
                attrs
                    .first()
                    .map(|a| a.span())
                    .unwrap_or_else(proc_macro2::Span::call_site),
                format!("range min ({}) > max ({})", min, max),
            ));
        }
    }
    Ok(out)
}