sval_derive_macros 2.9.2

Minimal derive support for `sval`
Documentation
use syn::{Attribute, Generics, Ident, Path};

use crate::{
    attr::{self},
    bound,
    index::{Index, IndexAllocator},
    label::label_or_ident,
    stream::stream_tag,
    tag::quote_optional_tag_owned,
};

pub(crate) struct UnitStructAttrs {
    tag: Option<Path>,
    label: Option<String>,
    index: Option<isize>,
}

impl UnitStructAttrs {
    pub(crate) fn from_attrs(attrs: &[Attribute]) -> Self {
        attr::check(
            "unit struct",
            &[&attr::TagAttr, &attr::LabelAttr, &attr::IndexAttr],
            attrs,
        );

        let tag = attr::get_unchecked("unit struct", attr::TagAttr, attrs);
        let label = attr::get_unchecked("unit struct", attr::LabelAttr, attrs);
        let index = attr::get_unchecked("unit struct", attr::IndexAttr, attrs);

        UnitStructAttrs { tag, label, index }
    }

    pub(crate) fn tag(&self) -> Option<&Path> {
        self.tag.as_ref()
    }

    pub(crate) fn label(&self) -> Option<&str> {
        self.label.as_deref()
    }

    pub(crate) fn index(&self) -> Option<Index> {
        self.index.map(IndexAllocator::const_index_of)
    }
}

pub(crate) fn derive_unit_struct<'a>(
    ident: &Ident,
    generics: &Generics,
    attrs: &UnitStructAttrs,
) -> proc_macro2::TokenStream {
    let (impl_generics, ty_generics, _) = generics.split_for_impl();

    let bound = parse_quote!(sval::Value);
    let bounded_where_clause = bound::where_clause_with_bound(&generics, bound);

    let match_arm = stream_tag(
        quote!(_),
        attrs.tag(),
        Some(label_or_ident(attrs.label(), ident)),
        attrs.index(),
    );

    let tag = quote_optional_tag_owned(attrs.tag());

    quote! {
        const _: () = {
            extern crate sval;

            impl #impl_generics sval::Value for #ident #ty_generics #bounded_where_clause {
                fn stream<'sval, S: sval::Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> sval::Result {
                    match self {
                        #match_arm
                    }

                    Ok(())
                }

                fn tag(&self) -> Option<sval::Tag> {
                    #tag
                }
            }
        };
    }
}