Skip to main content

arcature_macros/
lib.rs

1//! Proc-macro crate for Arcature.
2//!
3//! Provides the attribute/derive macros that power the Arcature developer
4//! experience:
5//! - `#[model(table = "users")]` — a SeaORM entity model with the query facade.
6//! - `#[request]` — a validated request struct (with `#[validate(...)]` rules).
7//! - `#[controller]` — an Axum controller with route metadata.
8//! - `#[derive(Job)]` — a typed background job with a `JobModel` const.
9//! - `#[derive(Event)]` — a typed in-process event for the `Dispatcher`.
10//! - `#[listener(Event)]` — an event listener with dispatch metadata.
11//!
12//! Each macro lives in its own file (one file, one macro). This `lib.rs` is
13//! only the dispatch surface: it declares each macro's `#[proc_macro_*]`
14//! entry point and forwards to its implementation module. All expansions
15//! reference Arcature APIs via absolute `::arcature::` paths that resolve in
16//! the downstream app crate. This crate must NOT depend on `arcature` (would
17//! create a cycle); it depends only on `syn`, `quote`, and `proc-macro2`.
18
19mod application;
20mod command;
21mod component;
22mod controller;
23mod diagnostic;
24mod event;
25mod field_shape;
26mod job;
27mod job_handler;
28mod listener;
29mod middleware;
30mod model;
31mod module;
32mod page;
33mod page_macro;
34mod policy;
35mod provider;
36mod redirect;
37mod request;
38mod request_cache;
39mod resource;
40mod route_model;
41mod routes;
42mod schema;
43mod service;
44mod signature;
45mod test_attr;
46mod util;
47
48use proc_macro::TokenStream;
49
50use crate::diagnostic::MacroResult;
51
52/// Converts a macro implementation's [`MacroResult`] into the token stream
53/// the compiler consumes: the expansion on success, a `compile_error!`
54/// invocation carrying the `ARC-M<NNN>` code on failure. No Arcature macro
55/// panics on an ordinary syntax mistake.
56fn finish(result: MacroResult) -> TokenStream {
57    match result {
58        Ok(tokens) => tokens.into(),
59        Err(error) => error.to_compile_error().into(),
60    }
61}
62
63/// `#[model(table = "users")]` — see `model.rs`.
64#[proc_macro_attribute]
65pub fn model(attr: TokenStream, item: TokenStream) -> TokenStream {
66    model::model(attr, item)
67}
68
69/// `#[request]` — see `request.rs`.
70#[proc_macro_attribute]
71pub fn request(attr: TokenStream, item: TokenStream) -> TokenStream {
72    finish(request::request(attr.into(), item.into()))
73}
74
75/// `#[controller]` — see `controller.rs`.
76#[proc_macro_attribute]
77pub fn controller(attr: TokenStream, item: TokenStream) -> TokenStream {
78    finish(controller::controller(attr.into(), item.into()))
79}
80
81/// `#[derive(Job)]` — see `job.rs`.
82#[proc_macro_derive(Job, attributes(job))]
83pub fn derive_job(input: TokenStream) -> TokenStream {
84    job::derive_job(input)
85}
86
87/// `#[derive(Event)]` — see `event.rs`.
88#[proc_macro_derive(Event)]
89pub fn derive_event(input: TokenStream) -> TokenStream {
90    event::derive_event(input)
91}
92
93/// `#[listener(Event)]` — see `listener.rs`.
94#[proc_macro_attribute]
95pub fn listener(attr: TokenStream, item: TokenStream) -> TokenStream {
96    listener::listener(attr, item)
97}
98
99/// `#[derive(DxComponent)]` — see `component.rs`.
100#[proc_macro_derive(DxComponent, attributes(component))]
101pub fn derive_dx_component(input: TokenStream) -> TokenStream {
102    finish(component::derive(input.into()))
103}
104
105/// `#[service]` — see `service.rs`.
106#[proc_macro_attribute]
107pub fn service(attr: TokenStream, item: TokenStream) -> TokenStream {
108    finish(service::service(attr.into(), item.into()))
109}
110
111/// `#[provider]` — see `provider.rs`.
112#[proc_macro_attribute]
113pub fn provider(attr: TokenStream, item: TokenStream) -> TokenStream {
114    finish(provider::provider(attr.into(), item.into()))
115}
116
117/// `#[policy(Model)]` — see `policy.rs`.
118#[proc_macro_attribute]
119pub fn policy(attr: TokenStream, item: TokenStream) -> TokenStream {
120    finish(policy::policy(attr.into(), item.into()))
121}
122
123/// `#[middleware]` — see `middleware.rs`.
124#[proc_macro_attribute]
125pub fn middleware(attr: TokenStream, item: TokenStream) -> TokenStream {
126    finish(middleware::middleware(attr.into(), item.into()))
127}
128
129/// `#[command("name")]` — see `command.rs`.
130#[proc_macro_attribute]
131pub fn command(attr: TokenStream, item: TokenStream) -> TokenStream {
132    finish(command::command(attr.into(), item.into()))
133}
134
135/// `#[job_handler]` — see `job_handler.rs`.
136#[proc_macro_attribute]
137pub fn job_handler(attr: TokenStream, item: TokenStream) -> TokenStream {
138    finish(job_handler::job_handler(attr.into(), item.into()))
139}
140
141/// `#[route_model(entity = ..., key_type = ...)]` — see `route_model.rs`.
142#[proc_macro_attribute]
143pub fn route_model(attr: TokenStream, item: TokenStream) -> TokenStream {
144    finish(route_model::route_model(attr.into(), item.into()))
145}
146
147/// `#[request_cache(name = "...", key = "...")]` — see `request_cache.rs`.
148#[proc_macro_attribute]
149pub fn request_cache(attr: TokenStream, item: TokenStream) -> TokenStream {
150    finish(self::request_cache::request_cache(attr.into(), item.into()))
151}
152
153/// `#[resource]` — see `resource.rs`.
154#[proc_macro_attribute]
155pub fn resource(attr: TokenStream, item: TokenStream) -> TokenStream {
156    finish(resource::resource(attr.into(), item.into()))
157}
158
159/// `#[arcature::test(app = ...)]` — see `test_attr.rs`.
160#[proc_macro_attribute]
161pub fn test(attr: TokenStream, item: TokenStream) -> TokenStream {
162    finish(test_attr::test_attr(attr.into(), item.into()))
163}
164
165/// `#[page("users/show")]` — see `page.rs`.
166#[proc_macro_attribute]
167pub fn page(attr: TokenStream, item: TokenStream) -> TokenStream {
168    finish(page::page(attr.into(), item.into()))
169}
170
171/// `page_macro!(ShowUserPage { .. })` — see `page_macro.rs`. Named
172/// `page_macro` rather than `page` because attribute and function-like
173/// macros share one namespace, and `#[page("name")]` already owns `page`.
174#[proc_macro]
175pub fn page_macro(input: TokenStream) -> TokenStream {
176    finish(self::page_macro::page_macro(input.into()))
177}
178
179/// `application! { pub App { .. } }` — see `application/mod.rs`.
180#[proc_macro]
181pub fn application(input: TokenStream) -> TokenStream {
182    finish(self::application::application(input.into()))
183}
184
185/// `module! { pub Accounts { .. } }` — see `module/mod.rs`.
186#[proc_macro]
187pub fn module(input: TokenStream) -> TokenStream {
188    finish(self::module::module(input.into()))
189}
190
191/// `routes! { pub app { .. } }` — see `routes/mod.rs`.
192#[proc_macro]
193pub fn routes(input: TokenStream) -> TokenStream {
194    finish(self::routes::routes(input.into()))
195}
196
197/// `redirect!(route::...)` — see `redirect.rs`.
198#[proc_macro]
199pub fn redirect(input: TokenStream) -> TokenStream {
200    finish(redirect::redirect(input.into()))
201}