diff --git a/src/rust/op_cache.rs b/src/rust/op_cache.rs index 0523975..67ca47c 100644 --- a/src/rust/op_cache.rs +++ b/src/rust/op_cache.rs @@ -1,11 +1,11 @@ -use std::collections::HashSet; +use std::collections::HashMap; use napi_derive::napi; -pub type OpTuple = (String, u32, String, u32); +pub type OpTuple = (String, u32, String, u32); // buf_path, start, text, end #[napi] pub struct OpCache { - store: HashSet, + store: HashMap } #[napi] @@ -13,30 +13,53 @@ impl OpCache { #[napi(constructor)] pub fn new() -> Self { OpCache { - store: HashSet::new(), + store: HashMap::new() } } #[napi] - pub fn put(&mut self, buf: String, start: u32, text: String, end: u32) -> bool { + pub fn to_string(&self) -> String { + self.store.iter() + .map(|(k, v)| format!("{}x Op(@{} {}:{} '{}')", k.0, v, k.1, k.3, k.2)) + .collect::>() + .join(", ") + } + + #[napi] + pub fn put(&mut self, buf: String, start: u32, text: String, end: u32) -> i32 { let op = (buf, start, text, end); - let res = self.store.contains(&op); - self.store.insert(op); - res + match self.store.get_mut(&op) { + Some(val) => { + if *val < 0 { *val = 0 } + *val += 1; + *val + }, + None => { + self.store.insert(op, 1); + return 1; + } + } } #[napi] pub fn get(&mut self, buf: String, start: u32, text: String, end: u32) -> bool { let op = (buf, start, text, end); - if self.store.contains(&op) { - self.store.remove(&op); - true - } else { - false + match self.store.get_mut(&op) { + Some(val) => { + *val -= 1; + *val >= 0 + } + None => { + tracing::warn!("never seen this op: {:?}", op); + self.store.insert(op, -1); + false + }, } } } - +//a +//consume a +//a @@ -44,28 +67,38 @@ impl OpCache { #[cfg(test)] mod test { #[test] - fn op_cache_put_returns_whether_it_already_contained_the_key() { + fn opcache_put_increments_internal_counter() { let mut op = super::OpCache::new(); - assert!(!op.put("default".into(), 0, "hello world".into(), 0)); // false: did not already contain it - assert!(op.put("default".into(), 0, "hello world".into(), 0)); // true: already contained it + assert_eq!(op.put("default".into(), 0, "hello world".into(), 0), 1); // 1: did not already contain it + assert_eq!(op.put("default".into(), 0, "hello world".into(), 0), 2); // 2: already contained it } #[test] - fn op_cache_contains_only_after_put() { + fn op_cache_get_checks_count() { let mut op = super::OpCache::new(); - assert!(!op.get("default".into(), 0, "hello world".into(), 0)); - op.put("default".into(), 0, "hello world".into(), 0); - assert!(op.get("default".into(), 0, "hello world".into(), 0)); + assert_eq!(op.get("default".into(), 0, "hello world".into(), 0), false); + assert_eq!(op.put("default".into(), 0, "hello world".into(), 0), 1); + assert_eq!(op.get("default".into(), 0, "hello world".into(), 0), true); + assert_eq!(op.get("default".into(), 0, "hello world".into(), 0), false); + } + #[test] + fn op_cache_get_works_for_multiple_puts() { + let mut op = super::OpCache::new(); + assert_eq!(op.get("default".into(), 0, "hello world".into(), 0), false); + assert_eq!(op.put("default".into(), 0, "hello world".into(), 0), 1); + assert_eq!(op.put("default".into(), 0, "hello world".into(), 0), 2); + assert_eq!(op.get("default".into(), 0, "hello world".into(), 0), true); + assert_eq!(op.get("default".into(), 0, "hello world".into(), 0), true); + assert_eq!(op.get("default".into(), 0, "hello world".into(), 0), false); } #[test] fn op_cache_different_keys(){ let mut op = super::OpCache::new(); - assert!(!op.get("default".into(), 0, "hello world".into(), 0)); - op.put("default".into(), 0, "hello world".into(), 0); - assert!(op.get("default".into(), 0, "hello world".into(), 0)); - assert!(!op.get("workspace".into(), 0, "hi".into(), 0)); - op.put("workspace".into(), 0, "hi".into(), 0); - assert!(op.get("workspace".into(), 0, "hi".into(), 0)); + assert_eq!(op.get("default".into(), 0, "hello world".into(), 0), false); + assert_eq!(op.put("default".into(), 0, "hello world".into(), 0), 1); + assert_eq!(op.get("workspace".into(), 0, "hi".into(), 0), false); + assert_eq!(op.put("workspace".into(), 0, "hi".into(), 0), 1); + assert_eq!(op.get("workspace".into(), 0, "hi".into(), 0), true); + assert_eq!(op.get("default".into(), 0, "hello world".into(), 0), true); } - } \ No newline at end of file