apigate-macros 0.2.2

Procedural macros for apigate — #[service], #[hook], #[map], and route attributes
Documentation
use proc_macro2::Span;
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::{Error, Ident, LitStr, Result, Token};

use crate::parse::{parse_assigned, required, set_once};

pub(crate) struct ServiceArgs {
    pub name: LitStr,
    pub prefix: Option<LitStr>,
    pub policy: Option<LitStr>,
}

enum ServiceArg {
    Name(LitStr),
    Prefix(LitStr),
    Policy(LitStr),
}

impl Parse for ServiceArg {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        let key: Ident = input.parse()?;
        let value: LitStr = parse_assigned(input)?;

        if key == "name" {
            Ok(Self::Name(value))
        } else if key == "prefix" {
            Ok(Self::Prefix(value))
        } else if key == "policy" {
            Ok(Self::Policy(value))
        } else {
            Err(Error::new(key.span(), format!("unknown argument `{key}`")))
        }
    }
}

impl Parse for ServiceArgs {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        let args = input.call(Punctuated::<ServiceArg, Token![,]>::parse_terminated)?;

        let mut name = None;
        let mut prefix = None;
        let mut policy = None;

        for arg in args {
            match arg {
                ServiceArg::Name(v) => set_once(&mut name, v.clone(), v.span(), "name")?,
                ServiceArg::Prefix(v) => set_once(&mut prefix, v.clone(), v.span(), "prefix")?,
                ServiceArg::Policy(v) => set_once(&mut policy, v.clone(), v.span(), "policy")?,
            }
        }

        Ok(Self {
            name: required(name, Span::call_site(), "missing `name = \"...\"`")?,
            prefix,
            policy,
        })
    }
}