Skip to main content

koruma_core/
lib.rs

1#![doc = include_str!("../README.md")]
2
3/// Trait for types that can validate a value of type `T`.
4///
5/// Implementors should return `true` if validation passes,
6/// or `false` if validation fails. The error details are
7/// captured in the validation struct itself.
8pub trait Validate<T> {
9    fn validate(&self, value: &T) -> bool;
10}
11
12/// Trait for validation error structs that have no errors.
13///
14/// This is auto-implemented by the derive macro for generated
15/// error structs, allowing easy checking if any validation failed.
16pub trait ValidationError {
17    /// Returns `true` if there are no validation errors.
18    fn is_empty(&self) -> bool;
19
20    /// Returns `true` if there are any validation errors.
21    fn has_errors(&self) -> bool {
22        !self.is_empty()
23    }
24}
25
26/// Trait for validator builders that can receive the value being validated.
27///
28/// This is auto-implemented by `#[koruma::validator]` to delegate to the
29/// field marked with `#[koruma(value)]`.
30pub trait BuilderWithValue<T> {
31    fn with_value(self, value: T) -> Self;
32}
33
34/// Trait for structs that derive `Koruma` and have a `validate()` method.
35///
36/// This trait provides an associated type for the validation error struct,
37/// which is used by nested validation to properly type the error fields.
38///
39/// This is auto-implemented by the `#[derive(Koruma)]` macro.
40pub trait ValidateExt {
41    /// The validation error type for this struct.
42    type Error: ValidationError;
43
44    /// Validates the struct and returns the error struct if validation fails.
45    fn validate(&self) -> Result<(), Self::Error>;
46}
47
48/// Marker trait for newtype structs (single-field wrappers) that derive `Koruma`.
49///
50/// This trait is auto-implemented by `#[derive(Koruma)]` when `#[koruma(newtype)]`
51/// is used at the struct level. It signals that this type is a newtype wrapper
52/// and its error type supports transparent `Deref` access.
53///
54/// When using a newtype as a field in another struct, use `#[koruma(newtype)]`
55/// on the field (instead of `#[koruma(nested)]`) to get transparent error access.
56pub trait NewtypeValidation: ValidateExt {}
57
58/// Showcase module for validator discovery and registration.
59///
60/// When the `internal-showcase` feature is enabled, validators decorated with
61/// `#[showcase(...)]` attributes are automatically registered for
62/// programmatic discovery by showcase consumers (for example, UIs, examples, or tooling).
63/// discovery for showcase purposes.
64#[cfg(feature = "internal-showcase")]
65pub mod showcase {
66    /// Trait for validators that can be presented by showcase consumers.
67    ///
68    /// This trait provides a type-erased interface for validators,
69    /// allowing consumers to work with any validator regardless of its
70    /// generic type parameters.
71    ///
72    /// Methods are always present but may return placeholder values
73    /// when the corresponding feature is not enabled.
74    pub trait DynValidator: Send + Sync {
75        /// Check if the validation passed.
76        fn is_valid(&self) -> bool;
77
78        /// Get the display string (via `to_string()` when `fmt` feature is enabled).
79        /// Returns "(fmt feature required)" if fmt is not enabled.
80        fn display_string(&self) -> String;
81
82        /// Get the fluent i18n string (via `to_fluent_string()` when `fluent` feature is enabled).
83        /// Returns "(fluent feature required)" if fluent is not enabled.
84        fn fluent_string(&self) -> String;
85    }
86
87    /// The type of input expected by the validator.
88    #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
89    pub enum InputType {
90        /// Any text input (default)
91        #[default]
92        Text,
93        /// Numeric input only (integers)
94        Numeric,
95    }
96
97    /// Information about a validator for showcase purposes.
98    ///
99    /// This struct is registered via `inventory` when a validator uses
100    /// `#[showcase(...)]` attributes.
101    pub struct ValidatorShowcase {
102        /// Human-readable name of the validator
103        pub name: &'static str,
104        /// Description of what the validator checks
105        pub description: &'static str,
106        /// The type of input expected by the validator
107        pub input_type: InputType,
108        /// The module/category this validator belongs to (e.g., "string", "format", "numeric", "collection", "general")
109        pub module: &'static str,
110        /// Factory function that creates a validator from string input.
111        /// Returns Ok(validator) on success, or Err(error) if input cannot be parsed.
112        pub create_validator: fn(&str) -> ::anyhow::Result<Box<dyn DynValidator>>,
113    }
114
115    inventory::collect!(ValidatorShowcase);
116
117    /// Get all registered showcase validators.
118    pub fn validators() -> Vec<&'static ValidatorShowcase> {
119        inventory::iter::<ValidatorShowcase>().collect()
120    }
121}