reinhardt-core

Crates.ioreinhardt-core
lib.rsreinhardt-core
version0.1.0-alpha.1
created_at2026-01-23 02:56:03.619871+00
updated_at2026-01-23 02:56:03.619871+00
descriptionCore components for Reinhardt framework
homepage
repositoryhttps://github.com/kent8192/reinhardt-rs
max_upload_size
id2063261
size1,462,345
kento (kent8192)

documentation

README

reinhardt-core

Core components for Reinhardt framework

Overview

reinhardt-core provides the fundamental building blocks for the Reinhardt framework. It contains essential types, traits, error handling, signals, security primitives, validators, and backend abstractions that other crates depend on.

This crate serves as the foundation for the entire Reinhardt ecosystem, providing core abstractions and utilities used throughout the framework.

Features

Implemented ✓

This crate provides the following modules:

  • Types: Core type definitions

    • Handler trait for request processing
    • Middleware trait for request/response pipelines
    • MiddlewareChain for composable middleware
    • Type aliases and async trait support
  • Exception: Exception handling and error types

    • Django-style exception hierarchy
    • HTTP status code exceptions (401, 403, 404, 500, etc.)
    • Validation error handling
    • Database exception types
    • Custom error types (ImproperlyConfigured, ParseError, etc.)
  • Signals: Event-driven hooks for lifecycle events

    • Type-safe signal system for decoupled communication
    • Lifecycle signals for models, migrations, requests
    • Async and sync signal dispatch patterns
    • Signal composition and middleware
    • Performance monitoring
  • Macros: Procedural macros for code generation

    • #[handler] macro for endpoint definitions
    • #[middleware] macro for middleware implementations
    • #[injectable] macro for dependency injection
  • Security: Security primitives and utilities

    • Password hashing and verification
    • CSRF protection
    • XSS prevention
    • Secure random generation
    • Constant-time comparisons
  • Validators: Data validation utilities

    • Email validation
    • URL validation
    • Length validators
    • Range validators
    • Custom validator support
  • Serializers: Serialization and deserialization

    • Django REST Framework-inspired field types
    • Validation system with field and object validators
    • Recursive serialization with circular reference detection
    • Arena allocation for high-performance serialization
  • Messages: Flash messages and user notifications

    • Message levels (Debug, Info, Success, Warning, Error)
    • Storage backends (Memory, Session, Cookie, Fallback)
    • Middleware integration
  • Pagination: Pagination strategies

    • PageNumberPagination for page-based pagination
    • LimitOffsetPagination for SQL-style pagination
    • CursorPagination for efficient large dataset pagination
    • Database cursor pagination with O(k) performance
  • Parsers: Request body parsing

    • JSON, XML, YAML, Form, MultiPart parsers
    • File upload handling
    • Content-type negotiation
  • Negotiation: Content negotiation

    • Media type selection based on Accept headers
    • Language negotiation (Accept-Language)
    • Encoding negotiation (Accept-Encoding)
  • Dependency Injection: FastAPI-style DI system

    • Automatic dependency resolution
    • Parameter injection
    • Cache control

Installation

Add this to your Cargo.toml:

[dependencies]
reinhardt-core = "0.1.0-alpha.1"

Optional Features

Enable specific modules based on your needs:

[dependencies]
reinhardt-core = { version = "0.1.0-alpha.1", features = ["signals", "macros", "security"] }

Available features:

  • types (default): Core type definitions
  • exception (default): Error handling
  • signals (default): Event system
  • macros (default): Procedural macros
  • security (default): Security primitives
  • validators (default): Data validation
  • serializers (default): Serialization utilities
  • http: HTTP types and traits (requires types)
  • messages: Flash messaging system
  • di: Dependency injection with parameter extraction
  • negotiation: Content negotiation
  • parsers: Request body parsers
  • pagination: Pagination strategies

Usage

Handler and Middleware

// Import from modules
use reinhardt::core::types::{Handler, Middleware};
use reinhardt::http::{Request, Response};
use reinhardt::core::exception::Result;
use async_trait::async_trait;

// Define a handler
async fn my_handler(req: Request) -> Result<Response> {
    Response::ok().with_body("Hello, world!")
}

// Define middleware
struct LoggingMiddleware;

#[async_trait]
impl Middleware for LoggingMiddleware {
    async fn process_request(&self, req: Request) -> Result<Request> {
        println!("Processing request: {:?}", req.uri());
        Ok(req)
    }
}

Error Handling

use reinhardt::core::exception::{Error, Result};

fn validate_user(authenticated: bool, authorized: bool) -> Result<()> {
    if !authenticated {
        return Err(Error::Authentication("Invalid credentials".into()));
    }
    if !authorized {
        return Err(Error::Authorization("Permission denied".into()));
    }
    Ok(())
}

Signals

use reinhardt::core::signals::{Signal, SignalDispatcher};
use std::sync::Arc;

#[derive(Debug, Clone)]
struct User {
    name: String,
}

// Connect a receiver to the signal
async fn setup_signal() {
    let signal = Signal::<User>::new();

    signal.connect(|user: Arc<User>| async move {
        println!("User created: {}", user.name);
        Ok(())
    });

    // Send signal
    let user = User { name: "Alice".to_string() };
    signal.send(user).await.unwrap();
}

Module Organization

`reinhardt-core` is organized into the following modules:

Core Modules

  • `types` - Core type definitions (Handler, Middleware, type aliases)
  • `exception` - Error handling and exception types
  • `signals` - Event-driven hooks for lifecycle events
  • `macros` - Procedural macros for code generation

Utility Modules

  • `security` - Security primitives (hashing, CSRF, XSS)
  • `validators` - Data validation utilities
  • `serializers` - Serialization and deserialization
  • `messages` - Flash messages and user notifications
  • `pagination` - Pagination strategies
  • `parsers` - Request body parsing
  • `negotiation` - Content negotiation

Using Modules

use reinhardt::core::types::{Handler, Middleware};
use reinhardt::core::exception::Result;
use reinhardt::core::signals::Signal;

Note: `reinhardt-di` and `reinhardt-http` are separate workspace-level crates that provide dependency injection and HTTP utilities. They can be used independently or alongside `reinhardt-core`.

exception

Features

Implemented ✓

  • Django-style exception hierarchy - Comprehensive Error enum with categorized error types

  • HTTP status code exceptions - Http, Authentication (401), Authorization (403), NotFound (404), Internal (500), etc.

  • Validation error handling - Validation variant with field-level error support

  • Database exception types - Database variant for DB-related errors

  • Custom error types - ImproperlyConfigured, BodyAlreadyConsumed, ParseError, etc.

  • Error serialization - All errors implement Display and can be converted to HTTP responses via status_code() method

  • thiserror integration - Full integration with thiserror for derived error impl

  • anyhow integration - Other variant wraps any anyhow::Error for compatibility

  • Error categorization - ErrorKind enum for categorical classification

  • Standard conversions - From implementations for serde_json::Error, std::io::Error, http::Error, String, &str, validator::ValidationErrors

  • Parameter validation context - ParamErrorContext struct with detailed parameter extraction error information

  • Parameter type enumeration - ParamType enum (Json, Query, Path, Form, Header, Cookie, Body)

  • Additional error types - TemplateNotFound (404), MissingContentType (400), MethodNotAllowed (405), Conflict (409)

  • Pagination error types - InvalidPage, InvalidCursor, InvalidLimit variants for pagination validation

  • URL parameter errors - MissingParameter variant for URL reverse operations

  • Helper utilities - extract_field_from_serde_error and extract_field_from_urlencoded_error functions

  • Error kind classification - kind() method returns ErrorKind for categorical error analysis

messages

Features

Implemented ✓

Core Message System

  • Message Levels: 5 predefined levels (Debug, Info, Success, Warning, Error) with numeric priority values (10, 20, 25, 30, 40)
  • Custom Levels: Support for user-defined message levels with custom numeric values
  • Message Tags: Level-based tags and extra custom tags for styling and filtering
  • Message Creation: Convenience methods for creating messages (Message::debug(), Message::info(), etc.)
  • Message Configuration: MessageConfig for customizing level tags globally

Storage Backends

  • MemoryStorage: In-memory storage using thread-safe Arc<Mutex<VecDeque>> for testing and temporary messages
  • SessionStorage: Session-based persistent storage with JSON serialization
    • Customizable session key (default: "_messages")
    • Session availability validation
    • Serialization/deserialization for session integration
  • CookieStorage: Cookie-based storage with automatic size management
    • Configurable cookie name and size limit (default: 4KB)
    • Automatic message truncation using binary search when exceeding size limits
    • Drops oldest messages first when size limit is exceeded
  • FallbackStorage: Intelligent fallback between Cookie and Session storage
    • Attempts cookie storage first for better performance
    • Automatically falls back to session storage when cookie size is exceeded
    • Tracks which storage backend(s) were used
    • Supports flushing messages from both backends

Utilities

  • Binary Search Algorithms: Efficient size-limited message management
    • bisect_keep_left(): Keep maximum messages from the beginning within size limit
    • bisect_keep_right(): Keep maximum messages from the end within size limit
  • SafeData: HTML-safe string wrapper for rendering pre-sanitized HTML content
    • Prevents double-escaping of HTML in messages
    • Serializable with serde support

Storage Trait

  • MessageStorage Trait: Unified interface for all storage backends
    • add(): Add a message to storage
    • get_all(): Retrieve and clear all messages
    • peek(): View messages without clearing
    • clear(): Remove all messages

Middleware Integration

  • MessagesMiddleware: Request/response middleware for automatic message handling
    • Automatic message retrieval and storage during request lifecycle
    • Thread-safe message container with Arc-based sharing
  • MessagesContainer: Container for messages during request processing
    • add(): Add messages during request
    • get_messages(): Retrieve all messages
    • add_from_storage(): Load messages from storage backend

Context Processor

  • MessagesContext: Context for template rendering integration
    • get_messages(): Retrieve messages for rendering
    • add_message(): Add messages to context
  • get_messages_context(): Helper function to create messages context
  • add_message(): Convenience function to add messages to context

Message Filtering

  • filter_by_level(): Filter messages by exact level match

  • filter_by_min_level(): Filter messages above or equal to minimum level

  • filter_by_max_level(): Filter messages below or equal to maximum level

  • filter_by_level_range(): Filter messages within a level range (inclusive)

  • filter_by_tag(): Filter messages by tag match

security

Features

Implemented ✓

CSRF Protection

  • Token Generation & Validation:
    • get_secret_bytes(): Generate cryptographically secure 32-byte secret for HMAC
    • generate_token_hmac(): Generate HMAC-SHA256 token from secret and message
    • get_token_hmac(): High-level token generation using secret and session ID
    • verify_token_hmac(): Constant-time HMAC verification
    • check_token_hmac(): Token validation with detailed error reporting
  • Token Rotation Support:
    • generate_token_with_timestamp(): Generate token with timestamp for rotation tracking
    • verify_token_with_timestamp(): Verify timestamped token and extract timestamp
    • get_token_timestamp(): Get current Unix timestamp for rotation logic
    • should_rotate_token(): Determine if token rotation is due based on interval
    • Configurable via CsrfConfig::with_token_rotation(interval)
  • Origin/Referer Checking: check_origin() and check_referer() validate request sources
  • Domain Validation: is_same_domain() for cross-domain request protection
  • Configurable Cookie Settings: Full control over SameSite, Secure, HttpOnly, Domain, Path, and Max-Age
  • Production-Ready Config: CsrfConfig::production() with security hardening (includes token rotation)
  • Middleware: CsrfMiddleware with customizable configuration
  • Error Handling: Detailed rejection reasons for debugging (bad origin, bad referer, missing token, etc.)
  • Constants: CSRF_TOKEN_LENGTH, CSRF_SECRET_LENGTH, CSRF_SESSION_KEY, rejection reason constants

XSS Prevention

  • HTML Escaping:
    • escape_html(): Escapes dangerous characters (<, >, &, ", ')
    • escape_html_attr(): Escapes HTML attributes including newlines and control characters
  • JavaScript Context Escaping: escape_javascript() for safe embedding in JavaScript strings
  • URL Encoding: escape_url() for URL encoding to prevent injection
  • HTML Sanitization: sanitize_html() for basic HTML input sanitization
  • XSS Pattern Detection: detect_xss_patterns() detects dangerous patterns (script tags, event handlers, etc.)
  • URL Validation: is_safe_url() validates URLs and allows only safe protocols (http, https, mailto, ftp)
  • Safe Output: Prevents script injection in user-generated content across multiple contexts

Security Headers

  • Content Security Policy (CSP): Configurable CSP with granular control over:
    • default-src, script-src, style-src, img-src
    • connect-src, font-src, object-src, media-src, frame-src
    • CSP Reporting: report-uri and report-to for violation reporting via with_report_uri() and with_report_to()
    • Nonce Generation: generate_nonce() for inline script/style nonces
    • Auto Nonce: Automatic nonce injection with with_auto_nonce()
  • Security Headers Middleware: SecurityHeadersMiddleware with comprehensive defaults
  • Configurable Headers:
    • X-Content-Type-Options: nosniff
    • X-Frame-Options: DENY (clickjacking protection)
    • X-XSS-Protection: 1; mode=block
    • Strict-Transport-Security (HSTS)
    • Referrer-Policy: strict-origin-when-cross-origin
    • Permissions-Policy (optional)
    • Cross-Origin Policies:
      • Cross-Origin-Embedder-Policy: require-corp
      • Cross-Origin-Opener-Policy: same-origin
      • Cross-Origin-Resource-Policy: same-origin
  • Environment Presets:
    • SecurityHeadersConfig::production(): Strict security headers for production
    • SecurityHeadersConfig::development(): Relaxed headers for development (no HSTS, no CSP)

HSTS (HTTP Strict Transport Security)

  • HSTS Configuration: HstsConfig with builder pattern
  • Configurable Options:
    • max_age: Configurable duration in seconds
    • includeSubDomains: Optional subdomain protection
    • preload: HSTS preload list support
  • Header Generation: build_header() for automatic header value construction
  • Secure Defaults: 1-year max-age default configuration

Security Utilities

The utils module provides internal security utilities:

  • Secure Token Generation: generate_token() creates cryptographically random tokens (internal use)
  • SHA-256 Hashing: hash_sha256() for secure string hashing (internal use)
  • Random Number Generation: Built on rand crate for security

Note: These utilities are available through the utils module but are not re-exported at the crate root. They are primarily used internally by CSRF and other security features.

Error Handling

  • Comprehensive Error Types: SecurityError enum with specific variants
  • CSRF Validation Errors: Detailed error messages for debugging
  • XSS Detection: Error type for potential XSS attempts
  • Configuration Errors: Validation for security configurations

IP Filtering

  • Whitelist/Blacklist Modes: IpFilterMode enum for configurable filtering strategy

    • Whitelist: Only allow IPs in the allowed list
    • Blacklist: Deny IPs in the blocked list (default)
  • IP Range Support: Add individual IPs or CIDR ranges (e.g., 192.168.1.0/24)

  • IPv4 and IPv6: Full support for both IP versions

  • Flexible Configuration: IpFilterConfig with builder-style methods

    • new(mode): Create with specified mode
    • whitelist(): Create with whitelist mode
    • blacklist(): Create with blacklist mode
    • add_allowed_ip(ip_or_range): Add IP addresses or ranges to whitelist
    • add_blocked_ip(ip_or_range): Add IP addresses or ranges to blacklist
    • is_allowed(&ip): Check if an IP address is permitted
  • Blacklist Override: Blocked IPs take precedence over allowed IPs

  • Middleware: IpFilterMiddleware for request filtering based on IP address

types

Features

Implemented ✓

  • Handler trait - Core abstraction for async request processing

    • async fn handle(&self, request: Request) -> Result<Response>
    • Blanket implementation for Arc<T> to enable Arc<dyn Handler>
  • Middleware trait - Request/response pipeline processing

    • async fn process(&self, request: Request, next: Arc<dyn Handler>) -> Result<Response>
    • fn should_continue(&self, request: &Request) -> bool - Conditional execution
  • MiddlewareChain - Composable middleware system with automatic chaining

    • Builder pattern: with_middleware() for method chaining
    • Mutable API: add_middleware() for imperative style
    • Performance optimizations:
      • O(k) complexity where k ≤ n (skips unnecessary middleware)
      • Short-circuiting with Response::with_stop_chain(true)
  • Type aliases - Re-export of Request and Response from reinhardt-http

  • Async trait support - Full async/await support via async_trait

  • Zero-cost abstractions - All traits compile to efficient code with no runtime overhead

validators

Features

Implemented ✓

Core Validation Framework

  • Validator Trait: Generic validation interface Validator<T> for implementing custom validators
  • OrmValidator Trait: Extension trait for ORM validators with custom error messages
  • SettingsValidator Trait: Extension trait for validating configuration settings
  • ValidationError: Comprehensive error types with descriptive messages
  • ValidationResult: Type-safe result type for validation operations
  • Prelude Module: Convenient re-exports of all validators and error types

String Validators

  • MinLengthValidator: Validates minimum string length
    • Works with both String and &str types
    • Provides detailed error messages with actual and expected lengths
    • Unicode-aware length checking
  • MaxLengthValidator: Validates maximum string length
    • Works with both String and &str types
    • Provides detailed error messages with actual and expected lengths
    • Unicode-aware length checking
  • RegexValidator: Pattern matching with regular expressions
    • Custom error message support via with_message()
    • Full regex syntax support
    • Works with both String and &str types

Numeric Validators

  • MinValueValidator: Validates minimum numeric values
    • Generic over any PartialOrd + Display + Clone type
    • Supports integers (i8, i16, i32, i64, isize, u8, u16, u32, u64, usize)
    • Supports floating-point numbers (f32, f64)
    • Provides detailed error messages with actual and expected values
  • MaxValueValidator: Validates maximum numeric values
    • Generic over any PartialOrd + Display + Clone type
    • Supports all integer and floating-point types
    • Provides detailed error messages with actual and expected values
  • RangeValidator: Validates values within a range (inclusive)
    • Generic over any PartialOrd + Display + Clone type
    • Supports all numeric types
    • Reports whether value is too small or too large

Email Validator

  • EmailValidator: RFC 5322 compliant email validation
    • Case-insensitive validation
    • Local part validation (max 64 characters)
      • Allows alphanumeric characters, dots, underscores, percent signs, plus and minus signs
      • Prevents consecutive dots
      • Prevents leading/trailing dots
    • Domain part validation (max 255 characters)
      • Supports subdomains
      • Each label max 63 characters
      • TLD minimum 2 characters
      • Prevents leading/trailing hyphens in domain labels
    • Total length limit (max 320 characters)
    • Works with both String and &str types

URL Validator

  • UrlValidator: HTTP/HTTPS URL validation
    • Scheme validation (http, https)
    • Port number support (1-5 digits)
    • Path validation
    • Query string support
    • Fragment identifier support
    • Subdomain support
    • Hyphen support in domain names (not at start/end of labels)
    • Works with both String and &str types

Error Types

  • InvalidEmail(String): Invalid email address format
  • InvalidUrl(String): Invalid URL format
  • TooSmall { value: String, min: String }: Value below minimum
  • TooLarge { value: String, max: String }: Value above maximum
  • TooShort { length: usize, min: usize }: String shorter than minimum
  • TooLong { length: usize, max: usize }: String longer than maximum
  • PatternMismatch(String): Regex pattern did not match
  • Custom(String): Custom validation error

Additional Validators (Implemented ✓)

  • SlugValidator: Validate URL-safe slugs
  • UUIDValidator: Validate UUID formats (v1-v5)
  • IPAddressValidator: Validate IPv4/IPv6 addresses
  • DateValidator: Validate date formats
  • TimeValidator: Validate time formats
  • DateTimeValidator: Validate datetime formats
  • JSONValidator: Validate JSON structure
  • ColorValidator: Validate color codes (hex, rgb, rgba, etc.)
  • PhoneNumberValidator: Validate phone numbers (E.164 format)
  • CreditCardValidator: Validate credit card numbers (Luhn algorithm)
  • IBANValidator: Validate international bank account numbers
  • CustomRegexValidator: User-defined regex pattern validation

File Validators (Implemented ✓)

  • FileTypeValidator: Comprehensive file type validation
    • Extension validation: FileTypeValidator::with_extensions()
      • Case-insensitive extension matching
      • Multiple extensions support
      • Whitelist-based filtering
    • MIME type validation: FileTypeValidator::with_mime_types()
      • Validates file MIME types
      • Multiple MIME types support
    • Preset validators:
      • FileTypeValidator::images_only(): Supports JPEG, PNG, GIF, WebP, SVG, BMP, TIFF, ICO, AVIF
      • FileTypeValidator::documents_only(): Supports PDF, DOC, DOCX, XLS, XLSX, PPT, PPTX, TXT

Example:

use reinhardt_validators::{FileTypeValidator, Validator};

// Extension validation
let validator = FileTypeValidator::with_extensions(vec![
    "jpg".to_string(),
    "png".to_string(),
]);
assert!(validator.validate_filename("photo.jpg").is_ok());
assert!(validator.validate_filename("photo.JPG").is_ok()); // Case-insensitive
assert!(validator.validate_filename("document.pdf").is_err());

// Preset validator
let image_validator = FileTypeValidator::images_only();
assert!(image_validator.validate_filename("photo.png").is_ok());

Async Validators (Implemented ✓)

  • ExistsValidator: Asynchronous foreign key existence validation

    • Custom async check function support
    • Database table reference validation
    • Validates that referenced records exist in the database
  • UniqueValidator: Asynchronous uniqueness constraint validation

    • Prevent duplicate entries
    • Instance exclusion during updates with exclude_id parameter
    • Custom async uniqueness check function

Example:

use reinhardt_validators::{ExistsValidator, UniqueValidator, Validator};

// Foreign key existence check
let exists_validator = ExistsValidator::new(
    "user_id",
    "users",
    Box::new(|value| Box::pin(async move {
        // Database check logic here
        // Return true if record exists, false otherwise
        true
    }))
);

// Async validation
let result = exists_validator.validate_async("123").await;
assert!(result.is_ok());

// Uniqueness check with instance exclusion
let unique_validator = UniqueValidator::new(
    "email",
    Box::new(|value, exclude_id| Box::pin(async move {
        // Check if email is unique, excluding the given ID
        true
    }))
);

// Validate new record (no exclusion)
let result = unique_validator.validate_async("new@example.com").await;
assert!(result.is_ok());

Database Identifier Validators (Implemented ✓)

  • TableName: Compile-time and runtime validated table names

    • SQL reserved word checking via is_sql_reserved_word()
    • Snake_case format validation
    • Length validation (max 63 characters for PostgreSQL compatibility)
    • Compile-time validation with new_const() constant function
    • Runtime validation with new() method
  • FieldName: SQL-safe field/column name validation

    • Same validation rules as TableName
    • Prevents SQL injection through identifier validation
  • ConstraintName: SQL-safe constraint name validation

    • Validates constraint identifiers for CREATE/ALTER statements

Example:

use reinhardt_validators::{TableName, FieldName};

// Runtime validation
let table = TableName::new("users")?;
assert!(TableName::new("select").is_err()); // SQL reserved word
assert!(TableName::new("User-Table").is_err()); // Not snake_case

// Compile-time validation
const VALID_TABLE: TableName = TableName::new_const("users");
const VALID_FIELD: FieldName = FieldName::new_const("email_address");

Custom Error Messages (Partial Implementation ✓)

Currently supported by:

  • RegexValidator: .with_message("Custom message")
  • CustomRegexValidator: Built-in custom message support

Planned Extension: Extend to all validators (see lib.rs for planned features)

Example:

use reinhardt_validators::{RegexValidator, Validator};

let validator = RegexValidator::new(r"^\d{3}-\d{4}$")
    .unwrap()
    .with_message("Phone number must be in format XXX-XXXX");

match validator.validate("invalid") {
    Err(e) => assert_eq!(e.to_string(), "Phone number must be in format XXX-XXXX"),
    Ok(_) => panic!("Expected validation error"),
}

File Size Validator (Implemented ✓)

  • FileSizeValidator: Validate file sizes with minimum, maximum, or range constraints
    • Min size validation: FileSizeValidator::min(bytes)
    • Max size validation: FileSizeValidator::max(bytes)
    • Range validation: FileSizeValidator::range(min_bytes, max_bytes)
    • Helper methods for unit conversion:
      • FileSizeValidator::from_kb(kb): Convert KB to bytes
      • FileSizeValidator::from_mb(mb): Convert MB to bytes
      • FileSizeValidator::from_gb(gb): Convert GB to bytes
    • Integrates well with FileTypeValidator for comprehensive file validation
    • Generic over u64 type for file size values

Example:

use reinhardt_validators::{FileSizeValidator, Validator};

// Validate minimum file size
let min_validator = FileSizeValidator::min(FileSizeValidator::from_kb(100)); // 100 KB minimum
assert!(min_validator.validate(&(150 * 1024)).is_ok()); // 150 KB passes
assert!(min_validator.validate(&(50 * 1024)).is_err()); // 50 KB fails

// Validate maximum file size
let max_validator = FileSizeValidator::max(FileSizeValidator::from_mb(5)); // 5 MB maximum
assert!(max_validator.validate(&(3 * 1024 * 1024)).is_ok()); // 3 MB passes
assert!(max_validator.validate(&(10 * 1024 * 1024)).is_err()); // 10 MB fails

// Validate file size range
let range_validator = FileSizeValidator::range(
    FileSizeValidator::from_kb(100),  // 100 KB minimum
    FileSizeValidator::from_mb(10),   // 10 MB maximum
);
assert!(range_validator.validate(&(5 * 1024 * 1024)).is_ok()); // 5 MB passes

Validator Composition (Implemented ✓)

  • AndValidator: Combine multiple validators with AND logic

    • All contained validators must pass for validation to succeed
    • Short-circuits on first failure for better performance
    • Supports nested composition (AND within OR, etc.)
    • Generic over any type T that validators can validate
  • OrValidator: Combine multiple validators with OR logic

    • At least one contained validator must pass
    • Optional error collection from all validators when all fail
    • Supports nested composition (OR within AND, etc.)
    • Generic over any type T that validators can validate

Example:

use reinhardt_validators::{AndValidator, OrValidator, MinLengthValidator, MaxLengthValidator, EmailValidator, UrlValidator, Validator};

// AND composition - Username must be 3-20 characters
let username_validator = AndValidator::new(vec![
    Box::new(MinLengthValidator::new(3)),
    Box::new(MaxLengthValidator::new(20)),
]);
assert!(username_validator.validate("john").is_ok());
assert!(username_validator.validate("jo").is_err()); // Too short
assert!(username_validator.validate("verylongusernamethatexceedslimit").is_err()); // Too long

// OR composition - Contact must be either email OR URL
let contact_validator = OrValidator::new(vec![
    Box::new(EmailValidator::new()),
    Box::new(UrlValidator::new()),
]);
assert!(contact_validator.validate("user@example.com").is_ok()); // Valid email
assert!(contact_validator.validate("http://example.com").is_ok()); // Valid URL
assert!(contact_validator.validate("invalid").is_err()); // Neither email nor URL

// Nested composition - Complex validation logic
let complex_validator = OrValidator::new(vec![
    Box::new(AndValidator::new(vec![
        Box::new(MinLengthValidator::new(3)),
        Box::new(MaxLengthValidator::new(10)),
    ])),
    Box::new(MinLengthValidator::new(20)), // Or very long string
]);
assert!(complex_validator.validate("hello").is_ok()); // Passes first (3-10 chars)
assert!(complex_validator.validate("verylongusernameexceeds20chars").is_ok()); // Passes second (20+ chars)
assert!(complex_validator.validate("hi").is_err()); // Fails both

// Error collection with OrValidator
let collecting_validator = OrValidator::new(vec![
    Box::new(MinLengthValidator::new(10)),
    Box::new(MinLengthValidator::new(20)),
])
.with_error_collection(true);

match collecting_validator.validate("short") {
    Err(e) => println!("All validators failed: {}", e), // Shows all error messages
    Ok(_) => unreachable!(),
}

Postal Code Validator (Implemented ✓)

  • PostalCodeValidator: Country-specific postal code format validation
    • Supported countries: US, UK, JP, CA, DE (5 countries)
    • Country restriction: with_countries(vec![Country::US, Country::JP])
    • Single country: for_country(Country::US)
    • Country detection: validate_with_country() returns detected country
    • Case-insensitive validation: Automatically handles uppercase/lowercase
    • Whitespace trimming: Handles leading/trailing spaces
    • Priority-based pattern matching: Resolves ambiguous formats correctly

Supported Formats:

  • US: ZIP (12345) and ZIP+4 (12345-6789) formats
  • UK: Complex alphanumeric format (SW1A 1AA, M1 1AE, etc.)
  • JP: 7-digit with hyphen (123-4567)
  • CA: Alphanumeric format (K1A 0B1, M5W 1E6)
  • DE: 5-digit format (10115, 80331)

Example:

use reinhardt_validators::{PostalCodeValidator, Country, Validator};

// Validate with country restriction
let validator = PostalCodeValidator::with_countries(vec![
    Country::US,
    Country::JP,
]);
assert!(validator.validate("12345").is_ok()); // US ZIP
assert!(validator.validate("12345-6789").is_ok()); // US ZIP+4
assert!(validator.validate("123-4567").is_ok()); // Japan
assert!(validator.validate("SW1A 1AA").is_err()); // UK not allowed

// Single country validation
let us_validator = PostalCodeValidator::for_country(Country::US);
assert!(us_validator.validate("90210").is_ok());
assert!(us_validator.validate("123-4567").is_err()); // Not US format

// Country detection
let detector = PostalCodeValidator::new(); // Accepts all countries
let country = detector.validate_with_country("12345-6789").unwrap();
assert_eq!(country, Country::US);

let country = detector.validate_with_country("SW1A 1AA").unwrap();
assert_eq!(country, Country::UK);

// Case-insensitive and whitespace handling
assert!(detector.validate("  sw1a 1aa  ").is_ok()); // UK lowercase with spaces
assert!(detector.validate("k1a 0b1").is_ok()); // Canada lowercase

Image Dimension Validator (Implemented ✓)

  • ImageDimensionValidator: Validate image width/height dimensions
    • Min/max width constraints: min_width(), max_width()
    • Min/max height constraints: min_height(), max_height()
    • Aspect ratio validation: aspect_ratio() with configurable tolerance
    • File validation: validate_file() for file paths
    • Bytes validation: validate_bytes() for in-memory images
    • Supported formats: JPEG, PNG, GIF, WebP, BMP, TIFF, ICO, and more via image crate

Example:

use reinhardt::validators::ImageDimensionValidator;

// Basic dimension constraints
let validator = ImageDimensionValidator::new()
	.with_min_width(100)
	.with_max_width(1920)
	.with_min_height(100)
	.with_max_height(1080);

// With aspect ratio validation (16:9 with 1% tolerance)
let hd_validator = ImageDimensionValidator::new()
	.with_min_width(1280)
	.with_min_height(720)
	.with_aspect_ratio(16, 9)
	.with_aspect_ratio_tolerance(0.01);

// Validate from file path
let result = validator.validate_file("image.jpg");

// Validate from bytes (in a function context)
# fn example() -> Result<(), Box<dyn std::error::Error>> {
let image_bytes: Vec<u8> = std::fs::read("image.png")?;
let result = validator.validate_bytes(&image_bytes);
# Ok(())
# }

Conditional Validation (Implemented ✓)

  • ConditionalValidator: Apply validators based on runtime conditions
    • when condition: Apply validator only when condition is true
    • unless condition: Apply validator only when condition is false
    • Closure-based conditions: Use custom logic for condition evaluation
    • Chainable API: Combine with other validators

Example:

use reinhardt::validators::{ConditionalValidator, MinLengthValidator, Validator};

// Apply validation only when condition is true
// Condition receives &T parameter, validator is boxed
let validator = ConditionalValidator::when(
	|value: &str| value.starts_with("admin_"), // Fn(&T) -> bool
	Box::new(MinLengthValidator::new(10)),      // Box<dyn Validator<T>>
);

// Validate admin username (must be at least 10 chars)
assert!(validator.validate("admin_john").is_ok());
assert!(validator.validate("admin_j").is_err()); // Too short

// Regular username (no validation applied)
assert!(validator.validate("john").is_ok());

// Apply validation unless condition is true
let validator = ConditionalValidator::unless(
	|value: &str| value.is_empty(),
	Box::new(MinLengthValidator::new(5)),
);

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.

Commit count: 2845

cargo fmt