| Crates.io | rod_validation |
| lib.rs | rod_validation |
| version | 0.2.2 |
| created_at | 2025-09-20 07:41:38.97826+00 |
| updated_at | 2025-09-30 10:10:15.503723+00 |
| description | A lightweight and ergonomic validation library for Rust |
| homepage | |
| repository | https://github.com/kommade/rod |
| max_upload_size | |
| id | 1847497 |
| size | 82,936 |
A powerful and flexible compile-time validation library for Rust structs and enums. Rod provides declarative validation through derive macros, allowing you to specify validation rules directly in your type definitions.
regex feature)Add Rod Validation to your Cargo.toml:
[dependencies]
rod_validation = "0.2.2"
For regex support:
[dependencies]
rod_validation = { version = "0.2.2", features = ["regex"] }
use rod_validation::prelude::*;
#[derive(RodValidate)]
struct User {
#[rod(String {
length: 3..=50,
format: Email,
})]
email: String,
#[rod(String {
length: 8..=100,
includes: "@",
})]
password: String,
#[rod(i32 {
size: 18..=120,
sign: Positive,
})]
age: i32,
#[rod(Option {
String {
length: 1..=100,
}
})]
bio: Option<String>,
}
fn main() {
let user = User {
email: "user@example.com".to_string(),
password: "secure@password123".to_string(),
age: 25,
bio: Some("Software developer".to_string()),
};
// Validate and get first error (fail-fast)
match user.validate() {
Ok(_) => println!("User is valid!"),
Err(e) => println!("Validation error: {}", e),
}
// Validate and collect all errors
match user.validate_all() {
Ok(_) => println!("User is valid!"),
Err(errors) => {
println!("Found {} validation errors:", errors.len());
for error in errors {
println!(" - {}", error);
}
}
}
}
#[derive(RodValidate)]
struct StringExample {
#[rod(String {
length: 5..=20, // Length between 5 and 20 characters
format: Email, // Built-in email format (requires regex feature)
starts_with: "user_", // Must start with "user_"
ends_with: "@domain.com", // Must end with "@domain.com"
includes: "test", // Must contain "test"
})]
field: String,
}
Available string formats (with regex feature):
Email - Email address validationUrl - URL validationUuid - UUID validationIpv4 - IPv4 address validationIpv6 - IPv6 address validationDateTime - DateTime validationRegex("pattern") - Custom regex pattern#[derive(RodValidate)]
struct IntegerExample {
#[rod(i32 {
size: 1..=100, // Value between 1 and 100
sign: Positive, // Must be positive
step: 5, // Must be multiple of 5
})]
field: i32,
}
Number signs:
Positive - Greater than 0Negative - Less than 0NonPositive - Less than or equal to 0NonNegative - Greater than or equal to 0#[derive(RodValidate)]
struct FloatExample {
#[rod(f64 {
size: 0.0..=100.0, // Value between 0.0 and 100.0
sign: NonNegative, // Must be non-negative
type: Finite, // Must be finite (not NaN or infinite)
})]
field: f64,
}
Float types:
Finite - Not NaN or infiniteInfinite - Must be infiniteNan - Must be NaNNormal - Must be normalSubnormal - Must be subnormal#[derive(RodValidate)]
struct OptionExample {
// Validate the inner value if Some
#[rod(Option {
String {
length: 5,
}
})]
optional_field: Option<String>,
// Require the field to be None
#[rod(Option {})]
must_be_none: Option<String>,
}
#[derive(RodValidate)]
struct TupleExample {
#[rod(Tuple (
i32 {
size: 1..=10,
sign: Positive,
},
String {
length: 5,
},
f64 {
size: 0.0..=1.0,
}
))]
coordinates: (i32, String, f64),
}
#[derive(RodValidate)]
struct LiteralExample {
#[rod(Literal {
value: "expected_value",
})]
field: String,
}
#[derive(RodValidate)]
struct CustomExample {
#[rod(
i32 {
size: 1..=100,
},
check = |x| x % 2 == 0 // Custom validation: must be even
)]
even_number: i32,
}
#[derive(RodValidate)]
struct IterableExample {
#[rod(Iterable {
length: 1..=10,
String {
length: 3..=20,
}
})]
tags: Vec<String>,
}
Rod provides two validation methods:
validate() - Returns the first validation error encountered (fail-fast)validate_all() - Collects and returns all validation errors// Fail-fast validation
match user.validate() {
Ok(_) => println!("Valid!"),
Err(error) => println!("Error: {}", error),
}
// Collect all errors
match user.validate_all() {
Ok(_) => println!("Valid!"),
Err(errors) => {
for error in errors.iter() {
println!("Error: {}", error);
}
}
}
Attach bespoke error messages to any validation rule using the ? "<error>" syntax. Messages placed immediately before a rule override its default error output.
#[derive(RodValidate)]
struct SignupForm {
#[rod(String {
? "Password must be at least eight characters long.",
length: 8..,
? "Password must include the @ symbol for legacy compatibility.",
includes: "@",
})]
password: String,
}
The custom messages are surfaced by both validate and validate_all, making it straightforward to deliver user-friendly, context-aware feedback.
You may also override the error messages for all validation rules of a type with the message: "<error>" syntax.
#[derive(RodValidate)]
struct SignupForm {
#[rod(
String {
length: 8..,
includes: "@",
},
message: "Password must be 8 characters AND have an @"
)]
password: String,
}
If both error message syntaxes are attached, messages attached to specific rules will be preferred.
## Nested Structures
Rod supports validation of nested structures that implement `RodValidate`:
```rust
#[derive(RodValidate)]
struct Address {
#[rod(String { length: 1..=100 })]
street: String,
#[rod(String { length: 2..=50 })]
city: String,
}
#[derive(RodValidate)]
struct Person {
#[rod(String { length: 1..=50 })]
name: String,
// No #[rod] attribute needed for custom types
address: Address,
}
Rod supports validation of enumeration variants:
#[derive(RodValidate)]
enum Status {
#[rod(String { length: 1..=100 })]
Active(String),
Inactive,
#[rod(i32 { size: 1..=30 })]
Pending { days: i32 },
}
The #[derive(RodValidate)] macro generates two validation methods for your types:
validate(&self) -> Result<(), RodValidateError> - Fail-fast validation (returns on first error)validate_all(&self) -> Result<(), RodValidateErrorList> - Collect all errors before returningThe generated validation code produces detailed error messages with field paths:
// Example error: "Expected `user.email` to be a string with length 3..=50, got 2"
The macro provides several compile-time guarantees:
RodValidateThe macro generates validation code that:
todo!() panic)&&T types are not allowedbool typeregex crate feature to be enabled["regex"]regex: Enables regex-based string format validationFor detailed documentation and examples, visit docs.rs/rod.
This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.
Contributions are welcome! Please feel free to submit a pull request.