darklua_core/rules/
rule_property.rsuse std::collections::HashMap;
use regex::Regex;
use serde::{Deserialize, Serialize};
use super::{require::PathRequireMode, RequireMode, RobloxRequireMode, RuleConfigurationError};
pub type RuleProperties = HashMap<String, RulePropertyValue>;
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(untagged, rename_all = "snake_case")]
pub enum RulePropertyValue {
Boolean(bool),
String(String),
Usize(usize),
Float(f64),
StringList(Vec<String>),
RequireMode(RequireMode),
None,
}
impl RulePropertyValue {
pub(crate) fn expect_bool(self, key: &str) -> Result<bool, RuleConfigurationError> {
if let Self::Boolean(value) = self {
Ok(value)
} else {
Err(RuleConfigurationError::BooleanExpected(key.to_owned()))
}
}
pub(crate) fn expect_string(self, key: &str) -> Result<String, RuleConfigurationError> {
if let Self::String(value) = self {
Ok(value)
} else {
Err(RuleConfigurationError::StringExpected(key.to_owned()))
}
}
pub(crate) fn expect_string_list(
self,
key: &str,
) -> Result<Vec<String>, RuleConfigurationError> {
if let Self::StringList(value) = self {
Ok(value)
} else {
Err(RuleConfigurationError::StringListExpected(key.to_owned()))
}
}
pub(crate) fn expect_regex_list(self, key: &str) -> Result<Vec<Regex>, RuleConfigurationError> {
if let Self::StringList(value) = self {
value
.into_iter()
.map(|regex_str| {
Regex::new(®ex_str).map_err(|err| RuleConfigurationError::UnexpectedValue {
property: key.to_owned(),
message: format!("invalid regex provided `{}`\n {}", regex_str, err),
})
})
.collect()
} else {
Err(RuleConfigurationError::StringListExpected(key.to_owned()))
}
}
pub(crate) fn expect_require_mode(
self,
key: &str,
) -> Result<RequireMode, RuleConfigurationError> {
match self {
Self::RequireMode(require_mode) => Ok(require_mode),
Self::String(value) => {
value
.parse()
.map_err(|err: String| RuleConfigurationError::UnexpectedValue {
property: key.to_owned(),
message: err,
})
}
_ => Err(RuleConfigurationError::RequireModeExpected(key.to_owned())),
}
}
}
impl From<bool> for RulePropertyValue {
fn from(value: bool) -> Self {
Self::Boolean(value)
}
}
impl From<&str> for RulePropertyValue {
fn from(value: &str) -> Self {
Self::String(value.to_owned())
}
}
impl From<&String> for RulePropertyValue {
fn from(value: &String) -> Self {
Self::String(value.to_owned())
}
}
impl From<String> for RulePropertyValue {
fn from(value: String) -> Self {
Self::String(value)
}
}
impl From<usize> for RulePropertyValue {
fn from(value: usize) -> Self {
Self::Usize(value)
}
}
impl From<f64> for RulePropertyValue {
fn from(value: f64) -> Self {
Self::Float(value)
}
}
impl From<&RequireMode> for RulePropertyValue {
fn from(value: &RequireMode) -> Self {
match value {
RequireMode::Path(mode) => {
if mode == &PathRequireMode::default() {
return Self::from("path");
}
}
RequireMode::Roblox(mode) => {
if mode == &RobloxRequireMode::default() {
return Self::from("roblox");
}
}
}
Self::RequireMode(value.clone())
}
}
impl<T: Into<RulePropertyValue>> From<Option<T>> for RulePropertyValue {
fn from(value: Option<T>) -> Self {
match value {
Some(value) => value.into(),
None => Self::None,
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn from_true() {
assert_eq!(
RulePropertyValue::from(true),
RulePropertyValue::Boolean(true)
);
}
#[test]
fn from_false() {
assert_eq!(
RulePropertyValue::from(false),
RulePropertyValue::Boolean(false)
);
}
#[test]
fn from_string() {
assert_eq!(
RulePropertyValue::from(String::from("hello")),
RulePropertyValue::String(String::from("hello"))
);
}
#[test]
fn from_string_ref() {
assert_eq!(
RulePropertyValue::from(&String::from("hello")),
RulePropertyValue::String(String::from("hello"))
);
}
#[test]
fn from_str() {
assert_eq!(
RulePropertyValue::from("hello"),
RulePropertyValue::String(String::from("hello"))
);
}
#[test]
fn from_usize() {
assert_eq!(RulePropertyValue::from(6), RulePropertyValue::Usize(6));
}
#[test]
fn from_float() {
assert_eq!(RulePropertyValue::from(1.0), RulePropertyValue::Float(1.0));
}
#[test]
fn from_boolean_option_some() {
let bool = Some(true);
assert_eq!(
RulePropertyValue::from(bool),
RulePropertyValue::Boolean(true)
);
}
#[test]
fn from_boolean_option_none() {
let bool: Option<bool> = None;
assert_eq!(RulePropertyValue::from(bool), RulePropertyValue::None);
}
}