use super::context::EvaluationContext;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ConditionResult {
True,
False,
Unknown,
}
impl ConditionResult {
pub fn is_true(self) -> bool {
matches!(self, ConditionResult::True)
}
pub fn is_false(self) -> bool {
matches!(self, ConditionResult::False)
}
pub fn is_unknown(self) -> bool {
matches!(self, ConditionResult::Unknown)
}
pub fn to_option(self) -> Option<bool> {
match self {
ConditionResult::True => Some(true),
ConditionResult::False => Some(false),
ConditionResult::Unknown => None,
}
}
}
impl From<bool> for ConditionResult {
fn from(value: bool) -> Self {
if value {
ConditionResult::True
} else {
ConditionResult::False
}
}
}
impl std::fmt::Display for ConditionResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ConditionResult::True => write!(f, "True"),
ConditionResult::False => write!(f, "False"),
ConditionResult::Unknown => write!(f, "Unknown"),
}
}
}
pub trait ConditionEvaluator: Send + Sync {
fn evaluate(&self, condition: u32, ctx: &EvaluationContext) -> ConditionResult;
fn is_external(&self, condition: u32) -> bool;
fn is_known(&self, _condition: u32) -> bool {
false
}
fn message_type(&self) -> &str;
fn format_version(&self) -> &str;
}
impl<T: ConditionEvaluator + ?Sized> ConditionEvaluator for std::sync::Arc<T> {
fn evaluate(&self, condition: u32, ctx: &EvaluationContext) -> ConditionResult {
(**self).evaluate(condition, ctx)
}
fn is_external(&self, condition: u32) -> bool {
(**self).is_external(condition)
}
fn is_known(&self, condition: u32) -> bool {
(**self).is_known(condition)
}
fn message_type(&self) -> &str {
(**self).message_type()
}
fn format_version(&self) -> &str {
(**self).format_version()
}
}
pub trait ExternalConditionProvider: Send + Sync {
fn evaluate(&self, condition_name: &str) -> ConditionResult;
}
pub struct NoOpExternalProvider;
impl ExternalConditionProvider for NoOpExternalProvider {
fn evaluate(&self, _condition_name: &str) -> ConditionResult {
ConditionResult::Unknown
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_condition_result_is_methods() {
assert!(ConditionResult::True.is_true());
assert!(!ConditionResult::True.is_false());
assert!(!ConditionResult::True.is_unknown());
assert!(!ConditionResult::False.is_true());
assert!(ConditionResult::False.is_false());
assert!(ConditionResult::Unknown.is_unknown());
}
#[test]
fn test_condition_result_to_option() {
assert_eq!(ConditionResult::True.to_option(), Some(true));
assert_eq!(ConditionResult::False.to_option(), Some(false));
assert_eq!(ConditionResult::Unknown.to_option(), None);
}
#[test]
fn test_condition_result_from_bool() {
assert_eq!(ConditionResult::from(true), ConditionResult::True);
assert_eq!(ConditionResult::from(false), ConditionResult::False);
}
#[test]
fn test_condition_result_display() {
assert_eq!(format!("{}", ConditionResult::True), "True");
assert_eq!(format!("{}", ConditionResult::False), "False");
assert_eq!(format!("{}", ConditionResult::Unknown), "Unknown");
}
#[test]
fn test_noop_external_provider() {
let provider = NoOpExternalProvider;
assert_eq!(
provider.evaluate("MessageSplitting"),
ConditionResult::Unknown
);
assert_eq!(provider.evaluate("anything"), ConditionResult::Unknown);
}
}