wasmer-bus-macros 1.1.0

WebAssembly Bus Macros
Documentation
use derivative::*;
use syn::parse::{Parse, ParseStream};
use syn::*;

#[derive(Derivative, Clone)]
#[derivative(Debug)]
pub struct ReturnTrait {
    #[derivative(Debug = "ignore")]
    pub path: Path,
    pub ident: Ident,
    #[derivative(Debug = "ignore")]
    pub ty: Type,
    pub client_name: String,
    pub client_ident: Ident,
    pub service_name: String,
    pub service_ident: Ident,
}

impl Parse for ReturnTrait {
    fn parse(input: ParseStream) -> Result<Self> {
        input.parse::<Option<Token![->]>>()?;

        let span = input.span();
        let path = input.parse::<Path>()?;

        let arc_segment = match path.segments.into_iter().last() {
            Some(a) if a.ident == "Arc" => a,
            _ => {
                return Err(Error::new(
                    span,
                    "only Arc is supported as a WASM trait return type",
                ));
            }
        };

        let span = arc_segment.ident.span();
        let inner = match arc_segment.arguments {
            PathArguments::AngleBracketed(brackets) => {
                let args = brackets.args;
                if args.len() != 1 {
                    return Err(Error::new(span, "the Arc must contain a dynamic trait"));
                }
                args.into_iter().last().unwrap()
            }
            _ => {
                return Err(Error::new(span, "the Arc must contain a dynamic trait"));
            }
        };

        let ty = match inner {
            GenericArgument::Type(a) => a,
            _ => {
                return Err(Error::new(
                    span,
                    "bindings, lifetimes, contraints and consts are not supported",
                ));
            }
        };

        let trait_bound = match ty.clone() {
            Type::TraitObject(a) => a
                .bounds
                .into_iter()
                .filter_map(|a| {
                    if let TypeParamBound::Trait(a) = a {
                        Some(a)
                    } else {
                        None
                    }
                })
                .next(),
            _ => {
                return Err(Error::new(span, "the Arc must contain a dynamic trait"));
            }
        };
        let trait_bound = match trait_bound {
            Some(a) => a,
            None => {
                return Err(Error::new(
                    span,
                    "the Arc must contain a dynamic trait without any other bounds",
                ));
            }
        };

        let path = trait_bound.path;
        let ident = if let Some(last) = path.segments.last() {
            last.ident.clone()
        } else {
            return Err(Error::new(
                input.span(),
                "return type must be a type identifier",
            ));
        };

        let client_name = format!("{}Client", ident.to_string());
        let client_ident = Ident::new(client_name.as_str(), span.clone());

        let service_name = format!("{}Service", ident.to_string());
        let service_ident = Ident::new(service_name.as_str(), span.clone());

        let ret = ReturnTrait {
            path,
            ident,
            ty,
            client_name,
            client_ident,
            service_name,
            service_ident,
        };

        Ok(ret)
    }
}