use super::{ParamId, Params};
#[derive(Clone, Debug, PartialEq)]
pub enum Cond<P = ParamId> {
Always,
Is(P),
Trigger(P),
Above(P, f32),
Below(P, f32),
Finished,
After(f32),
Not(Box<Cond<P>>),
All(Vec<Cond<P>>),
Any(Vec<Cond<P>>),
}
impl<P> Cond<P> {
#[allow(clippy::should_implement_trait)]
pub fn not(c: Cond<P>) -> Self {
Cond::Not(Box::new(c))
}
pub fn and(self, o: Cond<P>) -> Self {
match self {
Cond::All(mut v) => {
v.push(o);
Cond::All(v)
}
c => Cond::All(vec![c, o]),
}
}
pub fn resolve<Q, E>(&self, f: &mut dyn FnMut(&P, Use) -> Result<Q, E>) -> Result<Cond<Q>, E> {
Ok(match self {
Cond::Always => Cond::Always,
Cond::Is(p) => Cond::Is(f(p, Use::Bool)?),
Cond::Trigger(p) => Cond::Trigger(f(p, Use::Trigger)?),
Cond::Above(p, v) => Cond::Above(f(p, Use::Float)?, *v),
Cond::Below(p, v) => Cond::Below(f(p, Use::Float)?, *v),
Cond::Finished => Cond::Finished,
Cond::After(s) => Cond::After(*s),
Cond::Not(c) => Cond::Not(Box::new(c.resolve(f)?)),
Cond::All(v) => Cond::All(v.iter().map(|c| c.resolve(f)).collect::<Result<_, E>>()?),
Cond::Any(v) => Cond::Any(v.iter().map(|c| c.resolve(f)).collect::<Result<_, E>>()?),
})
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Use {
Bool,
Float,
Trigger,
}
impl Cond {
pub fn eval(&self, p: &Params, finished: bool, time: f32) -> bool {
match self {
Cond::Always => true,
Cond::Is(id) => p.get_bool(*id),
Cond::Trigger(id) => p.pending(*id),
Cond::Above(id, v) => p.get_float(*id) > *v,
Cond::Below(id, v) => p.get_float(*id) < *v,
Cond::Finished => finished,
Cond::After(s) => time >= *s,
Cond::Not(c) => !c.eval(p, finished, time),
Cond::All(v) => v.iter().all(|c| c.eval(p, finished, time)),
Cond::Any(v) => v.iter().any(|c| c.eval(p, finished, time)),
}
}
pub fn used_triggers(&self, p: &Params, out: &mut Vec<ParamId>) {
match self {
Cond::Trigger(id) if p.pending(*id) => out.push(*id),
Cond::All(v) | Cond::Any(v) => v.iter().for_each(|c| c.used_triggers(p, out)),
_ => {}
}
}
}