Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OnceCell::with_value and improve Clone implementation #170

Merged
merged 5 commits into from Mar 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions 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`).
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Expand Up @@ -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]
Expand Down
14 changes: 13 additions & 1 deletion src/imp_pl.rs
Expand Up @@ -35,6 +35,14 @@ impl<T> OnceCell<T> {
}
}

pub(crate) const fn with_value(value: T) -> OnceCell<T> {
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 {
Expand Down Expand Up @@ -115,7 +123,11 @@ impl<T> OnceCell<T> {

// 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) {
Expand Down
8 changes: 8 additions & 0 deletions src/imp_std.rs
Expand Up @@ -69,6 +69,14 @@ impl<T> OnceCell<T> {
}
}

pub(crate) const fn with_value(value: T) -> OnceCell<T> {
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 {
Expand Down
50 changes: 32 additions & 18 deletions src/lib.rs
Expand Up @@ -399,14 +399,17 @@ pub mod unsync {

impl<T: Clone> Clone for OnceCell<T> {
fn clone(&self) -> OnceCell<T> {
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
}
}

Expand All @@ -420,7 +423,7 @@ pub mod unsync {

impl<T> From<T> for OnceCell<T> {
fn from(value: T) -> Self {
OnceCell { inner: UnsafeCell::new(Some(value)) }
OnceCell::with_value(value)
}
}

Expand All @@ -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<T> {
OnceCell { inner: UnsafeCell::new(Some(value)) }
}

/// Gets a reference to the underlying value.
///
/// Returns `None` if the cell is empty.
Expand Down Expand Up @@ -810,22 +818,23 @@ pub mod sync {

impl<T: Clone> Clone for OnceCell<T> {
fn clone(&self) -> OnceCell<T> {
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<T> From<T> for OnceCell<T> {
fn from(value: T) -> Self {
let cell = Self::new();
cell.get_or_init(|| value);
cell
Self::with_value(value)
}
}

Expand All @@ -843,6 +852,11 @@ pub mod sync {
OnceCell(Imp::new())
}

/// Creates a new initialized cell.
pub const fn with_value(value: T) -> OnceCell<T> {
OnceCell(Imp::with_value(value))
}

/// Gets the reference to the underlying value.
///
/// Returns `None` if the cell is empty, or being initialized. This
Expand Down
13 changes: 13 additions & 0 deletions tests/it.rs
Expand Up @@ -17,6 +17,13 @@ mod unsync {
assert_eq!(c.get(), Some(&92));
}

#[test]
fn once_cell_with_value() {
const CELL: OnceCell<i32> = OnceCell::with_value(12);
let cell = CELL;
assert_eq!(cell.get(), Some(&12));
}

#[test]
fn once_cell_get_mut() {
let mut c = OnceCell::new();
Expand Down Expand Up @@ -230,6 +237,12 @@ mod sync {
assert_eq!(c.get(), Some(&92));
}

#[test]
fn once_cell_with_value() {
static CELL: OnceCell<i32> = OnceCell::with_value(12);
assert_eq!(CELL.get(), Some(&12));
}

#[test]
fn once_cell_get_mut() {
let mut c = OnceCell::new();
Expand Down