1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4
5use crate::{rule::IntoRuleList, ser::Serializer, Validatable, Value, ValueMap};
6
7use super::{field_name, FieldNames, InnerValidator, IntoFieldName, MessageKey, ValidatorError};
8
9pub trait IntoMessage {
10 fn into_message(rule: &'static str, field: &FieldNames, value: &Value) -> Self;
11}
12
13type CoreValidator<'v> = InnerValidator<String, HashMap<FieldNames, HashMap<&'v str, &'v str>>>;
14
15#[derive(Default, Clone)]
97pub struct ValidPhrase<'v>(CoreValidator<'v>);
98
99impl<'v> ValidPhrase<'v> {
100 pub fn new() -> Self {
102 Self::default()
103 }
104
105 pub fn validate<T>(self, data: T) -> Result<(), ValidatorError<String>>
107 where
108 T: Serialize,
109 {
110 let value = data.serialize(Serializer).unwrap();
111
112 debug_assert!(self.0.exist_field(&value));
113
114 let mut value_map = ValueMap::new(value);
115
116 self.inner_validate(&mut value_map).ok()
117 }
118
119 pub fn validate_mut<'de, T>(self, data: T) -> Result<T, ValidatorError<String>>
121 where
122 T: Serialize + serde::de::Deserialize<'de>,
123 {
124 let value = data.serialize(Serializer).unwrap();
125
126 debug_assert!(self.0.exist_field(&value));
127
128 let mut value_map = ValueMap::new(value);
129
130 self.inner_validate(&mut value_map)
131 .ok()
132 .map(|_| T::deserialize(value_map.value()).unwrap())
133 }
134
135 pub fn message<const N: usize>(mut self, list: [(&'v str, &'v str); N]) -> Self {
137 list.map(|(key_str, v)| {
138 let MessageKey { fields, rule } =
139 crate::panic_on_err!(field_name::parse_message(key_str));
140
141 debug_assert!(
142 self.0.rule_get(&fields).is_some(),
143 "the field \"{}\" not found in validator",
144 fields.as_str()
145 );
146 debug_assert!(
147 self.0.rule_get(&fields).unwrap().contains(rule),
148 "rule \"{rule}\" is not found in rules"
149 );
150
151 self.0
152 .message
153 .entry(fields)
154 .and_modify(|field| {
155 field
156 .entry(rule)
157 .and_modify(|msg| {
158 *msg = v;
159 })
160 .or_insert(v);
161 })
162 .or_insert({
163 let mut map = HashMap::new();
164 map.insert(rule, v);
165 map
166 });
167 });
168
169 Self(self.0)
170 }
171
172 pub fn rule<F, R>(self, field: F, rule: R) -> Self
181 where
182 F: IntoFieldName,
183 R: IntoRuleList<ValueMap, String>,
184 {
185 Self(self.0.rule(field, rule))
186 }
187
188 pub fn bail(self) -> Self {
190 Self(self.0.bail())
191 }
192
193 fn inner_validate(self, value_map: &mut ValueMap) -> ValidatorError<String> {
194 let mut resp_message = ValidatorError::with_capacity(self.0.rules.len());
195
196 let ValidPhrase(InnerValidator {
197 rules,
198 message,
199 is_bail,
200 }) = self;
201
202 let default_map = HashMap::new();
203
204 for (mut names, mut rules) in rules.into_iter() {
205 if is_bail {
206 rules.set_bail();
207 }
208
209 let msgs = message.get(&names).unwrap_or(&default_map);
210
211 value_map.index(names);
212
213 let field_msg = rules.call_string_message(value_map, msgs);
214
215 names = value_map.take_index();
216
217 resp_message.push(names, field_msg);
218
219 if is_bail && !resp_message.is_empty() {
220 resp_message.shrink_to(1);
221 return resp_message;
222 }
223 }
224
225 resp_message.shrink_to_fit();
226
227 resp_message
228 }
229}
230
231impl<'v, T> Validatable<ValidPhrase<'v>, ValidatorError<String>> for T
232where
233 T: Serialize,
234{
235 fn validate(&self, validator: ValidPhrase<'v>) -> Result<(), ValidatorError<String>> {
236 validator.validate(self)
237 }
238
239 fn validate_mut<'de>(self, validator: ValidPhrase<'v>) -> Result<Self, ValidatorError<String>>
240 where
241 Self: Deserialize<'de>,
242 {
243 validator.validate_mut(self)
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use std::marker::PhantomData;
250
251 use crate::{Rule, RuleExt};
252
253 use super::*;
254
255 #[derive(Clone, Copy)]
256 struct Required;
257
258 impl Rule for Required {
259 type Message = String;
260
261 const NAME: &'static str = "required";
262
263 fn message(&self) -> Self::Message {
264 "{field} is default msg".to_string()
265 }
266
267 fn call(&mut self, data: &mut Value) -> bool {
268 if *data == 8_i8 {
269 true
270 } else {
271 false
272 }
273 }
274 }
275
276 #[derive(Clone)]
277 struct StartWith(&'static str);
278
279 impl Rule for StartWith {
280 type Message = String;
281
282 fn call(&mut self, data: &mut Value) -> bool {
283 match data {
284 Value::String(s) => s.starts_with(self.0),
285 _ => false,
286 }
287 }
288 fn message(&self) -> Self::Message {
289 format!("this field must start with {}", self.0)
290 }
291
292 const NAME: &'static str = "starts_with";
293 }
294
295 #[test]
296 fn original() {
297 let num = (10_i8, 11_i8);
298
299 let validator = ValidPhrase::new()
300 .rule("0", Required)
301 .message([("0.required", "foo_message")]);
302
303 let res = validator.validate(num).unwrap_err();
304
305 let (filed, msg) = res.into_iter().next().unwrap();
306
307 assert_eq!(filed.as_str(), "0");
308
309 assert_eq!(msg[0], "foo_message");
310 }
311
312 #[test]
313 fn test_trait() {
314 let num = (10_i8, 11_i8);
315
316 let validator = ValidPhrase::new()
317 .rule("0", Required)
318 .message([("0.required", "foo_message")]);
319 num.validate(validator).unwrap_err();
320 }
321
322 #[test]
323 fn field() {
324 let num = (10_i8, 11_i8);
325
326 let validator = ValidPhrase::new()
327 .rule("0", Required)
328 .message([("0.required", "{field} is required")]);
329
330 let res = validator.validate(num).unwrap_err();
331
332 let (filed, msg) = res.into_iter().next().unwrap();
333
334 assert_eq!(filed.as_str(), "0");
335
336 assert_eq!(msg[0], "0 is required");
337 }
338
339 #[test]
340 fn default_field() {
341 let num = (10_i8, 11_i8);
342
343 let validator = ValidPhrase::new().rule("0", Required);
344
345 let res = validator.validate(num).unwrap_err();
346
347 let (filed, msg) = res.into_iter().next().unwrap();
348
349 assert_eq!(filed.as_str(), "0");
350
351 assert_eq!(msg[0], "0 is default msg");
352 }
353
354 #[test]
355 fn value() {
356 let num = (10_i8, 11_i8);
357
358 let validator = ValidPhrase::new()
359 .rule("0", Required)
360 .message([("0.required", "{value} is error value, 8 is true value")]);
361
362 let res = validator.validate(num).unwrap_err();
363
364 let (filed, msg) = res.into_iter().next().unwrap();
365
366 assert_eq!(filed.as_str(), "0");
367
368 assert_eq!(msg[0], "10 is error value, 8 is true value");
369 }
370
371 #[test]
372 fn message() {
373 let validator = ValidPhrase::new()
374 .rule("field1", Required.and(StartWith("foo")))
375 .rule("field2", Required.and(StartWith("foo2")))
376 .message([("field1.required", "msg1")]);
377 let message_list = validator.0.get_message();
378 assert_eq!(
379 message_list
380 .get(&("field1".into()))
381 .unwrap()
382 .get(&"required")
383 .unwrap(),
384 &"msg1"
385 );
386 assert_eq!(message_list.len(), 1);
387 assert_eq!(message_list.get(&("field1".into())).unwrap().len(), 1);
388
389 let validator2 = validator.clone().message([("field1.starts_with", "msg2")]);
390 let message_list2 = validator2.0.get_message();
391 assert_eq!(
392 message_list2
393 .get(&("field1".into()))
394 .unwrap()
395 .get(&"required")
396 .unwrap(),
397 &"msg1"
398 );
399 assert_eq!(
400 message_list2
401 .get(&("field1".into()))
402 .unwrap()
403 .get(&"starts_with")
404 .unwrap(),
405 &"msg2"
406 );
407 assert_eq!(message_list2.len(), 1);
408 assert_eq!(message_list2.get(&("field1".into())).unwrap().len(), 2);
409
410 let validator3 = validator2.clone().message([("field1.required", "msg3")]);
411 let message_list3 = validator3.0.get_message();
412 assert_eq!(
413 message_list3
414 .get(&("field1".into()))
415 .unwrap()
416 .get(&"required")
417 .unwrap(),
418 &"msg3"
419 );
420 assert_eq!(
421 message_list3
422 .get(&("field1".into()))
423 .unwrap()
424 .get(&"starts_with")
425 .unwrap(),
426 &"msg2"
427 );
428 assert_eq!(message_list3.len(), 1);
429 assert_eq!(message_list3.get(&("field1".into())).unwrap().len(), 2);
430 }
431}