Skip to main content

selene_core/library/collection/
rules.rs

1use serde::{Deserialize, Serialize};
2
3mod track_rules;
4pub use track_rules::*;
5
6mod album_rules;
7pub use album_rules::*;
8
9#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
10pub enum GroupOp {
11    Any,
12    All,
13}
14
15#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
16pub enum EqOp {
17    EqAny,
18    EqAll,
19    NeqAny,
20    NeqAll,
21}
22
23#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
24pub enum OrdOp {
25    Eq,
26    Neq,
27    Greater,
28    GreaterEq,
29    Lesser,
30    LesserEq,
31}
32
33pub trait Rule {
34    type Item;
35    fn matches(&self, item: &Self::Item) -> bool;
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct RuleGroup<R: Rule> {
40    pub rules: Vec<R>,
41    pub op: GroupOp,
42}
43
44impl<R: Rule> Default for RuleGroup<R> {
45    fn default() -> Self {
46        Self::new()
47    }
48}
49
50impl<R: Rule> RuleGroup<R> {
51    #[must_use] 
52    pub const fn new() -> Self {
53        Self {
54            rules: Vec::new(),
55            op: GroupOp::Any,
56        }
57    }
58
59    pub fn filter<'a>(&self, candidates: &'a [R::Item]) -> impl Iterator<Item = &'a R::Item> {
60        candidates.iter().filter(|c| {
61            if self.rules.is_empty() {
62                return true;
63            }
64
65            match self.op {
66                GroupOp::Any => self.rules.iter().any(|rule| rule.matches(c)),
67                GroupOp::All => self.rules.iter().all(|rule| rule.matches(c)),
68            }
69        })
70    }
71}
72
73pub(crate) fn eq_single<T: PartialEq>(item: &T, cmp: &[T], op: EqOp) -> bool {
74    match op {
75        EqOp::EqAny | EqOp::EqAll => cmp.contains(item),
76        EqOp::NeqAny => !cmp.contains(item),
77        EqOp::NeqAll => cmp.iter().any(|c| c != item),
78    }
79}
80
81pub(crate) fn eq_many<T: PartialEq>(values: &[T], cmp: &[T], op: EqOp) -> bool {
82    match op {
83        EqOp::EqAny => cmp.iter().any(|c| values.contains(c)),
84        EqOp::EqAll => cmp.iter().all(|c| values.contains(c)),
85        EqOp::NeqAny => cmp.iter().any(|c| !values.contains(c)),
86        EqOp::NeqAll => cmp.iter().all(|c| !values.contains(c)),
87    }
88}
89
90pub(crate) fn ord_single<T: PartialOrd>(value: T, cmp: T, op: OrdOp) -> bool {
91    match op {
92        OrdOp::Eq => value == cmp,
93        OrdOp::Neq => value != cmp,
94        OrdOp::Greater => value > cmp,
95        OrdOp::GreaterEq => value >= cmp,
96        OrdOp::Lesser => value < cmp,
97        OrdOp::LesserEq => value <= cmp,
98    }
99}