mod app;
mod handler;
mod json;
mod macros;
mod request;
mod response;
mod runtime;
mod types;
use macros::fibers;
use runtime::paths;
#[proc_macro_derive(Message, attributes(prost))]
pub fn message(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
use macros::message::Message;
match Message::new(input).and_then(Message::expand) {
Ok(tokens) => tokens.into(),
Err(error) => error.into_compile_error().into(),
}
}
#[proc_macro]
pub fn header_name(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let value = syn::parse_macro_input!(input as syn::LitStr);
emit(
|paths| Ok(response::name(paths, &value)),
runtime::Requirement::Http,
)
}
fn emit(
build: impl FnOnce(&paths::Paths) -> syn::Result<proc_macro2::TokenStream>,
need: runtime::Requirement,
) -> proc_macro::TokenStream {
let result = paths::Paths::resolve(need)
.and_then(|paths| build(&paths).and_then(|tokens| paths.finish(tokens)));
match result {
Ok(tokens) => tokens.into(),
Err(error) => error.into_compile_error().into(),
}
}
#[proc_macro]
pub fn fiber(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = syn::parse_macro_input!(input as fibers::Body);
emit(|paths| Ok(input.expand(paths)), runtime::Requirement::Fiber)
}
#[proc_macro]
pub fn define_route(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
use self::app::App;
let input = syn::parse_macro_input!(input as app::inputs::Input);
emit(
|paths| {
paths.h1.require()?;
App::new(paths, input).map(|app| app.expand(paths, runtime::H1::Available(None)))
},
runtime::Requirement::Fiber,
)
}
#[proc_macro]
pub fn define_cleartext_route(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = syn::parse_macro_input!(input as app::inputs::Input);
emit(
|paths| {
paths.h1.require()?;
let h2 = runtime::require("sark-h2", "define_cleartext_route")?;
app::App::new(paths, input)
.map(|app| app.expand(paths, runtime::H1::Available(Some(h2))))
},
runtime::Requirement::Fiber,
)
}
#[proc_macro]
pub fn define_task_route(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
use self::app::App;
let input = syn::parse_macro_input!(input as app::inputs::Input);
emit(
|paths| App::new(paths, input).map(|app| app.expand(paths, runtime::H1::Missing)),
runtime::Requirement::Fiber,
)
}
#[proc_macro]
pub fn define_router(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
use self::app::App;
let input = syn::parse_macro_input!(input as app::inputs::Input);
emit(
|paths| App::new_router(paths, input).map(|app| app.router(paths, paths.h1())),
runtime::Requirement::Portable,
)
}
#[proc_macro_attribute]
pub fn handler(
attr: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
use self::handler::{Entry, Handler, args};
let args = syn::parse_macro_input!(attr as args::Args);
let fun = syn::parse_macro_input!(item as syn::ItemFn);
let need = if fun.sig.asyncness.is_some() {
runtime::Requirement::Fiber
} else {
runtime::Requirement::Portable
};
emit(
|paths| {
Handler::new(args, fun, Entry::Handler)
.and_then(|handler| handler.expand(paths, paths.h1()))
},
need,
)
}
#[proc_macro_attribute]
pub fn duplex(
attr: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
use syn::{Error, Item};
use self::handler::{Entry, Handler};
let args = syn::parse_macro_input!(attr as handler::args::Args);
let item = syn::parse_macro_input!(item as Item);
emit(
|paths| match item {
Item::Fn(fun) => Handler::new(args, fun, Entry::Duplex)
.and_then(|handler| handler.expand(paths, paths.h1())),
other => Err(Error::new_spanned(
other,
"#[sark_gen::duplex] supports only fn",
)),
},
runtime::Requirement::Fiber,
)
}
#[proc_macro_attribute]
pub fn json(
attr: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let st = syn::parse_macro_input!(item as syn::ItemStruct);
let mode = syn::parse_macro_input!(attr as json::mode::Mode);
emit(
|paths| json::build(paths, mode, st),
runtime::Requirement::Json,
)
}
#[proc_macro_attribute]
pub fn request(
attr: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let mode = syn::parse_macro_input!(attr as request::mode::Mode);
let st = syn::parse_macro_input!(item as syn::ItemStruct);
emit(
|paths| {
if st
.attrs
.iter()
.any(|attr| attr.path().is_ident("json_body"))
{
paths.json.require()?;
}
request::build(paths, mode, st)
},
runtime::Requirement::Portable,
)
}
#[proc_macro_attribute]
pub fn response(
attr: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
use self::response::code;
let mode = syn::parse_macro_input!(attr as response::Mode);
let st = syn::parse_macro_input!(item as syn::ItemStruct);
emit(
|paths| {
if matches!(mode, response::Mode::Json) {
paths.json.require()?;
}
code::build(paths, mode, st)
},
runtime::Requirement::Portable,
)
}