sark-gen 0.11.0

Sark proc-macro generators
Documentation
use proc_macro2::{Ident, TokenStream};
use quote::quote;
use syn::{Type, TypePath};

use super::RouteKind;

pub(super) struct ArmsData {
    pub(super) parts_aliases: Vec<TokenStream>,
    pub(super) route_bounds: Vec<TokenStream>,
    pub(super) parts_vars: Vec<TokenStream>,
    pub(super) parts_header_bytes_arms: Vec<TokenStream>,
    pub(super) parts_query_name_arms: Vec<TokenStream>,
    pub(super) parts_query_slice_arms: Vec<TokenStream>,
    pub(super) parts_query_parse_arms: Vec<TokenStream>,
}

pub(super) fn build_arms(
    routes: &[TypePath],
    kinds: &[RouteKind],
    state_ty: &Type,
    params_alias: &[Ident],
    headers_alias: &[Ident],
    key_vars: &[Ident],
    parts_ident: &Ident,
) -> ArmsData {
    let parts_aliases: Vec<TokenStream> = routes
        .iter()
        .zip(params_alias.iter())
        .zip(headers_alias.iter())
        .map(|((route, p), h)| {
            quote! {
                type #p = <#route as sark::service::RouteSpec>::RawParams;
                type #h = <#route as sark::service::RouteSpec>::RawHeaders;
            }
        })
        .collect();

    let route_bounds: Vec<TokenStream> = routes
        .iter()
        .zip(kinds.iter())
        .map(|(route, kind)| {
            let (kind, invoke) = match kind {
                RouteKind::Sync => (
                    quote!(sark::service::manifold::Sync),
                    quote!(sark::service::manifold::Route<#state_ty>),
                ),
                RouteKind::Fiber => (
                    quote!(sark::service::manifold::NativeFiber),
                    quote!(sark::service::manifold::TaskRoute<'d, #state_ty>),
                ),
                RouteKind::Stream => (
                    quote!(sark::service::manifold::NativeStream),
                    quote! {
                        sark::service::manifold::Route<#state_ty>
                            + sark::service::manifold::TaskRoute<'d, #state_ty>
                    },
                ),
            };
            quote! {
                #route: sark::service::RouteSpec<Kind = #kind>
                    + #invoke,
            }
        })
        .collect();

    let parts_vars: Vec<TokenStream> = routes
        .iter()
        .zip(params_alias.iter())
        .zip(headers_alias.iter())
        .zip(key_vars.iter())
        .map(|(((_route, p), h), key)| {
            quote! {
                #key {
                    params: #p,
                    headers: #h,
                },
            }
        })
        .collect();

    let parts_header_bytes_arms: Vec<TokenStream> = routes
        .iter()
        .zip(key_vars.iter())
        .map(|(route, key)| {
            quote! {
                #parts_ident::#key { params: _, headers } => {
                    if let Some(slot) = <<#route as sark::service::RouteSpec>::Request as sark::service::RouteRequestImpl>::header_slot_bytes(name) {
                        <<#route as sark::service::RouteSpec>::Request as sark::service::RouteRequestImpl>::set_header_raw(headers, slot, value)?;
                    }
                }
            }
        })
        .collect();

    let parts_query_name_arms: Vec<TokenStream> = routes
        .iter()
        .zip(key_vars.iter())
        .map(|(route, key)| {
            quote! {
                #parts_ident::#key { params: _, headers } => <<#route as sark::service::RouteSpec>::Request as sark::service::RouteRequestImpl>::set_query_name_raw(headers, name, value)?,
            }
        })
        .collect();

    let parts_query_slice_arms: Vec<TokenStream> = routes
        .iter()
        .zip(key_vars.iter())
        .map(|(route, key)| {
            quote! {
                #parts_ident::#key { params: _, headers } => <<#route as sark::service::RouteSpec>::Request as sark::service::RouteRequestImpl>::set_query_slice_raw(headers, name, input, range)?,
            }
        })
        .collect();

    let parts_query_parse_arms: Vec<TokenStream> = routes
        .iter()
        .zip(key_vars.iter())
        .map(|(route, key)| {
            quote! {
                #parts_ident::#key { params: _, headers } => <<#route as sark::service::RouteSpec>::Request as sark::service::RouteRequestImpl>::parse_query_raw(headers, input, range)?,
            }
        })
        .collect();

    ArmsData {
        parts_aliases,
        route_bounds,
        parts_vars,
        parts_header_bytes_arms,
        parts_query_name_arms,
        parts_query_slice_arms,
        parts_query_parse_arms,
    }
}