Skip to main content

state_engine/core/
pool.rs

1use std::string::{String, ToString};
2use std::vec::Vec;
3
4/// Interns unique strings and assigns each a u16 index.
5/// Index 0 is reserved as null.
6pub struct DynamicPool {
7    slots: Vec<String>,
8}
9
10impl DynamicPool {
11    pub fn new() -> Self {
12        let mut slots = Vec::new();
13        slots.push(String::new()); // index 0 = null
14        Self { slots }
15    }
16
17    pub fn intern(&mut self, s: &str) -> u16 {
18        if let Some(idx) = self.slots.iter().position(|x| x == s) {
19            return idx as u16;
20        }
21        let idx = self.slots.len() as u16;
22        self.slots.push(s.to_string());
23        idx
24    }
25
26    pub fn get(&self, index: u16) -> Option<&str> {
27        self.slots.get(index as usize).map(|s: &String| s.as_str())
28    }
29}
30
31impl Default for DynamicPool {
32    fn default() -> Self {
33        Self::new()
34    }
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40
41    #[test]
42    fn test_intern_dedup() {
43        let mut pool = DynamicPool::new();
44        let i0 = pool.intern("foo");
45        let i1 = pool.intern("bar");
46        assert_eq!(pool.intern("foo"), i0);
47        assert_ne!(i0, i1);
48        assert_ne!(i0, 0);
49    }
50
51    #[test]
52    fn test_get() {
53        let mut pool = DynamicPool::new();
54        let i0 = pool.intern("foo");
55        assert_eq!(pool.get(i0), Some("foo"));
56        assert_eq!(pool.get(0), Some(""));  // null slot
57        assert_eq!(pool.get(999), None);
58    }
59}