pub type DomainVerificationFunctionBoxed<C, T, E> = Box<dyn Fn(&T, &C) -> Vec<E>>;
#[derive(Debug, Default)]
pub struct EmptyContext;
pub struct DomainVerifications<C: Sized, T: Sized, E> {
verification_fns: Vec<DomainVerificationFunctionBoxed<C, T, E>>,
}
pub trait VerifyDomainTrait<C: Sized, E>: Sized {
fn new_domain_verifications() -> DomainVerifications<C, Self, E> {
DomainVerifications::default()
}
fn verifiy_domain(&self, context: &C) -> Vec<E> {
let verifications = Self::new_domain_verifications();
verifications
.iter()
.flat_map(|f| f(self, context))
.collect()
}
}
impl<C, T, E> Default for DomainVerifications<C, T, E> {
fn default() -> Self {
Self {
verification_fns: Default::default(),
}
}
}
impl<C, T, E> DomainVerifications<C, T, E> {
pub fn add_verification(&mut self, fct: impl (Fn(&T, &C) -> Vec<E>) + 'static) {
self.verification_fns.push(Box::new(fct));
}
pub fn add_verification_with_vec_of_vec_errors(
&mut self,
fct: impl (Fn(&T, &C) -> Vec<Vec<E>>) + 'static,
) {
self.add_verification(move |t, c| fct(t, c).into_iter().flatten().collect())
}
pub fn iter(&self) -> std::slice::Iter<'_, DomainVerificationFunctionBoxed<C, T, E>> {
self.verification_fns.iter()
}
}
#[cfg(test)]
mod tests {
use super::*;
struct MyStruct {
value: u32,
}
impl VerifyDomainTrait<EmptyContext, String> for MyStruct {
fn new_domain_verifications() -> DomainVerifications<EmptyContext, Self, String> {
let mut verifications = DomainVerifications::default();
verifications.add_verification(|s: &MyStruct, _c: &EmptyContext| {
let mut errors = Vec::new();
if s.value < 10 {
errors.push("Value is less than 10".to_string());
}
if s.value > 100 {
errors.push("Value is greater than 100".to_string());
}
errors
});
verifications
}
}
#[test]
fn test_domain_verification() {
let my_struct = MyStruct { value: 5 };
let errors = my_struct.verifiy_domain(&EmptyContext);
assert_eq!(errors.len(), 1);
assert_eq!(errors[0], "Value is less than 10");
let my_struct = MyStruct { value: 150 };
let errors = my_struct.verifiy_domain(&EmptyContext);
assert_eq!(errors.len(), 1);
assert_eq!(errors[0], "Value is greater than 100");
let my_struct = MyStruct { value: 50 };
let errors = my_struct.verifiy_domain(&EmptyContext);
assert!(errors.is_empty());
}
#[test]
fn test_domain_verification_no_errors() {
let my_struct = MyStruct { value: 50 };
let errors = my_struct.verifiy_domain(&EmptyContext);
assert!(errors.is_empty());
}
struct MyStructNextedErrors;
impl VerifyDomainTrait<EmptyContext, String> for MyStructNextedErrors {
fn new_domain_verifications() -> DomainVerifications<EmptyContext, Self, String> {
let mut verifications = DomainVerifications::default();
verifications.add_verification_with_vec_of_vec_errors(
|_s: &MyStructNextedErrors, _c: &EmptyContext| {
vec![vec!["error1".to_string(), "error2".to_string()]]
},
);
verifications
}
}
#[test]
fn test_domain_verification_nexted_errors() {
let my_struct = MyStructNextedErrors {};
let errors = my_struct.verifiy_domain(&EmptyContext);
assert_eq!(errors, vec!["error1".to_string(), "error2".to_string()]);
}
}