Consider that I want to write a series of validations. I use Chain of responsibility design pattern.
so i write trait like
use crate::error::ValidationError;
/// This trait tries to create a set of rules for data validation
/// by implementing the chain of responsibility model.
pub trait Ruled<T> {
/// This method checks the validation rules.
/// If success return (), otherwise returns one of validation error.
fn handle(&mut self, value: &T) -> Result<(), ValidationError>;
/// This method specifies the next rule.
fn chain(&mut self, rule: Box<dyn Ruled<T>>);
/// This method refers to the next rule.
/// If success return next rule, otherwise return None.
fn next(&mut self) -> &mut Option<Box<dyn Ruled<T>>>;
/// This method performs validation for each rule.
/// If success return (), otherwise return None.
fn execute(&mut self, value: &T) -> Result<(), ValidationError> {
self.handle(value)?;
if let Some(next) = &mut self.next() {
next.execute(value)?;
}
Ok(())
}
}
And for example I implement extremum like this
use crate::{error::ValidationError, rule::Ruled};
/// Validates the minimum and maximum allowed value for each numeric type.
pub struct Extremum<T> {
min: Option<T>,
max: Option<T>,
next: Option<Box<dyn Ruled<T>>>,
}
impl<T> Extremum<T> {
pub fn min(&mut self, value: T) {
self.min = Some(value);
}
pub fn max(&mut self, value: T) {
self.max = Some(value);
}
}
impl<T> Default for Extremum<T> {
fn default() -> Self {
Self {
min: None,
max: None,
next: None,
}
}
}
impl<T> Ruled<T> for Extremum<T>
where
T: Ord + Eq + std::fmt::Display,
{
/// Validate the minimum and/or maximum allowed value.
///
/// ```
/// use validation::rule::{Extremum, Ruled};
///
/// let mut extremum = Extremum::<u64>::default();
/// extremum.min(10);
/// extremum.max(100);
///
/// let result = extremum.handle(&70);
/// assert_eq!(result, Ok(()));
/// ```
fn handle(&mut self, value: &T) -> Result<(), ValidationError> {
match (self.min.as_ref(), self.max.as_ref()) {
(Some(min), _) if value.lt(min) => Err(ValidationError::MinExceeded),
(_, Some(max)) if value.gt(max) => Err(ValidationError::MaxExceeded),
(None, None) => Err(ValidationError::MinMaxNotDefined),
_ => Ok(()),
}
}
/// This method specifies the next rule.
fn chain(&mut self, rule: Box<dyn Ruled<T>>) {
self.next = Some(rule);
}
/// This method refers to the next rule.
fn next(&mut self) -> &mut Option<Box<dyn Ruled<T>>> {
&mut self.next
}
}
But what I do not understand. How can I write a generic function that returns the length?
for example I want length on Vectors, Array, Tuples, String data type and of course String types should return chars().count()
.
use crate::{error::ValidationError, rule::Ruled};
pub struct Length<T> {
size: Option<usize>,
next: Option<Box<dyn Ruled<T>>>,
}
impl<T> Length<T> {
pub fn size(&mut self, value: usize) {
self.size = Some(value);
}
}
impl<T> Default for Length<T> {
fn default() -> Self {
Self { size: None, next: None }
}
}
impl<T> Ruled<T> for Length<T> {
fn handle(&mut self, value: &T) -> Result<(), ValidationError> {
/// todo how to write
Ok(())
}
/// This method specifies the next rule.
fn chain(&mut self, rule: Box<dyn Ruled<T>>) {
self.next = Some(rule);
}
/// This method refers to the next rule.
fn next(&mut self) -> &mut Option<Box<dyn Ruled<T>>> {
&mut self.next
}
}