reservoir_buf/
lib.rs

1use std::marker::PhantomData;
2use std::fmt::{self, Formatter};
3use std::hash::{self, Hasher};
4use std::cmp::Ordering;
5
6// TODO: would probably be nice to be able to set an upper bound on the size of the buffer
7
8// TODO: would probably be better to manage the allocation directly rather than delegating to Vec.
9// I think the finer control would be nice and would possibly make the interface nicer (like the sizes
10// being in terms of elements rather than bytes is kind of wonky)
11
12/* --- Reservoir --- */
13
14#[derive(Clone)]
15pub struct Reservoir<T>(Vec<T>);
16
17impl<T> Reservoir<T> {
18    pub const SMALL_CAPACITY: usize = 64;
19    pub const MEDIUM_CAPACITY: usize = 256;
20    pub const LARGE_CAPACITY: usize = 1024;
21
22    pub fn new(capacity: usize) -> Self {
23        Reservoir(Vec::with_capacity(capacity))
24    }
25
26    pub fn get(&self, handle: Handle<T>) -> &T {
27        &self.0[handle.0]
28    }
29
30    pub fn get_mut(&mut self, handle: Handle<T>) -> &mut T {
31        &mut self.0[handle.0]
32    }
33
34    pub fn insert(&mut self, data: T) -> Handle<T> {
35        self.0.push(data);
36        Handle(self.0.len() - 1, PhantomData)
37    }
38}
39
40impl<T> Default for Reservoir<T> {
41    fn default() -> Self {
42        Reservoir::new(Self::MEDIUM_CAPACITY)
43    }
44}
45
46/* --- Handle --- */
47
48pub struct Handle<T>(usize, PhantomData<T>);
49
50impl<T> Clone for Handle<T> {
51    fn clone(&self) -> Self {
52        Handle(self.0, self.1)
53    }
54}
55
56impl<T> fmt::Debug for Handle<T> {
57    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
58        write!(f, "Handle({})", self.0)
59    }
60}
61
62impl<T> hash::Hash for Handle<T> {
63    fn hash<H>(&self, state: &mut H) where H: Hasher {
64        self.0.hash(state)
65    }
66}
67
68impl<T> PartialEq for Handle<T> {
69    fn eq(&self, other: &Self) -> bool {
70        self.0 == other.0
71    }
72}
73
74impl<T> PartialOrd for Handle<T> {
75    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
76        self.0.partial_cmp(&other.0)
77    }
78}
79
80impl<T> Ord for Handle<T> {
81    fn cmp(&self, other: &Self) -> Ordering {
82        self.0.cmp(&other.0)
83    }
84}
85
86impl<T> Copy for Handle<T> {}
87impl<T> Eq for Handle<T> {}
88
89// TODO: manually implement Hash, Eq, Ord, PartialEq, PartialOrd
90// note to self: they need to be manually implemented because their
91// derive macros don't understand that this type doesn't actually
92// depend on its generic type for any of their impls.
93
94/* --- Tests --- */
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99
100    #[test]
101    fn sanity_check() {
102        let mut r: Reservoir<String> = Reservoir::default();
103        let h = r.insert(String::from("hello"));
104        assert_eq!("hello", r.get(h));
105
106        r.get_mut(h).push('!');
107        assert_eq!("hello!", r.get(h));
108    }
109}