about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2023-10-14 22:35:05 +0200
committerGitHub <noreply@github.com>2023-10-14 22:35:05 +0200
commitfcd75ccc90c23a7d669929e983c47ac0157a6d69 (patch)
tree990a41cbc4a535d69c1eb4ad8ced1ae86a0e88aa /library/std/src
parentee8c9d3c34719a129f280cd91ba5d324017bb02b (diff)
parentdd34d9027af3c0286aa038a365ff14387a6bf80c (diff)
downloadrust-fcd75ccc90c23a7d669929e983c47ac0157a6d69.tar.gz
rust-fcd75ccc90c23a7d669929e983c47ac0157a6d69.zip
Rollup merge of #116540 - daxpedda:once-cell-lock-try-insert, r=Mark-Simulacrum
Implement `OnceCell/Lock::try_insert()`

I took inspiration from [`once_cell`](https://crates.io/crates/once_cell):
- [`once_cell::unsync::OnceCell::try_insert()`](https://github.com/matklad/once_cell/blob/874f9373abd7feaf923a3b3c34bfb3383529c671/src/lib.rs#L551-L563)
- [`once_cell::sync::OnceCell::try_insert()`](https://github.com/matklad/once_cell/blob/874f9373abd7feaf923a3b3c34bfb3383529c671/src/lib.rs#L1080-L1087)

I tried to change as little code as possible in the first commit and applied some obvious optimizations in the second one.

ACP: https://github.com/rust-lang/libs-team/issues/276
Tracking issue: #116693
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/sync/once_lock.rs43
1 files changed, 40 insertions, 3 deletions
diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs
index e2b7b893cb5..f4963090795 100644
--- a/library/std/src/sync/once_lock.rs
+++ b/library/std/src/sync/once_lock.rs
@@ -126,11 +126,48 @@ impl<T> OnceLock<T> {
     #[inline]
     #[stable(feature = "once_cell", since = "1.70.0")]
     pub fn set(&self, value: T) -> Result<(), T> {
+        match self.try_insert(value) {
+            Ok(_) => Ok(()),
+            Err((_, value)) => Err(value),
+        }
+    }
+
+    /// Sets the contents of this cell to `value` if the cell was empty, then
+    /// returns a reference to it.
+    ///
+    /// May block if another thread is currently attempting to initialize the cell. The cell is
+    /// guaranteed to contain a value when set returns, though not necessarily the one provided.
+    ///
+    /// Returns `Ok(&value)` if the cell was empty and `Err(&current_value, value)` if it was full.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell_try_insert)]
+    ///
+    /// use std::sync::OnceLock;
+    ///
+    /// static CELL: OnceLock<i32> = OnceLock::new();
+    ///
+    /// fn main() {
+    ///     assert!(CELL.get().is_none());
+    ///
+    ///     std::thread::spawn(|| {
+    ///         assert_eq!(CELL.try_insert(92), Ok(&92));
+    ///     }).join().unwrap();
+    ///
+    ///     assert_eq!(CELL.try_insert(62), Err((&92, 62)));
+    ///     assert_eq!(CELL.get(), Some(&92));
+    /// }
+    /// ```
+    #[inline]
+    #[unstable(feature = "once_cell_try_insert", issue = "116693")]
+    pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> {
         let mut value = Some(value);
-        self.get_or_init(|| value.take().unwrap());
+        let res = self.get_or_init(|| value.take().unwrap());
         match value {
-            None => Ok(()),
-            Some(value) => Err(value),
+            None => Ok(res),
+            Some(value) => Err((res, value)),
         }
     }