Skip to main content

sim_kernel/
handle_store.rs

1//! The [`HandleStore`] contract: interning values behind opaque handle ids.
2//!
3//! This is protocol the libraries implement; the kernel ships a default store
4//! and defines the handle-id identity, not the lifetime policy.
5
6use std::collections::{BTreeMap, HashMap};
7
8use crate::{ref_id::HandleId, value::Value};
9
10/// Contract for interning runtime [`Value`]s behind opaque [`HandleId`]s.
11///
12/// This is protocol the libraries implement; the kernel ships a default
13/// [`BTreeHandleStore`] and defines the handle-id identity, not the lifetime
14/// policy.
15pub trait HandleStore {
16    /// Interns `value`, returning its handle; equal values reuse one handle.
17    fn intern(&mut self, value: Value) -> HandleId;
18    /// Resolves the value for `id`, or `None` when it is not stored here.
19    fn get(&self, id: &HandleId) -> Option<&Value>;
20    /// Returns whether `id` is interned in this store.
21    fn contains(&self, id: &HandleId) -> bool;
22    /// Returns the existing handle for `value`, if one is interned.
23    fn handle_for_value(&self, value: &Value) -> Option<HandleId>;
24}
25
26/// In-memory [`HandleStore`] keyed by [`HandleId`] with a reverse value index;
27/// the kernel default.
28#[derive(Clone, Debug, Default)]
29pub struct BTreeHandleStore {
30    values: BTreeMap<HandleId, Value>,
31    handles_by_value: HashMap<Value, HandleId>,
32}
33
34impl BTreeHandleStore {
35    /// Creates an empty store.
36    pub fn new() -> Self {
37        Self::default()
38    }
39
40    /// Returns the number of interned values.
41    pub fn len(&self) -> usize {
42        self.values.len()
43    }
44
45    /// Returns whether the store holds no values.
46    pub fn is_empty(&self) -> bool {
47        self.values.is_empty()
48    }
49}
50
51impl HandleStore for BTreeHandleStore {
52    fn intern(&mut self, value: Value) -> HandleId {
53        if let Some(handle) = self.handles_by_value.get(&value) {
54            return *handle;
55        }
56
57        let handle = HandleId::fresh();
58        self.handles_by_value.insert(value.clone(), handle);
59        self.values.insert(handle, value);
60        handle
61    }
62
63    fn get(&self, id: &HandleId) -> Option<&Value> {
64        self.values.get(id)
65    }
66
67    fn contains(&self, id: &HandleId) -> bool {
68        self.values.contains_key(id)
69    }
70
71    fn handle_for_value(&self, value: &Value) -> Option<HandleId> {
72        self.handles_by_value.get(value).copied()
73    }
74}
75
76#[cfg(test)]
77mod tests {
78    use crate::{DefaultFactory, Factory};
79
80    use super::*;
81
82    fn factory() -> DefaultFactory {
83        DefaultFactory
84    }
85
86    #[test]
87    fn handle_store_intern_followed_by_get_returns_original_value() {
88        let mut store = BTreeHandleStore::new();
89        let value = factory().string("stored".to_owned()).unwrap();
90
91        let handle = store.intern(value.clone());
92
93        assert_eq!(store.get(&handle), Some(&value));
94        assert!(store.contains(&handle));
95    }
96
97    #[test]
98    fn handle_store_reuses_handle_for_same_value() {
99        let mut store = BTreeHandleStore::new();
100        let value = factory().bool(true).unwrap();
101
102        let first = store.intern(value.clone());
103        let second = store.intern(value);
104
105        assert_eq!(first, second);
106        assert_eq!(store.len(), 1);
107    }
108
109    #[test]
110    fn handle_store_distinguishes_distinct_values() {
111        let mut store = BTreeHandleStore::new();
112        let first_value = factory().bool(true).unwrap();
113        let second_value = factory().bool(true).unwrap();
114
115        let first = store.intern(first_value);
116        let second = store.intern(second_value);
117
118        assert_ne!(first, second);
119        assert_eq!(store.len(), 2);
120    }
121
122    #[test]
123    fn handle_store_reuses_handle_for_cloned_value() {
124        let mut store = BTreeHandleStore::new();
125        let left = factory().string("same".to_owned()).unwrap();
126        let right = left.clone();
127
128        assert_eq!(store.intern(left), store.intern(right));
129    }
130}