carapax-codegen 0.2.0

Procedural macroses for carapax
Documentation
use proc_macro2::Span;
use syn::{
    parse::{Parse, ParseStream},
    FnArg, Ident, ItemFn, Result as SynResult, ReturnType, Type, Visibility,
};

pub(crate) struct HandlerMeta {
    pub(super) vis: Visibility,
    pub(super) ident: Ident,
    pub(super) ident_inner: Ident,
    pub(super) handler: ItemFn,
    pub(super) context: Box<Type>,
    pub(super) input: Box<Type>,
    pub(super) output: Option<Box<Type>>,
}

impl Parse for HandlerMeta {
    fn parse(input: ParseStream) -> SynResult<Self> {
        let mut handler = input.parse::<ItemFn>()?;
        if handler.sig.asyncness.is_none() {
            return Err(input.error("function must be async"));
        }
        let context = match handler.sig.inputs.first() {
            Some(FnArg::Typed(typed)) => match &*typed.ty {
                Type::Reference(reference) => reference.elem.clone(),
                _ => return Err(input.error("context must be a reference")),
            },
            _ => return Err(input.error("first argument must be context type")),
        };
        let input = match handler.sig.inputs.last() {
            Some(FnArg::Typed(arg)) => arg.ty.clone(),
            _ => return Err(input.error("unable to detect handler input")),
        };
        let output = match &handler.sig.output {
            ReturnType::Default => None,
            ReturnType::Type(_, output) => Some(output.clone()),
        };
        let vis = handler.vis.clone();
        let ident = handler.sig.ident.clone();
        let ident_inner = Ident::new(&format!("__carapax_{}", ident), Span::call_site());
        handler.sig.ident = ident_inner.clone();
        Ok(HandlerMeta {
            vis,
            handler,
            ident,
            ident_inner,
            context,
            input,
            output,
        })
    }
}