struct_validation_core/lib.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
/// Represents an error that occurs during validation of a struct's field.
///
/// Each `ValidationError` contains the name of the field that failed validation
/// and an associated error message explaining the reason for the failure.
#[derive(Debug)]
pub struct ValidationError {
/// The name of the field that failed validation.
pub field: String,
/// A message describing the validation error.
pub message: String,
}
impl ValidationError {
/// Creates a new `ValidationError` for a specific field with a given message.
///
/// # Arguments
///
/// * `field` - The name of the field that failed validation.
/// * `message` - A description of the validation error.
///
/// # Examples
///
/// ```
/// use struct_validation_core::ValidationError;
///
/// let error = ValidationError::new("username", "must not be empty");
/// assert_eq!(error.field, "username");
/// assert_eq!(error.message, "must not be empty");
/// ```
pub fn new(field: &str, message: &str) -> Self {
Self {
field: field.to_string(),
message: message.to_string(),
}
}
/// Adds a prefix to the field name, separated by a dot.
///
/// This can be useful for nested validation errors where the field
/// is part of a larger struct.
///
/// # Arguments
///
/// * `prefix` - The prefix to add to the field name.
///
/// # Examples
///
/// ```
/// use struct_validation_core::ValidationError;
///
/// let mut error = ValidationError::new("username", "must not be empty");
/// error.add_prefix("user");
/// assert_eq!(error.field, "user.username");
/// ```
pub fn add_prefix(&mut self, prefix: &str) {
self.field = format!("{}.{}", prefix, self.field);
}
}
/// A trait for validating structs.
///
/// Implement this trait for your structs to define custom validation logic.
/// The `validate` method should return a vector of `ValidationError`s indicating
/// any validation failures.
pub trait Validate {
/// Validates the current instance and returns a list of validation errors.
///
/// If the instance is valid, the returned vector should be empty.
///
/// # Examples
///
/// ```
/// use struct_validation_core::{Validate, ValidationError};
///
/// struct User {
/// username: String,
/// email: String,
/// }
///
/// impl Validate for User {
/// fn validate(&self) -> Vec<ValidationError> {
/// let mut errors = Vec::new();
///
/// if self.username.is_empty() {
/// errors.push(ValidationError::new("username", "must not be empty"));
/// }
///
/// if !self.email.contains('@') {
/// errors.push(ValidationError::new("email", "must contain '@'"));
/// }
///
/// errors
/// }
/// }
/// ```
fn validate(&self) -> Vec<ValidationError>;
}
/// A macro to simplify validation checks.
///
/// **Usage:** `validate!(vec, (boolean test expression), "field", "message")`
///
/// This macro checks the provided boolean test expression, and if it evaluates to `true`,
/// it pushes a new `ValidationError` onto the provided vector.
///
/// # Arguments
///
/// * `$vec` - The vector to which the `ValidationError` will be added.
/// * `$test` - A boolean expression that determines whether to add the error.
/// * `$field_name` - The name of the field related to the validation error.
/// * `$message` - A message describing the validation error.
///
/// # Examples
///
/// ```
/// use struct_validation_core::{validate, ValidationError};
///
/// let mut errors = Vec::new();
/// let username = "";
/// validate!(errors, username.is_empty(), "username", "must not be empty");
/// assert_eq!(errors.len(), 1);
/// assert_eq!(errors[0].field, "username");
/// assert_eq!(errors[0].message, "must not be empty");
/// ```
#[macro_export]
macro_rules! validate {
($vec:expr, $test:expr, $field_name:expr, $message:expr) => {
if $test {
$vec.push($crate::ValidationError::new($field_name, $message));
}
};
}