use fasteval3::bool_to_f64;
use fasteval3::{Cached, CachedCallbackNamespace, EmptyNamespace, Error, Evaler, Parser, Slab};
use std::collections::{BTreeMap, BTreeSet};
use std::mem;
#[test]
fn eval() {
let mut slab = Slab::new();
let mut ns = BTreeMap::<String, f64>::new();
ns.insert(String::from("x"), 1.0);
ns.insert(String::from("y"), 2.0);
ns.insert(String::from("z"), 3.0);
assert!(
(Parser::new()
.parse("3+3-3/3", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns)
.unwrap() - 5.0).abs() < f64::EPSILON
);
assert!(
(Parser::new()
.parse("x+y+z", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns)
.unwrap() - 6.0).abs() < f64::EPSILON
);
assert_eq!(
Parser::new()
.parse("x+y+z+a", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Err(Error::Undefined(String::from("a")))
);
}
#[test]
fn aaa_util() {
assert!((bool_to_f64!(true) - 1.0).abs() < f64::EPSILON);
assert!((bool_to_f64!(false) - 0.0).abs() < f64::EPSILON);
}
#[test]
fn aaa_aaa_sizes() {
eprintln!("sizeof(Slab):{}", mem::size_of::<Slab>());
assert!(mem::size_of::<Slab>() < 2usize.pow(18)); }
#[test]
fn aaa_aab_single() {
let mut slab = Slab::new();
let mut ns = EmptyNamespace;
assert!(
(Parser::new()
.parse("123.456", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns)
.unwrap() - 123.456f64).abs() < f64::EPSILON
);
}
#[allow(clippy::cognitive_complexity, clippy::too_many_lines)] #[test]
fn aaa_basics() {
let mut slab = Slab::new();
assert_eq!(
Parser::new()
.parse("12.34 + 43.21 + 11.11", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.var_names(&slab),
BTreeSet::new()
);
let mut ns = EmptyNamespace;
assert_eq!(
Parser::new()
.parse("12.34 + 43.21 + 11.11", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(66.66)
);
assert_eq!(
Parser::new()
.parse("12.34 + 43.21 - 11.11", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(44.44)
);
assert_eq!(
Parser::new()
.parse("11.11 * 3", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(33.33)
);
assert_eq!(
Parser::new()
.parse("33.33 / 3", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(11.11)
);
assert_eq!(
Parser::new()
.parse("33.33 % 3", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(0.329_999_999_999_998_3)
);
assert_eq!(
Parser::new()
.parse("1 and 2", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(2.0)
);
assert_eq!(
Parser::new()
.parse("1 && 2", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(2.0)
);
assert_eq!(
Parser::new()
.parse("2 or 0", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(2.0)
);
assert_eq!(
Parser::new()
.parse("2 || 0", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(2.0)
);
assert_eq!(
Parser::new()
.parse("1 > 0", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(1.0)
);
assert_eq!(
Parser::new()
.parse("1 < 0", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(0.0)
);
assert_eq!(
Parser::new()
.parse("+5.5", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(5.5)
);
assert_eq!(
Parser::new()
.parse("-5.5", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(-5.5)
);
assert_eq!(
Parser::new()
.parse("!5.5", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(0.0)
);
assert_eq!(
Parser::new()
.parse("!0", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(1.0)
);
assert_eq!(
Parser::new()
.parse("(3 * 3 + 3 / 3)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(10.0)
);
assert_eq!(
Parser::new()
.parse("(3 * (3 + 3) / 3)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(6.0)
);
assert_eq!(
Parser::new()
.parse("4.4 + -5.5", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(-1.099_999_999_999_999_6)
);
assert_eq!(
Parser::new()
.parse("4.4 + +5.5", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(9.9)
);
assert_eq!(
Parser::new()
.parse("x + 1", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Err(Error::Undefined(String::from("x")))
);
let mut ns = CachedCallbackNamespace::new(|_, _| Some(3.0));
assert_eq!(
Parser::new()
.parse("x + 1", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(4.0)
);
assert_eq!(
Parser::new()
.parse("1.2 + int(3.4)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(4.2)
);
assert_eq!(
Parser::new()
.parse("1.2 + ceil(3.4)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(5.2)
);
assert_eq!(
Parser::new()
.parse("1.2 + floor(3.4)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(4.2)
);
assert_eq!(
Parser::new()
.parse("1.2 + abs(-3.4)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(4.6)
);
assert_eq!(
Parser::new()
.parse("1.2 + log(1)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(1.2)
);
assert_eq!(
Parser::new()
.parse("1.2 + log(10)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(2.2)
);
assert_eq!(
Parser::new()
.parse("1.2 + log(0)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(std::f64::NEG_INFINITY)
);
assert!(Parser::new()
.parse("1.2 + log(-1)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns)
.unwrap()
.is_nan());
assert_eq!(
Parser::new()
.parse("1.2 + round(3.4)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(4.2)
);
assert_eq!(
Parser::new()
.parse("1.2 + round(0.5, 3.4)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(4.7)
);
assert_eq!(
Parser::new()
.parse("1.2 + round(-3.4)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(-1.8)
);
assert_eq!(
Parser::new()
.parse("1.2 + round(0.5, -3.4)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(-2.3)
);
assert_eq!(
Parser::new()
.parse("1.2 + min(1,2,0,3.3,-1)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(0.199_999_999_999_999_96)
);
assert_eq!(
Parser::new()
.parse("1.2 + min(1)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(2.2)
);
assert_eq!(
Parser::new()
.parse("1.2 + max(1,2,0,3.3,-1)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(4.5)
);
assert_eq!(
Parser::new()
.parse("1.2 + max(1)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(2.2)
);
assert_eq!(
Parser::new()
.parse(r#"12.34 + print ( 43.21, "yay" ) + 11.11"#, &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(66.66)
);
assert_eq!(
Parser::new()
.parse("e()", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(std::f64::consts::E) );
assert_eq!(
Parser::new()
.parse("pi()", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(std::f64::consts::PI) );
assert_eq!(
Parser::new()
.parse("sin(pi()/2)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(1.0)
);
assert_eq!(
Parser::new()
.parse("cos(pi()/2)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(0.000_000_000_000_000_061_232_339_957_367_66)
);
assert_eq!(
Parser::new()
.parse("tan(pi()/4)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(0.999_999_999_999_999_9)
);
assert_eq!(
Parser::new()
.parse("asin(1)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(std::f64::consts::FRAC_PI_2)
);
assert_eq!(
Parser::new()
.parse("acos(0)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(std::f64::consts::FRAC_PI_2) );
assert_eq!(
Parser::new()
.parse("atan(1)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(std::f64::consts::FRAC_PI_4) );
assert_eq!(
Parser::new()
.parse("sinh(pi()/2)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(2.301_298_902_307_294_7)
);
assert_eq!(
Parser::new()
.parse("cosh(pi()/2)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(2.509_178_478_658_056_7)
);
assert_eq!(
Parser::new()
.parse("tanh(pi()/4)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(0.655_794_202_632_672_4)
);
}
#[test]
fn corners() {
let mut slab = Slab::new();
let mut ns = EmptyNamespace;
assert_eq!(
format!(
"{:?}",
Parser::new()
.parse("(-1) ^ 0.5", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns)
),
"Ok(NaN)"
);
}
fn my_evalns_cb_function(_: &str, _: Vec<f64>) -> Option<f64> {
None
}
#[test]
fn evalns_cb_ownership() {
let _ns = CachedCallbackNamespace::new(my_evalns_cb_function);
let _ns = CachedCallbackNamespace::new(my_evalns_cb_function);
let closure = |_: &str, _: Vec<f64>| None;
let _ns = CachedCallbackNamespace::new(closure);
let _ns = CachedCallbackNamespace::new(closure);
let x = 1.0;
let closure = |_: &str, _: Vec<f64>| Some(x);
let _ns = CachedCallbackNamespace::new(closure);
let _ns = CachedCallbackNamespace::new(closure);
let mut x = 1.0;
let closure = |_: &str, _: Vec<f64>| {
x += 1.0;
Some(x)
};
let _ns = CachedCallbackNamespace::new(closure);
}
#[allow(clippy::too_many_lines)]
#[test]
fn custom_func() {
let mut slab = Slab::new();
let mut ns = CachedCallbackNamespace::new(|name, args| {
eprintln!("In CB: {name}");
match name {
"x" => Some(1.0),
"y" => Some(2.0),
"z" => Some(3.0),
"foo" => Some(args.first().unwrap_or(&std::f64::NAN) * 10.0),
"bar" => {
Some(args.first().unwrap_or(&std::f64::NAN) + args.get(1).unwrap_or(&std::f64::NAN))
}
_ => None,
}
});
assert_eq!(
Parser::new()
.parse("x + 1.5", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, {
ns.cache_clear();
&mut ns
}),
Ok(2.5)
);
assert_eq!(
Parser::new()
.parse("x() + 1.5", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, {
ns.cache_clear();
&mut ns
}),
Ok(2.5)
);
assert_eq!(
Parser::new()
.parse("x(1,2,3) + 1.5", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, {
ns.cache_clear();
&mut ns
}),
Ok(2.5)
);
eprintln!("I should see TWO x lookups, 1 y, and 1 z:");
assert_eq!(
Parser::new()
.parse("x(x,y,z) + 1.5", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, {
ns.cache_clear();
&mut ns
}),
Ok(2.5)
);
eprintln!("I should see TWO x lookups:");
assert_eq!(
Parser::new()
.parse("x(x,x,x) + 1.5", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, {
ns.cache_clear();
&mut ns
}),
Ok(2.5)
);
eprintln!("I should see TWO x lookups:");
assert_eq!(
Parser::new()
.parse("x(1.0) + x(1.1) + x(1.0) + x(1.1)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, {
ns.cache_clear();
&mut ns
}),
Ok(4.0)
);
eprintln!("---------------------------");
assert_eq!(
Parser::new()
.parse("foo(1.23)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, {
ns.cache_clear();
&mut ns
}),
Ok(12.3)
);
assert_eq!(
Parser::new()
.parse("bar(1.23, 3.21)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, {
ns.cache_clear();
&mut ns
}),
Ok(4.439_999_999_999_999_5)
);
assert_eq!(
format!(
"{:?}",
Parser::new()
.parse("bar(1.23)", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, {
ns.cache_clear();
&mut ns
})
),
"Ok(NaN)"
);
}
#[test]
#[cfg(feature = "unsafe-vars")]
fn unsafe_var() {
let mut slab = Slab::new();
let mut ua = 1.23;
let mut ub = 4.56;
unsafe {
slab.ps.add_unsafe_var("ua".to_string(), &ua);
slab.ps.add_unsafe_var("ub".to_string(), &ub);
}
let mut ns = EmptyNamespace;
assert_eq!(
Parser::new()
.parse("ua + ub + 5", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(10.79)
);
ua += 1.0;
ub += 2.0;
assert_eq!(
Parser::new()
.parse("ua + ub + 5", &mut slab.ps)
.unwrap()
.from(&slab.ps)
.eval(&slab, &mut ns),
Ok(13.79)
);
let _ = (ua, ub); }