1use std::borrow::Borrow;
2use std::hash::{BuildHasher, Hash, RandomState};
3use std::pin::pin;
4use std::sync::Arc;
5
6use dashmap::DashMap;
7use tokio::sync::Notify;
8
9pub struct OnceMap<K, V, S = RandomState> {
19 items: DashMap<K, Value<V>, S>,
20}
21
22impl<K: Eq + Hash, V: Clone, H: BuildHasher + Clone> OnceMap<K, V, H> {
23 pub fn with_hasher(hasher: H) -> Self {
25 Self {
26 items: DashMap::with_hasher(hasher),
27 }
28 }
29
30 pub fn with_capacity_and_hasher(capacity: usize, hasher: H) -> Self {
32 Self {
33 items: DashMap::with_capacity_and_hasher(capacity, hasher),
34 }
35 }
36
37 pub fn register(&self, key: K) -> bool {
43 let entry = self.items.entry(key);
44 match entry {
45 dashmap::mapref::entry::Entry::Occupied(_) => false,
46 dashmap::mapref::entry::Entry::Vacant(entry) => {
47 entry.insert(Value::Waiting(Arc::new(Notify::new())));
48 true
49 }
50 }
51 }
52
53 pub fn done(&self, key: K, value: V) {
55 if let Some(Value::Waiting(notify)) = self.items.insert(key, Value::Filled(value)) {
56 notify.notify_waiters();
57 }
58 }
59
60 pub async fn wait(&self, key: &K) -> Option<V> {
64 let notify = {
65 let entry = self.items.get(key)?;
66 match entry.value() {
67 Value::Filled(value) => return Some(value.clone()),
68 Value::Waiting(notify) => notify.clone(),
69 }
70 };
71
72 let notification = pin!(notify.notified());
74
75 if let Value::Filled(value) = self.items.get(key).expect("map is append-only").value() {
77 return Some(value.clone());
78 }
79
80 notification.await;
82
83 let entry = self.items.get(key).expect("map is append-only");
84 match entry.value() {
85 Value::Filled(value) => Some(value.clone()),
86 Value::Waiting(_) => unreachable!("notify was called"),
87 }
88 }
89
90 pub fn wait_blocking(&self, key: &K) -> Option<V> {
94 futures::executor::block_on(self.wait(key))
95 }
96
97 pub fn get<Q: ?Sized + Hash + Eq>(&self, key: &Q) -> Option<V>
99 where
100 K: Borrow<Q>,
101 {
102 let entry = self.items.get(key)?;
103 match entry.value() {
104 Value::Filled(value) => Some(value.clone()),
105 Value::Waiting(_) => None,
106 }
107 }
108
109 pub fn remove<Q: ?Sized + Hash + Eq>(&self, key: &Q) -> Option<V>
111 where
112 K: Borrow<Q>,
113 {
114 let entry = self.items.remove(key)?;
115 match entry {
116 (_, Value::Filled(value)) => Some(value),
117 (_, Value::Waiting(_)) => None,
118 }
119 }
120}
121
122impl<K: Eq + Hash + Clone, V, H: Default + BuildHasher + Clone> Default for OnceMap<K, V, H> {
123 fn default() -> Self {
124 Self {
125 items: DashMap::with_hasher(H::default()),
126 }
127 }
128}
129
130impl<K, V, H> FromIterator<(K, V)> for OnceMap<K, V, H>
131where
132 K: Eq + Hash,
133 H: Default + Clone + BuildHasher,
134{
135 fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
136 Self {
137 items: iter
138 .into_iter()
139 .map(|(k, v)| (k, Value::Filled(v)))
140 .collect(),
141 }
142 }
143}
144
145enum Value<V> {
146 Waiting(Arc<Notify>),
147 Filled(V),
148}