rust_webx_macros/lib.rs
1// rust-webx-macros — Procedural macros for the Rust WebApi framework.
2// - #[endpoint(HttpMethod, "/path")] — full form
3// - #[get("/path")], #[post("/path")], #[put("/path")], #[delete("/path")] — shortcuts
4// - #[handler] — auto-registration via inventory
5// - #[FromBody], #[FromRoute], #[FromQuery] — parameter binding
6// - #[claims] — authentication claims injection
7// - #[authorize] — declarative authorization
8
9mod claims;
10mod endpoint;
11mod handler;
12mod param;
13
14use proc_macro::TokenStream;
15
16// ---------------------------------------------------------------------------
17// Route macros: full form + shortcuts
18// ---------------------------------------------------------------------------
19
20/// Full form: marks an IRequest impl with HTTP method and route path.
21///
22/// ```ignore
23/// #[endpoint(HttpGet, "/users/{id}")]
24/// impl IRequest<UserModel> for GetUserRequest {}
25/// ```
26#[proc_macro_attribute]
27pub fn endpoint(attr: TokenStream, item: TokenStream) -> TokenStream {
28 endpoint::endpoint_impl(attr, item)
29}
30
31/// Shortcut: registers an IRequest impl at GET /path.
32///
33/// ```ignore
34/// #[get("/users/{id}")]
35/// impl IRequest<UserModel> for GetUserRequest {}
36/// ```
37#[proc_macro_attribute]
38pub fn get(attr: TokenStream, item: TokenStream) -> TokenStream {
39 endpoint::shortcut_get(attr, item)
40}
41
42/// Shortcut: registers an IRequest impl at POST /path.
43///
44/// ```ignore
45/// #[post("/users")]
46/// impl IRequest<UserModel> for CreateUserRequest {}
47/// ```
48#[proc_macro_attribute]
49pub fn post(attr: TokenStream, item: TokenStream) -> TokenStream {
50 endpoint::shortcut_post(attr, item)
51}
52
53/// Shortcut: registers an IRequest impl at PUT /path.
54///
55/// ```ignore
56/// #[put("/users/{id}")]
57/// impl IRequest<UserModel> for UpdateUserRequest {}
58/// ```
59#[proc_macro_attribute]
60pub fn put(attr: TokenStream, item: TokenStream) -> TokenStream {
61 endpoint::shortcut_put(attr, item)
62}
63
64/// Shortcut: registers an IRequest impl at DELETE /path.
65///
66/// ```ignore
67/// #[delete("/users/{id}")]
68/// impl IRequest<String> for DeleteUserRequest {}
69/// ```
70#[proc_macro_attribute]
71pub fn delete(attr: TokenStream, item: TokenStream) -> TokenStream {
72 endpoint::shortcut_delete(attr, item)
73}
74
75// ---------------------------------------------------------------------------
76// Handler auto-registration
77// ---------------------------------------------------------------------------
78
79/// Auto-registers an IRequestHandler implementation at compile time via inventory.
80///
81/// Place on `impl IRequestHandler<T, R> for Handler` blocks.
82/// The handler struct MUST implement `Default`.
83///
84/// ```ignore
85/// #[handler]
86/// #[async_trait]
87/// impl IRequestHandler<HelloRequest, String> for HelloHandler {
88/// async fn handle(&mut self, _req: HelloRequest) -> Result<String> { ... }
89/// }
90/// ```
91#[proc_macro_attribute]
92pub fn handler(attr: TokenStream, item: TokenStream) -> TokenStream {
93 handler::handler_impl(attr, item)
94}
95
96// ---------------------------------------------------------------------------
97// Parameter binding
98// ---------------------------------------------------------------------------
99
100/// Marks a field or parameter as deserialized from the JSON request body.
101#[proc_macro_attribute]
102pub fn from_body(_attr: TokenStream, item: TokenStream) -> TokenStream {
103 param::from_attribute_impl("Body", item)
104}
105
106/// Marks a field or parameter as extracted from the route path.
107#[proc_macro_attribute]
108pub fn from_route(_attr: TokenStream, item: TokenStream) -> TokenStream {
109 param::from_attribute_impl("Route", item)
110}
111
112/// Marks a field or parameter as extracted from the query string.
113#[proc_macro_attribute]
114pub fn from_query(_attr: TokenStream, item: TokenStream) -> TokenStream {
115 param::from_attribute_impl("Query", item)
116}
117
118// ---------------------------------------------------------------------------
119// Declaration macros
120// ---------------------------------------------------------------------------
121
122// ---------------------------------------------------------------------------
123// Claims attribute
124// ---------------------------------------------------------------------------
125
126/// Marks a request struct as carrying authentication claims.
127///
128/// Appends a `#[serde(skip)] pub claims: Option<Box<dyn IClaims>>` field to
129/// the struct and generates an inherent `set_claims` method that shadows the
130/// blanket no-op `IClaimsCarrier::set_claims`. The dispatcher injects claims
131/// into the request *before* calling `IRequestHandler::handle`.
132///
133/// Must be the outermost attribute so that `#[derive(...)]` sees the injected
134/// field:
135///
136/// ```ignore
137/// #[claims]
138/// #[derive(Default, Deserialize)]
139/// pub struct CreateCommentRequest {
140/// pub blog_id: i32,
141/// pub content: String,
142/// }
143/// ```
144#[proc_macro_attribute]
145pub fn claims(attr: TokenStream, item: TokenStream) -> TokenStream {
146 claims::claims_impl(attr, item)
147}
148
149// ---------------------------------------------------------------------------
150// Authorization attribute (declarative, handled by emit_endpoint)
151// ---------------------------------------------------------------------------
152
153/// Declares authorization requirements on a route.
154///
155/// ```ignore
156/// #[get("/api/users")]
157/// #[authorize(role = "admin")]
158/// impl IRequest<Vec<UserModel>> for ListUsersRequest {}
159///
160/// #[get("/api/auth/me")]
161/// #[authorize]
162/// impl IRequest<UserView> for AuthMeRequest {}
163/// ```
164#[proc_macro_attribute]
165pub fn authorize(_attr: TokenStream, item: TokenStream) -> TokenStream {
166 // Pass through — the attribute is read by emit_endpoint inside
167 // the route macro (get, post, etc.) via item_impl.attrs.
168 item
169}