1use super::{names_equal, Builder};
2use crate::{
3 validation::{self, Validate},
4 Ref, Value,
5};
6use cfg_if::cfg_if;
7use di::{transient_factory, Ref as Svc};
8use std::marker::PhantomData;
9
10fn message_or_default<T: AsRef<str>>(message: T) -> String {
11 let msg = message.as_ref();
12
13 if msg.is_empty() {
14 String::from("A validation error has occurred.")
15 } else {
16 String::from(msg)
17 }
18}
19
20macro_rules! validate_impl {
21 (($($bounds:tt)+), _Validate, validate, []) => {
23 struct _Validate<TOptions, TAction> {
24 name: String,
25 action: Ref<TAction>,
26 failure_message: String,
27 _type: PhantomData<TOptions>,
28 }
29
30 impl<TOptions, TAction> Validate<TOptions> for _Validate<TOptions, TAction>
31 where
32 TOptions: Value,
33 TAction: Fn(&TOptions) -> bool + $($bounds)+,
34 {
35 fn run(&self, name: &str, options: &TOptions) -> validation::Result {
36 if names_equal(&self.name, name) {
37 if (self.action)(options) {
38 return validation::success();
39 } else {
40 return validation::fail(&self.failure_message);
41 }
42 }
43
44 validation::skip()
45 }
46 }
47 };
48 (($($bounds:tt)+), $struct_name:ident, $method:ident, [$(($dep_generic:ident, $dep_field:ident)),+]) => {
50 struct $struct_name<TOptions, TAction, $($dep_generic),+> {
51 name: String,
52 action: Ref<TAction>,
53 failure_message: String,
54 $($dep_field: Svc<$dep_generic>,)+
55 _type: PhantomData<TOptions>,
56 }
57
58 impl<TOptions, TAction, $($dep_generic),+> Validate<TOptions>
59 for $struct_name<TOptions, TAction, $($dep_generic),+>
60 where
61 TOptions: Value,
62 TAction: Fn(&TOptions, $(Svc<$dep_generic>),+) -> bool + $($bounds)+,
63 $($dep_generic: Value,)+
64 {
65 fn run(&self, name: &str, options: &TOptions) -> validation::Result {
66 if names_equal(&self.name, name) {
67 if (self.action)(options, $(self.$dep_field.clone()),+) {
68 return validation::success();
69 } else {
70 return validation::fail(&self.failure_message);
71 }
72 }
73
74 validation::skip()
75 }
76 }
77 };
78}
79
80macro_rules! validate_builder_method {
83 (($($bounds:tt)+), $method:ident, $struct_name:ident, ($d1:ident, $f1:ident)) => {
84 pub fn $method<F, M, $d1>(self, action: F, failure_message: M) -> Self
91 where
92 F: Fn(&T, Svc<$d1>) -> bool + $($bounds)+,
93 M: AsRef<str>,
94 $d1: $($bounds)+,
95 {
96 let action = Ref::new(action);
97 let name = self.name.clone();
98 let failure_message = message_or_default(failure_message);
99
100 self.services.add(transient_factory(move |sp| {
101 let validate: Ref<dyn Validate<T>> = Ref::new($struct_name {
102 name: name.clone(),
103 action: action.clone(),
104 failure_message: failure_message.clone(),
105 $f1: sp.get_required::<$d1>(),
106 _type: PhantomData,
107 });
108 validate
109 }));
110
111 self
112 }
113 };
114 (($($bounds:tt)+), $method:ident, $struct_name:ident, ($d1:ident, $f1:ident), ($d2:ident, $f2:ident)) => {
115 pub fn $method<F, M, $d1, $d2>(self, action: F, failure_message: M) -> Self
122 where
123 F: Fn(&T, Svc<$d1>, Svc<$d2>) -> bool + $($bounds)+,
124 M: AsRef<str>,
125 $d1: $($bounds)+,
126 $d2: $($bounds)+,
127 {
128 let action = Ref::new(action);
129 let name = self.name.clone();
130 let failure_message = message_or_default(failure_message);
131
132 self.services.add(transient_factory(move |sp| {
133 let validate: Ref<dyn Validate<T>> = Ref::new($struct_name {
134 name: name.clone(),
135 action: action.clone(),
136 failure_message: failure_message.clone(),
137 $f1: sp.get_required::<$d1>(),
138 $f2: sp.get_required::<$d2>(),
139 _type: PhantomData,
140 });
141 validate
142 }));
143
144 self
145 }
146 };
147 (($($bounds:tt)+), $method:ident, $struct_name:ident, ($d1:ident, $f1:ident), ($d2:ident, $f2:ident), ($d3:ident, $f3:ident)) => {
148 pub fn $method<F, M, $d1, $d2, $d3>(self, action: F, failure_message: M) -> Self
155 where
156 F: Fn(&T, Svc<$d1>, Svc<$d2>, Svc<$d3>) -> bool + $($bounds)+,
157 M: AsRef<str>,
158 $d1: $($bounds)+,
159 $d2: $($bounds)+,
160 $d3: $($bounds)+,
161 {
162 let action = Ref::new(action);
163 let name = self.name.clone();
164 let failure_message = message_or_default(failure_message);
165
166 self.services.add(transient_factory(move |sp| {
167 let validate: Ref<dyn Validate<T>> = Ref::new($struct_name {
168 name: name.clone(),
169 action: action.clone(),
170 failure_message: failure_message.clone(),
171 $f1: sp.get_required::<$d1>(),
172 $f2: sp.get_required::<$d2>(),
173 $f3: sp.get_required::<$d3>(),
174 _type: PhantomData,
175 });
176 validate
177 }));
178
179 self
180 }
181 };
182 (($($bounds:tt)+), $method:ident, $struct_name:ident, ($d1:ident, $f1:ident), ($d2:ident, $f2:ident), ($d3:ident, $f3:ident), ($d4:ident, $f4:ident)) => {
183 pub fn $method<F, M, $d1, $d2, $d3, $d4>(self, action: F, failure_message: M) -> Self
190 where
191 F: Fn(&T, Svc<$d1>, Svc<$d2>, Svc<$d3>, Svc<$d4>) -> bool + $($bounds)+,
192 M: AsRef<str>,
193 $d1: $($bounds)+,
194 $d2: $($bounds)+,
195 $d3: $($bounds)+,
196 $d4: $($bounds)+,
197 {
198 let action = Ref::new(action);
199 let name = self.name.clone();
200 let failure_message = message_or_default(failure_message);
201
202 self.services.add(transient_factory(move |sp| {
203 let validate: Ref<dyn Validate<T>> = Ref::new($struct_name {
204 name: name.clone(),
205 action: action.clone(),
206 failure_message: failure_message.clone(),
207 $f1: sp.get_required::<$d1>(),
208 $f2: sp.get_required::<$d2>(),
209 $f3: sp.get_required::<$d3>(),
210 $f4: sp.get_required::<$d4>(),
211 _type: PhantomData,
212 });
213 validate
214 }));
215
216 self
217 }
218 };
219 (($($bounds:tt)+), $method:ident, $struct_name:ident, ($d1:ident, $f1:ident), ($d2:ident, $f2:ident), ($d3:ident, $f3:ident), ($d4:ident, $f4:ident), ($d5:ident, $f5:ident)) => {
220 pub fn $method<F, M, $d1, $d2, $d3, $d4, $d5>(self, action: F, failure_message: M) -> Self
227 where
228 F: Fn(&T, Svc<$d1>, Svc<$d2>, Svc<$d3>, Svc<$d4>, Svc<$d5>) -> bool + $($bounds)+,
229 M: AsRef<str>,
230 $d1: $($bounds)+,
231 $d2: $($bounds)+,
232 $d3: $($bounds)+,
233 $d4: $($bounds)+,
234 $d5: $($bounds)+,
235 {
236 let action = Ref::new(action);
237 let name = self.name.clone();
238 let failure_message = message_or_default(failure_message);
239
240 self.services.add(transient_factory(move |sp| {
241 let validate: Ref<dyn Validate<T>> = Ref::new($struct_name {
242 name: name.clone(),
243 action: action.clone(),
244 failure_message: failure_message.clone(),
245 $f1: sp.get_required::<$d1>(),
246 $f2: sp.get_required::<$d2>(),
247 $f3: sp.get_required::<$d3>(),
248 $f4: sp.get_required::<$d4>(),
249 $f5: sp.get_required::<$d5>(),
250 _type: PhantomData,
251 });
252 validate
253 }));
254
255 self
256 }
257 };
258}
259
260macro_rules! validate_methods {
261 (($($bounds:tt)+)) => {
262 impl<'a, T: $($bounds)+> Builder<'a, T> {
263 pub fn validate<F, M>(self, action: F, failure_message: M) -> Self
270 where
271 F: Fn(&T) -> bool + $($bounds)+,
272 M: AsRef<str>,
273 {
274 let action = Ref::new(action);
275 let name = self.name.clone();
276 let failure_message = message_or_default(failure_message);
277
278 self.services.add(transient_factory(move |_| {
279 let validate: Ref<dyn Validate<T>> = Ref::new(_Validate {
280 name: name.clone(),
281 action: action.clone(),
282 failure_message: failure_message.clone(),
283 _type: PhantomData,
284 });
285 validate
286 }));
287
288 self
289 }
290
291 validate_builder_method!(($($bounds)+), validate1, _Validate1, (D, dependency));
292 validate_builder_method!(($($bounds)+), validate2, _Validate2, (D1, dependency1), (D2, dependency2));
293 validate_builder_method!(($($bounds)+), validate3, _Validate3, (D1, dependency1), (D2, dependency2), (D3, dependency3));
294 validate_builder_method!(($($bounds)+), validate4, _Validate4, (D1, dependency1), (D2, dependency2), (D3, dependency3), (D4, dependency4));
295 validate_builder_method!(($($bounds)+), validate5, _Validate5, (D1, dependency1), (D2, dependency2), (D3, dependency3), (D4, dependency4), (D5, dependency5));
296 }
297 };
298}
299
300cfg_if! {
301 if #[cfg(feature = "async")] {
302 validate_impl!((Send + Sync + 'static), _Validate, validate, []);
303 validate_impl!((Send + Sync + 'static), _Validate1, validate1, [(TDep1, dependency)]);
304 validate_impl!((Send + Sync + 'static), _Validate2, validate2, [(TDep1, dependency1), (TDep2, dependency2)]);
305 validate_impl!((Send + Sync + 'static), _Validate3, validate3, [(TDep1, dependency1), (TDep2, dependency2), (TDep3, dependency3)]);
306 validate_impl!((Send + Sync + 'static), _Validate4, validate4, [(TDep1, dependency1), (TDep2, dependency2), (TDep3, dependency3), (TDep4, dependency4)]);
307 validate_impl!((Send + Sync + 'static), _Validate5, validate5, [(TDep1, dependency1), (TDep2, dependency2), (TDep3, dependency3), (TDep4, dependency4), (TDep5, dependency5)]);
308 validate_methods!((Send + Sync + 'static));
309 } else {
310 validate_impl!(('static), _Validate, validate, []);
311 validate_impl!(('static), _Validate1, validate1, [(TDep1, dependency)]);
312 validate_impl!(('static), _Validate2, validate2, [(TDep1, dependency1), (TDep2, dependency2)]);
313 validate_impl!(('static), _Validate3, validate3, [(TDep1, dependency1), (TDep2, dependency2), (TDep3, dependency3)]);
314 validate_impl!(('static), _Validate4, validate4, [(TDep1, dependency1), (TDep2, dependency2), (TDep3, dependency3), (TDep4, dependency4)]);
315 validate_impl!(('static), _Validate5, validate5, [(TDep1, dependency1), (TDep2, dependency2), (TDep3, dependency3), (TDep4, dependency4), (TDep5, dependency5)]);
316 validate_methods!(('static));
317 }
318}