Skip to main content

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}