tanzim_validate/
either.rs1use crate::error::{Error, ErrorKind};
2use crate::{Meta, Validator};
3use tanzim_value::Value;
4
5pub struct Either {
12 meta: Meta,
13 first: Box<dyn Validator>,
14 second: Box<dyn Validator>,
15}
16
17impl Either {
18 pub fn with_meta(mut self, meta: Meta) -> Self {
20 self.meta = meta;
21 self
22 }
23
24 pub fn new(
25 first: impl Into<Box<dyn Validator>>,
26 second: impl Into<Box<dyn Validator>>,
27 ) -> Self {
28 Self {
29 meta: Meta::default(),
30 first: first.into(),
31 second: second.into(),
32 }
33 }
34}
35
36crate::impl_meta_methods!(Either);
37
38impl Validator for Either {
39 fn meta(&self) -> &Meta {
40 &self.meta
41 }
42
43 fn meta_mut(&mut self) -> &mut Meta {
44 &mut self.meta
45 }
46
47 fn check(&self, value: &mut Value) -> Result<(), Error> {
48 let mut candidate = value.clone();
51 let first_error = match self.first.validate(&mut candidate) {
52 Ok(()) => {
53 *value = candidate;
54 return Ok(());
55 }
56 Err(error) => error,
57 };
58
59 let mut candidate = value.clone();
60 let second_error = match self.second.validate(&mut candidate) {
61 Ok(()) => {
62 *value = candidate;
63 return Ok(());
64 }
65 Err(error) => error,
66 };
67
68 Err(Error::new(ErrorKind::Either {
69 first: Box::new(first_error),
70 second: Box::new(second_error),
71 }))
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78 use crate::{Bool, Integer};
79
80 #[test]
81 fn accepts_when_either_matches() {
82 let validator = Either::new(Integer::new(), Bool::new());
83 assert!(validator.validate(&mut Value::Int(3)).is_ok());
84 assert!(validator.validate(&mut Value::Bool(true)).is_ok());
85 }
86
87 #[test]
88 fn commits_coercion_of_winning_branch() {
89 let validator = Either::new(Integer::new(), Bool::new());
90 let mut value = Value::String("5".into());
91 validator.validate(&mut value).unwrap();
92 assert_eq!(value, Value::Int(5));
93 }
94
95 #[test]
96 fn original_value_preserved_for_second_attempt() {
97 let validator = Either::new(Integer::new(), Bool::new());
100 let mut value = Value::Bool(true);
101 validator.validate(&mut value).unwrap();
102 assert_eq!(value, Value::Bool(true));
103 }
104
105 #[test]
106 fn combines_errors_when_both_fail() {
107 let validator = Either::new(Bool::new(), Integer::new());
108 let mut value = Value::String("nope".into());
109 let error = validator.validate(&mut value).unwrap_err();
110 assert!(matches!(error.kind, ErrorKind::Either { .. }));
111 assert_eq!(value, Value::String("nope".into()));
113 }
114}