1mod app;
6mod handler;
7mod json;
8mod macros;
9mod request;
10mod response;
11mod runtime;
12mod types;
13
14use macros::fibers;
15use runtime::paths;
16
17#[proc_macro_derive(Message, attributes(prost))]
19pub fn message(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
20 let input = syn::parse_macro_input!(input as syn::DeriveInput);
21 use macros::message::Message;
22 match Message::new(input).and_then(Message::expand) {
23 Ok(tokens) => tokens.into(),
24 Err(error) => error.into_compile_error().into(),
25 }
26}
27
28#[proc_macro]
30pub fn header_name(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
31 let value = syn::parse_macro_input!(input as syn::LitStr);
32 emit(
33 |paths| Ok(response::name(paths, &value)),
34 runtime::Requirement::Http,
35 )
36}
37
38fn emit(
39 build: impl FnOnce(&paths::Paths) -> syn::Result<proc_macro2::TokenStream>,
40 need: runtime::Requirement,
41) -> proc_macro::TokenStream {
42 let result = paths::Paths::resolve(need)
43 .and_then(|paths| build(&paths).and_then(|tokens| paths.finish(tokens)));
44 match result {
45 Ok(tokens) => tokens.into(),
46 Err(error) => error.into_compile_error().into(),
47 }
48}
49
50#[proc_macro]
52pub fn fiber(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
53 let input = syn::parse_macro_input!(input as fibers::Body);
54 emit(|paths| Ok(input.expand(paths)), runtime::Requirement::Fiber)
55}
56
57#[proc_macro]
62pub fn define_route(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
63 use self::app::App;
64 let input = syn::parse_macro_input!(input as app::inputs::Input);
65 emit(
66 |paths| {
67 paths.h1.require()?;
68 App::new(paths, input).map(|app| app.expand(paths, runtime::H1::Available(None)))
69 },
70 runtime::Requirement::Fiber,
71 )
72}
73
74#[proc_macro]
75pub fn define_cleartext_route(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
76 let input = syn::parse_macro_input!(input as app::inputs::Input);
77 emit(
78 |paths| {
79 paths.h1.require()?;
80 let h2 = runtime::require("sark-h2", "define_cleartext_route")?;
81 app::App::new(paths, input)
82 .map(|app| app.expand(paths, runtime::H1::Available(Some(h2))))
83 },
84 runtime::Requirement::Fiber,
85 )
86}
87
88#[proc_macro]
91pub fn define_task_route(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
92 use self::app::App;
93 let input = syn::parse_macro_input!(input as app::inputs::Input);
94 emit(
95 |paths| App::new(paths, input).map(|app| app.expand(paths, runtime::H1::Missing)),
96 runtime::Requirement::Fiber,
97 )
98}
99
100#[proc_macro]
104pub fn define_router(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
105 use self::app::App;
106 let input = syn::parse_macro_input!(input as app::inputs::Input);
107 emit(
108 |paths| App::new_router(paths, input).map(|app| app.router(paths, paths.h1())),
109 runtime::Requirement::Portable,
110 )
111}
112
113#[proc_macro_attribute]
117pub fn handler(
118 attr: proc_macro::TokenStream,
119 item: proc_macro::TokenStream,
120) -> proc_macro::TokenStream {
121 use self::handler::{Entry, Handler, args};
122 let args = syn::parse_macro_input!(attr as args::Args);
123 let fun = syn::parse_macro_input!(item as syn::ItemFn);
124 let need = if fun.sig.asyncness.is_some() {
125 runtime::Requirement::Fiber
126 } else {
127 runtime::Requirement::Portable
128 };
129 emit(
130 |paths| {
131 Handler::new(args, fun, Entry::Handler)
132 .and_then(|handler| handler.expand(paths, paths.h1()))
133 },
134 need,
135 )
136}
137
138#[proc_macro_attribute]
142pub fn duplex(
143 attr: proc_macro::TokenStream,
144 item: proc_macro::TokenStream,
145) -> proc_macro::TokenStream {
146 use syn::{Error, Item};
147
148 use self::handler::{Entry, Handler};
149
150 let args = syn::parse_macro_input!(attr as handler::args::Args);
151 let item = syn::parse_macro_input!(item as Item);
152 emit(
153 |paths| match item {
154 Item::Fn(fun) => Handler::new(args, fun, Entry::Duplex)
155 .and_then(|handler| handler.expand(paths, paths.h1())),
156 other => Err(Error::new_spanned(
157 other,
158 "#[sark_gen::duplex] supports only fn",
159 )),
160 },
161 runtime::Requirement::Fiber,
162 )
163}
164
165#[proc_macro_attribute]
169pub fn json(
170 attr: proc_macro::TokenStream,
171 item: proc_macro::TokenStream,
172) -> proc_macro::TokenStream {
173 let st = syn::parse_macro_input!(item as syn::ItemStruct);
174 let mode = syn::parse_macro_input!(attr as json::mode::Mode);
175 emit(
176 |paths| json::build(paths, mode, st),
177 runtime::Requirement::Json,
178 )
179}
180
181#[proc_macro_attribute]
185pub fn request(
186 attr: proc_macro::TokenStream,
187 item: proc_macro::TokenStream,
188) -> proc_macro::TokenStream {
189 let mode = syn::parse_macro_input!(attr as request::mode::Mode);
190 let st = syn::parse_macro_input!(item as syn::ItemStruct);
191 emit(
192 |paths| {
193 if st
194 .attrs
195 .iter()
196 .any(|attr| attr.path().is_ident("json_body"))
197 {
198 paths.json.require()?;
199 }
200 request::build(paths, mode, st)
201 },
202 runtime::Requirement::Portable,
203 )
204}
205
206#[proc_macro_attribute]
207pub fn response(
208 attr: proc_macro::TokenStream,
209 item: proc_macro::TokenStream,
210) -> proc_macro::TokenStream {
211 use self::response::code;
212 let mode = syn::parse_macro_input!(attr as response::Mode);
213 let st = syn::parse_macro_input!(item as syn::ItemStruct);
214 emit(
215 |paths| {
216 if matches!(mode, response::Mode::Json) {
217 paths.json.require()?;
218 }
219 code::build(paths, mode, st)
220 },
221 runtime::Requirement::Portable,
222 )
223}