use serde::{Deserialize, Serialize};
mod track_rules;
pub use track_rules::*;
mod album_rules;
pub use album_rules::*;
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum GroupOp {
Any,
All,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum EqOp {
EqAny,
EqAll,
NeqAny,
NeqAll,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum OrdOp {
Eq,
Neq,
Greater,
GreaterEq,
Lesser,
LesserEq,
}
pub trait Rule {
type Item;
fn matches(&self, item: &Self::Item) -> bool;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RuleGroup<R: Rule> {
pub rules: Vec<R>,
pub op: GroupOp,
}
impl<R: Rule> Default for RuleGroup<R> {
fn default() -> Self {
Self::new()
}
}
impl<R: Rule> RuleGroup<R> {
#[must_use]
pub const fn new() -> Self {
Self {
rules: Vec::new(),
op: GroupOp::Any,
}
}
pub fn filter<'a>(&self, candidates: &'a [R::Item]) -> impl Iterator<Item = &'a R::Item> {
candidates.iter().filter(|c| {
if self.rules.is_empty() {
return true;
}
match self.op {
GroupOp::Any => self.rules.iter().any(|rule| rule.matches(c)),
GroupOp::All => self.rules.iter().all(|rule| rule.matches(c)),
}
})
}
}
pub(crate) fn eq_single<T: PartialEq>(item: &T, cmp: &[T], op: EqOp) -> bool {
match op {
EqOp::EqAny | EqOp::EqAll => cmp.contains(item),
EqOp::NeqAny => !cmp.contains(item),
EqOp::NeqAll => cmp.iter().any(|c| c != item),
}
}
pub(crate) fn eq_many<T: PartialEq>(values: &[T], cmp: &[T], op: EqOp) -> bool {
match op {
EqOp::EqAny => cmp.iter().any(|c| values.contains(c)),
EqOp::EqAll => cmp.iter().all(|c| values.contains(c)),
EqOp::NeqAny => cmp.iter().any(|c| !values.contains(c)),
EqOp::NeqAll => cmp.iter().all(|c| !values.contains(c)),
}
}
pub(crate) fn ord_single<T: PartialOrd>(value: T, cmp: T, op: OrdOp) -> bool {
match op {
OrdOp::Eq => value == cmp,
OrdOp::Neq => value != cmp,
OrdOp::Greater => value > cmp,
OrdOp::GreaterEq => value >= cmp,
OrdOp::Lesser => value < cmp,
OrdOp::LesserEq => value <= cmp,
}
}