sark-gen 0.11.0

Sark proc-macro generators
Documentation
#![allow(clippy::too_many_arguments)]

use proc_macro2::{Ident, TokenStream};
use quote::quote;

pub(crate) struct Config<'a> {
    pub(crate) name: &'a Ident,

    pub(crate) request_ident: &'a Ident,

    pub(crate) raw_params_ident: &'a Ident,
    pub(crate) raw_headers_ident: &'a Ident,
    pub(crate) params_inner_ident: &'a Ident,
    pub(crate) headers_inner_ident: &'a Ident,

    pub(crate) header_slot_ty: &'a TokenStream,

    pub(crate) static_response: bool,
    pub(crate) kind_ty: &'a TokenStream,
    pub(crate) native_response_ty: Option<&'a syn::Type>,
    pub(crate) native_response_ty_static: Option<&'a syn::Type>,
    pub(crate) async_response_ty: Option<&'a syn::Type>,
    pub(crate) parsed_body_ty: Option<&'a TokenStream>,
    pub(crate) parse_body_body: Option<&'a TokenStream>,
    pub(crate) max_body: Option<&'a syn::Expr>,
    pub(crate) head_skip: crate::model::HeadSkip,
}

impl Config<'_> {
    pub(crate) fn build(&self) -> TokenStream {
        let Config {
            name,
            request_ident,
            raw_params_ident,
            raw_headers_ident,
            params_inner_ident,
            headers_inner_ident,
            header_slot_ty,
            static_response,
            kind_ty,
            native_response_ty,
            native_response_ty_static,
            async_response_ty,
            parsed_body_ty,
            parse_body_body,
            max_body,
            ..
        } = *self;

        let default_response_ty = quote!(sark_core::http::Serve<'__req>);
        let native_response_shape = native_response_ty.map(|ty| {
            quote! {
                <#ty as sark::service::manifold::NativeResponse<'__req>>::Shape
            }
        });
        let response_ty = native_response_shape
            .as_ref()
            .unwrap_or(&default_response_ty);
        let default_async_response_ty: syn::Type = syn::parse_quote!(sark_core::http::Response);
        let async_response_ty = async_response_ty.unwrap_or(&default_async_response_ty);
        let response_body_kind_tokens = if let Some(ty) = native_response_ty_static {
            quote! {
                <#ty as sark::service::manifold::NativeResponse<'static>>::BODY_KIND
            }
        } else {
            quote! {
                <#async_response_ty as sark_core::http::OwnedShape>::BODY_KIND
            }
        };
        let stream_ty = native_response_ty_static
            .map(|ty| {
                quote! {
                    <#ty as sark::service::manifold::NativeResponse<'static>>::Stream
                }
            })
            .unwrap_or_else(|| quote!(sark_core::http::NeverStream));
        let default_parsed_body_ty = quote!(());
        let parsed_body_ty_token = parsed_body_ty.unwrap_or(&default_parsed_body_ty);
        let default_parse_body_body = quote!({
            let _ = raw;
            Ok(())
        });
        let parse_body_body_token = parse_body_body.unwrap_or(&default_parse_body_body);
        let max_body_token = match max_body {
            Some(expr) => quote! { const MAX_BODY: usize = #expr; },
            None => quote! {},
        };
        let emit_date_token = if self.head_skip.date {
            quote! { const EMIT_DATE: bool = false; }
        } else {
            quote! {}
        };
        let emit_server_token = if self.head_skip.server {
            quote! { const EMIT_SERVER: bool = false; }
        } else {
            quote! {}
        };

        quote! {
            impl sark::service::RouteSpec for #name {
                type Kind = #kind_ty;
                type Request = #request_ident;
                type Params<'__req> = #params_inner_ident<'__req>;
                type RawParams = #raw_params_ident;
                type Headers<'__req> = #headers_inner_ident<'__req>;
                type RawHeaders = #raw_headers_ident;
                type HeaderSlot = #header_slot_ty;
                type Response<'__req> = #response_ty;
                type AsyncResponse = #async_response_ty;
                type Stream = #stream_ty;
                type ParsedBody<'__req> = #parsed_body_ty_token;

                fn parse_body<'__req>(
                    raw: &'__req [u8],
                ) -> sark::error::Result<Self::ParsedBody<'__req>> {
                    #parse_body_body_token
                }
                const STATIC_RESPONSE: bool = #static_response;
                const RESPONSE_BODY_KIND: sark::http::body_kind::ResponseKind = #response_body_kind_tokens;
                #max_body_token
                #emit_date_token
                #emit_server_token

                type Captures =
                    <#raw_params_ident as sark::service::RawRouteParams>::Captures;

                fn from_captures<P: sark::service::PathProbe>(
                    path: &P,
                    captures: Self::Captures,
                ) -> Option<Self::RawParams> {
                    <#raw_params_ident as sark::service::RawRouteParams>::from_captures(
                        path, captures,
                    )
                }
            }
        }
    }
}