Skip to content

Commit

Permalink
Use generics and macros (#274)
Browse files Browse the repository at this point in the history
* Reduce boilerplate code using generics and macros

* Remove `HasLen`

Plus a couple of clippy suggestions
  • Loading branch information
future-highway authored and Keats committed Mar 4, 2024
1 parent 283a00a commit 11cc0e9
Show file tree
Hide file tree
Showing 9 changed files with 160 additions and 931 deletions.
2 changes: 1 addition & 1 deletion validator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ pub use validation::regex::ValidateRegex;
pub use validation::required::ValidateRequired;
pub use validation::urls::ValidateUrl;

pub use traits::{HasLen, Validate, ValidateArgs};
pub use traits::{Validate, ValidateArgs};
pub use types::{ValidationError, ValidationErrors, ValidationErrorsKind};

#[cfg(feature = "derive")]
Expand Down
150 changes: 3 additions & 147 deletions validator/src/traits.rs
Original file line number Diff line number Diff line change
@@ -1,149 +1,5 @@
use std::borrow::Cow;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};

#[cfg(feature = "indexmap")]
use indexmap::{IndexMap, IndexSet};

use crate::types::ValidationErrors;

/// Trait to implement if one wants to make the `length` validator
/// work for more types
///
/// A bit sad it's not there by default in Rust
pub trait HasLen {
fn length(&self) -> u64;
}

impl HasLen for String {
fn length(&self) -> u64 {
self.chars().count() as u64
}
}

impl<'a> HasLen for &'a String {
fn length(&self) -> u64 {
self.chars().count() as u64
}
}

impl<'a> HasLen for &'a str {
fn length(&self) -> u64 {
self.chars().count() as u64
}
}

impl<'a> HasLen for Cow<'a, str> {
fn length(&self) -> u64 {
self.len() as u64
}
}

impl<T> HasLen for Vec<T> {
fn length(&self) -> u64 {
self.len() as u64
}
}

impl<'a, T> HasLen for &'a Vec<T> {
fn length(&self) -> u64 {
self.len() as u64
}
}

impl<T> HasLen for &[T] {
fn length(&self) -> u64 {
self.len() as u64
}
}

impl<T, const N: usize> HasLen for [T; N] {
fn length(&self) -> u64 {
N as u64
}
}

impl<T, const N: usize> HasLen for &[T; N] {
fn length(&self) -> u64 {
N as u64
}
}

impl<'a, K, V, S> HasLen for &'a HashMap<K, V, S> {
fn length(&self) -> u64 {
self.len() as u64
}
}

impl<K, V, S> HasLen for HashMap<K, V, S> {
fn length(&self) -> u64 {
self.len() as u64
}
}

impl<'a, T, S> HasLen for &'a HashSet<T, S> {
fn length(&self) -> u64 {
self.len() as u64
}
}

impl<T, S> HasLen for HashSet<T, S> {
fn length(&self) -> u64 {
self.len() as u64
}
}

impl<'a, K, V> HasLen for &'a BTreeMap<K, V> {
fn length(&self) -> u64 {
self.len() as u64
}
}

impl<K, V> HasLen for BTreeMap<K, V> {
fn length(&self) -> u64 {
self.len() as u64
}
}

impl<'a, T> HasLen for &'a BTreeSet<T> {
fn length(&self) -> u64 {
self.len() as u64
}
}

impl<T> HasLen for BTreeSet<T> {
fn length(&self) -> u64 {
self.len() as u64
}
}

#[cfg(feature = "indexmap")]
impl<'a, K, V> HasLen for &'a IndexMap<K, V> {
fn length(&self) -> u64 {
self.len() as u64
}
}

#[cfg(feature = "indexmap")]
impl<K, V> HasLen for IndexMap<K, V> {
fn length(&self) -> u64 {
self.len() as u64
}
}

#[cfg(feature = "indexmap")]
impl<'a, T> HasLen for &'a IndexSet<T> {
fn length(&self) -> u64 {
self.len() as u64
}
}

#[cfg(feature = "indexmap")]
impl<T> HasLen for IndexSet<T> {
fn length(&self) -> u64 {
self.len() as u64
}
}

/// This is the original trait that was implemented by deriving `Validate`. It will still be
/// implemented for struct validations that don't take custom arguments. The call is being
/// forwarded to the `ValidateArgs<'v_a>` trait.
Expand All @@ -153,7 +9,7 @@ pub trait Validate {

impl<T: Validate> Validate for &T {
fn validate(&self) -> Result<(), ValidationErrors> {
T::validate(*self)
T::validate(self)
}
}

Expand All @@ -168,8 +24,8 @@ pub trait ValidateArgs<'v_a> {
}

impl<'v_a, T, U> ValidateArgs<'v_a> for Option<T>
where
T: ValidateArgs<'v_a, Args = U>,
where
T: ValidateArgs<'v_a, Args=U>,
{
type Args = U;

Expand Down
157 changes: 11 additions & 146 deletions validator/src/validation/contains.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,57 +12,30 @@ impl ValidateContains for String {
}
}

impl ValidateContains for Option<String> {
impl<T> ValidateContains for Option<T>
where T: ValidateContains {
fn validate_contains(&self, needle: &str) -> bool {
if let Some(v) = self {
v.contains(needle)
v.validate_contains(needle)
} else {
true
}
}
}

impl ValidateContains for Option<Option<String>> {
impl<T> ValidateContains for &T
where T: ValidateContains {
fn validate_contains(&self, needle: &str) -> bool {
if let Some(v) = self {
if let Some(v) = v {
v.contains(needle)
} else {
true
}
} else {
true
}
}
}

impl ValidateContains for &String {
fn validate_contains(&self, needle: &str) -> bool {
self.contains(needle)
}
}

impl ValidateContains for Option<&String> {
fn validate_contains(&self, needle: &str) -> bool {
if let Some(v) = self {
v.contains(needle)
} else {
true
}
T::validate_contains(self, needle)
}
}

impl ValidateContains for Option<Option<&String>> {
impl<'cow, T> ValidateContains for Cow<'cow, T>
where T: ToOwned + ?Sized,
for<'a> &'a T: ValidateContains
{
fn validate_contains(&self, needle: &str) -> bool {
if let Some(v) = self {
if let Some(v) = v {
v.contains(needle)
} else {
true
}
} else {
true
}
self.as_ref().validate_contains(needle)
}
}

Expand All @@ -72,120 +45,12 @@ impl<'a> ValidateContains for &'a str {
}
}

impl<'a> ValidateContains for Option<&'a str> {
fn validate_contains(&self, needle: &str) -> bool {
if let Some(v) = self {
v.contains(needle)
} else {
true
}
}
}

impl<'a> ValidateContains for Option<Option<&'a str>> {
fn validate_contains(&self, needle: &str) -> bool {
if let Some(v) = self {
if let Some(v) = v {
v.contains(needle)
} else {
true
}
} else {
true
}
}
}

impl<'a> ValidateContains for Cow<'a, str> {
fn validate_contains(&self, needle: &str) -> bool {
self.contains(needle)
}
}

impl<'a> ValidateContains for Option<Cow<'a, str>> {
fn validate_contains(&self, needle: &str) -> bool {
if let Some(v) = self {
v.contains(needle)
} else {
true
}
}
}

impl<'a> ValidateContains for Option<Option<Cow<'a, str>>> {
fn validate_contains(&self, needle: &str) -> bool {
if let Some(v) = self {
if let Some(v) = v {
v.contains(needle)
} else {
true
}
} else {
true
}
}
}

impl<S, H: BuildHasher> ValidateContains for HashMap<String, S, H> {
fn validate_contains(&self, needle: &str) -> bool {
self.contains_key(needle)
}
}

impl<S, H: BuildHasher> ValidateContains for Option<HashMap<String, S, H>> {
fn validate_contains(&self, needle: &str) -> bool {
if let Some(v) = self {
v.contains_key(needle)
} else {
true
}
}
}

impl<S, H: BuildHasher> ValidateContains for Option<Option<HashMap<String, S, H>>> {
fn validate_contains(&self, needle: &str) -> bool {
if let Some(v) = self {
if let Some(v) = v {
v.contains_key(needle)
} else {
true
}
} else {
true
}
}
}

impl<'a, S, H: BuildHasher> ValidateContains for &'a HashMap<String, S, H> {
fn validate_contains(&self, needle: &str) -> bool {
self.contains_key(needle)
}
}

impl<'a, S, H: BuildHasher> ValidateContains for Option<&'a HashMap<String, S, H>> {
fn validate_contains(&self, needle: &str) -> bool {
if let Some(v) = self {
v.contains_key(needle)
} else {
true
}
}
}

impl<'a, S, H: BuildHasher> ValidateContains for Option<Option<&'a HashMap<String, S, H>>> {
fn validate_contains(&self, needle: &str) -> bool {
if let Some(v) = self {
if let Some(v) = v {
v.contains_key(needle)
} else {
true
}
} else {
true
}
}
}

#[cfg(test)]
mod tests {
use std::borrow::Cow;
Expand Down
Loading

0 comments on commit 11cc0e9

Please sign in to comment.