a3s-boot-macros 0.1.2

Attribute macros for a3s-boot
Documentation
use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::{Attribute, Expr, LitStr, Result, Token};

use super::is_attribute_named;
use crate::parse_optional_comma;

pub(crate) fn take_controller_metadata_attrs(
    attrs: &[Attribute],
) -> (Vec<Attribute>, ControllerMetadataAttrs, Vec<syn::Error>) {
    let mut clean_attrs = Vec::new();
    let mut metadata = ControllerMetadataAttrs::default();
    let mut errors = Vec::new();

    for attr in attrs {
        if !is_attribute_named(attr, "metadata") {
            clean_attrs.push(attr.clone());
            continue;
        }

        match attr.parse_args::<MetadataSpec>() {
            Ok(spec) => metadata.specs.push(spec),
            Err(error) => errors.push(error),
        }
    }

    (clean_attrs, metadata, errors)
}

pub(crate) fn take_route_metadata_attrs(
    attrs: &[Attribute],
) -> (Vec<Attribute>, Vec<MetadataSpec>, Vec<syn::Error>) {
    let mut clean_attrs = Vec::new();
    let mut specs = Vec::new();
    let mut errors = Vec::new();

    for attr in attrs {
        if !is_attribute_named(attr, "metadata") {
            clean_attrs.push(attr.clone());
            continue;
        }

        match attr.parse_args::<MetadataSpec>() {
            Ok(spec) => specs.push(spec),
            Err(error) => errors.push(error),
        }
    }

    (clean_attrs, specs, errors)
}

#[derive(Default)]
pub(crate) struct ControllerMetadataAttrs {
    specs: Vec<MetadataSpec>,
}

impl ControllerMetadataAttrs {
    pub(crate) fn tokens(&self) -> Vec<proc_macro2::TokenStream> {
        self.specs
            .iter()
            .map(|spec| {
                let key = &spec.key;
                let value = &spec.value;
                quote!(with_metadata(#key, #value))
            })
            .collect()
    }
}

#[derive(Clone)]
pub(crate) struct MetadataSpec {
    pub(crate) key: LitStr,
    pub(crate) value: Expr,
}

impl Parse for MetadataSpec {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        let key = input.parse::<LitStr>()?;
        input.parse::<Token![,]>()?;
        let value = input.parse::<Expr>()?;
        parse_optional_comma(input)?;
        Ok(Self { key, value })
    }
}