use std::collections::HashMap;
use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ValidationError {
code: &'static str,
message: String,
}
impl ValidationError {
pub fn new(code: &'static str, message: impl Into<String>) -> Self {
Self {
code,
message: message.into(),
}
}
pub fn code(&self) -> &'static str {
self.code
}
pub fn message(&self) -> &str {
&self.message
}
}
impl fmt::Display for ValidationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{}]: {}", self.code, self.message)
}
}
impl std::error::Error for ValidationError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FieldError {
field: String,
errors: Vec<ValidationError>,
}
impl FieldError {
pub fn new(field: impl Into<String>, errors: Vec<ValidationError>) -> Self {
Self {
field: field.into(),
errors,
}
}
pub fn field(&self) -> &str {
&self.field
}
pub fn errors(&self) -> &[ValidationError] {
&self.errors
}
}
impl fmt::Display for FieldError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "field '{}' has {} error(s)", self.field, self.errors.len())
}
}
impl std::error::Error for FieldError {}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct ValidationErrors {
fields: HashMap<String, Vec<ValidationError>>,
}
impl ValidationErrors {
pub fn new() -> Self {
Self {
fields: HashMap::new(),
}
}
pub fn add(&mut self, field: impl Into<String>, error: ValidationError) {
self.fields.entry(field.into()).or_default().push(error);
}
pub fn add_many(&mut self, field: impl Into<String>, errors: Vec<ValidationError>) {
if !errors.is_empty() {
self.fields.entry(field.into()).or_default().extend(errors);
}
}
pub fn is_empty(&self) -> bool {
self.fields.is_empty()
}
pub fn len(&self) -> usize {
self.fields.len()
}
pub fn get(&self, field: &str) -> Option<&[ValidationError]> {
self.fields.get(field).map(|v| v.as_slice())
}
pub fn iter(&self) -> impl Iterator<Item = (&str, &[ValidationError])> {
self.fields.iter().map(|(k, v)| (k.as_str(), v.as_slice()))
}
}
impl fmt::Display for ValidationErrors {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Validation failed with {} invalid field(s):", self.fields.len())?;
for (field, errors) in &self.fields {
for err in errors {
writeln!(f, " - [{}]: {}", field, err)?;
}
}
Ok(())
}
}
impl std::error::Error for ValidationErrors {}