rbe/
match_cond.rs

1use crate::{rbe_error::RbeError, Pending};
2use crate::{Key, Ref, Value};
3use core::hash::Hash;
4use serde::{Deserialize, Serialize};
5use std::fmt::Debug;
6use std::fmt::{Display, Formatter};
7use std::hash::Hasher;
8
9/// A `MatchCond` represents a matching condition
10/// It can be a single condition or a combination of the logical operators `And`, `Or` and `Not`
11#[derive(PartialEq, Eq, Hash, Clone, Serialize, Debug, Deserialize)]
12pub enum MatchCond<K, V, R>
13where
14    K: Key,
15    V: Value,
16    R: Ref,
17{
18    Single(SingleCond<K, V, R>),
19    Ref(R),
20    And(Vec<MatchCond<K, V, R>>),
21    // Or(Vec<MatchCond<K, V, R>>),
22    // Not(Box<MatchCond<K, V, R>>),
23}
24
25impl<K, V, R> MatchCond<K, V, R>
26where
27    K: Key,
28    V: Value,
29    R: Ref,
30{
31    pub fn new() -> MatchCond<K, V, R> {
32        MatchCond::Single(SingleCond::new())
33    }
34
35    pub fn empty() -> MatchCond<K, V, R> {
36        MatchCond::Single(SingleCond::new().with_name("empty"))
37    }
38
39    pub fn ref_(r: R) -> MatchCond<K, V, R> {
40        MatchCond::Ref(r)
41    }
42
43    pub fn matches(&self, value: &V) -> Result<Pending<V, R>, RbeError<K, V, R>> {
44        match self {
45            MatchCond::Single(single) => single.matches(value),
46            MatchCond::Ref(r) => Ok(Pending::from_pair(value.clone(), r.clone())),
47            /*MatchCond::And(vs) => vs.iter().try_fold(Pending::new(), |mut current, c| {
48                let new_pending = c.matches(value)?;
49                current.merge(new_pending);
50                Ok(current)
51            }), */
52            _ => {
53                todo!()
54            }
55        }
56    }
57
58    pub fn single(single: SingleCond<K, V, R>) -> Self {
59        MatchCond::Single(single)
60    }
61
62    pub fn simple(
63        name: &str,
64        cond: impl Fn(&V) -> Result<Pending<V, R>, RbeError<K, V, R>> + Clone + 'static,
65    ) -> Self {
66        MatchCond::single(SingleCond::new().with_name(name).with_cond(cond))
67    }
68}
69
70impl<K, V, R> Display for MatchCond<K, V, R>
71where
72    K: Key,
73    V: Value,
74    R: Ref,
75{
76    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
77        match self {
78            MatchCond::Single(sc) => {
79                write!(f, "{sc}")?;
80                Ok(())
81            }
82            MatchCond::Ref(r) => {
83                write!(f, "@{r}")?;
84                Ok(())
85            }
86            MatchCond::And(cs) => {
87                write!(f, "And(")?;
88                cs.iter().try_fold((), |_, c| write!(f, "|{c}"))?;
89                write!(f, ")")
90            } /* MatchCond::Or(cs) => {
91                  write!(f, "Or")?;
92                  cs.iter().try_fold((), |_, c| write!(f, "|{c}"))?;
93                  write!(f, ")")
94              }
95              MatchCond::Not(c) => write!(f, "Not({c})"),*/
96        }
97    }
98}
99
100impl<K, V, R> Default for MatchCond<K, V, R>
101where
102    K: Key,
103    V: Value,
104    R: Ref,
105{
106    fn default() -> Self {
107        MatchCond::Single(SingleCond::default())
108    }
109}
110
111/// Represents a matching condition
112#[derive(Serialize, Deserialize)]
113pub struct SingleCond<K, V, R>
114where
115    K: Hash + Eq + Display + Default,
116    V: Hash + Eq + Default + PartialEq + Clone,
117    R: Hash + Default + PartialEq + Clone,
118{
119    #[serde(skip_serializing_if = "Option::is_none")]
120    name: Option<String>,
121
122    #[serde(skip)]
123    cond: Vec<Box<dyn Cond<K, V, R>>>,
124}
125
126/// We use trait objects instead of function pointers because we need to
127/// capture some values in the condition closure.
128/// This pattern is inspired by the answer in this thread:
129/// https://users.rust-lang.org/t/how-to-clone-a-boxed-closure/31035
130trait Cond<K, V, R>
131where
132    K: Key,
133    V: Value,
134    R: Ref,
135{
136    fn clone_box(&self) -> Box<dyn Cond<K, V, R>>;
137    fn call(&self, v: &V) -> Result<Pending<V, R>, RbeError<K, V, R>>;
138}
139
140impl<K, V, R, F> Cond<K, V, R> for F
141where
142    K: Key,
143    V: Value,
144    R: Ref,
145    F: 'static + Fn(&V) -> Result<Pending<V, R>, RbeError<K, V, R>> + Clone,
146{
147    fn clone_box(&self) -> Box<dyn Cond<K, V, R>> {
148        Box::new(self.clone())
149    }
150
151    fn call(&self, v: &V) -> Result<Pending<V, R>, RbeError<K, V, R>> {
152        self(v)
153    }
154}
155
156impl<K, V, R> Clone for Box<dyn Cond<K, V, R>>
157where
158    K: Key,
159    V: Value,
160    R: Ref,
161{
162    fn clone(&self) -> Self {
163        self.clone_box()
164    }
165}
166
167/*impl <K, V, R> PartialEq for Box<dyn Cond<K, V, R>>
168where  K: Hash + Eq + Display + Default,
169       V: Hash + Eq + Default + PartialEq + Clone,
170       R: Default + PartialEq + Clone,
171{
172    fn eq(&self, other: &Box<dyn Cond<K, V, R>>) -> bool {
173        todo!()
174    }
175}*/
176
177impl<K, V, R> Clone for SingleCond<K, V, R>
178where
179    K: Key,
180    V: Value,
181    R: Ref,
182{
183    fn clone(&self) -> Self {
184        SingleCond {
185            name: self.name.clone(),
186            cond: {
187                let mut r = Vec::new();
188                for c in self.cond.iter() {
189                    r.push(c.clone())
190                }
191                r
192                // self.cond.into_iter().map(|c| (*c).clone_box()).collect()
193            }, /*            match &self.cond {
194                   Option::None => {
195                       None
196                   },
197                   Option::Some(f) => {
198                       Some((*f).clone())
199                   }
200               } */
201        }
202    }
203}
204
205impl<K, V, R> SingleCond<K, V, R>
206where
207    K: Key,
208    V: Value,
209    R: Ref,
210{
211    pub fn matches(&self, value: &V) -> Result<Pending<V, R>, RbeError<K, V, R>> {
212        self.cond.iter().try_fold(Pending::new(), |mut current, f| {
213            let pending = f.call(value)?;
214            current.merge(pending);
215            Ok(current)
216        })
217    }
218
219    pub fn new() -> SingleCond<K, V, R> {
220        SingleCond {
221            name: None,
222            cond: Vec::new(),
223        }
224    }
225
226    pub fn with_name(mut self, name: &str) -> Self {
227        self.name = Some(name.to_string());
228        self
229    }
230
231    pub fn with_cond(
232        mut self,
233        cond: impl Fn(&V) -> Result<Pending<V, R>, RbeError<K, V, R>> + Clone + 'static,
234    ) -> Self {
235        self.cond.push(Box::new(cond));
236        self
237    }
238
239    pub fn name(&self) -> String {
240        self.name.clone().unwrap_or_default()
241    }
242}
243
244impl<K, V, R> PartialEq for SingleCond<K, V, R>
245where
246    K: Key,
247    V: Value,
248    R: Ref,
249{
250    fn eq(&self, other: &Self) -> bool {
251        self.name == other.name
252    }
253}
254
255impl<K, V, R> Eq for SingleCond<K, V, R>
256where
257    K: Key,
258    V: Value,
259    R: Ref,
260{
261}
262
263impl<K, V, R> Hash for SingleCond<K, V, R>
264where
265    K: Key,
266    V: Value,
267    R: Ref,
268{
269    fn hash<H: Hasher>(&self, hasher: &mut H) {
270        self.name.hash(hasher)
271    }
272}
273
274impl<K, V, R> Default for SingleCond<K, V, R>
275where
276    K: Key,
277    V: Value,
278    R: Ref,
279{
280    fn default() -> Self {
281        SingleCond::new()
282    }
283}
284
285impl<K, V, R> Debug for SingleCond<K, V, R>
286where
287    K: Key,
288    V: Value,
289    R: Ref,
290{
291    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
292        write!(f, "{}", self.name.clone().unwrap_or_default())?;
293        Ok(())
294    }
295}
296
297impl<K, V, R> Display for SingleCond<K, V, R>
298where
299    K: Key,
300    V: Value,
301    R: Ref,
302{
303    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
304        write!(f, "{}", self.name.clone().unwrap_or_default())?;
305        Ok(())
306    }
307}
308
309#[cfg(test)]
310mod tests {
311    use super::*;
312
313    #[test]
314    fn test_even_cond_2_pass() {
315        let cond_even: SingleCond<char, i32, String> = SingleCond::new().with_cond(|v| {
316            if v % 2 == 0 {
317                Ok(Pending::new())
318            } else {
319                Err(RbeError::MsgError {
320                    msg: format!("Value {v} is not even"),
321                })
322            }
323        });
324
325        assert_eq!(cond_even.matches(&2), Ok(Pending::new()));
326    }
327
328    #[test]
329    fn test_even_cond_3_fail() {
330        let cond_even: SingleCond<char, i32, String> = SingleCond::new().with_cond(|v| {
331            if v % 2 == 0 {
332                Ok(Pending::new())
333            } else {
334                Err(RbeError::MsgError {
335                    msg: format!("Value {v} is not even"),
336                })
337            }
338        });
339
340        assert!(cond_even.matches(&3).is_err());
341    }
342
343    #[test]
344    fn test_name_fail() {
345        fn cond_name(name: String) -> SingleCond<char, String, String> {
346            SingleCond::new().with_cond(move |v: &String| {
347                if *v == name {
348                    Ok(Pending::new())
349                } else {
350                    Err(RbeError::MsgError {
351                        msg: format!("Value {v} is not equal to {name}"),
352                    })
353                }
354            })
355        }
356
357        assert!(cond_name("foo".to_string())
358            .matches(&"baz".to_string())
359            .is_err());
360    }
361
362    #[test]
363    fn test_name_pass() {
364        fn cond_name(name: String) -> SingleCond<char, String, String> {
365            SingleCond::new()
366                .with_name("name")
367                .with_cond(move |v: &String| {
368                    if *v == name {
369                        Ok(Pending::new())
370                    } else {
371                        Err(RbeError::MsgError {
372                            msg: format!("Value {v} failed condition is not equal to {name}",),
373                        })
374                    }
375                })
376        }
377
378        assert_eq!(
379            cond_name("foo".to_string()).matches(&"foo".to_string()),
380            Ok(Pending::new())
381        );
382    }
383}