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:
[]
= "0.1.0-alpha.1"
Optional Features
Enable specific modules based on your needs:
[]
= { = "0.1.0-alpha.1", = ["signals", "macros", "security"] }
Available features:
types(default): Core type definitionsexception(default): Error handlingsignals(default): Event systemmacros(default): Procedural macrossecurity(default): Security primitivesvalidators(default): Data validationserializers(default): Serialization utilitieshttp: HTTP types and traits (requirestypes)messages: Flash messaging systemdi: Dependency injection with parameter extractionnegotiation: Content negotiationparsers: Request body parserspagination: Pagination strategies
Usage
Handler and Middleware
// Import from modules
use ;
use ;
use Result;
use async_trait;
// Define a handler
async
// Define middleware
;
Error Handling
use ;
Signals
use ;
use Arc;
// Connect a receiver to the signal
async
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 ;
use Result;
use 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
Errorenum with categorized error types - HTTP status code exceptions -
Http,Authentication(401),Authorization(403),NotFound(404),Internal(500), etc. - Validation error handling -
Validationvariant with field-level error support - Database exception types -
Databasevariant for DB-related errors - Custom error types -
ImproperlyConfigured,BodyAlreadyConsumed,ParseError, etc. - Error serialization - All errors implement
Displayand can be converted to HTTP responses viastatus_code()method - thiserror integration - Full integration with
thiserrorfor derived error impl - anyhow integration -
Othervariant wraps anyanyhow::Errorfor compatibility - Error categorization -
ErrorKindenum for categorical classification - Standard conversions -
Fromimplementations forserde_json::Error,std::io::Error,http::Error,String,&str,validator::ValidationErrors - Parameter validation context -
ParamErrorContextstruct with detailed parameter extraction error information - Parameter type enumeration -
ParamTypeenum (Json,Query,Path,Form,Header,Cookie,Body) - Additional error types -
TemplateNotFound(404),MissingContentType(400),MethodNotAllowed(405),Conflict(409) - Pagination error types -
InvalidPage,InvalidCursor,InvalidLimitvariants for pagination validation - URL parameter errors -
MissingParametervariant for URL reverse operations - Helper utilities -
extract_field_from_serde_errorandextract_field_from_urlencoded_errorfunctions - Error kind classification -
kind()method returnsErrorKindfor 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:
MessageConfigfor 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
- Customizable session key (default:
- 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 limitbisect_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 storageget_all(): Retrieve and clear all messagespeek(): View messages without clearingclear(): 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 requestget_messages(): Retrieve all messagesadd_from_storage(): Load messages from storage backend
Context Processor
- MessagesContext: Context for template rendering integration
get_messages(): Retrieve messages for renderingadd_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 HMACgenerate_token_hmac(): Generate HMAC-SHA256 token from secret and messageget_token_hmac(): High-level token generation using secret and session IDverify_token_hmac(): Constant-time HMAC verificationcheck_token_hmac(): Token validation with detailed error reporting
- Token Rotation Support:
generate_token_with_timestamp(): Generate token with timestamp for rotation trackingverify_token_with_timestamp(): Verify timestamped token and extract timestampget_token_timestamp(): Get current Unix timestamp for rotation logicshould_rotate_token(): Determine if token rotation is due based on interval- Configurable via
CsrfConfig::with_token_rotation(interval)
- Origin/Referer Checking:
check_origin()andcheck_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:
CsrfMiddlewarewith 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-srcconnect-src,font-src,object-src,media-src,frame-src- CSP Reporting:
report-uriandreport-tofor violation reporting viawith_report_uri()andwith_report_to() - Nonce Generation:
generate_nonce()for inline script/style nonces - Auto Nonce: Automatic nonce injection with
with_auto_nonce()
- Security Headers Middleware:
SecurityHeadersMiddlewarewith comprehensive defaults - Configurable Headers:
X-Content-Type-Options: nosniffX-Frame-Options: DENY(clickjacking protection)X-XSS-Protection: 1; mode=blockStrict-Transport-Security(HSTS)Referrer-Policy: strict-origin-when-cross-originPermissions-Policy(optional)- Cross-Origin Policies:
Cross-Origin-Embedder-Policy: require-corpCross-Origin-Opener-Policy: same-originCross-Origin-Resource-Policy: same-origin
- Environment Presets:
SecurityHeadersConfig::production(): Strict security headers for productionSecurityHeadersConfig::development(): Relaxed headers for development (no HSTS, no CSP)
HSTS (HTTP Strict Transport Security)
- HSTS Configuration:
HstsConfigwith builder pattern - Configurable Options:
max_age: Configurable duration in secondsincludeSubDomains: Optional subdomain protectionpreload: 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
randcrate 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:
SecurityErrorenum 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:
IpFilterModeenum for configurable filtering strategyWhitelist: Only allow IPs in the allowed listBlacklist: 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:
IpFilterConfigwith builder-style methodsnew(mode): Create with specified modewhitelist(): Create with whitelist modeblacklist(): Create with blacklist modeadd_allowed_ip(ip_or_range): Add IP addresses or ranges to whitelistadd_blocked_ip(ip_or_range): Add IP addresses or ranges to blacklistis_allowed(&ip): Check if an IP address is permitted
- Blacklist Override: Blocked IPs take precedence over allowed IPs
- Middleware:
IpFilterMiddlewarefor 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 enableArc<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)
- Builder pattern:
- Type aliases - Re-export of
RequestandResponsefromreinhardt-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
Stringand&strtypes - Provides detailed error messages with actual and expected lengths
- Unicode-aware length checking
- Works with both
- MaxLengthValidator: Validates maximum string length
- Works with both
Stringand&strtypes - Provides detailed error messages with actual and expected lengths
- Unicode-aware length checking
- Works with both
- RegexValidator: Pattern matching with regular expressions
- Custom error message support via
with_message() - Full regex syntax support
- Works with both
Stringand&strtypes
- Custom error message support via
Numeric Validators
- MinValueValidator: Validates minimum numeric values
- Generic over any
PartialOrd + Display + Clonetype - 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
- Generic over any
- MaxValueValidator: Validates maximum numeric values
- Generic over any
PartialOrd + Display + Clonetype - Supports all integer and floating-point types
- Provides detailed error messages with actual and expected values
- Generic over any
- RangeValidator: Validates values within a range (inclusive)
- Generic over any
PartialOrd + Display + Clonetype - Supports all numeric types
- Reports whether value is too small or too large
- Generic over any
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
Stringand&strtypes
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
Stringand&strtypes
Error Types
InvalidEmail(String): Invalid email address formatInvalidUrl(String): Invalid URL formatTooSmall { value: String, min: String }: Value below minimumTooLarge { value: String, max: String }: Value above maximumTooShort { length: usize, min: usize }: String shorter than minimumTooLong { length: usize, max: usize }: String longer than maximumPatternMismatch(String): Regex pattern did not matchCustom(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, AVIFFileTypeValidator::documents_only(): Supports PDF, DOC, DOCX, XLS, XLSX, PPT, PPTX, TXT
- Extension validation:
Example:
use ;
// Extension validation
let validator = with_extensions;
assert!;
assert!; // Case-insensitive
assert!;
// Preset validator
let image_validator = images_only;
assert!;
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_idparameter - Custom async uniqueness check function
Example:
use ;
// Foreign key existence check
let exists_validator = new;
// Async validation
let result = exists_validator.validate_async.await;
assert!;
// Uniqueness check with instance exclusion
let unique_validator = new;
// Validate new record (no exclusion)
let result = unique_validator.validate_async.await;
assert!;
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
- SQL reserved word checking via
-
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 ;
// Runtime validation
let table = new?;
assert!; // SQL reserved word
assert!; // Not snake_case
// Compile-time validation
const VALID_TABLE: TableName = new_const;
const VALID_FIELD: FieldName = new_const;
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 ;
let validator = new
.unwrap
.with_message;
match validator.validate
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 bytesFileSizeValidator::from_mb(mb): Convert MB to bytesFileSizeValidator::from_gb(gb): Convert GB to bytes
- Integrates well with
FileTypeValidatorfor comprehensive file validation - Generic over
u64type for file size values
- Min size validation:
Example:
use ;
// Validate minimum file size
let min_validator = min; // 100 KB minimum
assert!; // 150 KB passes
assert!; // 50 KB fails
// Validate maximum file size
let max_validator = max; // 5 MB maximum
assert!; // 3 MB passes
assert!; // 10 MB fails
// Validate file size range
let range_validator = range;
assert!; // 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
Tthat 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
Tthat validators can validate
Example:
use ;
// AND composition - Username must be 3-20 characters
let username_validator = new;
assert!;
assert!; // Too short
assert!; // Too long
// OR composition - Contact must be either email OR URL
let contact_validator = new;
assert!; // Valid email
assert!; // Valid URL
assert!; // Neither email nor URL
// Nested composition - Complex validation logic
let complex_validator = new;
assert!; // Passes first (3-10 chars)
assert!; // Passes second (20+ chars)
assert!; // Fails both
// Error collection with OrValidator
let collecting_validator = new
.with_error_collection;
match collecting_validator.validate
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 ;
// Validate with country restriction
let validator = with_countries;
assert!; // US ZIP
assert!; // US ZIP+4
assert!; // Japan
assert!; // UK not allowed
// Single country validation
let us_validator = for_country;
assert!;
assert!; // Not US format
// Country detection
let detector = new; // Accepts all countries
let country = detector.validate_with_country.unwrap;
assert_eq!;
let country = detector.validate_with_country.unwrap;
assert_eq!;
// Case-insensitive and whitespace handling
assert!; // UK lowercase with spaces
assert!; // 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
imagecrate
- Min/max width constraints:
Example:
use ImageDimensionValidator;
// Basic dimension constraints
let validator = new
.with_min_width
.with_max_width
.with_min_height
.with_max_height;
// With aspect ratio validation (16:9 with 1% tolerance)
let hd_validator = new
.with_min_width
.with_min_height
.with_aspect_ratio
.with_aspect_ratio_tolerance;
// Validate from file path
let result = validator.validate_file;
// Validate from bytes (in a function context)
#
Conditional Validation (Implemented ✓)
- ConditionalValidator: Apply validators based on runtime conditions
whencondition: Apply validator only when condition is trueunlesscondition: Apply validator only when condition is false- Closure-based conditions: Use custom logic for condition evaluation
- Chainable API: Combine with other validators
Example:
use ;
// Apply validation only when condition is true
// Condition receives &T parameter, validator is boxed
let validator = when;
// Validate admin username (must be at least 10 chars)
assert!;
assert!; // Too short
// Regular username (no validation applied)
assert!;
// Apply validation unless condition is true
let validator = unless;
License
Licensed under the BSD 3-Clause License.