use std::collections::BTreeMap;
use std::fmt;
pub struct Context<'a> {
values: BTreeMap<String, f64>,
query: Option<Box<Fn(&str) -> Option<f64> + 'a>>,
}
impl<'a> fmt::Debug for Context<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let query = match self.query {
Some(_) => "Some(<boxed closure>)",
None => "None",
};
fmt.debug_struct("Context")
.field("value", &self.values)
.field("query", &query)
.finish()
}
}
impl<'a> Context<'a> {
pub fn new() -> Context<'a> {
Context {
values: BTreeMap::new(),
query: None,
}
}
pub fn set<S: Into<String>>(&mut self, name: S, value: f64) {
self.values.insert(name.into(), value);
}
pub fn get(&self, name: &str) -> Option<f64> {
self.values.get(name).cloned().or_else(|| {
self.query.as_ref().and_then(|function| function(name))
})
}
pub fn set_query<F>(&mut self, function: F)
where
F: Fn(&str) -> Option<f64> + 'a,
{
self.query = Some(Box::new(function));
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::fmt::Write;
#[test]
fn variables() {
let mut context = Context::new();
context.set("a", 2.0);
assert_eq!(context.get("a"), Some(2.0));
assert_eq!(context.get("b"), None);
context.set("a", 5.0);
context.set("b", 1.0);
assert_eq!(context.get("a"), Some(5.0));
assert_eq!(context.get("b"), Some(1.0));
}
#[test]
fn debug() {
let mut context = Context::new();
context.set("a", 2.4);
let mut string = String::new();
let _ = write!(string, "{:?}", context);
assert_eq!(string, "Context { value: {\"a\": 2.4}, query: \"None\" }");
let mut string = String::new();
let _ = write!(string, "{:#?}", context);
assert_eq!(string, "Context {\n value: {\n \"a\": 2.4\n },\n query: \"None\"\n}");
context.set_query(|_| None);
let mut string = String::new();
let _ = write!(string, "{:?}", context);
assert_eq!(string, "Context { value: {\"a\": 2.4}, query: \"Some(<boxed closure>)\" }");
}
}