asyncband/once/once_cell/mod.rs
1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18// Portions of this file originated from Tokio 1.47.0's OnceCell implementation.
19// Copyright (c) Tokio Contributors
20// The Tokio-derived portions remain licensed under the MIT License.
21// Asyncband substantially changed the synchronization model: initialization does not close the
22// semaphore, the cell can be emptied and initialized again, and value storage is delegated to a
23// reusable ValueCell shared with LazyCell.
24// Upstream source:
25// https://github.com/tokio-rs/tokio/blob/3911cb8523f190142f61c64b66881c07c0d3e7be/tokio/src/sync/once_cell.rs
26
27use std::convert::Infallible;
28use std::fmt;
29
30use crate::internal::value_cell::ValueCell;
31use crate::semaphore::Semaphore;
32use crate::semaphore::SemaphorePermit;
33
34/// A thread-safe cell whose value is asynchronously initialized at most once.
35///
36/// Callers provide an initializer when accessing an empty cell. An initializer that returns an
37/// error, panics, or is cancelled leaves the cell empty so a later caller can retry. Use
38/// `LazyCell` instead when the cell should own a one-shot initializer and preserve its in-flight
39/// future across caller cancellation.
40///
41/// # Examples
42///
43/// ```
44/// # #[tokio::main]
45/// # async fn main() {
46/// use std::sync::Arc;
47///
48/// use asyncband::once::OnceCell;
49///
50/// static CELL: OnceCell<u8> = OnceCell::new();
51///
52/// let handle1 = tokio::spawn(async { CELL.get_or_init(move || async { 1 }).await });
53/// let handle2 = tokio::spawn(async { CELL.get_or_init(move || async { 2 }).await });
54/// let result1 = handle1.await.unwrap();
55/// let result2 = handle2.await.unwrap();
56/// assert_eq!(result1, result2);
57/// assert!(*result1 == 1 || *result1 == 2);
58/// # }
59/// ```
60pub struct OnceCell<T> {
61 value: ValueCell<T>,
62 semaphore: Semaphore,
63}
64
65impl<T> Default for OnceCell<T> {
66 fn default() -> Self {
67 Self::new()
68 }
69}
70
71impl<T> OnceCell<T> {
72 /// Creates a new empty `OnceCell`.
73 pub const fn new() -> Self {
74 Self {
75 value: ValueCell::new(),
76 semaphore: Semaphore::new(1),
77 }
78 }
79
80 /// Creates a new `OnceCell` initialized with the provided value.
81 pub const fn from_value(value: T) -> Self {
82 Self {
83 value: ValueCell::from_value(value),
84 semaphore: Semaphore::new(1),
85 }
86 }
87
88 /// Returns whether the cell contains a value.
89 // `OnceMap` and `singleflight` inspect this state, while a standalone `OnceCell` build does
90 // not need the internal helper.
91 #[allow(dead_code)]
92 pub(crate) fn initialized(&self) -> bool {
93 self.value.is_initialized()
94 }
95
96 /// Returns whether the cell contains a value.
97 pub(crate) fn initialized_mut(&mut self) -> bool {
98 self.value.is_initialized_mut()
99 }
100
101 /// Returns the stored value.
102 ///
103 /// Returns `None` if the cell is uninitialized, or being initialized.
104 ///
105 /// This method never blocks.
106 pub fn get(&self) -> Option<&T> {
107 self.value.get()
108 }
109
110 /// Returns mutable access to the stored value.
111 ///
112 /// Returns `None` if the cell is uninitialized.
113 ///
114 /// This method never blocks. Since it borrows the `OnceCell` mutably, it is statically
115 /// guaranteed that no active borrows to the `OnceCell` exist, including from other threads.
116 pub fn get_mut(&mut self) -> Option<&mut T> {
117 self.value.get_mut()
118 }
119
120 /// Returns the value, initializing an empty cell with the provided asynchronous function.
121 ///
122 /// If some other task is currently working on initializing the `OnceCell`, this call will wait
123 /// for that other task to finish, then return the value that the other task produced.
124 ///
125 /// If the provided operation is cancelled, the initialization attempt is cancelled. If there
126 /// are other tasks waiting for the value to be initialized, one of them will start another
127 /// attempt at initializing the value.
128 ///
129 /// This will deadlock if `init` tries to initialize the cell recursively.
130 pub async fn get_or_init<F>(&self, init: F) -> &T
131 where
132 F: AsyncFnOnce() -> T,
133 {
134 match self
135 .get_or_try_init(async || Ok::<T, Infallible>(init().await))
136 .await
137 {
138 Ok(val) => val,
139 }
140 }
141
142 /// Returns the value, initializing an empty cell with the provided fallible asynchronous
143 /// function.
144 ///
145 /// If some other task is currently working on initializing the `OnceCell`, this call will wait
146 /// for that other task to finish, then return the value that the other task produced.
147 ///
148 /// If the provided operation returns an error, is cancelled or panics, the initialization
149 /// attempt is cancelled. If there are other tasks waiting for the value to be initialized
150 /// one of them will start another attempt at initializing the value.
151 ///
152 /// This will deadlock if `init` tries to initialize the cell recursively.
153 pub async fn get_or_try_init<E, F>(&self, init: F) -> Result<&T, E>
154 where
155 F: AsyncFnOnce() -> Result<T, E>,
156 {
157 if let Some(v) = self.get() {
158 return Ok(v);
159 }
160
161 let permit = self.semaphore.acquire(1).await;
162
163 if let Some(v) = self.get() {
164 // double-checked: another task initialized the value
165 // while we were waiting for the permit
166 return Ok(v);
167 }
168
169 let value = init().await?;
170 Ok(self.set_value(value, permit))
171 }
172
173 /// Returns mutable access to the value, initializing an empty cell asynchronously.
174 ///
175 /// This method never blocks other tasks because it takes `&mut self`, which guarantees
176 /// exclusive access to the `OnceCell` and thus no concurrent initialization can be in
177 /// progress.
178 ///
179 /// If the cell is already initialized, it returns a mutable reference to the existing value.
180 /// Otherwise, it runs `init`, stores the result, and returns a mutable reference to the newly
181 /// initialized value.
182 ///
183 /// # Examples
184 ///
185 /// ```
186 /// # #[tokio::main]
187 /// # async fn main() {
188 /// use asyncband::once::OnceCell;
189 ///
190 /// let mut cell: OnceCell<u32> = OnceCell::new();
191 /// let v = cell.get_mut_or_init(|| async { 41 }).await;
192 /// *v += 1;
193 /// assert_eq!(*cell.get().unwrap(), 42);
194 /// # }
195 /// ```
196 pub async fn get_mut_or_init<F>(&mut self, init: F) -> &mut T
197 where
198 F: AsyncFnOnce() -> T,
199 {
200 match self
201 .get_mut_or_try_init(async || Ok::<T, Infallible>(init().await))
202 .await
203 {
204 Ok(val) => val,
205 }
206 }
207
208 /// Returns mutable access to the value, initializing an empty cell with a fallible asynchronous
209 /// function.
210 ///
211 /// This method never blocks other tasks because it takes `&mut self`, which guarantees
212 /// exclusive access to the `OnceCell` and thus no concurrent initialization can be in
213 /// progress.
214 ///
215 /// If the cell is already initialized, it returns a mutable reference to the existing value.
216 /// Otherwise, it runs `init`. On success, it stores the result and returns a mutable
217 /// reference to the newly initialized value. On error, it returns the error and leaves the
218 /// cell uninitialized.
219 ///
220 /// # Examples
221 ///
222 /// ```
223 /// # #[tokio::main]
224 /// # async fn main() {
225 /// use asyncband::once::OnceCell;
226 ///
227 /// let mut cell: OnceCell<u32> = OnceCell::new();
228 /// assert!(
229 /// cell.get_mut_or_try_init(|| async { Err(()) })
230 /// .await
231 /// .is_err()
232 /// );
233 /// let v = cell
234 /// .get_mut_or_try_init(|| async { Ok::<_, ()>(10) })
235 /// .await
236 /// .unwrap();
237 /// *v += 5;
238 /// assert_eq!(*cell.get().unwrap(), 15);
239 /// # }
240 /// ```
241 pub async fn get_mut_or_try_init<E, F>(&mut self, init: F) -> Result<&mut T, E>
242 where
243 F: AsyncFnOnce() -> Result<T, E>,
244 {
245 // Workaround if let Some(v) = self.get_mut() { return Ok(v); }
246 // @see https://github.com/rust-lang/rust/issues/51545
247 if self.initialized_mut() {
248 return Ok(self
249 .value
250 .get_mut()
251 .expect("OnceCell initialized value missing"));
252 }
253
254 let value = init().await?;
255 Ok(self.set_value_mut(value))
256 }
257
258 /// Initializes the contents of the cell to `value` if the cell was uninitialized,
259 /// then returns a reference to it.
260 ///
261 /// May wait if another task is currently attempting to initialize the cell. The cell is
262 /// guaranteed to contain a value when `try_insert` returns, though not necessarily the
263 /// one provided.
264 ///
265 /// Returns `Ok(&value)` if the cell was uninitialized and `Err((¤t_value, value))`
266 /// if it was already initialized.
267 ///
268 /// # Examples
269 ///
270 /// ```
271 /// use asyncband::once::OnceCell;
272 ///
273 /// static CELL: OnceCell<i32> = OnceCell::new();
274 ///
275 /// # #[tokio::main]
276 /// # async fn main() {
277 /// assert!(CELL.get().is_none());
278 ///
279 /// tokio::spawn(async {
280 /// assert_eq!(CELL.try_insert(92).await, Ok(&92));
281 /// })
282 /// .await
283 /// .unwrap();
284 ///
285 /// assert_eq!(CELL.try_insert(62).await, Err((&92, 62)));
286 /// assert_eq!(CELL.get(), Some(&92));
287 /// # }
288 /// ```
289 pub async fn try_insert(&self, value: T) -> Result<&T, (&T, T)> {
290 let mut value = Some(value);
291 let res = self.get_or_init(async || value.take().unwrap()).await;
292 match value {
293 None => Ok(res),
294 Some(value) => Err((res, value)),
295 }
296 }
297
298 /// Initializes the contents of the cell to `value`.
299 ///
300 /// May wait if another thread is currently attempting to initialize the cell. The cell is
301 /// guaranteed to contain a value when `set` returns, though not necessarily the one provided.
302 ///
303 /// Returns `Ok(())` if the cell was uninitialized and `Err(value)` if the cell was already
304 /// initialized.
305 ///
306 /// # Examples
307 ///
308 /// ```
309 /// use asyncband::once::OnceCell;
310 ///
311 /// static CELL: OnceCell<i32> = OnceCell::new();
312 ///
313 /// # #[tokio::main]
314 /// # async fn main() {
315 /// assert!(CELL.get().is_none());
316 ///
317 /// tokio::spawn(async {
318 /// assert_eq!(CELL.set(92).await, Ok(()));
319 /// })
320 /// .await
321 /// .unwrap();
322 ///
323 /// assert_eq!(CELL.set(62).await, Err(62));
324 /// assert_eq!(CELL.get(), Some(&92));
325 /// # }
326 /// ```
327 pub async fn set(&self, value: T) -> Result<(), T> {
328 match self.try_insert(value).await {
329 Ok(_) => Ok(()),
330 Err((_, value)) => Err(value),
331 }
332 }
333
334 /// Consumes the `OnceCell`, returning the wrapped value. Returns `None` if the cell was
335 /// uninitialized.
336 ///
337 /// # Examples
338 ///
339 /// ```
340 /// use asyncband::once::OnceCell;
341 ///
342 /// # #[tokio::main]
343 /// # async fn main() {
344 /// let cell: OnceCell<String> = OnceCell::new();
345 /// assert_eq!(cell.into_inner(), None);
346 ///
347 /// let cell = OnceCell::new();
348 /// cell.set("hello".to_string()).await.unwrap();
349 /// assert_eq!(cell.into_inner(), Some("hello".to_string()));
350 /// # }
351 /// ```
352 pub fn into_inner(self) -> Option<T> {
353 self.value.into_inner()
354 }
355
356 /// Takes the value out of this `OnceCell`, moving it back to an uninitialized state.
357 ///
358 /// Has no effect and returns `None` if the `OnceCell` was uninitialized.
359 ///
360 /// Since this method borrows the `OnceCell` mutably, it is statically guaranteed that
361 /// no active borrows to the `OnceCell` exist, including from other threads.
362 ///
363 /// # Examples
364 ///
365 /// ```
366 /// use asyncband::once::OnceCell;
367 ///
368 /// # #[tokio::main]
369 /// # async fn main() {
370 /// let mut cell: OnceCell<String> = OnceCell::new();
371 /// assert_eq!(cell.take(), None);
372 ///
373 /// let mut cell = OnceCell::new();
374 /// cell.set("hello".to_string()).await.unwrap();
375 /// assert_eq!(cell.take(), Some("hello".to_string()));
376 /// assert_eq!(cell.get(), None);
377 /// # }
378 /// ```
379 pub fn take(&mut self) -> Option<T> {
380 self.value.take()
381 }
382
383 fn set_value(&self, value: T, permit: SemaphorePermit<'_>) -> &T {
384 let _permit = permit;
385 // SAFETY: Holding the only semaphore permit serializes initialization.
386 unsafe { self.value.set(value) }
387 }
388
389 fn set_value_mut(&mut self, value: T) -> &mut T {
390 self.value.set_mut(value)
391 }
392}
393
394impl<T: fmt::Debug> fmt::Debug for OnceCell<T> {
395 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
396 let mut d = f.debug_tuple("OnceCell");
397 match self.get() {
398 Some(v) => d.field(v),
399 None => d.field(&format_args!("<uninit>")),
400 };
401 d.finish()
402 }
403}
404
405impl<T: Clone> Clone for OnceCell<T> {
406 fn clone(&self) -> OnceCell<T> {
407 match self.get() {
408 Some(v) => OnceCell::from_value(v.clone()),
409 None => OnceCell::new(),
410 }
411 }
412}
413
414impl<T> From<T> for OnceCell<T> {
415 fn from(value: T) -> Self {
416 OnceCell::from_value(value)
417 }
418}
419
420impl<T: PartialEq> PartialEq for OnceCell<T> {
421 fn eq(&self, other: &Self) -> bool {
422 self.get() == other.get()
423 }
424}
425
426impl<T: Eq> Eq for OnceCell<T> {}