1mod registered;
2
3pub use registered::{RegisteredEntry, RegisteredOnceMap, Registration};
4
5use std::borrow::Borrow;
6use std::fmt::{Debug, Formatter};
7use std::hash::{BuildHasher, Hash, RandomState};
8use std::sync::{Arc, Mutex, MutexGuard, PoisonError};
9
10use papaya::{HashMap, ResizeMode};
11use tokio::sync::Notify;
12
13pub struct OnceMap<K, V, S = RandomState> {
23 items: HashMap<K, Value<V>, S>,
24}
25
26impl<K: Eq + Hash + Debug, V: Debug, S: BuildHasher + Clone> Debug for OnceMap<K, V, S> {
27 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
28 Debug::fmt(&self.items, f)
29 }
30}
31
32impl<K: Eq + Hash + Clone, V: Clone, H: BuildHasher + Clone> OnceMap<K, V, H> {
33 fn register(&self, key: K) -> bool {
39 self.items
40 .pin()
41 .try_insert_with(key, || Value::Waiting(Arc::new(Notify::new())))
42 .is_ok()
43 }
44
45 pub async fn register_or_wait(&self, key: &K) -> Option<V> {
64 let notify = {
65 let items = self.items.pin();
66 match items.try_insert_with(key.clone(), || Value::Waiting(Arc::new(Notify::new()))) {
67 Ok(_) => return None,
68 Err(value) => match value {
69 Value::Filled(_) => return value.get(),
70 Value::Waiting(notify) => notify.clone(),
71 },
72 }
73 };
74
75 self.wait_pending(key, notify).await
76 }
77
78 async fn wait_registered(&self, key: &K) -> Option<V> {
80 let notify = {
81 let items = self.items.pin();
82 match items.get(key)? {
83 value @ Value::Filled(_) => return value.get(),
84 Value::Waiting(notify) => notify.clone(),
85 }
86 };
87 self.wait_pending(key, notify).await
88 }
89
90 async fn wait_pending(&self, key: &K, notify: Arc<Notify>) -> Option<V> {
91 let notification = notify.notified();
93
94 if let Some(value) = self.items.pin().get(key).expect("map is append-only").get() {
96 return Some(value);
97 }
98
99 notification.await;
101
102 let items = self.items.pin();
103 let value = items.get(key).expect("map is append-only");
104 match value {
105 Value::Filled(_) => value.get(),
106 Value::Waiting(_) => unreachable!("notify was called"),
107 }
108 }
109
110 pub fn done(&self, key: K, value: V) {
112 if let Some(Value::Waiting(notify)) = self.items.pin().insert(key, Value::filled(value)) {
113 notify.notify_waiters();
114 }
115 }
116
117 pub fn get<Q: ?Sized + Hash + Eq>(&self, key: &Q) -> Option<V>
119 where
120 K: Borrow<Q>,
121 {
122 let items = self.items.pin();
123 items.get(key)?.get()
124 }
125
126 pub fn remove<Q: ?Sized + Hash + Eq>(&self, key: &Q) -> Option<V>
128 where
129 K: Borrow<Q>,
130 {
131 let items = self.items.pin();
132 items.remove(key)?.take()
133 }
134}
135
136impl<K: Eq + Hash + Clone, V, H: Default + BuildHasher + Clone> Default for OnceMap<K, V, H> {
137 fn default() -> Self {
138 Self {
139 items: HashMap::builder()
140 .hasher(H::default())
141 .resize_mode(ResizeMode::Blocking)
142 .build(),
143 }
144 }
145}
146
147impl<K, V, H> FromIterator<(K, V)> for OnceMap<K, V, H>
148where
149 K: Eq + Hash,
150 H: Default + Clone + BuildHasher,
151{
152 fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
153 Self {
154 items: iter
155 .into_iter()
156 .map(|(k, v)| (k, Value::filled(v)))
157 .collect(),
158 }
159 }
160}
161
162#[derive(Debug)]
163enum Value<V> {
164 Waiting(Arc<Notify>),
165 Filled(Mutex<Option<V>>),
167}
168
169impl<V> Value<V> {
170 fn filled(value: V) -> Self {
171 Self::Filled(Mutex::new(Some(value)))
172 }
173
174 fn lock(value: &Mutex<Option<V>>) -> MutexGuard<'_, Option<V>> {
175 value.lock().unwrap_or_else(PoisonError::into_inner)
176 }
177
178 fn take(&self) -> Option<V> {
179 match self {
180 Self::Filled(value) => Self::lock(value).take(),
181 Self::Waiting(_) => None,
182 }
183 }
184}
185
186impl<V: Clone> Value<V> {
187 fn get(&self) -> Option<V> {
188 match self {
189 Self::Filled(value) => Self::lock(value).clone(),
190 Self::Waiting(_) => None,
191 }
192 }
193}