1use std::collections::BTreeMap;
2use fasteval::{self, Compiler, Evaler};
3use crate::expr::fasteval::eval_compiled_ref;
4use crate::note::Note;
5
6#[derive(Debug)]
7pub struct Expr {
8 slab: fasteval::Slab,
9 compiled: fasteval::Instruction,
10}
11
12impl Expr {
13 pub fn new<S: AsRef<str>>(expr: S) -> Result<Self, fasteval::Error> {
14 let parser = fasteval::Parser::new();
15 let mut slab = fasteval::Slab::new();
16 let compiled: fasteval::Instruction = parser.parse(expr.as_ref(), &mut slab.ps)?.from(&slab.ps).compile(&slab.ps, &mut slab.cs);
17
18 Ok(Self { slab, compiled })
19 }
20
21 pub fn evaluate_note(&self, note: &Note) -> Result<bool, fasteval::Error>{
22 let mut map: BTreeMap<&str, f64> = BTreeMap::new();
23 map.insert("v", note.velocity().as_u8() as f64); map.insert("bv", note.base_velocity.as_u8() as f64); map.insert("vt0", note.velocity_trimmer.value(0) as f64); map.insert("vt1", note.velocity_trimmer.value(1) as f64); map.insert("vt2", note.velocity_trimmer.value(2) as f64); map.insert("vt3", note.velocity_trimmer.value(3) as f64); map.insert("vt", note.velocity_trimmer.sum() as f64); #[allow(unexpected_cfgs)]
32 let val: f64 = eval_compiled_ref!(&self.compiled, &self.slab, &mut map);
33
34 Ok(val != 0.)
35 }
36}
37
38#[cfg(test)]
39mod tests {
40 use crate::{note::{Note, NoteBuilder}, trimmer::Trimmer, velocity::Velocity};
41 use super::Expr;
42
43 #[test]
44 fn eval_note_velocity() {
45 let expr0: Expr = Expr::new("bv < 64").unwrap();
46 let expr1: Expr = Expr::new("vt0 < 20").unwrap();
47 let expr2: Expr = Expr::new("vt0 <= 20").unwrap();
48 let expr3: Expr = Expr::new("vt < 20").unwrap();
49 let expr4: Expr = Expr::new("vt <= 20").unwrap();
50 let note0: Note = NoteBuilder::default()
51 .base_velocity(Velocity::new(64))
52 .velocity_trimmer(Trimmer::new(20, 0, 0, 0))
53 .build().unwrap();
54 assert!(!expr0.evaluate_note(¬e0).unwrap());
55 assert!(!expr1.evaluate_note(¬e0).unwrap());
56 assert!(expr2.evaluate_note(¬e0).unwrap());
57 assert!(!expr3.evaluate_note(¬e0).unwrap());
58 assert!(expr4.evaluate_note(¬e0).unwrap());
59
60 let note1: Note = NoteBuilder::default()
61 .base_velocity(Velocity::new(63))
62 .velocity_trimmer(Trimmer::new(10, 10, 0, 0))
63 .build().unwrap();
64 assert!(expr0.evaluate_note(¬e1).unwrap());
65 assert!(expr1.evaluate_note(¬e1).unwrap());
66 assert!(expr2.evaluate_note(¬e1).unwrap());
67 assert!(!expr3.evaluate_note(¬e1).unwrap());
68 assert!(expr4.evaluate_note(¬e1).unwrap());
69
70 assert_eq!(Expr::new("foo <= 20").unwrap().evaluate_note(¬e1), Err(fasteval::Error::Undefined("foo".to_owned())));
71 }
72}