soilrust/
validation.rs

1use serde::Serialize;
2use std::fmt::{self, Display};
3
4#[derive(Debug, Serialize)]
5pub struct ValidationError {
6    pub code: String,
7    pub message: String, // English fallback (optional but helpful for debugging)
8}
9impl fmt::Display for ValidationError {
10    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
11        write!(f, "[{}] {}", self.code, self.message)
12    }
13}
14impl From<ValidationError> for String {
15    fn from(err: ValidationError) -> Self {
16        format!("[{}] {}", err.code, err.message)
17    }
18}
19
20/// Validates a single optional numeric field against optional bounds, returning a structured error.
21///
22/// # Arguments
23/// * `field_name` - A name for the field (e.g. "cu")
24/// * `value` - Option<T> to validate
25/// * `min` - Optional minimum value (inclusive)
26/// * `max` - Optional maximum value (inclusive)
27/// * `error_code_prefix` - A short prefix for generating the error code, e.g., "layer"
28///
29/// # Returns
30/// Ok(()) if valid, Err(ValidationError) otherwise
31pub fn validate_field<T>(
32    field_name: &str,
33    value: Option<T>,
34    min: Option<T>,
35    max: Option<T>,
36    error_code_prefix: &str,
37) -> Result<(), ValidationError>
38where
39    T: PartialOrd + Display + Copy,
40{
41    let val = value.ok_or(ValidationError {
42        code: format!("{}.{}.missing", error_code_prefix, field_name),
43        message: format!("{} must be provided.", field_name),
44    })?;
45
46    if let Some(min_val) = min {
47        if val < min_val {
48            return Err(ValidationError {
49                code: format!("{}.{}.too_small.{}", error_code_prefix, field_name, min_val),
50                message: format!(
51                    "{} must be greater than or equal to {}.",
52                    field_name, min_val
53                ),
54            });
55        }
56    }
57
58    if let Some(max_val) = max {
59        if val > max_val {
60            return Err(ValidationError {
61                code: format!("{}.{}.too_large.{}", error_code_prefix, field_name, max_val),
62                message: format!("{} must be less than or equal to {}.", field_name, max_val),
63            });
64        }
65    }
66
67    Ok(())
68}