diff options
| author | tison <wander4096@gmail.com> | 2024-02-14 19:51:02 +0800 |
|---|---|---|
| committer | tison <wander4096@gmail.com> | 2024-03-27 16:16:08 +0800 |
| commit | 95e195f41ea6cc64846b1fec4fad9bf6d8f7db82 (patch) | |
| tree | 29600890b35b91c6daafa60fcf841d2df86b3aad /library/std/src | |
| parent | 548e14b43963882fb758deb89e8258d9b8c2fc2a (diff) | |
| download | rust-95e195f41ea6cc64846b1fec4fad9bf6d8f7db82.tar.gz rust-95e195f41ea6cc64846b1fec4fad9bf6d8f7db82.zip | |
impl get_mut_or_init and get_mut_or_try_init for OnceCell and OnceLock
See also https://github.com/rust-lang/rust/issues/74465#issuecomment-1676522051 Signed-off-by: tison <wander4096@gmail.com>
Diffstat (limited to 'library/std/src')
| -rw-r--r-- | library/std/src/sync/once_lock.rs | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index 6d068613f8f..fc830bacced 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -252,6 +252,46 @@ impl<T> OnceLock<T> { } } + /// Gets the mutable reference of the contents of the cell, initializing + /// it with `f` if the cell was empty. + /// + /// Many threads may call `get_mut_or_init` concurrently with different + /// initializing functions, but it is guaranteed that only one function + /// will be executed. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and the cell + /// remains uninitialized. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell_get_mut)] + /// + /// use std::sync::OnceLock; + /// + /// let mut cell = OnceLock::new(); + /// let value = cell.get_mut_or_init(|| 92); + /// assert_eq!(*value, 92); + /// + /// *value += 2; + /// assert_eq!(*value, 94); + /// + /// let value = cell.get_mut_or_init(|| unreachable!()); + /// assert_eq!(*value, 94); + /// ``` + #[inline] + #[unstable(feature = "once_cell_get_mut", issue = "121641")] + pub fn get_mut_or_init<F>(&mut self, f: F) -> &mut T + where + F: FnOnce() -> T, + { + match self.get_mut_or_try_init(|| Ok::<T, !>(f())) { + Ok(val) => val, + } + } + /// Gets the contents of the cell, initializing it with `f` if /// the cell was empty. If the cell was empty and `f` failed, an /// error is returned. @@ -303,6 +343,47 @@ impl<T> OnceLock<T> { Ok(unsafe { self.get_unchecked() }) } + /// Gets the mutable reference of the contents of the cell, initializing + /// it with `f` if the cell was empty. If the cell was empty and `f` failed, + /// an error is returned. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and + /// the cell remains uninitialized. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell_get_mut)] + /// + /// use std::sync::OnceLock; + /// + /// let mut cell: OnceLock<u32> = OnceLock::new(); + /// + /// // Failed initializers do not change the value + /// assert!(cell.get_mut_or_try_init(|| "not a number!".parse()).is_err()); + /// assert!(cell.get().is_none()); + /// + /// let value = cell.get_mut_or_try_init(|| "1234".parse()); + /// assert_eq!(value, Ok(&mut 1234)); + /// *value.unwrap() += 2; + /// assert_eq!(cell.get(), Some(&1236)) + /// ``` + #[inline] + #[unstable(feature = "once_cell_get_mut", issue = "121641")] + pub fn get_mut_or_try_init<F, E>(&mut self, f: F) -> Result<&mut T, E> + where + F: FnOnce() -> Result<T, E>, + { + if self.get().is_none() { + self.initialize(f)?; + } + debug_assert!(self.is_initialized()); + // SAFETY: The inner value has been initialized + Ok(unsafe { self.get_unchecked_mut() }) + } + /// Consumes the `OnceLock`, returning the wrapped value. Returns /// `None` if the cell was empty. /// |
