darklua_core/rules/
rule_property.rs1use std::collections::HashMap;
2
3use regex::Regex;
4use serde::{Deserialize, Serialize};
5
6use super::{require::PathRequireMode, RequireMode, RobloxRequireMode, RuleConfigurationError};
7
8pub type RuleProperties = HashMap<String, RulePropertyValue>;
9
10#[derive(Debug, Serialize, Deserialize, PartialEq)]
13#[serde(untagged, rename_all = "snake_case")]
14pub enum RulePropertyValue {
15 Boolean(bool),
16 String(String),
17 Usize(usize),
18 Float(f64),
19 StringList(Vec<String>),
20 RequireMode(RequireMode),
21 None,
22}
23
24impl RulePropertyValue {
25 pub(crate) fn expect_bool(self, key: &str) -> Result<bool, RuleConfigurationError> {
26 if let Self::Boolean(value) = self {
27 Ok(value)
28 } else {
29 Err(RuleConfigurationError::BooleanExpected(key.to_owned()))
30 }
31 }
32
33 pub(crate) fn expect_string(self, key: &str) -> Result<String, RuleConfigurationError> {
34 if let Self::String(value) = self {
35 Ok(value)
36 } else {
37 Err(RuleConfigurationError::StringExpected(key.to_owned()))
38 }
39 }
40
41 pub(crate) fn expect_string_list(
42 self,
43 key: &str,
44 ) -> Result<Vec<String>, RuleConfigurationError> {
45 if let Self::StringList(value) = self {
46 Ok(value)
47 } else {
48 Err(RuleConfigurationError::StringListExpected(key.to_owned()))
49 }
50 }
51
52 pub(crate) fn expect_regex_list(self, key: &str) -> Result<Vec<Regex>, RuleConfigurationError> {
53 if let Self::StringList(value) = self {
54 value
55 .into_iter()
56 .map(|regex_str| {
57 Regex::new(®ex_str).map_err(|err| RuleConfigurationError::UnexpectedValue {
58 property: key.to_owned(),
59 message: format!("invalid regex provided `{}`\n {}", regex_str, err),
60 })
61 })
62 .collect()
63 } else {
64 Err(RuleConfigurationError::StringListExpected(key.to_owned()))
65 }
66 }
67
68 pub(crate) fn expect_require_mode(
69 self,
70 key: &str,
71 ) -> Result<RequireMode, RuleConfigurationError> {
72 match self {
73 Self::RequireMode(require_mode) => Ok(require_mode),
74 Self::String(value) => {
75 value
76 .parse()
77 .map_err(|err: String| RuleConfigurationError::UnexpectedValue {
78 property: key.to_owned(),
79 message: err,
80 })
81 }
82 _ => Err(RuleConfigurationError::RequireModeExpected(key.to_owned())),
83 }
84 }
85}
86
87impl From<bool> for RulePropertyValue {
88 fn from(value: bool) -> Self {
89 Self::Boolean(value)
90 }
91}
92
93impl From<&str> for RulePropertyValue {
94 fn from(value: &str) -> Self {
95 Self::String(value.to_owned())
96 }
97}
98
99impl From<&String> for RulePropertyValue {
100 fn from(value: &String) -> Self {
101 Self::String(value.to_owned())
102 }
103}
104
105impl From<String> for RulePropertyValue {
106 fn from(value: String) -> Self {
107 Self::String(value)
108 }
109}
110
111impl From<usize> for RulePropertyValue {
112 fn from(value: usize) -> Self {
113 Self::Usize(value)
114 }
115}
116
117impl From<f64> for RulePropertyValue {
118 fn from(value: f64) -> Self {
119 Self::Float(value)
120 }
121}
122
123impl From<&RequireMode> for RulePropertyValue {
124 fn from(value: &RequireMode) -> Self {
125 match value {
126 RequireMode::Path(mode) => {
127 if mode == &PathRequireMode::default() {
128 return Self::from("path");
129 }
130 }
131 RequireMode::Roblox(mode) => {
132 if mode == &RobloxRequireMode::default() {
133 return Self::from("roblox");
134 }
135 }
136 }
137
138 Self::RequireMode(value.clone())
139 }
140}
141
142impl<T: Into<RulePropertyValue>> From<Option<T>> for RulePropertyValue {
143 fn from(value: Option<T>) -> Self {
144 match value {
145 Some(value) => value.into(),
146 None => Self::None,
147 }
148 }
149}
150
151#[cfg(test)]
152mod test {
153 use super::*;
154
155 #[test]
156 fn from_true() {
157 assert_eq!(
158 RulePropertyValue::from(true),
159 RulePropertyValue::Boolean(true)
160 );
161 }
162
163 #[test]
164 fn from_false() {
165 assert_eq!(
166 RulePropertyValue::from(false),
167 RulePropertyValue::Boolean(false)
168 );
169 }
170
171 #[test]
172 fn from_string() {
173 assert_eq!(
174 RulePropertyValue::from(String::from("hello")),
175 RulePropertyValue::String(String::from("hello"))
176 );
177 }
178
179 #[test]
180 fn from_string_ref() {
181 assert_eq!(
182 RulePropertyValue::from(&String::from("hello")),
183 RulePropertyValue::String(String::from("hello"))
184 );
185 }
186
187 #[test]
188 fn from_str() {
189 assert_eq!(
190 RulePropertyValue::from("hello"),
191 RulePropertyValue::String(String::from("hello"))
192 );
193 }
194
195 #[test]
196 fn from_usize() {
197 assert_eq!(RulePropertyValue::from(6), RulePropertyValue::Usize(6));
198 }
199
200 #[test]
201 fn from_float() {
202 assert_eq!(RulePropertyValue::from(1.0), RulePropertyValue::Float(1.0));
203 }
204
205 #[test]
206 fn from_boolean_option_some() {
207 let bool = Some(true);
208 assert_eq!(
209 RulePropertyValue::from(bool),
210 RulePropertyValue::Boolean(true)
211 );
212 }
213
214 #[test]
215 fn from_boolean_option_none() {
216 let bool: Option<bool> = None;
217 assert_eq!(RulePropertyValue::from(bool), RulePropertyValue::None);
218 }
219}