Rule

Struct Rule 

Source
pub struct Rule<T: ?Sized> { /* private fields */ }
Expand description

A composable validation rule for values of type T.

Rules are the building blocks of domainstack’s validation system. They can be composed using and(), or(), not(), and when() to create complex validation logic.

Rules now receive a RuleContext providing field information for better error messages.

§Examples

§Basic Rule

use domainstack::prelude::*;

let rule = rules::min_len(3);
let ctx = RuleContext::root("username");
assert!(rule.apply_with_context("alice", &ctx).is_empty());
assert!(!rule.apply_with_context("ab", &ctx).is_empty());

§Composing Rules

use domainstack::prelude::*;

// Username must be 3-20 characters and alphanumeric
let rule = rules::min_len(3)
    .and(rules::max_len(20))
    .and(rules::alphanumeric());

let ctx = RuleContext::root("username");
assert!(rule.apply_with_context("alice123", &ctx).is_empty());
assert!(!rule.apply_with_context("ab", &ctx).is_empty());  // too short

§Custom Rules with Context

use domainstack::{Rule, RuleContext, ValidationError, Path};

fn lowercase_only() -> Rule<str> {
    Rule::new(|value: &str, ctx: &RuleContext| {
        if value.chars().all(|c| c.is_lowercase() || !c.is_alphabetic()) {
            ValidationError::default()
        } else {
            ValidationError::single(
                ctx.full_path(),
                "not_lowercase",
                "Must contain only lowercase letters"
            )
        }
    })
}

let rule = lowercase_only();
let ctx = RuleContext::root("username");
assert!(rule.apply_with_context("hello", &ctx).is_empty());
assert!(!rule.apply_with_context("Hello", &ctx).is_empty());

Implementations§

Source§

impl<T: ?Sized + 'static> Rule<T>

Source

pub fn new<F>(f: F) -> Self
where F: Fn(&T, &RuleContext) -> ValidationError + Send + Sync + 'static,

Creates a new validation rule.

Rules receive both the value to validate and a RuleContext providing field information for better error messages.

Source

pub fn apply(&self, value: &T) -> ValidationError

Applies the rule with an anonymous context.

For better error messages, use apply_with_context() instead.

Source

pub fn apply_with_context( &self, value: &T, ctx: &RuleContext, ) -> ValidationError

Applies the rule with a specific context for field-aware error messages.

Source

pub fn code(self, code: &'static str) -> Rule<T>

Customize the error code for validation failures.

§Examples
use domainstack::prelude::*;

let rule = rules::min_len(5).code("email_too_short");
let err = rule.apply("hi");
assert_eq!(err.violations[0].code, "email_too_short");
Source

pub fn message( self, msg: impl Into<String> + Clone + Send + Sync + 'static, ) -> Rule<T>

Customize the error message for validation failures.

§Examples
use domainstack::prelude::*;

let rule = rules::min_len(5).message("Email too short");
let err = rule.apply("hi");
assert_eq!(err.violations[0].message, "Email too short");
Source

pub fn meta( self, key: &'static str, value: impl Into<String> + Clone + Send + Sync + 'static, ) -> Rule<T>

Add metadata to validation errors.

§Examples
use domainstack::prelude::*;

let rule = rules::min_len(5)
    .meta("hint", "Use at least 5 characters");

let err = rule.apply("hi");
assert_eq!(err.violations[0].meta.get("hint"), Some("Use at least 5 characters"));
Source

pub fn and(self, other: Rule<T>) -> Rule<T>

Source

pub fn or(self, other: Rule<T>) -> Rule<T>

Source

pub fn not(self, code: &'static str, message: &'static str) -> Rule<T>

Source

pub fn map_path( self, prefix: impl Into<Path> + Clone + Send + Sync + 'static, ) -> Rule<T>

Source

pub fn when<F>(self, predicate: F) -> Rule<T>
where F: Fn() -> bool + Send + Sync + 'static,

Trait Implementations§

Source§

impl<T: ?Sized> Clone for Rule<T>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T: ?Sized> Debug for Rule<T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<T> Freeze for Rule<T>
where T: ?Sized,

§

impl<T> !RefUnwindSafe for Rule<T>

§

impl<T> Send for Rule<T>
where T: ?Sized,

§

impl<T> Sync for Rule<T>
where T: ?Sized,

§

impl<T> Unpin for Rule<T>
where T: ?Sized,

§

impl<T> !UnwindSafe for Rule<T>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.