append_only/lib.rs
1#![deny(missing_docs)]
2//! append-only
3//!
4//! append-only contains versions of data structures that ... only allow appends.
5//! Data structures where values cannot be modified once added, combined with
6//! Boxing, allow immutable references to one key's value to be handed out while
7//! preserving the ability to append other key/value pairs to the structure.
8
9use std::borrow::Borrow;
10use std::collections::{hash_map, HashMap};
11use std::hash::Hash;
12use std::mem;
13use std::ops::Deref;
14use std::sync::RwLock;
15
16/// The sync module contains append-only data structures that can be used from
17/// multiple threads.
18pub mod sync {
19 use super::*;
20
21 /// Like `std::collections::HashMap`, but append-only.
22 #[derive(Debug)]
23 pub struct AppendOnlyHashMap<K, V>(RwLock<HashMap<K, Box<V>>>);
24
25 impl<K, V> AppendOnlyHashMap<K, V> {
26 /// Creates an empty `AppendOnlyHashMap`.
27 pub fn new() -> Self {
28 AppendOnlyHashMap(RwLock::new(HashMap::new()))
29 }
30
31 /// Creates an empty `AppendOnlyHashMap` with the specified capacity.
32 pub fn with_capacity(capacity: usize) -> Self {
33 AppendOnlyHashMap(RwLock::new(HashMap::with_capacity(capacity)))
34 }
35 }
36
37 impl<K, V> AppendOnlyHashMap<K, V>
38 where
39 K: Eq + Hash,
40 {
41 /// Returns a reference to the value corresponding to the key.
42 pub fn get<'map, Q: ?Sized>(&'map self, key: &Q) -> Option<&'map V>
43 where
44 Q: Borrow<K>
45 {
46 let locked = self.0.read().unwrap();
47 let value_ptr = locked.get(key.borrow())?.deref() as *const V;
48 mem::drop(locked);
49 // Safe because this value can never be removed or mutated as long
50 // as this map survives.
51 Some(unsafe {
52 &*value_ptr
53 })
54 }
55
56 /// Returns a reference to the value corresponding to the key, invoking
57 /// the provided callback if it is not already present.
58 pub fn get_or_insert_with<'map, F>(&'map self, key: K, f: F) -> &'map V
59 where
60 F: FnOnce(&K) -> V
61 {
62 self.get_or_insert_with_fallible::<(), _>(key, |k| Ok(f(k))).unwrap()
63 }
64
65 /// Returns a reference to the value corresponding to the key, invoking
66 /// the provided callback if it is not already present.
67 pub fn get_or_insert_with_fallible<'map, E, F>(&'map self, key: K, f: F) -> Result<&'map V, E>
68 where
69 F: FnOnce(&K) -> Result<V, E>
70 {
71 let mut locked = self.0.write().unwrap();
72 let value_ptr = match locked.entry(key) {
73 hash_map::Entry::Occupied(o) => o.get().deref() as *const V,
74 hash_map::Entry::Vacant(v) => {
75 let value = Box::new(f(v.key())?);
76 (*v.insert(value)).deref() as *const V
77 }
78 };
79 mem::drop(locked);
80 // Safe because this value can never be removed or mutated as long
81 // as this map survives.
82 Ok(unsafe {
83 &*value_ptr
84 })
85 }
86 }
87}