use crate::{
app::{route, serve::handle, spec},
runtime::paths::Paths,
};
pub(in crate::app::serve::handle) struct Dispatch {
pub(in crate::app::serve::handle) methods: Methods,
pub(in crate::app::serve::handle) shape: Shape,
}
pub(in crate::app::serve::handle) struct Methods {
pub(in crate::app::serve::handle) method_mask: proc_macro2::TokenStream,
pub(in crate::app::serve::handle) head_method_key: proc_macro2::TokenStream,
}
pub(in crate::app::serve) struct Shape {
pub(in crate::app::serve) base_bounds: proc_macro2::TokenStream,
pub(in crate::app::serve) generic_def: proc_macro2::TokenStream,
pub(in crate::app::serve) core_generic_def: proc_macro2::TokenStream,
pub(in crate::app::serve) protocol_generic_def: proc_macro2::TokenStream,
pub(in crate::app::serve) generic_use: proc_macro2::TokenStream,
pub(in crate::app::serve) multiplexed_generic_use: proc_macro2::TokenStream,
}
impl Methods {
pub(in crate::app::serve::handle) fn build(paths: &Paths, spec: &spec::Spec) -> Self {
use quote::quote;
let symbols = &spec.state_generics;
let [v_mbytes, v_mkey] = symbols.locals(["__method_bytes", "__method_key"]);
let mut enabled = [false; route::Method::ALL.len()];
for entry in spec.route_specs.iter() {
enabled[entry.method.ord() as usize] = true;
}
let methods = || {
let enabled = enabled;
route::Method::ALL
.into_iter()
.filter(move |method| enabled[method.ord() as usize])
};
let bits = methods().map(|method| method.bit_token(paths));
let mask = quote!(0u8 #( | #bits )*);
let hchecks = methods().map(|method| {
let bytes = method.bytes_token();
let key = method.key_token(paths);
quote! {
if #v_mbytes.is_equal(#bytes) {
::core::option::Option::Some(#key)
}
}
});
let head = quote! {
let #v_mkey = #( #hchecks else )*
{
::core::option::Option::None
};
};
Self {
method_mask: mask,
head_method_key: head,
}
}
}
impl Shape {
fn build(paths: &Paths, context: &handle::Context<'_, '_, '_>) -> Self {
let [l_env, g_brand] = context.plan.spec.state_generics.lives(["env", "brand"]);
let [g_target, g_id, g_mode, g_store, g_stamp, g_wire] = context
.plan
.spec
.state_generics
.idents(["__C", "__ID", "__M", "__P", "__S", "__W"]);
use quote::quote;
let ns_core = &paths.core;
let ns_fiber = &paths.fiber;
let spec = context.plan.spec;
let lives = &spec.state_generics.lifetimes;
let decls = &spec.state_generics.parameters;
let values = &spec.state_generics.arguments;
let clauses = &spec.state_generics.predicates;
let routes = &spec.route_bounds;
let core = &context.core_ident;
let slabs = &context.exec.slab_bounds;
let make_req = &context.exec.producer_bounds;
let base = quote! {
#( #clauses, )*
#( #routes )*
#( #make_req )*
#( #slabs )*
};
let generic = |stamp: bool| {
let (futures, makers) = context.exec.producers();
let stamp = stamp.then_some(&g_stamp);
let stamp = stamp.as_slice();
quote! {
<
#g_brand: #l_env,
#l_env,
#( #lives: #l_env, )*
'd: #l_env,
#( #decls, )*
#g_id: #ns_fiber::Identity,
#g_wire: #ns_fiber::dope::net::wire::Spec + #l_env,
#g_store: #ns_fiber::manifold::runtime::Storage,
#g_mode,
#( #stamp, )*
#( #futures, )*
#( #makers, )*
>
}
};
let (futures, makers) = context.exec.producers();
let proto = quote! {
<
#g_brand: #l_env,
#l_env,
#( #lives: #l_env, )*
'd: #l_env,
#( #decls, )*
#g_id: #ns_fiber::Identity,
#g_wire: #ns_fiber::dope::net::wire::Spec + #l_env,
#g_target: #ns_core::manifold::task::Target + 'd,
#( #futures, )*
#( #makers, )*
>
};
let (futures, makers) = context.exec.producers();
let use_ = quote! {
<#core<#g_brand, #l_env, #( #lives, )* 'd, #( #values, )* #g_id, #g_wire, #g_store, #g_mode, #( #futures, )* #( #makers, )*>, #g_stamp>
};
let (futures, makers) = context.exec.producers();
let multi = quote! {
<#core<
#g_brand,
#l_env,
#( #lives, )*
'd,
#( #values, )*
#g_id,
#g_wire,
#ns_fiber::manifold::runtime::Prepared<#g_target>,
#ns_core::life::mode::Disabled,
#( #futures, )*
#( #makers, )*
>, ()>
};
Self {
base_bounds: base,
generic_def: generic(true),
core_generic_def: generic(false),
protocol_generic_def: proto,
generic_use: use_,
multiplexed_generic_use: multi,
}
}
}
impl Dispatch {
pub(in crate::app::serve::handle) fn build(
paths: &Paths,
context: &handle::Context<'_, '_, '_>,
) -> Self {
Self {
methods: Methods::build(paths, context.plan.spec),
shape: Shape::build(paths, context),
}
}
}