1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
use crate::slab::Slab;
use crate::evaler::Evaler;

use kerr::KErr;

use std::collections::BTreeMap;

//---- Types:

pub trait EvalNamespace {
    fn get_cached(&mut self, name:&str, args:Vec<f64>) -> Option<f64>;
    fn set_cached(&mut self, name:String, val:f64);
    fn create_cached(&mut self, name:String, val:f64) -> Result<(),KErr>;
    fn clear_cached(&mut self);

    #[inline(always)]
    fn eval(&mut self, slab:&Slab, evaler:& impl Evaler) -> Result<f64,KErr> where Self:Sized {
        evaler.eval(slab, self).map_err(|e| e.pre(&format!("eval({:?})",evaler)))
    }
}

pub struct EmptyNamespace;

pub struct FlatNamespace<'a> {
    map:BTreeMap<String,f64>,
    cb :Box<dyn FnMut(&str, Vec<f64>)->Option<f64> + 'a>,  // I think a reference would be more efficient than a Box, but then I would need to use a funky 'let cb=|n|{}; Namespace::new(&cb)' syntax.  The Box results in a super convenient pass-the-cb-by-value API interface.
}

pub struct ScopedNamespace<'a> {
    maps:Vec<BTreeMap<String,f64>>,
    cb  :Box<dyn FnMut(&str, Vec<f64>)->Option<f64> + 'a>,
}

//---- Impls:

#[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.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> {
    fn get_cached(&mut self, name:&str, args:Vec<f64>) -> Option<f64> {
        let mut keybuf = String::new();
        let key = key_from_nameargs(&mut keybuf, name, &args);
        self.get(key).copied()
    }
    // Think of the 'self' BTreeMap as an alternative to a callback.  When you set/create/clear for other Namespace types,
    // it doesn't modify the callback results -- it modifies the Namespace cache.  Therefore, these become no-ops for this type:
    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<(),KErr> { panic!("cannot create cached value in BTreeMap Namespace"); }
    fn clear_cached(&mut self) {}
}

impl EvalNamespace for Vec<BTreeMap<String,f64>> {
    fn get_cached(&mut self, name:&str, args:Vec<f64>) -> Option<f64> {
        let mut keybuf = String::new();
        let key = key_from_nameargs(&mut keybuf, name, &args);

        for map in self.iter().rev() {
            if let Some(&val) = map.get(key) { return Some(val); }
        }
        None
    }
    // Think of the 'self' Vec<BTreeMap> as an alternative to a callback.  When you set/create/clear for other Namespace types,
    // it doesn't modify the callback results -- it modifies the Namespace cache.  Therefore, these become no-ops for this type:
    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<(),KErr> { panic!("cannot create cached value in Vec<BTreeMap> Namespace"); }
    fn clear_cached(&mut self) {}
}

impl EvalNamespace for EmptyNamespace {
    fn get_cached(&mut self, _name:&str, _args:Vec<f64>) -> 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<(),KErr> { panic!("cannot create cached value in EmptyNamespace"); }
    fn clear_cached(&mut self) {}
}


impl EvalNamespace for FlatNamespace<'_> {
    fn get_cached(&mut self, name:&str, args:Vec<f64>) -> Option<f64> {
        let mut keybuf = String::new();
        let key = key_from_nameargs(&mut 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<(),KErr> {
        if self.map.contains_key(&name) { return Err(KErr::new("AlreadyExists")); }
        self.map.insert(name, val);
        Ok(())
    }
    fn clear_cached(&mut self) {
        self.map = BTreeMap::new();
    }
}

impl<'a> FlatNamespace<'a> {
    #[inline]
    pub fn new<F>(cb:F) -> Self where F:FnMut(&str,Vec<f64>)->Option<f64> + 'a {
        FlatNamespace{
            map:BTreeMap::new(),
            cb :Box::new(cb),
        }
    }
}

impl EvalNamespace for ScopedNamespace<'_> {
    fn get_cached(&mut self, name:&str, args:Vec<f64>) -> Option<f64> {
        let mut keybuf = String::new();
        let key = key_from_nameargs(&mut 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) => {
                self.maps.last_mut().unwrap().insert(key.to_string(),val);
                Some(val)
            }
            None => None,
        }
    }
    fn set_cached(&mut self, name:String, val:f64) {
        self.maps.last_mut().unwrap().insert(name, val);
    }
    fn create_cached(&mut self, name:String, val:f64) -> Result<(),KErr> {
        let cur_layer = self.maps.last_mut().unwrap();
        if cur_layer.contains_key(&name) { return Err(KErr::new("AlreadyExists")); }
        cur_layer.insert(name, val);
        Ok(())
    }
    fn clear_cached(&mut self) {
        self.maps = Vec::with_capacity(self.maps.len());  // Assume the future usage will be similar to historical usage.
        self.push();
    }
}

impl<'a> ScopedNamespace<'a> {
    #[inline]
    pub fn new<F>(cb:F) -> Self where F:FnMut(&str,Vec<f64>)->Option<f64> + 'a {
        let mut ns = ScopedNamespace{
            maps:Vec::with_capacity(2),
            cb  :Box::new(cb),
        };
        ns.push();
        ns
    }

    #[inline]
    pub fn push(&mut self) {
        self.maps.push(BTreeMap::new());
    }
    #[inline]
    pub fn pop(&mut self) {
        self.maps.pop();
    }

    pub fn eval_bubble(&mut self, slab:&Slab, evaler:& impl Evaler) -> Result<f64,KErr> {
        self.push();
        let out = self.eval(slab,evaler);
        self.pop();
        out
    }
    #[inline]
    pub fn eval(&mut self, slab:&Slab, evaler:& impl Evaler) -> Result<f64,KErr> {
        evaler.eval(slab, self).map_err(|e| e.pre(&format!("eval({:?})",evaler)))
    }
}