tanzim_validate/
enumeration.rs1use crate::error::{Error, ErrorKind};
2use crate::{Meta, Validator};
3use tanzim_value::Value;
4
5#[derive(Debug, Clone, Default)]
8pub struct Enum {
9 meta: Meta,
10 allowed: Vec<Value>,
11 case_insensitive: bool,
12}
13
14impl Enum {
15 pub fn with_meta(mut self, meta: Meta) -> Self {
17 self.meta = meta;
18 self
19 }
20
21 pub fn new(values: impl IntoIterator<Item = Value>) -> Self {
23 let mut allowed = Vec::new();
24 for value in values {
25 allowed.push(value);
26 }
27 Self {
28 meta: Meta::default(),
29 allowed,
30 case_insensitive: false,
31 }
32 }
33
34 pub fn case_insensitive(mut self) -> Self {
36 self.case_insensitive = true;
37 self
38 }
39}
40
41crate::impl_meta_methods!(Enum);
42
43impl Validator for Enum {
44 fn meta(&self) -> &Meta {
45 &self.meta
46 }
47
48 fn meta_mut(&mut self) -> &mut Meta {
49 &mut self.meta
50 }
51
52 fn check(&self, value: &mut Value) -> Result<(), Error> {
53 for candidate in &self.allowed {
54 let matches = match (candidate, &*value) {
55 (Value::String(allowed), Value::String(actual)) if self.case_insensitive => {
56 allowed.eq_ignore_ascii_case(actual)
57 }
58 (allowed, actual) => allowed == actual,
59 };
60 if matches {
61 return Ok(());
62 }
63 }
64
65 Err(Error::new(ErrorKind::NotAllowed {
66 value: value.to_string(),
67 }))
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn string_membership() {
77 let validator = Enum::new([Value::String("debug".into()), Value::String("info".into())]);
78 assert!(
79 validator
80 .validate(&mut Value::String("info".into()))
81 .is_ok()
82 );
83 let error = validator
84 .validate(&mut Value::String("trace".into()))
85 .unwrap_err();
86 assert!(matches!(error.kind, ErrorKind::NotAllowed { .. }));
87 }
88
89 #[test]
90 fn accepts_non_string_types() {
91 let validator = Enum::new([Value::Int(1), Value::Int(2), Value::Bool(true)]);
92 assert!(validator.validate(&mut Value::Int(2)).is_ok());
93 assert!(validator.validate(&mut Value::Bool(true)).is_ok());
94 assert!(validator.validate(&mut Value::Int(3)).is_err());
95 }
96
97 #[test]
98 fn case_insensitive_strings() {
99 let validator = Enum::new([Value::String("Info".into())]).case_insensitive();
100 assert!(
101 validator
102 .validate(&mut Value::String("INFO".into()))
103 .is_ok()
104 );
105 }
106}