micro_tower_codegen/lib.rs
1#![feature(proc_macro_diagnostic)]
2
3use darling::FromMeta;
4use proc_macro::TokenStream;
5use service::Service;
6use syn::{parse_macro_input, AttributeArgs};
7
8mod service;
9mod util;
10
11/// Proc macro attribute to generate service implementation from function declaration. Will
12/// generate a struct which implements `micro_tower::Service`.
13///
14/// # Usage
15///
16/// A service can be generated by putting `#[micro_tower::codegen::service]` in front of `async`
17/// functions.
18///
19/// ```rust
20/// #[micro_tower::codegen::service]
21/// async fn service_name(request: ()) -> &'static str {
22/// "Hello, World!"
23/// }
24/// ```
25///
26/// Errors can be handled using [`Result`].
27///
28/// ```rust
29/// #[micro_tower::codegen::service]
30/// async fn service_name(request: ()) -> Result<&'static str, Infallible> {
31/// Ok("Hello, World!")
32/// }
33/// ```
34///
35/// It is possible to use other services (inner service) in a service by putting an argument with
36/// the type of the service.
37///
38/// ```rust
39/// #[micro_tower::codegen::service]
40/// async fn service_other(request: (), inner: service_name) -> Result<&'static str, BoxError> {
41/// Ok(inner.call(request).await?)
42/// }
43/// ```
44///
45/// A service generated with this macro can be build using the builder pattern.
46///
47/// ```rust
48/// let service = service_name::builder().build();
49/// ```
50///
51/// or in case an inner service is used
52///
53/// ```rust
54/// let inner = service_name::builder().build();
55/// let service = service_other::builder().inner(inner).build();
56/// ```
57///
58/// the setter for inner services will always be named the same as the service argument.
59///
60/// # Attributes
61///
62/// - `crate = "<path>"`: Use to specify a crate path different from `::micro_tower`.
63/// - `name = "<name>"`: Change log name of service to `<name>`.
64/// - `extend`: Specifies that the service already exists and only `tower::Service` should be
65/// implemented.
66///
67/// # Caveats / Notes
68///
69/// - non-`async` functions are not supported
70/// - for error handling [`std::result::Result`] must be used (and no specialized like
71/// [`std::io::Result`])
72/// - the generated service is **not** clonable
73#[proc_macro_attribute]
74pub fn service(args: TokenStream, items: TokenStream) -> TokenStream {
75 let args = parse_macro_input!(args as AttributeArgs);
76 let args = match service::args::Args::from_list(&args) {
77 Ok(args) => args,
78 Err(err) => return TokenStream::from(err.write_errors()),
79 };
80 let decl = parse_macro_input!(items as syn::ItemFn);
81 Service::new(&args, decl).generate(&args).into()
82}