systemprompt_traits/
validation.rs

1use std::fmt::Debug;
2
3#[derive(Debug, Clone)]
4pub struct ValidationError {
5    pub field: String,
6    pub message: String,
7    pub context: Option<String>,
8}
9
10impl ValidationError {
11    #[must_use]
12    pub fn new(field: impl Into<String>, message: impl Into<String>) -> Self {
13        Self {
14            field: field.into(),
15            message: message.into(),
16            context: None,
17        }
18    }
19
20    #[must_use]
21    pub fn with_context(mut self, context: impl Into<String>) -> Self {
22        self.context = Some(context.into());
23        self
24    }
25}
26
27impl std::fmt::Display for ValidationError {
28    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29        if let Some(ref ctx) = self.context {
30            write!(
31                f,
32                "VALIDATION ERROR [{}]: {} (context: {})",
33                self.field, self.message, ctx
34            )
35        } else {
36            write!(f, "VALIDATION ERROR [{}]: {}", self.field, self.message)
37        }
38    }
39}
40
41impl std::error::Error for ValidationError {}
42
43pub type ValidationResult<T> = Result<T, ValidationError>;
44
45pub trait Validate: Debug {
46    fn validate(&self) -> ValidationResult<()>;
47}
48
49pub trait MetadataValidation: Validate {
50    fn required_string_fields(&self) -> Vec<(&'static str, &str)>;
51
52    fn validate_required_fields(&self) -> ValidationResult<()> {
53        for (field_name, field_value) in self.required_string_fields() {
54            if field_value.is_empty() {
55                return Err(ValidationError::new(
56                    field_name,
57                    format!("{field_name} cannot be empty"),
58                ));
59            }
60        }
61        Ok(())
62    }
63}