reliakit-validate 0.1.0

Composable validation traits and error types for Rust structs and values.
Documentation

reliakit-validate

Composable validation traits and error types for Rust structs and values.

CI codecov License: MIT

reliakit-validate provides a small set of types for expressing validation rules as part of a type's contract, collecting multiple failures at once, and carrying proof of validation in the type system.

The crate has no dependencies and forbids unsafe code.

When To Use It

Use this crate when:

  • a struct or value has validity rules that go beyond what a type alone can express,
  • you want to collect all validation failures at once rather than short-circuiting on the first one,
  • you want function signatures to carry proof that a value was validated (Valid<T>),
  • you are building a form, API handler, config loader, or CLI where user-facing error messages should name the failing field.

When Not To Use It

Do not use this crate as a replacement for:

  • type-level constraints at construction time — use reliakit-primitives for those,
  • schema validation or deserialization — use a dedicated parsing library,
  • domain-specific business rules that belong in your own code.

Installation

[dependencies]
reliakit-validate = "0.1"

For no_std environments:

[dependencies]
reliakit-validate = { version = "0.1", default-features = false, features = ["alloc"] }

Examples

Single-field validation

use reliakit_validate::{Validate, Valid, ValidationError};

struct Score(u8);

impl Validate for Score {
    type Error = ValidationError;

    fn validate(&self) -> Result<(), Self::Error> {
        if self.0 > 100 {
            return Err(ValidationError::new("score must not exceed 100"));
        }
        Ok(())
    }
}

let score = Valid::new(Score(95)).unwrap();
assert_eq!(score.0, 95);

assert!(Valid::new(Score(101)).is_err());

Multi-field struct validation

use reliakit_validate::{Validate, Valid, ValidationError, Violation};

struct CreateUser {
    name: String,
    age: u8,
}

impl Validate for CreateUser {
    type Error = ValidationError;

    fn validate(&self) -> Result<(), Self::Error> {
        let mut errors = ValidationError::empty();

        if self.name.is_empty() {
            errors.push(Violation::with_field("name", "must not be empty"));
        }
        if self.age < 18 {
            errors.push(Violation::with_field("age", "must be at least 18"));
        }

        if errors.is_empty() { Ok(()) } else { Err(errors) }
    }
}

let result = CreateUser { name: String::new(), age: 15 }.validate();
let err = result.unwrap_err();
assert_eq!(err.len(), 2);

Building errors with chaining

use reliakit_validate::{ValidationError, Violation};

let error = ValidationError::empty()
    .with(Violation::with_field("email", "invalid format"))
    .with(Violation::with_field("password", "too short"));

assert_eq!(error.len(), 2);
println!("{error}"); // "email: invalid format; password: too short"

API Overview

Item Description
Validate Trait for types that can validate themselves
Valid<T> Zero-cost wrapper carrying proof of successful validation
ValidationError Error collecting one or more Violations
Violation A single failed constraint with optional field name
ValidateResult<T> Result<T, ValidationError> alias

Feature Flags

Flag Default Description
std yes Enables std::error::Error for ValidationError
alloc no Enables ValidationError without std

no_std

The crate supports no_std environments when std is disabled and alloc is available.

Safety

This crate is #![forbid(unsafe_code)].

Minimum Supported Rust Version

Rust 1.85 stable. No nightly features are used.

Status

Active. Not yet published to crates.io.

Contributing

See CONTRIBUTING.md.

License

Licensed under the MIT License.