use crate::error::Error;
pub fn apply<T: Length>(v: &T, (min, max): (usize, usize)) -> Result<(), Error> {
if let Err(e) = v.validate_length(min, max) {
match e {
InvalidLength::Min => return Err(Error::new(format!("length is lower than {min}"))),
InvalidLength::Max => return Err(Error::new(format!("length is greater than {max}"))),
}
}
Ok(())
}
pub trait Length {
fn validate_length(&self, min: usize, max: usize) -> Result<(), InvalidLength>;
}
pub enum InvalidLength {
Min,
Max,
}
#[allow(clippy::len_without_is_empty)]
pub trait HasLength {
fn length(&self) -> usize;
}
impl<T: HasLength> Length for T {
fn validate_length(&self, min: usize, max: usize) -> Result<(), InvalidLength> {
let len = HasLength::length(self);
if len < min {
Err(InvalidLength::Min)
} else if len > max {
Err(InvalidLength::Max)
} else {
Ok(())
}
}
}
impl<T: Length> Length for Option<T> {
fn validate_length(&self, min: usize, max: usize) -> Result<(), InvalidLength> {
match self {
Some(value) => value.validate_length(min, max),
None => Ok(()),
}
}
}
impl HasLength for String {
fn length(&self) -> usize {
self.chars().count()
}
}
impl<'a> HasLength for &'a String {
fn length(&self) -> usize {
self.chars().count()
}
}
impl<'a> HasLength for &'a str {
fn length(&self) -> usize {
self.chars().count()
}
}
impl<'a> HasLength for std::borrow::Cow<'a, str> {
fn length(&self) -> usize {
self.len()
}
}
impl<T> HasLength for Vec<T> {
fn length(&self) -> usize {
self.len()
}
}
impl<'a, T> HasLength for &'a Vec<T> {
fn length(&self) -> usize {
self.len()
}
}
impl<T> HasLength for &[T] {
fn length(&self) -> usize {
self.len()
}
}
impl<T, const N: usize> HasLength for [T; N] {
fn length(&self) -> usize {
N
}
}
impl<T, const N: usize> HasLength for &[T; N] {
fn length(&self) -> usize {
N
}
}
impl<'a, K, V, S> HasLength for &'a std::collections::HashMap<K, V, S> {
fn length(&self) -> usize {
self.len()
}
}
impl<K, V, S> HasLength for std::collections::HashMap<K, V, S> {
fn length(&self) -> usize {
self.len()
}
}
impl<'a, T, S> HasLength for &'a std::collections::HashSet<T, S> {
fn length(&self) -> usize {
self.len()
}
}
impl<T, S> HasLength for std::collections::HashSet<T, S> {
fn length(&self) -> usize {
self.len()
}
}
impl<'a, K, V> HasLength for &'a std::collections::BTreeMap<K, V> {
fn length(&self) -> usize {
self.len()
}
}
impl<K, V> HasLength for std::collections::BTreeMap<K, V> {
fn length(&self) -> usize {
self.len()
}
}
impl<'a, T> HasLength for &'a std::collections::BTreeSet<T> {
fn length(&self) -> usize {
self.len()
}
}
impl<T> HasLength for std::collections::BTreeSet<T> {
fn length(&self) -> usize {
self.len()
}
}
impl<T> HasLength for std::collections::VecDeque<T> {
fn length(&self) -> usize {
self.len()
}
}
impl<T> HasLength for std::collections::BinaryHeap<T> {
fn length(&self) -> usize {
self.len()
}
}
impl<T> HasLength for std::collections::LinkedList<T> {
fn length(&self) -> usize {
self.len()
}
}