| Crates.io | reinhardt-core |
| lib.rs | reinhardt-core |
| version | 0.1.0-alpha.1 |
| created_at | 2026-01-23 02:56:03.619871+00 |
| updated_at | 2026-01-23 02:56:03.619871+00 |
| description | Core components for Reinhardt framework |
| homepage | |
| repository | https://github.com/kent8192/reinhardt-rs |
| max_upload_size | |
| id | 2063261 |
| size | 1,462,345 |
Core components for Reinhardt framework
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.
This crate provides the following modules:
Types: Core type definitions
Exception: Exception handling and error types
Signals: Event-driven hooks for lifecycle events
Macros: Procedural macros for code generation
#[handler] macro for endpoint definitions#[middleware] macro for middleware implementations#[injectable] macro for dependency injectionSecurity: Security primitives and utilities
Validators: Data validation utilities
Serializers: Serialization and deserialization
Messages: Flash messages and user notifications
Pagination: Pagination strategies
Parsers: Request body parsing
Negotiation: Content negotiation
Dependency Injection: FastAPI-style DI system
Add this to your Cargo.toml:
[dependencies]
reinhardt-core = "0.1.0-alpha.1"
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 definitionsexception (default): Error handlingsignals (default): Event systemmacros (default): Procedural macrossecurity (default): Security primitivesvalidators (default): Data validationserializers (default): Serialization utilitieshttp: HTTP types and traits (requires types)messages: Flash messaging systemdi: Dependency injection with parameter extractionnegotiation: Content negotiationparsers: Request body parserspagination: Pagination strategies// 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)
}
}
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(())
}
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();
}
`reinhardt-core` is organized into the following 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`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 negotiationuse 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`.
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
Message::debug(), Message::info(), etc.)MessageConfig for customizing level tags globallyArc<Mutex<VecDeque>> for testing and temporary messages"_messages")bisect_keep_left(): Keep maximum messages from the beginning within size limitbisect_keep_right(): Keep maximum messages from the end within size limitadd(): Add a message to storageget_all(): Retrieve and clear all messagespeek(): View messages without clearingclear(): Remove all messagesadd(): Add messages during requestget_messages(): Retrieve all messagesadd_from_storage(): Load messages from storage backendget_messages(): Retrieve messages for renderingadd_message(): Add messages to contextfilter_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
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 reportinggenerate_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 intervalCsrfConfig::with_token_rotation(interval)check_origin() and check_referer() validate request sourcesis_same_domain() for cross-domain request protectionCsrfConfig::production() with security hardening (includes token rotation)CsrfMiddleware with customizable configurationCSRF_TOKEN_LENGTH, CSRF_SECRET_LENGTH, CSRF_SESSION_KEY, rejection reason constantsescape_html(): Escapes dangerous characters (<, >, &, ", ')escape_html_attr(): Escapes HTML attributes including newlines and control charactersescape_javascript() for safe embedding in JavaScript stringsescape_url() for URL encoding to prevent injectionsanitize_html() for basic HTML input sanitizationdetect_xss_patterns() detects dangerous patterns (script tags, event handlers, etc.)is_safe_url() validates URLs and allows only safe protocols (http, https, mailto, ftp)default-src, script-src, style-src, img-srcconnect-src, font-src, object-src, media-src, frame-srcreport-uri and report-to for violation reporting via with_report_uri() and with_report_to()generate_nonce() for inline script/style nonceswith_auto_nonce()SecurityHeadersMiddleware with comprehensive defaultsX-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-Embedder-Policy: require-corpCross-Origin-Opener-Policy: same-originCross-Origin-Resource-Policy: same-originSecurityHeadersConfig::production(): Strict security headers for productionSecurityHeadersConfig::development(): Relaxed headers for development (no HSTS, no CSP)HstsConfig with builder patternmax_age: Configurable duration in secondsincludeSubDomains: Optional subdomain protectionpreload: HSTS preload list supportbuild_header() for automatic header value constructionThe utils module provides internal security utilities:
generate_token() creates cryptographically random tokens (internal use)hash_sha256() for secure string hashing (internal use)rand crate for securityNote: 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.
SecurityError enum with specific variantsWhitelist/Blacklist Modes: IpFilterMode enum for configurable filtering strategy
Whitelist: 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: IpFilterConfig with builder-style methods
new(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 permittedBlacklist Override: Blocked IPs take precedence over allowed IPs
Middleware: IpFilterMiddleware for request filtering based on IP address
Handler trait - Core abstraction for async request processing
async fn handle(&self, request: Request) -> Result<Response>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 executionMiddlewareChain - Composable middleware system with automatic chaining
with_middleware() for method chainingadd_middleware() for imperative styleResponse::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
Validator<T> for implementing custom validatorsString and &str typesString and &str typeswith_message()String and &str typesPartialOrd + Display + Clone typePartialOrd + Display + Clone typePartialOrd + Display + Clone typeString and &str typesString and &str typesInvalidEmail(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 errorFileTypeValidator::with_extensions()
FileTypeValidator::with_mime_types()
FileTypeValidator::images_only(): Supports JPEG, PNG, GIF, WebP, SVG, BMP, TIFF, ICO, AVIFFileTypeValidator::documents_only(): Supports PDF, DOC, DOCX, XLS, XLSX, PPT, PPTX, TXTExample:
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());
ExistsValidator: Asynchronous foreign key existence validation
UniqueValidator: Asynchronous uniqueness constraint validation
exclude_id parameterExample:
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());
TableName: Compile-time and runtime validated table names
is_sql_reserved_word()new_const() constant functionnew() methodFieldName: SQL-safe field/column name validation
ConstraintName: SQL-safe constraint name validation
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");
Currently supported by:
.with_message("Custom message")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"),
}
FileSizeValidator::min(bytes)FileSizeValidator::max(bytes)FileSizeValidator::range(min_bytes, max_bytes)FileSizeValidator::from_kb(kb): Convert KB to bytesFileSizeValidator::from_mb(mb): Convert MB to bytesFileSizeValidator::from_gb(gb): Convert GB to bytesFileTypeValidator for comprehensive file validationu64 type for file size valuesExample:
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
AndValidator: Combine multiple validators with AND logic
T that validators can validateOrValidator: Combine multiple validators with OR logic
T that validators can validateExample:
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!(),
}
with_countries(vec![Country::US, Country::JP])for_country(Country::US)validate_with_country() returns detected countrySupported Formats:
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
min_width(), max_width()min_height(), max_height()aspect_ratio() with configurable tolerancevalidate_file() for file pathsvalidate_bytes() for in-memory imagesimage crateExample:
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(())
# }
when condition: Apply validator only when condition is trueunless condition: Apply validator only when condition is falseExample:
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)),
);
Licensed under either of Apache License, Version 2.0 or MIT license at your option.