taut_rpc_macros/lib.rs
1//! Procedural macros for `taut-rpc`.
2//!
3//! This crate is an implementation detail of `taut-rpc`; users should depend on
4//! `taut-rpc` and import the macros via its re-exports rather than depending on
5//! this crate directly.
6//!
7//! Four macros are provided through Phase 4:
8//!
9//! - `#[rpc]` — attribute macro applied to a free `async fn` (queries and
10//! mutations only in Phase 1; `#[rpc(stream)]` lands in Phase 3). Supports
11//! `#[rpc]` and `#[rpc(method = "GET")]`. See SPEC §2 (architecture) and §4
12//! (wire format).
13//! - `#[derive(Type)]` — derive macro that records a Rust type in the IR so
14//! the codegen step can emit a corresponding TypeScript definition. Works on
15//! structs (named, tuple, unit) and enums (unit, tuple, struct variants).
16//! See SPEC §3 (type mapping).
17//! - `#[derive(TautError)]` — derive macro that supplies the `TautError`
18//! trait impl (per-variant `code()` and `http_status()`) for an enum. See
19//! SPEC §3.3 (errors).
20//! - `#[derive(Validate)]` — derive macro that emits the `Validate` trait impl
21//! from per-field `#[taut(...)]` constraint attributes (`min`, `max`,
22//! `length`, `pattern`, `email`, `url`, `custom`). See SPEC §7 (validation
23//! bridge).
24//!
25//! All macros report errors via `syn::Error::into_compile_error` so failures
26//! surface as compiler diagnostics rather than panics.
27
28use proc_macro::TokenStream;
29
30mod derive_taut_error;
31mod derive_type;
32mod derive_validate;
33mod rpc_attr;
34
35/// Marks an `async fn` as a `taut-rpc` procedure.
36///
37/// Forms:
38/// - `#[rpc]` — query (default).
39/// - `#[rpc(stream)]` — server-streaming subscription.
40/// - `#[rpc(method = "GET")]` — opt-in cacheable GET query.
41#[proc_macro_attribute]
42pub fn rpc(attr: TokenStream, item: TokenStream) -> TokenStream {
43 rpc_attr::expand(attr.into(), item.into())
44 .unwrap_or_else(syn::Error::into_compile_error)
45 .into()
46}
47
48/// Derives `taut-rpc`'s type-registration trait for a struct or enum so the
49/// type appears in the IR and gets a TypeScript definition emitted.
50#[proc_macro_derive(Type, attributes(taut))]
51pub fn derive_type(input: TokenStream) -> TokenStream {
52 derive_type::expand(input.into())
53 .unwrap_or_else(syn::Error::into_compile_error)
54 .into()
55}
56
57/// Derives `taut-rpc`'s `TautError` trait for an enum, supplying `code()`
58/// (default: variant name in `snake_case`) and `http_status()` (default: 400)
59/// per variant. Both can be overridden via `#[taut(code = "...", status =
60/// 401)]`. See SPEC §3.3.
61#[proc_macro_derive(TautError, attributes(taut))]
62pub fn derive_taut_error(input: TokenStream) -> TokenStream {
63 derive_taut_error::expand(input.into())
64 .unwrap_or_else(syn::Error::into_compile_error)
65 .into()
66}
67
68/// Derives `taut-rpc`'s `Validate` trait for a struct or enum, walking each
69/// field's `#[taut(...)]` constraints (`min`, `max`, `length`, `pattern`,
70/// `email`, `url`, `custom`) and dispatching to the corresponding
71/// `validate::check::*` runtime helpers. Foreign `#[taut(...)]` keys owned by
72/// other derives (`rename`, `tag`, `optional`, `undefined`, `code`, `status`)
73/// are silently ignored. See SPEC §7.
74#[proc_macro_derive(Validate, attributes(taut))]
75pub fn derive_validate(input: TokenStream) -> TokenStream {
76 derive_validate::expand(input.into())
77 .unwrap_or_else(syn::Error::into_compile_error)
78 .into()
79}