Skip to main content

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((&current_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> {}