mycroft_support/storage/
data.rs

1//! `data` provides a facility to hold typed data in a deduped fashion, identified by a `usize`
2//! key. The only requirements are that the data be `Hash` and `PartialEq`.
3//! At the moment, this is done as an in-memory store.
4use index::hash::HashIndex;
5use std::hash::Hash;
6use std::ops::Index;
7use std::rc::Rc;
8use std::cell::UnsafeCell;
9
10/// A typed storage object which keeps deduped values of type T.
11/// Keys produced by this object follow the relation:
12///
13/// `data[key] == data[key2]` <-> `key == key2`
14pub struct Data<T> {
15    raw: Rc<UnsafeCell<RawData<T>>>,
16}
17
18impl<T> Clone for Data<T> {
19    fn clone(&self) -> Self {
20        Self {
21            raw: self.raw.clone(),
22        }
23    }
24}
25
26#[derive(Debug, Eq, Clone, PartialEq)]
27enum Usage {
28    Read(usize),
29    Write,
30}
31
32struct RawData<T> {
33    inner: Vec<T>,
34    index: HashIndex<T>,
35    //TODO: Once multithreaded, Usage needs to be locked
36    usage: Usage,
37}
38
39impl<T: PartialEq + Hash> Data<T> {
40    /// Constructs a fresh typed store
41    pub fn new() -> Self {
42        Self {
43            raw: Rc::new(UnsafeCell::new(RawData::new())),
44        }
45    }
46
47    /// Returns the key for the provided data, relative to the store
48    /// If the object is already in the store, it will be dropped, otherwise it will not.
49    pub fn insert(&self, data: T) -> usize {
50        unsafe {
51            let raw: &mut RawData<T> = &mut *self.raw.get();
52            raw.insert(data)
53        }
54    }
55
56    /// Releases read borrows in progress
57    pub unsafe fn read_exit(&self, delta: usize) {
58        (*self.raw.get()).read_exit(delta)
59    }
60}
61
62impl<T: PartialEq + Hash> RawData<T> {
63    fn new() -> Self {
64        RawData {
65            inner: Vec::new(),
66            index: HashIndex::new(),
67            usage: Usage::Read(0),
68        }
69    }
70
71    fn insert(&mut self, data: T) -> usize {
72        // Make sure no refs are out
73        assert_eq!(self.usage, Usage::Read(0));
74        self.usage = Usage::Write;
75        let key = match self.find(&data) {
76            Some(key) => key,
77            None => {
78                let key = self.inner.len();
79                self.index.insert(key, &data);
80                self.inner.push(data);
81                key
82            }
83        };
84        self.usage = Usage::Read(0);
85        key
86    }
87
88    fn find(&self, data: &T) -> Option<usize> {
89        self.index.find(data, &self.inner)
90    }
91}
92
93impl<T> RawData<T> {
94    fn read_exit(&mut self, delta: usize) {
95        match self.usage {
96            Usage::Read(n) => self.usage = Usage::Read(n - delta),
97            Usage::Write => panic!("Tried to end read borrow while write was in progress"),
98        }
99    }
100    fn read_enter(&mut self, delta: usize) {
101        match self.usage {
102            Usage::Read(n) => self.usage = Usage::Read(n + delta),
103            Usage::Write => panic!("Tried to start reading while a write is in progress"),
104        }
105    }
106}
107
108impl<T> Index<usize> for Data<T> {
109    type Output = T;
110    fn index(&self, key: usize) -> &Self::Output {
111        unsafe {
112            let raw = &mut *self.raw.get();
113            raw.read_enter(1);
114            &raw.inner[key]
115        }
116    }
117}