darklua_core/rules/
configuration_error.rs

1use std::fmt;
2
3/// When implementing the configure method of the Rule trait, the method returns a result that uses
4/// this error type.
5#[derive(Debug, Clone, Eq, PartialEq)]
6pub enum RuleConfigurationError {
7    /// When a rule gets an unknown property. The string should be the unknown field name.
8    UnexpectedProperty(String),
9    /// When a rule has a required property. The string should be the field name.
10    MissingProperty(String),
11    /// When a rule must define at least one property in a given set.
12    MissingAnyProperty(Vec<String>),
13    /// When a property is associated with something else than an expected boolean. The string is
14    /// the property name.
15    BooleanExpected(String),
16    /// When a property is associated with something else than an expected string. The string is
17    /// the property name.
18    StringExpected(String),
19    /// When a property is associated with something else than an expected unsigned number. The
20    /// string is the property name.
21    UsizeExpected(String),
22    /// When a property is associated with something else than an expected float. The string is the
23    /// property name.
24    FloatExpected(String),
25    /// When a property is associated with something else than an expected list of strings. The
26    /// string is the property name.
27    StringListExpected(String),
28    /// When a property is associated with something else than an expected require mode. The
29    /// string is the property name.
30    RequireModeExpected(String),
31    /// When the value type is invalid. The string is the property name that was given the wrong
32    /// value type.
33    UnexpectedValueType(String),
34    /// When the value is invalid.
35    UnexpectedValue { property: String, message: String },
36    /// When a rule cannot have multiple properties defined at the same time.
37    PropertyCollision(Vec<String>),
38    /// When a rule can only be used internally by darklua. The string is the rule name
39    /// (this error should not surface to external consumers)
40    InternalUsageOnly(String),
41}
42
43fn enumerate_properties(properties: &[String]) -> String {
44    let last_index = properties.len().saturating_sub(1);
45    properties
46        .iter()
47        .enumerate()
48        .map(|(i, name)| {
49            if i == 0 {
50                format!("`{}`", name)
51            } else if i == last_index {
52                format!(" and `{}`", name)
53            } else {
54                format!(", `{}`", name)
55            }
56        })
57        .collect()
58}
59
60impl fmt::Display for RuleConfigurationError {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        use RuleConfigurationError::*;
63
64        match self {
65            UnexpectedProperty(property) => write!(f, "unexpected field '{}'", property),
66            MissingProperty(property) => write!(f, "missing required field '{}'", property),
67            MissingAnyProperty(properties) => write!(
68                f,
69                "missing one field from {}",
70                enumerate_properties(properties)
71            ),
72            BooleanExpected(property) => {
73                write!(f, "boolean value expected for field '{}'", property)
74            }
75            StringExpected(property) => write!(f, "string value expected for field '{}'", property),
76            UsizeExpected(property) => {
77                write!(f, "unsigned integer expected for field '{}'", property)
78            }
79            FloatExpected(property) => write!(f, "float value expected for field '{}'", property),
80            StringListExpected(property) => {
81                write!(f, "list of string expected for field '{}'", property)
82            }
83            RequireModeExpected(property) => {
84                write!(f, "require mode value expected for field `{}`", property)
85            }
86            UnexpectedValueType(property) => write!(f, "unexpected type for field '{}'", property),
87            UnexpectedValue { property, message } => {
88                write!(f, "unexpected value for field '{}': {}", property, message)
89            }
90            PropertyCollision(properties) => write!(
91                f,
92                "the fields {} cannot be defined together",
93                enumerate_properties(properties)
94            ),
95            InternalUsageOnly(rule_name) => {
96                write!(
97                    f,
98                    "usage of rule `{}` is reserved for darklua internal processing",
99                    rule_name
100                )
101            }
102        }
103    }
104}
105
106#[cfg(test)]
107mod test {
108    use super::*;
109
110    #[test]
111    fn enumerate_one_property() {
112        assert_eq!(enumerate_properties(&["prop".to_owned()]), "`prop`")
113    }
114
115    #[test]
116    fn enumerate_two_properties() {
117        assert_eq!(
118            enumerate_properties(&["prop".to_owned(), "prop2".to_owned()]),
119            "`prop` and `prop2`"
120        )
121    }
122
123    #[test]
124    fn enumerate_three_properties() {
125        assert_eq!(
126            enumerate_properties(&["prop".to_owned(), "prop2".to_owned(), "prop3".to_owned()]),
127            "`prop`, `prop2` and `prop3`"
128        )
129    }
130}