use std::{
fmt::{Debug, Display},
rc::Rc,
};
pub struct ValidationError<Key> {
pub key: Key,
pub type_id: &'static str,
message: Rc<dyn Fn(&Key) -> String>,
}
impl<Key> PartialEq for ValidationError<Key>
where
Key: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.key == other.key
&& self.type_id == other.type_id
&& self.get_message() == other.get_message()
}
}
impl<Key> Clone for ValidationError<Key>
where
Key: Clone,
{
fn clone(&self) -> Self {
Self {
key: self.key.clone(),
type_id: self.type_id,
message: self.message.clone(),
}
}
}
impl<Key> ValidationError<Key> {
pub fn new(key: Key, type_id: &'static str) -> Self {
Self {
key,
message: Rc::new(|_| "Validation error".to_string()),
type_id,
}
}
pub fn message<S: Into<String>>(mut self, message: S) -> Self {
let message_string = message.into();
self.message = Rc::new(move |_| message_string.clone());
self
}
pub fn with_message<F: Fn(&Key) -> String + 'static>(mut self, message_fn: F) -> Self {
self.message = Rc::new(message_fn);
self
}
fn get_message(&self) -> String {
(self.message)(&self.key)
}
}
impl<Key> Display for ValidationError<Key> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.get_message())
}
}
impl<Key> Debug for ValidationError<Key>
where
Key: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"ValidationError{{ key: {0:?}, type_id: {1}, message: {2} }}",
self.key,
self.type_id,
self.get_message()
)
}
}
impl<Key> std::error::Error for ValidationError<Key> where Key: Debug {}
#[derive(Debug, Clone)]
pub struct ValidationErrors<Key> {
pub errors: Vec<ValidationError<Key>>,
}
impl<Key> PartialEq for ValidationErrors<Key>
where
Key: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.errors.eq(&other.errors)
}
}
impl<Key> ValidationErrors<Key>
where
Key: PartialEq + Clone,
{
pub fn new(errors: Vec<ValidationError<Key>>) -> Self {
Self { errors }
}
pub fn get(&self, key: &Key) -> Option<ValidationErrors<Key>> {
let errors: Vec<ValidationError<Key>> = self
.errors
.iter()
.filter(|error| &error.key == key)
.map(|error| (*error).clone())
.collect();
if !errors.is_empty() {
Some(ValidationErrors::new(errors))
} else {
None
}
}
pub fn is_empty(&self) -> bool {
self.errors.is_empty()
}
pub fn extend(&mut self, errors: ValidationErrors<Key>) {
self.errors.extend(errors.errors)
}
pub fn len(&self) -> usize {
self.errors.len()
}
}
impl<Key> Default for ValidationErrors<Key> {
fn default() -> Self {
Self { errors: Vec::new() }
}
}
impl<Key> Display for ValidationErrors<Key> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let errors: Vec<String> = self.errors.iter().map(|e| format!("{}", e)).collect();
write!(f, "{}", errors.join(", "))
}
}
impl<Key> std::error::Error for ValidationErrors<Key> where Key: std::fmt::Debug {}
impl<Key> From<ValidationError<Key>> for ValidationErrors<Key>
where
Key: Clone + PartialEq,
{
fn from(err: ValidationError<Key>) -> Self {
ValidationErrors::new(vec![err])
}
}