axum_starter_macro/lib.rs
1#![forbid(unsafe_code)]
2mod derive_config;
3mod derive_provider;
4mod from_state_collector;
5mod prepare_macro;
6
7use prepare_macro::inputs::attr_name::PrepareName;
8use syn::{parse_macro_input, DeriveInput, ItemFn};
9
10#[macro_use]
11mod utils;
12
13/// implement [`Provider<T>`](https://docs.rs/axum-starter/latest/axum_starter/trait.Provider.html) for each field of the struct
14///
15/// ## Example
16///
17/// ```rust
18/// use std::net::SocketAddr;
19/// use axum_starter;
20/// use axum_starter_macro::Provider;
21/// #[derive(Debug, Provider)]
22/// #[provider(r#ref)]
23/// struct Configure {
24/// // this will impl `Provider<&String>`
25/// // because of the `ref` on container and its own `transparent`
26/// #[provider(transparent)]
27/// foo: String,
28/// // this will not impl provide
29/// #[provider(skip)]
30/// bar: SocketAddr,
31/// // this will impl `Provide<FooBar>`
32/// // where `FooBar` is `struct FooBar((i32,i32));`
33/// // `ignore_global` will ignore the `ref` on the container
34/// #[provider(ignore_global)]
35/// foo_bar: (i32, i32),
36/// }
37///
38/// fn foo_fetch(foo: &String, FooBar(foo_bar): FooBar){
39/// // do somethings
40/// }
41///
42/// ```
43///
44/// - using `r#ref` to impl `Provider` provide reference instant of Owned (with clone) .Can be using on container to apply on all fields
45/// - using `transparent` to impl `Provider` the original type instant of generate a wrapper type. Can be using on container to apply on all fields
46/// - using `ignore_global` to ignore the `ref` and `transparent` setting on container
47/// - using `skip` to not impl `Provider` for this field
48/// - using `map_to(ty , by)` to adding extra provide for [Type](syn::Type) by the giving function, if the type need lifetime mark,
49/// adding `lifetime = "'a"`, then using`'a` in your type for example `& 'a str`
50#[proc_macro_derive(Provider, attributes(provider))]
51pub fn derive_config_provider(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
52 let derive_input = parse_macro_input!(input as DeriveInput);
53 darling_err!(derive_provider::provider_derive(derive_input))
54}
55
56/// help macro from impl `ServeAddress`, `LoggerInitialization`, `ConfigureServerEffect`
57///
58/// ## Example
59///
60/// ```rust
61/// use std::net::SocketAddr;
62/// use axum_starter_macro::{Configure, Provider};
63/// #[derive(Debug, Provider, Configure)]
64/// #[conf(
65/// address(provide),
66/// logger(error = "log::SetLoggerError", func = "Self::init_log"),
67/// server
68///)]
69/// struct Configure {
70/// #[provider(transparent)]
71/// bar: SocketAddr,
72/// }
73///
74/// impl Configure {
75/// fn init_log(&self) -> Result<(), log::SetLoggerError>{
76/// // initial the logger
77/// Ok(())
78/// }
79/// }
80///
81/// ```
82/// ## Usage
83/// ### address
84/// - using `address(provide)` direct using the config provide to get address,
85/// - using `address(provide(ty = "..."))` similar to previous one, but using the provide type
86/// **Note**: the provided type need impl [Into<std::net::SocketAddr>](Into<std::net::SocketAddr>)
87///
88/// - using `address(func(path = "...", ty = "...", associate))` using provide function get the socket address
89/// - `path` a path to a function or a closure expr, its signature is `Fn(config: &Self) -> $ty`
90/// - `ty` (optional) default is [std::net::SocketAddr]
91/// - `associate`(optional) set whether the function to call need argument `Self`,
92/// if set `associate` the signature of function to call is `Fn()->$ty`
93///
94/// ### logger
95/// - using `logger(error="...", func="...",associate)` to impl `LoggerInitialization`,
96/// the `func` and `associate` is similar to the `path` and `associate` of `address(func(path="...", associate))` but the return type became `Result<(),$error>`
97/// - `error` the error that might occur during initialization the log system
98///
99/// ### server
100/// - using `server="..."` to impl `ConfigureServerEffect` with internally call the `provide` func or
101/// just using `server` or ignore it to having an empty implement. The function look like `fn (&self, Builder<AddrIncome>) -> Builder<AddrIncome>`
102///
103#[proc_macro_derive(Configure, attributes(conf))]
104pub fn derive_config_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
105 let derive_input = parse_macro_input!(input as DeriveInput);
106 darling_err!(derive_config::provider_derive(derive_input))
107}
108
109/// impl `FromStateCollector` for special type
110///
111/// this implement is easy but boring, thus need macro to simplify it
112#[proc_macro_derive(FromStateCollector)]
113pub fn derive_from_state_collector(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
114 let derive_input = parse_macro_input!(input as DeriveInput);
115 darling_err!(from_state_collector::from_state_collector_macro(
116 derive_input
117 ))
118}
119
120/// make a function can apply as a `Prepare`
121///
122/// ## Example
123///
124/// [macro@prepare] support either sync or async function.
125/// It can generate type which implement the [`Prepare`](https://docs.rs/axum-starter/latest/axum_starter/trait.Prepare.html) trait
126///
127/// the function arguments require can be provided by the `Configure`.
128///
129/// the return type , usually can be one of :
130/// - `()`
131/// - `Result<impl @, CustomError>`
132/// - `impl @`
133/// > the `@` can be `PrepareRouteEffect`,
134/// `PrepareStateEffect` or
135/// `PrepareMiddlewareEffect`
136///
137/// **Note** if the return type is `Result<impl @, Error>`, need add `?` following the
138/// generate Name
139///
140/// ```rust
141/// use axum_starter_macro::prepare;
142/// #[prepare(Foo?)]
143/// fn prepare_foo() -> Result<(), std::io::Error>{
144/// // do something that might return Err()
145/// todo!()
146/// }
147/// ```
148///
149/// the generate type name is present by the macro argument, for example, if you want a Prepare task
150/// named `SeaConn`, just using like `#[prepare(SeaConn)]`
151///
152/// if your function argument contain reference or other types witch need a lifetime, just add the lifetime to the macro arguments list,
153/// like this.
154///
155/// ```rust
156/// use axum_starter_macro::prepare;
157/// #[prepare(Foo 'f)]
158/// fn prepare_foo(foo_name: &'f String){
159/// // do somethings
160/// }
161/// ```
162/// Or,you can not provide any lifetime symbol, the macro will automatic find all needing lifetime places and giving a default symbol
163///
164/// ```rust
165/// use axum_starter_macro::prepare;
166/// #[prepare(Foo)]
167/// fn prepare_foo(foo_name: &String){
168/// // do somethings
169/// }
170/// ```
171///
172/// Or only give lifetime symbol in macro input. The macro will auto replace `'_` into `'arg` if necessary
173///
174/// ```rust
175/// use axum_starter_macro::prepare;
176/// #[prepare(Foo 'arg)]
177/// fn prepare_foo(foo_name: &String){
178/// // do somethings
179/// }
180/// ```
181///
182/// sometimes store `Future` on stack may cause ***Stack Overflow***, you can using `box` before generate name
183/// make the return type became `Pin<Box<dyn Future>>`
184///
185/// ```rust
186/// use axum_starter_macro::prepare;
187/// #[prepare(box Foo)]
188/// async fn prepare_foo(){
189/// // do something may take place large space
190/// }
191/// ```
192///
193/// if you want a `Prepare` return `Ready`, or in other word, a sync `Prepare`,you can use `sync` before the Ident.
194/// note that `box` and `sync` cannot use in the same time
195///
196/// ```rust
197/// use axum_starter_macro::prepare;
198/// #[prepare(sync Foo)]
199/// fn prepare_foo(){
200/// // do something not using `await`
201/// }
202/// ```
203///
204/// By default, the macro will not keep the origin function exist, if you want use that original function, using `origin`,
205/// the `origin` is after the `box` or `sync`, but before the Ident
206///
207///```rust
208/// use axum_starter_macro::prepare;
209/// #[prepare(sync origin Foo)]
210/// fn prepare_foo(){
211/// // do something not using `await`
212/// }
213/// ```
214///```
215#[proc_macro_attribute]
216pub fn prepare(
217 attrs: proc_macro::TokenStream,
218 input: proc_macro::TokenStream,
219) -> proc_macro::TokenStream {
220 let prepare_name = parse_macro_input!(attrs as PrepareName);
221 let fn_item = parse_macro_input!(input as ItemFn);
222
223 prepare_macro::prepare_macro(&prepare_name, fn_item)
224 .unwrap_or_else(|error| error.to_compile_error().into())
225}