1use crate::{Validation, ValidationErrors};
2use std::{fmt::Debug, rc::Rc};
3use uuid::Uuid;
4
5#[cfg(feature = "async")]
6use std::{future::Future, marker::PhantomData, pin::Pin};
7
8type ValidatorFnTraitObject<Value, Key> = dyn Fn(&Value, &Key) -> Result<(), ValidationErrors<Key>>;
9
10pub struct ValidatorFn<Value, Key> {
44 closure: Rc<ValidatorFnTraitObject<Value, Key>>,
45 id: Uuid,
46}
47
48impl<Value, Key> ValidatorFn<Value, Key> {
49 pub fn new<C>(closure: C) -> Self
51 where
52 C: Fn(&Value, &Key) -> Result<(), ValidationErrors<Key>> + 'static,
53 {
54 Self {
55 closure: Rc::new(closure),
56 id: Uuid::new_v4(),
57 }
58 }
59}
60
61impl<Value, Key> Clone for ValidatorFn<Value, Key> {
62 fn clone(&self) -> Self {
63 Self {
64 closure: Rc::clone(&self.closure),
65 id: self.id,
66 }
67 }
68}
69
70impl<Value, Key> PartialEq for ValidatorFn<Value, Key> {
71 fn eq(&self, other: &Self) -> bool {
72 self.id == other.id
73 }
74}
75
76impl<C, Value, Key> From<C> for ValidatorFn<Value, Key>
77where
78 C: Fn(&Value, &Key) -> Result<(), ValidationErrors<Key>> + 'static,
79{
80 fn from(closure: C) -> Self {
81 ValidatorFn::new(closure)
82 }
83}
84
85impl<Value, Key> Debug for ValidatorFn<Value, Key> {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 write!(
88 f,
89 "ValidatorFn(closure: {:p}, id: {})",
90 self.closure, self.id
91 )
92 }
93}
94
95impl<Value, Key> Validation<Value, Key> for ValidatorFn<Value, Key>
96where
97 Key: Clone + PartialEq,
98{
99 fn validate_value(&self, value: &Value, key: &Key) -> Result<(), ValidationErrors<Key>> {
100 (self.closure)(value, key)
101 }
102}
103
104#[cfg(feature = "async")]
148#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
149pub struct AsyncValidatorFn<Value, Key> {
150 future_producer: Rc<
151 dyn Fn(&Value, &Key) -> Pin<Box<dyn Future<Output = Result<(), ValidationErrors<Key>>>>>,
152 >,
153 id: Uuid,
154 key_type: PhantomData<Key>,
155 value_type: PhantomData<Value>,
156}
157
158#[cfg(feature = "async")]
159impl<Value, Key> AsyncValidatorFn<Value, Key>
160where
161 Key: Clone + PartialEq,
162 Value: Clone + PartialEq,
163{
164 pub fn new<C>(closure: C) -> Self
167 where
168 C: Fn(&Value, &Key) -> Pin<Box<dyn Future<Output = Result<(), ValidationErrors<Key>>>>>
169 + 'static,
170 {
171 Self {
172 future_producer: Rc::new(closure),
173 id: Uuid::new_v4(),
174 key_type: PhantomData,
175 value_type: PhantomData,
176 }
177 }
178
179 pub async fn validate_value(
182 &self,
183 value: &Value,
184 key: &Key,
185 ) -> Result<(), ValidationErrors<Key>> {
186 let future = (self.future_producer)(value, key);
187 future.await
188 }
189}
190
191#[cfg(feature = "async")]
192impl<Value, Key> From<ValidatorFn<Value, Key>> for AsyncValidatorFn<Value, Key>
193where
194 Key: Clone + PartialEq + 'static,
195 Value: Clone + PartialEq + 'static,
196{
197 fn from(validator_fn: ValidatorFn<Value, Key>) -> Self {
198 Self::new(move |value, key| {
199 let value_clone = value.clone();
200 let key_clone = key.clone();
201 let new_fn = validator_fn.clone();
202 Box::pin(async move { new_fn.validate_value(&value_clone, &key_clone) })
203 })
204 }
205}
206
207#[cfg(feature = "async")]
208impl<Value, Key> PartialEq for AsyncValidatorFn<Value, Key> {
209 fn eq(&self, other: &Self) -> bool {
210 self.id == other.id
211 }
212}
213
214#[cfg(feature = "async")]
215impl<Value, Key> Clone for AsyncValidatorFn<Value, Key> {
216 fn clone(&self) -> Self {
217 Self {
218 future_producer: Rc::clone(&self.future_producer),
219 id: self.id,
220 key_type: PhantomData,
221 value_type: PhantomData,
222 }
223 }
224}
225
226#[cfg(feature = "async")]
227impl<Value, Key> Debug for AsyncValidatorFn<Value, Key> {
228 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
229 write!(
230 f,
231 "AsyncValidatorFn(future_producer: {:p}, id: {})",
232 self.future_producer, self.id
233 )
234 }
235}