use crate::{Validation, ValidationErrors};
use std::{fmt::Debug, rc::Rc};
use uuid::Uuid;
#[cfg(feature = "async")]
use std::{future::Future, marker::PhantomData, pin::Pin};
type ValidatorFnTraitObject<Value, Key> = dyn Fn(&Value, &Key) -> Result<(), ValidationErrors<Key>>;
pub struct ValidatorFn<Value, Key> {
closure: Rc<ValidatorFnTraitObject<Value, Key>>,
id: Uuid,
}
impl<Value, Key> ValidatorFn<Value, Key> {
pub fn new<C>(closure: C) -> Self
where
C: Fn(&Value, &Key) -> Result<(), ValidationErrors<Key>> + 'static,
{
Self {
closure: Rc::new(closure),
id: Uuid::new_v4(),
}
}
}
impl<Value, Key> Clone for ValidatorFn<Value, Key> {
fn clone(&self) -> Self {
Self {
closure: Rc::clone(&self.closure),
id: self.id,
}
}
}
impl<Value, Key> PartialEq for ValidatorFn<Value, Key> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl<C, Value, Key> From<C> for ValidatorFn<Value, Key>
where
C: Fn(&Value, &Key) -> Result<(), ValidationErrors<Key>> + 'static,
{
fn from(closure: C) -> Self {
ValidatorFn::new(closure)
}
}
impl<Value, Key> Debug for ValidatorFn<Value, Key> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"ValidatorFn(closure: {:p}, id: {})",
self.closure, self.id
)
}
}
impl<Value, Key> Validation<Value, Key> for ValidatorFn<Value, Key>
where
Key: Clone + PartialEq,
{
fn validate_value(&self, value: &Value, key: &Key) -> Result<(), ValidationErrors<Key>> {
(self.closure)(value, key)
}
}
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
pub struct AsyncValidatorFn<Value, Key> {
future_producer: Rc<
dyn Fn(&Value, &Key) -> Pin<Box<dyn Future<Output = Result<(), ValidationErrors<Key>>>>>,
>,
id: Uuid,
key_type: PhantomData<Key>,
value_type: PhantomData<Value>,
}
#[cfg(feature = "async")]
impl<Value, Key> AsyncValidatorFn<Value, Key>
where
Key: Clone + PartialEq,
Value: Clone + PartialEq,
{
pub fn new<C>(closure: C) -> Self
where
C: Fn(&Value, &Key) -> Pin<Box<dyn Future<Output = Result<(), ValidationErrors<Key>>>>>
+ 'static,
{
Self {
future_producer: Rc::new(closure),
id: Uuid::new_v4(),
key_type: PhantomData,
value_type: PhantomData,
}
}
pub async fn validate_value(
&self,
value: &Value,
key: &Key,
) -> Result<(), ValidationErrors<Key>> {
let future = (self.future_producer)(value, key);
future.await
}
}
#[cfg(feature = "async")]
impl<Value, Key> From<ValidatorFn<Value, Key>> for AsyncValidatorFn<Value, Key>
where
Key: Clone + PartialEq + 'static,
Value: Clone + PartialEq + 'static,
{
fn from(validator_fn: ValidatorFn<Value, Key>) -> Self {
Self::new(move |value, key| {
let value_clone = value.clone();
let key_clone = key.clone();
let new_fn = validator_fn.clone();
Box::pin(async move { new_fn.validate_value(&value_clone, &key_clone) })
})
}
}
#[cfg(feature = "async")]
impl<Value, Key> PartialEq for AsyncValidatorFn<Value, Key> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
#[cfg(feature = "async")]
impl<Value, Key> Clone for AsyncValidatorFn<Value, Key> {
fn clone(&self) -> Self {
Self {
future_producer: Rc::clone(&self.future_producer),
id: self.id,
key_type: PhantomData,
value_type: PhantomData,
}
}
}
#[cfg(feature = "async")]
impl<Value, Key> Debug for AsyncValidatorFn<Value, Key> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"AsyncValidatorFn(future_producer: {:p}, id: {})",
self.future_producer, self.id
)
}
}