[][src]Module fasteval::evalns

Evaluation Namespaces used for Variable-lookups and custom Functions.

Several Evaluation Namespace types are defined, each with their own advantages:

  • EmptyNamespace -- Useful when you know that your expressions don't need to look up any variables.
  • BTreeMap -- A simple way to define variables with a map.
  • FnMut(&str,Vec<f64>) -> Option<f64> -- Define variables and custom functions using a callback function.
  • CachedCallbackNamespace -- Like the above callback-based Namespace, but results are cached so the callback is not queried more than once for a given variable.
  • Vec<BTreeMap<String,f64>> -- Define variables with layered maps. Each layer is a separate 'scope'. Higher layers take precedence over lower layers. Very useful for creating scoped higher-level-languages.

Examples

EmptyNamespace

fn main() -> Result<(), fasteval::Error> {
    let mut ns = fasteval::EmptyNamespace;

    let val = fasteval::ez_eval("sin(pi()/2)", &mut ns)?;
    assert_eq!(val, 1.0);

    Ok(())
}

BTreeMap<String,f64>

use std::collections::BTreeMap;
fn main() -> Result<(), fasteval::Error> {
    let mut map : BTreeMap<String,f64> = BTreeMap::new();
    map.insert("x".to_string(), 2.0);

    let val = fasteval::ez_eval("x * (x + 1)", &mut map)?;
    assert_eq!(val, 6.0);

    Ok(())
}

BTreeMap<&'static str,f64>

use std::collections::BTreeMap;
fn main() -> Result<(), fasteval::Error> {
    let mut map : BTreeMap<&'static str,f64> = BTreeMap::new();
    map.insert("x", 2.0);

    let val = fasteval::ez_eval("x * (x + 1)", &mut map)?;
    assert_eq!(val, 6.0);

    Ok(())
}

Callback: FnMut(&str,Vec) -> Option

fn main() -> Result<(), fasteval::Error> {
    let mut num_lookups = 0;
    let mut cb = |name:&str, args:Vec<f64>| -> Option<f64> {
        num_lookups += 1;
        match name {
            "x" => Some(2.0),
            _ => None,
        }
    };

    let val = fasteval::ez_eval("x * (x + 1)", &mut cb)?;
    assert_eq!(val, 6.0);
    assert_eq!(num_lookups, 2);  // Notice that 'x' was looked-up twice.

    Ok(())
}

CachedCallbackNamespace

fn main() -> Result<(), fasteval::Error> {
    let mut num_lookups = 0;
    let val = {
        let cb = |name:&str, args:Vec<f64>| -> Option<f64> {
            num_lookups += 1;
            match name {
                "x" => {
                    // Pretend that it is very expensive to calculate this,
                    // and that's why we want to use the CachedCallbackNamespace cache.
                    for i in 0..1000000 { /* do work */ }  // Fake Work for this example.
                    Some(2.0)
                }
                _ => None,
            }
        };
        let mut ns = fasteval::CachedCallbackNamespace::new(cb);

        fasteval::ez_eval("x * (x + 1)", &mut ns)?
    };
    assert_eq!(val, 6.0);
    assert_eq!(num_lookups, 1);  // Notice that only 1 lookup occurred.
                                 // The second 'x' value was cached.

    Ok(())
}

Vec<BTreeMap<String,64>>

use std::collections::BTreeMap;
fn main() -> Result<(), fasteval::Error> {
    let mut layer1 = BTreeMap::new();
    layer1.insert("x".to_string(), 2.0);
    layer1.insert("y".to_string(), 3.0);

    let mut layers : Vec<BTreeMap<String,f64>> = vec![layer1];

    let val = fasteval::ez_eval("x * y", &mut layers)?;
    assert_eq!(val, 6.0);

    // Let's add another layer which shadows the previous one:
    let mut layer2 = BTreeMap::new();
    layer2.insert("x".to_string(), 3.0);
    layers.push(layer2);

    let val = fasteval::ez_eval("x * y", &mut layers)?;
    assert_eq!(val, 9.0);

    // Remove the top layer and we'll be back to what we had before:
    layers.pop();

    let val = fasteval::ez_eval("x * y", &mut layers)?;
    assert_eq!(val, 6.0);

    Ok(())
}

Custom Namespace Types

If the pre-defined Namespace types aren't perfect for your application, you can create your own namespace type -- just implemenet the EvalNamespace trait (and maybe the Cached and Layered traits too). Also, as fasteval becomes more mature and is used for more real-life things, I will continue to add more useful Namespace types.

Here are a few ideas of possibly-useful custom Namespace types:

  • BTreeMap<String, Fn(Vec)->Option> -- This namespace type would provide a very convenient way to register variables and custom functions. It would be a bit slower than the Callback-based Namespace shown above, but it has isolation and composition advantages.

  • Vec<Fn(&str,Vec)->Option> -- This would be a Layered namespace, with each layer having its own callback. Really powerful!

  • CachedCallbacksNamespace -- Same as above, but with a cache for each layer. Good for expensive look-ups.

Structs

CachedCallbackNamespace

CachedCallbackNamespace is useful when your variable/function lookups are expensive.

EmptyNamespace

Use EmptyNamespace when you know that you won't be looking up any variables.

Traits

Cached

Cache operations for EvalNamespaces.

EvalNamespace

All fasteval Namespaces must implement the EvalNamespace trait.