diff --git a/src/bng.rs b/src/bng.rs index b1c96c8..b4a9cd3 100644 --- a/src/bng.rs +++ b/src/bng.rs @@ -1,13 +1,14 @@ -use std::collections::HashMap; +use std::{collections::HashMap, str::FromStr}; use amplify::{From, Wrapper}; use derive_new::new; use derived_deref::Deref; -use fasteval::Instruction; +use fasteval::{Compiler, Instruction}; pub(super) use instrument::Instrument; pub(super) use score::Atom; #[cfg(debug_assertions)] use serde::Serialize; +use serde::{de::Visitor, Deserialize}; mod instrument; mod score; @@ -26,6 +27,44 @@ impl Serialize for Expression { } } +impl<'de> Deserialize<'de> for Expression { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_str(ExpressionVisitor) + } +} + +pub struct ExpressionVisitor; + +impl<'de> Visitor<'de> for ExpressionVisitor { + type Value = Expression; + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter + .write_str("a math expression following fasteval syntax (https://docs.rs/fasteval)") + } + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + v.parse().map_err(serde::de::Error::custom) + } +} + +impl FromStr for Expression { + type Err = fasteval::Error; + fn from_str(s: &str) -> Result { + let parser = fasteval::Parser::new(); + let mut slab = fasteval::Slab::new(); + Ok(parser + .parse(s, &mut slab.ps)? + .from(&slab.ps) + .compile(&slab.ps, &mut slab.cs) + .into()) + } +} + #[derive(new)] #[cfg_attr(debug_assertions, derive(Serialize))] pub(super) struct Channel { diff --git a/src/bng/score/lex/lexer.rs b/src/bng/score/lex/lexer.rs index cdafbb7..acf1372 100644 --- a/src/bng/score/lex/lexer.rs +++ b/src/bng/score/lex/lexer.rs @@ -65,19 +65,9 @@ fn flat_atom_parser(notes: &str) -> impl Parser<&str, FlatAtom, nom::error::Erro separated_pair( SlopeModifier::parse, char(' '), - map_res(take_till1(|c| c == ','), |s| { - let parser = fasteval::Parser::new(); - let mut slab = fasteval::Slab::new(); - Result::>::Ok( - parser - .parse(s, &mut slab.ps) - .map_err(|_| { - nom::error::Error::new(s, nom::error::ErrorKind::Verify) - })? - .from(&slab.ps) - .compile(&slab.ps, &mut slab.cs) - .into(), - ) + map_res(take_till1(|c| c == ','), |s: &str| { + s.parse() + .map_err(|_| nom::error::Error::new(s, nom::error::ErrorKind::Verify)) }), ), ), diff --git a/src/bng/score/lex/lexer/tests.rs b/src/bng/score/lex/lexer/tests.rs index 2b29867..96a4af7 100644 --- a/src/bng/score/lex/lexer/tests.rs +++ b/src/bng/score/lex/lexer/tests.rs @@ -136,19 +136,7 @@ mod flat_atom { assert_eq!( Ok(( SAMPLE_STR, - FlatAtom::SlopeStarts( - SlopeModifier::Note, - { - let parser = fasteval::Parser::new(); - let mut slab = fasteval::Slab::new(); - parser - .parse(FASTEVAL_INSTRUCTION, &mut slab.ps) - .unwrap() - .from(&slab.ps) - .compile(&slab.ps, &mut slab.cs) - } - .into() - ) + FlatAtom::SlopeStarts(SlopeModifier::Note, FASTEVAL_INSTRUCTION.parse().unwrap()) )), flat_atom_parser("abcdefg").parse(concatcp!( Atom::SLOPE.0, diff --git a/src/bng/score/utils/tests.rs b/src/bng/score/utils/tests.rs index ff32448..88d08b9 100644 --- a/src/bng/score/utils/tests.rs +++ b/src/bng/score/utils/tests.rs @@ -8,14 +8,7 @@ mod inflate { const FASTEVAL_INSTRUCTION: &str = "1-cos((PI*x)/2)"; fn instruction() -> Instruction { - let parser = fasteval::Parser::new(); - let mut slab = fasteval::Slab::new(); - parser - .parse(FASTEVAL_INSTRUCTION, &mut slab.ps) - .unwrap() - .from(&slab.ps) - .compile(&slab.ps, &mut slab.cs) - .into() + FASTEVAL_INSTRUCTION.parse().unwrap() } #[test] diff --git a/src/main.rs b/src/main.rs index 23b5054..0af91ba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,12 +18,12 @@ fn main() -> Result<(), serde_yml::Error> { vec![HashMap::from([ ( "sine".to_string(), - Instrument::new(instruction("sin(2*PI*f*t)"), None) + Instrument::new("sin(2*PI*f*t)".parse().unwrap(), None) ), ( "square".to_string(), Instrument::new( - instruction("v*abs(sin(2*PI*f*t))"), + "v*abs(sin(2*PI*f*t))".parse().unwrap(), Some(HashMap::from([("v".to_string(), 1f32)])) ) ) @@ -38,14 +38,3 @@ fn main() -> Result<(), serde_yml::Error> { println!("{:?}", args); Ok(()) } - -fn instruction(expr_str: &str) -> Expression { - let parser = fasteval::Parser::new(); - let mut slab = fasteval::Slab::new(); - parser - .parse(expr_str, &mut slab.ps) - .unwrap() - .from(&slab.ps) - .compile(&slab.ps, &mut slab.cs) - .into() -}