1use std::fmt;
23/// 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.
8UnexpectedProperty(String),
9/// When a rule has a required property. The string should be the field name.
10MissingProperty(String),
11/// When a rule must define at least one property in a given set.
12MissingAnyProperty(Vec<String>),
13/// When a property is associated with something else than an expected boolean. The string is
14 /// the property name.
15BooleanExpected(String),
16/// When a property is associated with something else than an expected string. The string is
17 /// the property name.
18StringExpected(String),
19/// When a property is associated with something else than an expected unsigned number. The
20 /// string is the property name.
21UsizeExpected(String),
22/// When a property is associated with something else than an expected float. The string is the
23 /// property name.
24FloatExpected(String),
25/// When a property is associated with something else than an expected list of strings. The
26 /// string is the property name.
27StringListExpected(String),
28/// When a property is associated with something else than an expected require mode. The
29 /// string is the property name.
30RequireModeExpected(String),
31/// When the value type is invalid. The string is the property name that was given the wrong
32 /// value type.
33UnexpectedValueType(String),
34/// When the value is invalid.
35UnexpectedValue { property: String, message: String },
36/// When a rule cannot have multiple properties defined at the same time.
37PropertyCollision(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)
40InternalUsageOnly(String),
41}
4243fn enumerate_properties(properties: &[String]) -> String {
44let last_index = properties.len().saturating_sub(1);
45 properties
46 .iter()
47 .enumerate()
48 .map(|(i, name)| {
49if i == 0 {
50format!("`{}`", name)
51 } else if i == last_index {
52format!(" and `{}`", name)
53 } else {
54format!(", `{}`", name)
55 }
56 })
57 .collect()
58}
5960impl fmt::Display for RuleConfigurationError {
61fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62use RuleConfigurationError::*;
6364match 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) => {
73write!(f, "boolean value expected for field '{}'", property)
74 }
75 StringExpected(property) => write!(f, "string value expected for field '{}'", property),
76 UsizeExpected(property) => {
77write!(f, "unsigned integer expected for field '{}'", property)
78 }
79 FloatExpected(property) => write!(f, "float value expected for field '{}'", property),
80 StringListExpected(property) => {
81write!(f, "list of string expected for field '{}'", property)
82 }
83 RequireModeExpected(property) => {
84write!(f, "require mode value expected for field `{}`", property)
85 }
86 UnexpectedValueType(property) => write!(f, "unexpected type for field '{}'", property),
87 UnexpectedValue { property, message } => {
88write!(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) => {
96write!(
97 f,
98"usage of rule `{}` is reserved for darklua internal processing",
99 rule_name
100 )
101 }
102 }
103 }
104}
105106#[cfg(test)]
107mod test {
108use super::*;
109110#[test]
111fn enumerate_one_property() {
112assert_eq!(enumerate_properties(&["prop".to_owned()]), "`prop`")
113 }
114115#[test]
116fn enumerate_two_properties() {
117assert_eq!(
118 enumerate_properties(&["prop".to_owned(), "prop2".to_owned()]),
119"`prop` and `prop2`"
120)
121 }
122123#[test]
124fn enumerate_three_properties() {
125assert_eq!(
126 enumerate_properties(&["prop".to_owned(), "prop2".to_owned(), "prop3".to_owned()]),
127"`prop`, `prop2` and `prop3`"
128)
129 }
130}