• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use super::SmallCString;
2 use std::cell::RefCell;
3 use std::collections::BTreeMap;
4 
5 /// Maps parameter names to parameter indices.
6 #[derive(Default, Clone, Debug)]
7 // BTreeMap seems to do better here unless we want to pull in a custom hash
8 // function.
9 pub(crate) struct ParamIndexCache(RefCell<BTreeMap<SmallCString, usize>>);
10 
11 impl ParamIndexCache {
get_or_insert_with<F>(&self, s: &str, func: F) -> Option<usize> where F: FnOnce(&std::ffi::CStr) -> Option<usize>,12     pub fn get_or_insert_with<F>(&self, s: &str, func: F) -> Option<usize>
13     where
14         F: FnOnce(&std::ffi::CStr) -> Option<usize>,
15     {
16         let mut cache = self.0.borrow_mut();
17         // Avoid entry API, needs allocation to test membership.
18         if let Some(v) = cache.get(s) {
19             return Some(*v);
20         }
21         // If there's an internal nul in the name it couldn't have been a
22         // parameter, so early return here is ok.
23         let name = SmallCString::new(s).ok()?;
24         let val = func(&name)?;
25         cache.insert(name, val);
26         Some(val)
27     }
28 }
29 
30 #[cfg(test)]
31 mod test {
32     use super::*;
33     #[test]
test_cache()34     fn test_cache() {
35         let p = ParamIndexCache::default();
36         let v = p.get_or_insert_with("foo", |cstr| {
37             assert_eq!(cstr.to_str().unwrap(), "foo");
38             Some(3)
39         });
40         assert_eq!(v, Some(3));
41         let v = p.get_or_insert_with("foo", |_| {
42             panic!("shouldn't be called this time");
43         });
44         assert_eq!(v, Some(3));
45         let v = p.get_or_insert_with("gar\0bage", |_| {
46             panic!("shouldn't be called here either");
47         });
48         assert_eq!(v, None);
49         let v = p.get_or_insert_with("bar", |cstr| {
50             assert_eq!(cstr.to_str().unwrap(), "bar");
51             None
52         });
53         assert_eq!(v, None);
54         let v = p.get_or_insert_with("bar", |cstr| {
55             assert_eq!(cstr.to_str().unwrap(), "bar");
56             Some(30)
57         });
58         assert_eq!(v, Some(30));
59     }
60 }
61