diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d1a02d..497fbbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 1.11 + +- Add `OnceCell::with_value` to create initialized `OnceCell` at compile time. +- Improve `Clone` implementation for `OnceCell`. + ## 1.10 - upgrade `parking_lot` to `0.12.0` (note that this bumps MSRV with `parking_lot` feature enabled to `1.49.0`). diff --git a/Cargo.toml b/Cargo.toml index ea3d266..92f1a1c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ atomic-polyfill = { version = "0.1", optional = true } [dev-dependencies] lazy_static = "1.0.0" -crossbeam-utils = "0.7.2" +crossbeam-utils = "0.8.7" regex = "1.2.0" [features] diff --git a/src/imp_pl.rs b/src/imp_pl.rs index 6c9b0fe..a9bae85 100644 --- a/src/imp_pl.rs +++ b/src/imp_pl.rs @@ -35,6 +35,14 @@ impl OnceCell { } } + pub(crate) const fn with_value(value: T) -> OnceCell { + OnceCell { + mutex: parking_lot::const_mutex(()), + is_initialized: AtomicBool::new(true), + value: UnsafeCell::new(Some(value)), + } + } + /// Safety: synchronizes with store to value via Release/Acquire. #[inline] pub(crate) fn is_initialized(&self) -> bool { @@ -115,7 +123,11 @@ impl OnceCell { // Note: this is intentionally monomorphic #[inline(never)] -fn initialize_inner(mutex: &Mutex<()>, is_initialized: &AtomicBool, init: &mut dyn FnMut() -> bool) { +fn initialize_inner( + mutex: &Mutex<()>, + is_initialized: &AtomicBool, + init: &mut dyn FnMut() -> bool, +) { let _guard = mutex.lock(); if !is_initialized.load(Ordering::Acquire) { diff --git a/src/imp_std.rs b/src/imp_std.rs index d7dda96..9a1c83d 100644 --- a/src/imp_std.rs +++ b/src/imp_std.rs @@ -69,6 +69,14 @@ impl OnceCell { } } + pub(crate) const fn with_value(value: T) -> OnceCell { + OnceCell { + state_and_queue: AtomicUsize::new(COMPLETE), + _marker: PhantomData, + value: UnsafeCell::new(Some(value)), + } + } + /// Safety: synchronizes with store to value via Release/(Acquire|SeqCst). #[inline] pub(crate) fn is_initialized(&self) -> bool { diff --git a/src/lib.rs b/src/lib.rs index 3c7dfcb..b344251 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -399,14 +399,17 @@ pub mod unsync { impl Clone for OnceCell { fn clone(&self) -> OnceCell { - let res = OnceCell::new(); - if let Some(value) = self.get() { - match res.set(value.clone()) { - Ok(()) => (), - Err(_) => unreachable!(), - } + match self.get() { + Some(value) => OnceCell::with_value(value.clone()), + None => OnceCell::new(), + } + } + + fn clone_from(&mut self, source: &Self) { + match (self.get_mut(), source.get()) { + (Some(this), Some(source)) => this.clone_from(source), + _ => *self = source.clone(), } - res } } @@ -420,7 +423,7 @@ pub mod unsync { impl From for OnceCell { fn from(value: T) -> Self { - OnceCell { inner: UnsafeCell::new(Some(value)) } + OnceCell::with_value(value) } } @@ -430,6 +433,11 @@ pub mod unsync { OnceCell { inner: UnsafeCell::new(None) } } + /// Creates a new initialized cell. + pub const fn with_value(value: T) -> OnceCell { + OnceCell { inner: UnsafeCell::new(Some(value)) } + } + /// Gets a reference to the underlying value. /// /// Returns `None` if the cell is empty. @@ -810,22 +818,23 @@ pub mod sync { impl Clone for OnceCell { fn clone(&self) -> OnceCell { - let res = OnceCell::new(); - if let Some(value) = self.get() { - match res.set(value.clone()) { - Ok(()) => (), - Err(_) => unreachable!(), - } + match self.get() { + Some(value) => Self::with_value(value.clone()), + None => Self::new(), + } + } + + fn clone_from(&mut self, source: &Self) { + match (self.get_mut(), source.get()) { + (Some(this), Some(source)) => this.clone_from(source), + _ => *self = source.clone(), } - res } } impl From for OnceCell { fn from(value: T) -> Self { - let cell = Self::new(); - cell.get_or_init(|| value); - cell + Self::with_value(value) } } @@ -843,6 +852,11 @@ pub mod sync { OnceCell(Imp::new()) } + /// Creates a new initialized cell. + pub const fn with_value(value: T) -> OnceCell { + OnceCell(Imp::with_value(value)) + } + /// Gets the reference to the underlying value. /// /// Returns `None` if the cell is empty, or being initialized. This diff --git a/tests/it.rs b/tests/it.rs index 81faaff..4d6efdc 100644 --- a/tests/it.rs +++ b/tests/it.rs @@ -17,6 +17,13 @@ mod unsync { assert_eq!(c.get(), Some(&92)); } + #[test] + fn once_cell_with_value() { + const CELL: OnceCell = OnceCell::with_value(12); + let cell = CELL; + assert_eq!(cell.get(), Some(&12)); + } + #[test] fn once_cell_get_mut() { let mut c = OnceCell::new(); @@ -230,6 +237,12 @@ mod sync { assert_eq!(c.get(), Some(&92)); } + #[test] + fn once_cell_with_value() { + static CELL: OnceCell = OnceCell::with_value(12); + assert_eq!(CELL.get(), Some(&12)); + } + #[test] fn once_cell_get_mut() { let mut c = OnceCell::new();