use crate::error::Error;
use std::collections::BTreeMap;
pub trait EvalNamespace {
fn get_cached( &mut self, name:&str, args:Vec<f64>, keybuf:&mut String) -> Option<f64>;
fn set_cached( &mut self, name:String, val:f64);
fn create_cached(&mut self, name:String, val:f64) -> Result<(),Error>;
fn clear_cached(&mut self);
}
pub trait Layered {
fn push(&mut self);
fn pop(&mut self);
}
pub struct EmptyNamespace;
pub struct CachedFlatNamespace<'a> {
map:BTreeMap<String,f64>,
cb :Box<dyn FnMut(&str, Vec<f64>)->Option<f64> + 'a>, }
pub struct CachedScopedNamespace<'a> {
maps:Vec<BTreeMap<String,f64>>,
cb :Box<dyn FnMut(&str, Vec<f64>)->Option<f64> + 'a>,
}
pub struct Bubble<'a,'b:'a> {
ns :&'a mut CachedScopedNamespace<'b>,
count:usize,
}
#[inline(always)]
fn key_from_nameargs<'a,'b:'a>(keybuf:&'a mut String, name:&'b str, args:&[f64]) -> &'a str {
if args.is_empty() {
name
} else {
keybuf.clear();
keybuf.reserve(name.len() + 20*args.len());
keybuf.push_str(name);
for f in args {
keybuf.push_str(" , ");
keybuf.push_str(&f.to_string());
};
keybuf.as_str()
}
}
impl EvalNamespace for BTreeMap<String,f64> {
#[inline]
fn get_cached(&mut self, name:&str, args:Vec<f64>, keybuf:&mut String) -> Option<f64> {
let key = key_from_nameargs(keybuf, name, &args);
self.get(key).copied()
}
fn set_cached(&mut self, _name:String, _val:f64) { panic!("cannot set cached value in BTreeMap Namespace"); }
fn create_cached(&mut self, _name:String, _val:f64) -> Result<(),Error> { panic!("cannot create cached value in BTreeMap Namespace"); }
fn clear_cached(&mut self) {}
}
impl EvalNamespace for Vec<BTreeMap<String,f64>> {
#[inline]
fn get_cached(&mut self, name:&str, args:Vec<f64>, keybuf:&mut String) -> Option<f64> {
let key = key_from_nameargs(keybuf, name, &args);
for map in self.iter().rev() {
if let Some(&val) = map.get(key) { return Some(val); }
}
None
}
fn set_cached(&mut self, _name:String, _val:f64) { panic!("cannot set cached value in Vec<BTreeMap> Namespace"); }
fn create_cached(&mut self, _name:String, _val:f64) -> Result<(),Error> { panic!("cannot create cached value in Vec<BTreeMap> Namespace"); }
fn clear_cached(&mut self) {}
}
impl<F> EvalNamespace for F where F:FnMut(&str,Vec<f64>)->Option<f64> {
#[inline]
fn get_cached(&mut self, name:&str, args:Vec<f64>, _keybuf:&mut String) -> Option<f64> {
self(name,args)
}
fn set_cached(&mut self, _name:String, _val:f64) { panic!("cannot set cached value in Uncached CB Namespace"); }
fn create_cached(&mut self, _name:String, _val:f64) -> Result<(),Error> { panic!("cannot create cached value in Uncached CB Namespace"); }
fn clear_cached(&mut self) {}
}
impl EvalNamespace for EmptyNamespace {
#[inline]
fn get_cached(&mut self, _name:&str, _args:Vec<f64>, _keybuf:&mut String) -> Option<f64> { None }
fn set_cached(&mut self, _name:String, _val:f64) { panic!("cannot set cached value in EmptyNamespace"); }
fn create_cached(&mut self, _name:String, _val:f64) -> Result<(),Error> { panic!("cannot create cached value in EmptyNamespace"); }
fn clear_cached(&mut self) {}
}
impl EvalNamespace for CachedFlatNamespace<'_> {
fn get_cached(&mut self, name:&str, args:Vec<f64>, keybuf:&mut String) -> Option<f64> {
let key = key_from_nameargs(keybuf, name, &args);
if let Some(&val) = self.map.get(key) { return Some(val); }
match (self.cb)(name,args) {
Some(val) => {
self.map.insert(key.to_string(),val);
Some(val)
}
None => None,
}
}
fn set_cached(&mut self, name:String, val:f64) {
self.map.insert(name, val);
}
fn create_cached(&mut self, name:String, val:f64) -> Result<(),Error> {
if self.map.contains_key(&name) { return Err(Error::AlreadyExists); }
self.map.insert(name, val);
Ok(())
}
fn clear_cached(&mut self) {
self.map = BTreeMap::new();
}
}
impl<'a> CachedFlatNamespace<'a> {
#[inline]
pub fn new<F>(cb:F) -> Self where F:FnMut(&str,Vec<f64>)->Option<f64> + 'a {
CachedFlatNamespace{
map:BTreeMap::new(),
cb :Box::new(cb),
}
}
}
impl EvalNamespace for CachedScopedNamespace<'_> {
fn get_cached(&mut self, name:&str, args:Vec<f64>, keybuf:&mut String) -> Option<f64> {
let key = key_from_nameargs(keybuf, name, &args);
for map in self.maps.iter().rev() {
if let Some(&val) = map.get(key) { return Some(val); }
}
match (self.cb)(name,args) {
Some(val) => {
match self.maps.last_mut() {
Some(m_ref) => { m_ref.insert(key.to_string(),val); }
None => (), }
Some(val)
}
None => None,
}
}
fn set_cached(&mut self, name:String, val:f64) {
match self.maps.last_mut() {
Some(m_ref) => { m_ref.insert(name, val); }
None => (), }
}
fn create_cached(&mut self, name:String, val:f64) -> Result<(),Error> {
match self.maps.last_mut() {
Some(cur_layer) => {
if cur_layer.contains_key(&name) { return Err(Error::AlreadyExists); }
cur_layer.insert(name, val);
}
None => return Err(Error::Unreachable),
};
Ok(())
}
fn clear_cached(&mut self) {
self.maps = Vec::with_capacity(self.maps.len()); self.push();
}
}
impl Layered for CachedScopedNamespace<'_> {
#[inline]
fn push(&mut self) {
self.maps.push(BTreeMap::new());
}
#[inline]
fn pop(&mut self) {
self.maps.pop();
}
}
impl<'a> CachedScopedNamespace<'a> {
#[inline]
pub fn new<F>(cb:F) -> Self where F:FnMut(&str,Vec<f64>)->Option<f64> + 'a {
let mut ns = CachedScopedNamespace{
maps:Vec::with_capacity(2),
cb :Box::new(cb),
};
ns.push();
ns
}
}
impl Bubble<'_,'_> {
pub fn new<'a,'b:'a>(ns:&'a mut CachedScopedNamespace<'b>) -> Bubble<'a,'b> {
Bubble{
ns,
count:0,
}
}
}
impl Drop for Bubble<'_,'_> {
fn drop(&mut self) {
while self.count>0 {
self.pop();
}
}
}
impl EvalNamespace for Bubble<'_,'_> {
#[inline]
fn get_cached(&mut self, name:&str, args:Vec<f64>, keybuf:&mut String) -> Option<f64> {
self.ns.get_cached(name,args,keybuf)
}
#[inline]
fn set_cached(&mut self, name:String, val:f64) {
self.ns.set_cached(name,val)
}
#[inline]
fn create_cached(&mut self, name:String, val:f64) -> Result<(),Error> {
self.ns.create_cached(name,val)
}
#[inline]
fn clear_cached(&mut self) {
self.ns.clear_cached()
}
}
impl Layered for Bubble<'_,'_> {
#[inline]
fn push(&mut self) {
self.count += 1;
self.ns.push();
}
#[inline]
fn pop(&mut self) {
self.ns.pop();
self.count -= 1;
}
}
#[cfg(test)]
mod internal_tests {
use super::*;
#[test]
fn bubble() {
let mut ns = CachedScopedNamespace::new(|_,_| None);
assert_eq!(ns.maps.len(), 1);
{
let mut bub = Bubble::new(&mut ns); bub.push();
assert_eq!(bub.ns.maps.len(), 2);
bub.push();
assert_eq!(bub.ns.maps.len(), 3);
bub.push();
assert_eq!(bub.ns.maps.len(), 4);
bub.pop();
assert_eq!(bub.ns.maps.len(), 3);
}
assert_eq!(ns.maps.len(), 1);
}
}