sark-gen 0.8.5

Sark proc-macro generators
Documentation
use syn::punctuated::Punctuated;
use syn::{Expr, ExprLit, Lit, Meta, Result};

#[derive(Clone, Copy, Default)]
pub(super) struct FieldMode {
    pub(super) raw: bool,
    pub(super) unused: bool,
    pub(super) plain: bool,
    pub(super) nested: bool,
    pub(super) seq: bool,
}

impl FieldMode {
    pub(super) fn from_field(
        field: &syn::Field,
        default_plain: bool,
    ) -> Result<(Self, Option<String>)> {
        let mut mode = Self {
            plain: default_plain,
            ..Self::default()
        };
        let mut name = None;
        for attr in &field.attrs {
            if attr.path().is_ident("raw") {
                mode.raw = true;
                continue;
            }
            if attr.path().is_ident("unused") {
                mode.unused = true;
                continue;
            }
            if attr.path().is_ident("plain") {
                mode.plain = true;
                continue;
            }
            if attr.path().is_ident("field") {
                let items =
                    attr.parse_args_with(Punctuated::<Meta, syn::Token![,]>::parse_terminated)?;
                for item in items {
                    match item {
                        Meta::Path(path) if path.is_ident("raw") => mode.raw = true,
                        Meta::Path(path) if path.is_ident("unused") => mode.unused = true,
                        Meta::Path(path) if path.is_ident("plain") => mode.plain = true,
                        Meta::Path(path) if path.is_ident("nested") => mode.nested = true,
                        Meta::Path(path) if path.is_ident("seq") => mode.seq = true,
                        Meta::NameValue(nv) if nv.path.is_ident("name") => {
                            let Expr::Lit(ExprLit {
                                lit: Lit::Str(s), ..
                            }) = nv.value
                            else {
                                return Err(syn::Error::new_spanned(
                                    nv.value,
                                    "#[field(name = ...)] expects a string literal",
                                ));
                            };
                            name = Some(s.value());
                        }
                        other => {
                            return Err(syn::Error::new_spanned(
                                other,
                                "#[field(...)] supports only `raw`, `unused`, `plain`, `nested`, `seq`, or `name = \"...\"`",
                            ));
                        }
                    }
                }
            }
        }
        Ok((mode, name))
    }
}