Skip to main content

vouched_derive/
lib.rs

1//! Proc-macro implementation for `vouched`.
2//!
3//! Users normally import [`Vouched`](macro@Vouched) from the facade crate: `use vouched::Vouched;`.
4
5mod vouched;
6
7use proc_macro::TokenStream;
8
9/// Derives validated construction for tuple-struct newtypes.
10///
11/// `Vouched` supports tuple structs with exactly one field.
12/// The generated code validates incoming values and constructs the newtype only when all configured constraints pass.
13///
14/// # Generated API
15///
16/// For `struct Name(String)`, the derive generates:
17///
18/// - `impl TryFrom<String> for Name`.
19/// - a generated `NameVouchedError` enum by default.
20/// - `Display`, `core::error::Error`, and `vouched::VouchedError` for the generated error enum.
21/// - extra integer `TryFrom` implementations requested by `cast(try_from(...))`.
22///
23/// # Attribute Reference
24///
25/// Put all options in one or more `#[vouched(...)]` attributes. Each marker can be specified at most once.
26///
27/// | syntax | effect |
28/// | --- | --- |
29/// | `len(N..M)` / `len(N..=M)` / `len(N..)` / `len(..M)` / `len(..=M)` | validate string length by Unicode scalar value count |
30/// | `chars("abc", '0'..='9', '_')` | validate allowed characters |
31/// | `range(N..M)` / `range(N..=M)` / `range(N..)` / `range(..M)` / `range(..=M)` | validate numeric bounds for fixed-width integers, `f32`, and `f64` |
32/// | `cast(try_from(i64, u32))` | add fallible integer source types |
33/// | `error(name = CustomError, vis = pub(crate))` | override the generated error enum name or visibility |
34///
35/// `error = Name` is not supported.
36///
37/// `cast(try_from(...))` remains integer-only. Float `range(...)` validation rejects an actual `NaN` value, and float
38/// bound expressions must not evaluate to `NaN` because Rust float comparison rules make that boundary ineffective.
39///
40/// # Error Visibility
41///
42/// The generated error enum uses the derived type's visibility by default.
43/// `error(...)` can override the name, the visibility, or both:
44///
45/// ```ignore
46/// # use vouched::Vouched;
47/// #[derive(Debug, PartialEq, Eq, Vouched)]
48/// #[vouched(error(name = DisplayNameError, vis = pub(crate)), len(1..=32))]
49/// pub(crate) struct DisplayName(String);
50/// ```
51///
52/// Rust visibility rules still apply when the generated error type appears in `TryFrom::Error`.
53///
54/// # Validation Semantics
55///
56/// Validation returns the first error encountered.
57/// When multiple constraints fail, the exact evaluation order is an implementation detail.
58/// Implementations may evaluate expensive whole-string validations later to reduce validation cost.
59#[proc_macro_derive(Vouched, attributes(vouched))]
60pub fn derive_vouched(input: TokenStream) -> TokenStream {
61    let input = syn::parse_macro_input!(input as syn::DeriveInput);
62    vouched::derive_vouched(&input)
63}