use std::collections::{BTreeMap, HashMap};
use crate::{ref_id::HandleId, value::Value};
pub trait HandleStore {
fn intern(&mut self, value: Value) -> HandleId;
fn get(&self, id: &HandleId) -> Option<&Value>;
fn contains(&self, id: &HandleId) -> bool;
fn handle_for_value(&self, value: &Value) -> Option<HandleId>;
}
#[derive(Clone, Debug, Default)]
pub struct BTreeHandleStore {
values: BTreeMap<HandleId, Value>,
handles_by_value: HashMap<Value, HandleId>,
}
impl BTreeHandleStore {
pub fn new() -> Self {
Self::default()
}
pub fn len(&self) -> usize {
self.values.len()
}
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
}
impl HandleStore for BTreeHandleStore {
fn intern(&mut self, value: Value) -> HandleId {
if let Some(handle) = self.handles_by_value.get(&value) {
return *handle;
}
let handle = HandleId::fresh();
self.handles_by_value.insert(value.clone(), handle);
self.values.insert(handle, value);
handle
}
fn get(&self, id: &HandleId) -> Option<&Value> {
self.values.get(id)
}
fn contains(&self, id: &HandleId) -> bool {
self.values.contains_key(id)
}
fn handle_for_value(&self, value: &Value) -> Option<HandleId> {
self.handles_by_value.get(value).copied()
}
}
#[cfg(test)]
mod tests {
use crate::{DefaultFactory, Factory};
use super::*;
fn factory() -> DefaultFactory {
DefaultFactory
}
#[test]
fn handle_store_intern_followed_by_get_returns_original_value() {
let mut store = BTreeHandleStore::new();
let value = factory().string("stored".to_owned()).unwrap();
let handle = store.intern(value.clone());
assert_eq!(store.get(&handle), Some(&value));
assert!(store.contains(&handle));
}
#[test]
fn handle_store_reuses_handle_for_same_value() {
let mut store = BTreeHandleStore::new();
let value = factory().bool(true).unwrap();
let first = store.intern(value.clone());
let second = store.intern(value);
assert_eq!(first, second);
assert_eq!(store.len(), 1);
}
#[test]
fn handle_store_distinguishes_distinct_values() {
let mut store = BTreeHandleStore::new();
let first_value = factory().bool(true).unwrap();
let second_value = factory().bool(true).unwrap();
let first = store.intern(first_value);
let second = store.intern(second_value);
assert_ne!(first, second);
assert_eq!(store.len(), 2);
}
#[test]
fn handle_store_reuses_handle_for_cloned_value() {
let mut store = BTreeHandleStore::new();
let left = factory().string("same".to_owned()).unwrap();
let right = left.clone();
assert_eq!(store.intern(left), store.intern(right));
}
}