sark-gen 0.22.0

Sark proc-macro generators
Documentation
use handle::{decode, dispatch};

use crate::{app::serve::handle, macros::tokens::local, runtime::paths::Paths};

pub(super) fn build(
    paths: &Paths,
    ctx: &handle::Context<'_, '_, '_>,
    disp: &dispatch::Dispatch,
    decode: &decode::Decode,
) -> proc_macro2::TokenStream {
    let f_core = local("core");
    let symbols = &ctx.plan.spec.state_generics;
    let [v_body, v_encode, v_error] = symbols.locals(["body", "encoder", "error"]);
    let [v_head, v_prep] = symbols.locals(["head", "prepared"]);
    let [v_proj, v_req, v_source] = symbols.locals(["project", "request", "source"]);
    let [v_value, v_visit] = symbols.locals(["value", "visit"]);
    let [l_driver, l_req, l_out] =
        ctx.plan
            .spec
            .state_generics
            .lives(["__sark_driver", "__sark_request", "o"]);
    let [g_e, g_f, g_g, g_i, g_t, g_v, g_store] = ctx
        .plan
        .spec
        .state_generics
        .idents(["__E", "__F", "__G", "__I", "__T", "__V", "__P"]);
    use quote::quote;

    let ns_core = &paths.core;
    let ns_fiber = &paths.fiber;
    let ns_http = &paths.http;

    let name = &ctx.name;
    let core = &ctx.core_ident;
    let bounds = &disp.shape.base_bounds;
    let def = &disp.shape.generic_def;
    let args = &disp.shape.generic_use;
    let req = &decode.prepared.state.request;
    let policy = (!ctx.exec.fibers().is_empty()).then(|| {
        quote! {
            #g_store: #ns_fiber::manifold::runtime::Runnable,
        }
    });
    let guarded = decode.guard.is_some().then(|| {
        quote! {
            impl #def #ns_core::decode::Guarded for #name #args
            where
                #policy
                #bounds
            {
                fn try_admit<
                    #l_req,
                    #l_driver: #l_req,
                    #g_e: #ns_core::decode::Encode<
                        #l_req,
                        #l_driver,
                    >,
                    #g_f: #ns_core::decode::state::Set,
                    #g_g: #ns_core::decode::state::Set,
                    #g_v: #ns_core::decode::state::admit::TryVisit<
                        Self::Prepared,
                        #g_f,
                        #g_g,
                        <#g_e as #ns_core::decode::Encode<
                            #l_req, #l_driver,
                        >>::Error,
                    >,
                >(
                    &self,
                    #v_req: #ns_core::decode::request::Guarded<
                        <Self::Routes as #ns_core::decode::state::Family<
                            Self::Prepared,
                        >>::State<#g_f>,
                    >,
                    #v_encode: #g_e,
                    #v_visit: &mut #g_v,
                ) -> ::core::ops::ControlFlow<
                    #g_v::Break<#g_e::Prepared, #g_e::Target>,
                    #req<#g_g>,
                > {
                    #ns_core::decode::Guarded::try_admit(
                        &self.#f_core,
                        #v_req,
                        #v_encode,
                        #v_visit,
                    )
                }
            }
        }
    });
    quote! {
            impl #def #ns_core::decode::Decode for #name #args
            where
                #policy
                #bounds
            {
                type Head = <#core #args as #ns_core::decode::Decode>::Head;
                type Prepared = <#core #args as #ns_core::decode::Decode>::Prepared;
                type Routes = <#core #args as #ns_core::decode::Decode>::Routes;
                type Plan = <#core #args as #ns_core::decode::Decode>::Plan;
                type Cause = <#core #args as #ns_core::decode::Decode>::Cause;
                type Error<#l_req> = <#core #args as #ns_core::decode::Decode>::Error<#l_req>;
                type Projected<#l_req, #l_driver> =
                    <#core #args as #ns_core::decode::Decode>::Projected<#l_req, #l_driver>
                where
                    #l_driver: #l_req;
                type Egress<#l_out> = <#core #args as #ns_core::decode::Decode>::Egress<#l_out>;

                fn reject<#l_req>(#v_error: Self::Error<#l_req>) -> #ns_core::route::Reject {
                    <#core #args as #ns_core::decode::Decode>::reject(#v_error)
                }

                fn try_full(
                    &self,
                    #v_head: #ns_http::field::metadata::section::state::RetainedHead<
                        #ns_http::field::metadata::packed::Decoded,
                        #ns_http::field::metadata::section::state::Selected<
                            #ns_http::field::metadata::section::rules::RetainRaw,
                        >,
                    >,
                ) -> ::core::result::Result<
                    Self::Head,
                    #ns_core::decode::HeadError<Self::Cause>,
                > {
                    #ns_core::decode::Decode::try_full(&self.#f_core, #v_head)
                }

                fn try_head(
                    &self,
                    #v_head: #ns_http::field::metadata::section::state::RetainedHead<
                        <Self::Plan as #ns_http::field::metadata::section::Policy>::Block,
                        #ns_http::field::metadata::section::state::Selected<Self::Plan>,
                    >,
                ) -> ::core::result::Result<
                    Self::Head,
                    #ns_core::decode::HeadError<Self::Cause>,
                > {
                    #ns_core::decode::Decode::try_head(&self.#f_core, #v_head)
                }

                fn try_dispatch<
                    #l_req,
                    #l_driver,
                    #g_e: #ns_core::decode::Encode<
                        #l_req,
                        #l_driver,
                    >,
                >(
                    &self,
                    #v_req: Self::Projected<#l_req, #l_driver>,
                    #v_encode: #g_e,
                ) -> ::core::result::Result<
                    #g_e::Prepared,
                    (
                        #ns_core::decode::dispatch::Error<
                            <#g_e as #ns_core::decode::Encode<
                                #l_req, #l_driver,
                            >>::Error,
                            ::core::convert::Infallible,
                            Self::Error<#l_req>,
                        >,
                        #g_e::Target,
                    ),
                > {
                    #ns_core::decode::Decode::try_dispatch(
                        &self.#f_core,
                        #v_req,
                        #v_encode,
                    )
                }

                fn try_project<
                    #l_driver,
                    #g_i: #ns_http::owner::handoff::Project<#l_driver>,
                    #g_t,
                    #g_f: for<#l_req> ::core::ops::FnOnce(
                        #ns_core::decode::Scoped<
                            #l_req,
                            #l_driver,
                            Self,
                            #g_i::Proof,
                        >,
                    ) -> #g_t,
                >(
                    &self,
                    #v_prep: Self::Prepared,
                    #v_body: #ns_core::body::Input<#g_i>,
                    #v_proj: #g_f,
                ) -> #ns_core::body::Projection<
                    #g_t,
                    #g_i::Owner,
                    (Self::Prepared, #ns_core::body::Input<#g_i>),
                >
                {
                    #ns_core::decode::Decode::try_project(
                        &self.#f_core,
                        #v_prep,
                        #v_body,
                        |#v_req| {
                            let (#v_value, #v_source) = #v_req.into_parts();
                            #v_proj(#ns_core::decode::Scoped::new(#v_value, #v_source))
                        },
                    )
                }
            }

            #guarded
    }
}