use crate::{Context, Key, Ref, Value};
use crate::{Pending, rbe_error::RbeError};
use core::hash::Hash;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::fmt::{Display, Formatter};
use std::hash::Hasher;
#[derive(PartialEq, Eq, Hash, Clone, Serialize, Debug, Deserialize)]
pub enum MatchCond<K, V, R, Ctx>
where
K: Key,
V: Value,
R: Ref,
Ctx: Context,
{
Single(SingleCond<K, V, R, Ctx>),
Ref(R),
And(Vec<MatchCond<K, V, R, Ctx>>),
}
unsafe impl<K, V, R, Ctx> Sync for MatchCond<K, V, R, Ctx>
where
K: Key,
V: Value,
R: Ref,
Ctx: Context,
{
}
impl<K, V, R, Ctx> MatchCond<K, V, R, Ctx>
where
K: Key,
V: Value,
R: Ref,
Ctx: Context,
{
pub fn new() -> MatchCond<K, V, R, Ctx> {
MatchCond::Single(SingleCond::new())
}
pub fn and(conds: Vec<MatchCond<K, V, R, Ctx>>) -> MatchCond<K, V, R, Ctx> {
MatchCond::And(conds)
}
pub fn empty() -> MatchCond<K, V, R, Ctx> {
MatchCond::Single(SingleCond::new().with_name("empty"))
}
pub fn ref_(r: R) -> MatchCond<K, V, R, Ctx> {
MatchCond::Ref(r)
}
pub fn matches(&self, value: &V, ctx: &Ctx) -> Result<Pending<V, R>, RbeError<K, V, R, Ctx>> {
match self {
MatchCond::Single(single) => single.matches(value, ctx),
MatchCond::Ref(r) => Ok(Pending::from_pair(value.clone(), r.clone())),
MatchCond::And(vs) => vs.iter().try_fold(Pending::new(), |mut current, cond| {
let new_pending = cond.matches(value, ctx)?;
current.merge(new_pending);
Ok(current)
}),
}
}
pub fn single(single: SingleCond<K, V, R, Ctx>) -> Self {
MatchCond::Single(single)
}
pub fn simple(
name: &str,
cond: impl Fn(&V, &Ctx) -> Result<Pending<V, R>, RbeError<K, V, R, Ctx>> + Clone + 'static + Send + Sync,
) -> Self {
MatchCond::single(SingleCond::new().with_name(name).with_cond(cond))
}
pub fn show(&self) -> String {
format!("{}", self)
}
}
impl<K, V, R, Ctx> Display for MatchCond<K, V, R, Ctx>
where
K: Key,
V: Value,
R: Ref,
Ctx: Context,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
MatchCond::Single(sc) => {
write!(f, "{sc}")?;
Ok(())
},
MatchCond::Ref(r) => {
write!(f, "@{r}")?;
Ok(())
},
MatchCond::And(cs) => {
write!(f, "And(")?;
cs.iter().try_fold((), |_, c| write!(f, "|{c}"))?;
write!(f, ")")
},
}
}
}
impl<K, V, R, Ctx> Default for MatchCond<K, V, R, Ctx>
where
K: Key,
V: Value,
R: Ref,
Ctx: Context,
{
fn default() -> Self {
MatchCond::Single(SingleCond::default())
}
}
#[derive(Serialize, Deserialize)]
pub struct SingleCond<K, V, R, Ctx>
where
K: Hash + Eq + Display + Default,
V: Hash + Eq + Default + PartialEq + Clone,
R: Hash + Default + PartialEq + Clone,
Ctx: Hash + Default + PartialEq + Clone,
{
#[serde(skip_serializing_if = "Option::is_none")]
name: Option<String>,
#[serde(skip)]
cond: Vec<Box<dyn Cond<K, V, R, Ctx> + Send + Sync>>,
}
unsafe impl<K, V, R, Ctx> Sync for SingleCond<K, V, R, Ctx>
where
K: Key,
V: Value,
R: Ref,
Ctx: Context,
{
}
trait Cond<K, V, R, Ctx>: Send + Sync
where
K: Key,
V: Value,
R: Ref,
Ctx: Context,
{
fn clone_box(&self) -> Box<dyn Cond<K, V, R, Ctx> + Send + Sync>;
fn call(&self, v: &V, ctx: &Ctx) -> Result<Pending<V, R>, RbeError<K, V, R, Ctx>>;
}
impl<K, V, R, F, Ctx> Cond<K, V, R, Ctx> for F
where
K: Key,
V: Value,
R: Ref,
Ctx: Context,
F: 'static + Fn(&V, &Ctx) -> Result<Pending<V, R>, RbeError<K, V, R, Ctx>> + Clone + Send + Sync,
{
fn clone_box(&self) -> Box<dyn Cond<K, V, R, Ctx> + Send + Sync> {
Box::new(self.clone())
}
fn call(&self, v: &V, ctx: &Ctx) -> Result<Pending<V, R>, RbeError<K, V, R, Ctx>> {
self(v, ctx)
}
}
impl<K, V, R, Ctx> Clone for Box<dyn Cond<K, V, R, Ctx> + Send + Sync>
where
K: Key,
V: Value,
R: Ref,
Ctx: Context,
{
fn clone(&self) -> Self {
self.clone_box()
}
}
impl<K, V, R, Ctx> Clone for SingleCond<K, V, R, Ctx>
where
K: Key,
V: Value,
R: Ref,
Ctx: Context,
{
fn clone(&self) -> Self {
SingleCond {
name: self.name.clone(),
cond: {
let mut r = Vec::new();
for c in self.cond.iter() {
r.push(c.clone())
}
r
},
}
}
}
impl<K, V, R, Ctx> SingleCond<K, V, R, Ctx>
where
K: Key,
V: Value,
R: Ref,
Ctx: Context,
{
pub fn matches(&self, value: &V, ctx: &Ctx) -> Result<Pending<V, R>, RbeError<K, V, R, Ctx>> {
self.cond.iter().try_fold(Pending::new(), |mut current, f| {
let pending = f.call(value, ctx)?;
current.merge(pending);
Ok(current)
})
}
pub fn new() -> SingleCond<K, V, R, Ctx> {
SingleCond {
name: None,
cond: Vec::new(),
}
}
pub fn with_name(mut self, name: &str) -> Self {
self.name = Some(name.to_string());
self
}
pub fn with_cond(
mut self,
cond: impl Fn(&V, &Ctx) -> Result<Pending<V, R>, RbeError<K, V, R, Ctx>> + Clone + 'static + Send + Sync,
) -> Self {
self.cond.push(Box::new(cond));
self
}
pub fn name(&self) -> String {
self.name.clone().unwrap_or_default()
}
}
impl<K, V, R, Ctx> PartialEq for SingleCond<K, V, R, Ctx>
where
K: Key,
V: Value,
R: Ref,
Ctx: Context,
{
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
impl<K, V, R, Ctx> Eq for SingleCond<K, V, R, Ctx>
where
K: Key,
V: Value,
R: Ref,
Ctx: Context,
{
}
impl<K, V, R, Ctx> Hash for SingleCond<K, V, R, Ctx>
where
K: Key,
V: Value,
R: Ref,
Ctx: Context,
{
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.name.hash(hasher)
}
}
impl<K, V, R, Ctx> Default for SingleCond<K, V, R, Ctx>
where
K: Key,
V: Value,
R: Ref,
Ctx: Context,
{
fn default() -> Self {
SingleCond::new()
}
}
impl<K, V, R, Ctx> Debug for SingleCond<K, V, R, Ctx>
where
K: Key,
V: Value,
R: Ref,
Ctx: Context,
{
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(f, "{}", self.name.clone().unwrap_or_default())?;
Ok(())
}
}
impl<K, V, R, Ctx> Display for SingleCond<K, V, R, Ctx>
where
K: Key,
V: Value,
R: Ref,
Ctx: Context,
{
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(f, "{}", self.name.clone().unwrap_or_default())?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_even_cond_2_pass() {
let cond_even: SingleCond<char, i32, String, char> = SingleCond::new().with_cond(|v, _ctx| {
if v % 2 == 0 {
Ok(Pending::new())
} else {
Err(RbeError::MsgError {
msg: format!("Value {v} is not even"),
})
}
});
assert_eq!(cond_even.matches(&2, &'a'), Ok(Pending::new()));
}
#[test]
fn test_even_cond_3_fail() {
let cond_even: SingleCond<char, i32, String, char> = SingleCond::new().with_cond(|v, _ctx| {
if v % 2 == 0 {
Ok(Pending::new())
} else {
Err(RbeError::MsgError {
msg: format!("Value {v} is not even"),
})
}
});
assert!(cond_even.matches(&3, &'a').is_err());
}
#[test]
fn test_name_fail() {
fn cond_name(name: String) -> SingleCond<char, String, String, char> {
SingleCond::new().with_cond(move |v: &String, _ctx: &char| {
if *v == name {
Ok(Pending::new())
} else {
Err(RbeError::MsgError {
msg: format!("Value {v} is not equal to {name}"),
})
}
})
}
assert!(cond_name("foo".to_string()).matches(&"baz".to_string(), &'a').is_err());
}
#[test]
fn test_name_pass() {
fn cond_name(name: String) -> SingleCond<char, String, String, char> {
SingleCond::new()
.with_name("name")
.with_cond(move |v: &String, _ctx: &char| {
if *v == name {
Ok(Pending::new())
} else {
Err(RbeError::MsgError {
msg: format!("Value {v} failed condition is not equal to {name}",),
})
}
})
}
assert_eq!(
cond_name("foo".to_string()).matches(&"foo".to_string(), &'a'),
Ok(Pending::new())
);
}
}