protect-endpoints-proc-macro 0.2.1

A proc-macro way to protect your endpoints
Documentation
use crate::expand::ProtectEndpoint;
use proc_macro2::{Ident, Span, TokenStream as TokenStream2};
use quote::{quote, ToTokens};
use syn::ReturnType;

impl ProtectEndpoint {
    pub(super) fn to_tokens_actix_web(&self, output: &mut TokenStream2) {
        let func_vis = &self.func.vis();
        let func_block = &self.func.block();

        let fn_sig = &self.func.sig();
        let fn_attrs = &self.func.attrs();
        let fn_name = &fn_sig.ident;
        let fn_generics = &fn_sig.generics;
        let fn_args = &fn_sig.inputs;
        let fn_async = &fn_sig
            .asyncness
            .expect("only async functions are supported");
        let fn_output = match &fn_sig.output {
            ReturnType::Type(ref _arrow, ref ty) => ty.to_token_stream(),
            ReturnType::Default => {
                quote! {()}
            }
        };

        let auth_details = format!("_auth_details_{}", fn_args.len());
        let auth_details: Ident = Ident::new(&auth_details, Span::call_site());

        let ty = self
            .args
            .ty
            .as_ref()
            .map(ToTokens::to_token_stream)
            .unwrap_or(quote! {String});

        let condition = self
            .args
            .cond
            .to_tokens(&auth_details, self.args.ty.is_some());
        let condition = quote!(if #condition);

        let err_resp = if let Some(expr) = &self.args.error_fn {
            quote!(#expr())
        } else {
            quote!(actix_web::HttpResponse::Forbidden().finish())
        };

        let stream = quote! {
            #(#fn_attrs)*
            #func_vis #fn_async fn #fn_name #fn_generics(
                #auth_details: actix_web_grants::authorities::AuthDetails<#ty>,
                #fn_args
            ) -> actix_web::Either<#fn_output, actix_web::HttpResponse> {
                use actix_web_grants::authorities::AuthoritiesCheck;
                #condition {
                    let f = || async move #func_block;
                    actix_web::Either::Left(f().await)
                } else {
                    actix_web::Either::Right(#err_resp)
                }
            }
        };

        output.extend(stream);
    }
}