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 or `&str` `TryFrom` implementations requested by `impls(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/// | `impls(try_from(i64, u32))` | add fallible integer source types |
33/// | `impls(try_from(&str))` | add borrowed string input for `len(...)` and/or `chars(...)` newtypes with `String`, `Box<str>`, `Rc<str>`, or `Arc<str>` inner types |
34/// | `error(name = CustomError, vis = pub(crate))` | override the generated error enum name or visibility |
35///
36/// `error = Name` is not supported.
37///
38/// Integer `impls(try_from(...))` sources cannot be mixed with `&str`. Custom string wrapper inners and borrowed inners
39/// that store the input lifetime are not supported for `impls(try_from(&str))`.
40/// Float `range(...)` validation rejects an actual `NaN` value, and float bound expressions must not evaluate to
41/// `NaN` because Rust float comparison rules make that boundary ineffective.
42///
43/// # Error Visibility
44///
45/// The generated error enum uses the derived type's visibility by default.
46/// `error(...)` can override the name, the visibility, or both:
47///
48/// ```ignore
49/// # use vouched::Vouched;
50/// #[derive(Debug, PartialEq, Eq, Vouched)]
51/// #[vouched(error(name = DisplayNameError, vis = pub(crate)), len(1..=32))]
52/// pub(crate) struct DisplayName(String);
53/// ```
54///
55/// Rust visibility rules still apply when the generated error type appears in `TryFrom::Error`.
56///
57/// # Validation Semantics
58///
59/// Validation returns the first error encountered.
60/// When multiple constraints fail, the exact evaluation order is an implementation detail.
61/// Implementations may evaluate expensive whole-string validations later to reduce validation cost.
62#[proc_macro_derive(Vouched, attributes(vouched))]
63pub fn derive_vouched(input: TokenStream) -> TokenStream {
64 let input = syn::parse_macro_input!(input as syn::DeriveInput);
65 vouched::derive_vouched(&input)
66}