Skip to content

Commit

Permalink
publish 1.16.0
Browse files Browse the repository at this point in the history
This also reshuffles features a bit, to clearly separate public API from
internal features.
  • Loading branch information
matklad committed Oct 22, 2022
1 parent b56e329 commit 1faad40
Show file tree
Hide file tree
Showing 9 changed files with 51 additions and 61 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,11 @@

-

## 1.16.0-pre.1

- Add `no_std` implementation based on `critical-section`
- Deprecate `atomic-polyfill` feature (use the new `critical-section` instead)

## 1.15.0

- Increase minimal supported Rust version to 1.56.0.
Expand Down
40 changes: 21 additions & 19 deletions Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "once_cell"
version = "1.15.0"
version = "1.16.0-pre.1"
authors = ["Aleksey Kladov <aleksey.kladov@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
Expand All @@ -20,19 +20,10 @@ exclude = ["*.png", "*.svg", "/Cargo.lock.msrv", "rustfmt.toml"]
members = ["xtask"]

[dependencies]
# Uses parking_lot to implement once_cell::sync::OnceCell.
# This makes no speed difference, but makes each OnceCell<T>
# up to 16 bytes smaller, depending on the size of the T.
# These optional dependencies are considered private impl details,
# only features from `[features]` table are a part of semver-guarded API.
parking_lot_core = { version = "0.9.3", optional = true, default_features = false }

# To be used in order to enable the race feature on targets
# that do not have atomics
# *Warning:* This can be unsound. Please read the README of
# [atomic-polyfill](https://github.com/embassy-rs/atomic-polyfill)
# and make sure you understand all the implications
atomic-polyfill = { version = "1", optional = true }

# Uses `critical-section` to implement `once_cell::sync::OnceCell`.
atomic_polyfill = { package = "atomic-polyfill", version = "1", optional = true }
critical_section = { package = "critical-section", version = "1", optional = true }

[dev-dependencies]
Expand All @@ -43,21 +34,32 @@ critical_section = { package = "critical-section", version = "1.1.1", features =

[features]
default = ["std"]

# Enables `once_cell::sync` module.
std = ["alloc", "sync"]
std = ["alloc"]

# Enables `once_cell::race::OnceBox` type.
alloc = ["race"]

# Enables `once_cell::race` module.
race = []

# Uses parking_lot to implement once_cell::sync::OnceCell.
# This makes no speed difference, but makes each OnceCell<T>
# up to 16 bytes smaller, depending on the size of the T.
parking_lot = ["parking_lot_core"]

# Uses `critical-section` to implement `sync` and `race` modules. in
# `#![no_std]` mode. Please read `critical-section` docs carefully
# before enabling this feature.
critical-section = ["critical_section", "atomic_polyfill" ]

# Enables semver-exempt APIs of this crate.
# At the moment, this feature is unused.
unstable = []

sync = []

parking_lot = ["parking_lot_core"]

critical-section = ["critical_section", "atomic-polyfill", "sync"]
# Only for backwards compatibility.
atomic-polyfill = ["critical-section"]

[[example]]
name = "bench"
Expand Down
2 changes: 1 addition & 1 deletion src/imp_cs.rs
Expand Up @@ -63,7 +63,7 @@ impl<T> OnceCell<T> {
pub(crate) unsafe fn get_unchecked(&self) -> &T {
debug_assert!(self.is_initialized());
// SAFETY: The caller ensures that the value is initialized and access synchronized.
self.value.borrow(CriticalSection::new()).get_unchecked()
crate::unwrap_unchecked(self.value.borrow(CriticalSection::new()).get())
}

#[inline]
Expand Down
2 changes: 1 addition & 1 deletion src/imp_pl.rs
Expand Up @@ -58,7 +58,7 @@ impl<T> OnceCell<T> {
// but that is more complicated
// - finally, if it returns Ok, we store the value and store the flag with
// `Release`, which synchronizes with `Acquire`s.
let f = unsafe { crate::take_unchecked(&mut f) };
let f = unsafe { crate::unwrap_unchecked(f.take()) };
match f() {
Ok(value) => unsafe {
// Safe b/c we have a unique access and no panic may happen
Expand Down
2 changes: 1 addition & 1 deletion src/imp_std.rs
Expand Up @@ -78,7 +78,7 @@ impl<T> OnceCell<T> {
initialize_or_wait(
&self.queue,
Some(&mut || {
let f = unsafe { crate::take_unchecked(&mut f) };
let f = unsafe { crate::unwrap_unchecked(f.take()) };
match f() {
Ok(value) => {
unsafe { *slot = Some(value) };
Expand Down
27 changes: 5 additions & 22 deletions src/lib.rs
Expand Up @@ -474,18 +474,6 @@ pub mod unsync {
unsafe { &mut *self.inner.get() }.as_mut()
}

/// Get the reference to the underlying value, without checking if the
/// cell is initialized.
///
/// # Safety
///
/// Caller must ensure that the cell is in initialized state.
#[cfg(feature = "critical-section")]
#[inline]
pub(crate) unsafe fn get_unchecked(&self) -> &T {
crate::unwrap_unchecked(self.get())
}

/// Sets the contents of this cell to `value`.
///
/// Returns `Ok(())` if the cell was empty and `Err(value)` if it was
Expand Down Expand Up @@ -830,7 +818,7 @@ pub mod unsync {
}

/// Thread-safe, blocking version of `OnceCell`.
#[cfg(feature = "sync")]
#[cfg(any(feature = "std", feature = "critical-section"))]
pub mod sync {
use core::{
cell::Cell,
Expand All @@ -839,7 +827,7 @@ pub mod sync {
panic::RefUnwindSafe,
};

use super::{imp::OnceCell as Imp, take_unchecked};
use super::{imp::OnceCell as Imp, unwrap_unchecked};

/// A thread-safe cell which can be written to only once.
///
Expand Down Expand Up @@ -960,7 +948,7 @@ pub mod sync {
/// assert_eq!(*value, 92);
/// t.join().unwrap();
/// ```
#[cfg(not(feature = "critical-section"))]
#[cfg(feature = "std")]
pub fn wait(&self) -> &T {
if !self.0.is_initialized() {
self.0.wait()
Expand Down Expand Up @@ -1050,7 +1038,7 @@ pub mod sync {
/// ```
pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> {
let mut value = Some(value);
let res = self.get_or_init(|| unsafe { take_unchecked(&mut value) });
let res = self.get_or_init(|| unsafe { unwrap_unchecked(value.take()) });
match value {
None => Ok(res),
Some(value) => Err((res, value)),
Expand Down Expand Up @@ -1377,12 +1365,7 @@ pub mod sync {
#[cfg(feature = "race")]
pub mod race;

#[cfg(feature = "sync")]
#[inline]
unsafe fn take_unchecked<T>(val: &mut Option<T>) -> T {
unwrap_unchecked(val.take())
}

// Remove once MSRV is at least 1.58.
#[inline]
unsafe fn unwrap_unchecked<T>(val: Option<T>) -> T {
match val {
Expand Down
4 changes: 2 additions & 2 deletions src/race.rs
Expand Up @@ -19,9 +19,9 @@
//! `Acquire` and `Release` have very little performance overhead on most
//! architectures versus `Relaxed`.

#[cfg(feature = "atomic-polyfill")]
#[cfg(feature = "critical-section")]
use atomic_polyfill as atomic;
#[cfg(not(feature = "atomic-polyfill"))]
#[cfg(not(feature = "critical-section"))]
use core::sync::atomic;

use atomic::{AtomicUsize, Ordering};
Expand Down
28 changes: 14 additions & 14 deletions tests/it.rs
Expand Up @@ -249,14 +249,14 @@ mod unsync {
}
}

#[cfg(feature = "sync")]
#[cfg(any(feature = "std", feature = "critical-section"))]
mod sync {
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};

#[cfg(not(feature = "critical-section"))]
#[cfg(feature = "std")]
use std::sync::Barrier;

#[cfg(feature = "critical-section")]
#[cfg(not(feature = "std"))]
use core::cell::Cell;

use crossbeam_utils::thread::scope;
Expand Down Expand Up @@ -360,7 +360,7 @@ mod sync {
assert_eq!(cell.get(), Some(&"hello".to_string()));
}

#[cfg(not(feature = "critical-section"))]
#[cfg(feature = "std")]
#[test]
fn wait() {
let cell: OnceCell<String> = OnceCell::new();
Expand All @@ -372,7 +372,7 @@ mod sync {
.unwrap();
}

#[cfg(not(feature = "critical-section"))]
#[cfg(feature = "std")]
#[test]
fn get_or_init_stress() {
let n_threads = if cfg!(miri) { 30 } else { 1_000 };
Expand Down Expand Up @@ -437,7 +437,7 @@ mod sync {

#[test]
#[cfg_attr(miri, ignore)] // miri doesn't support processes
#[cfg(not(feature = "critical-section"))]
#[cfg(feature = "std")]
fn reentrant_init() {
let examples_dir = {
let mut exe = std::env::current_exe().unwrap();
Expand Down Expand Up @@ -465,7 +465,7 @@ mod sync {
}
}

#[cfg(feature = "critical-section")]
#[cfg(not(feature = "std"))]
#[test]
#[should_panic(expected = "reentrant init")]
fn reentrant_init() {
Expand Down Expand Up @@ -658,7 +658,7 @@ mod sync {
}
}

#[cfg(not(feature = "critical-section"))]
#[cfg(feature = "std")]
#[test]
fn get_does_not_block() {
let cell = OnceCell::new();
Expand Down Expand Up @@ -692,7 +692,7 @@ mod sync {

#[cfg(feature = "race")]
mod race {
#[cfg(not(feature = "critical-section"))]
#[cfg(feature = "std")]
use std::sync::Barrier;
use std::{
num::NonZeroUsize,
Expand Down Expand Up @@ -748,7 +748,7 @@ mod race {
assert_eq!(cell.get(), Some(val1));
}

#[cfg(not(feature = "critical-section"))]
#[cfg(feature = "std")]
#[test]
fn once_non_zero_usize_first_wins() {
let val1 = NonZeroUsize::new(92).unwrap();
Expand Down Expand Up @@ -828,14 +828,14 @@ mod race {

#[cfg(all(feature = "race", feature = "alloc"))]
mod race_once_box {
#[cfg(not(feature = "critical-section"))]
#[cfg(feature = "std")]
use std::sync::Barrier;
use std::sync::{
atomic::{AtomicUsize, Ordering::SeqCst},
Arc,
};

#[cfg(not(feature = "critical-section"))]
#[cfg(feature = "std")]
use crossbeam_utils::thread::scope;

use once_cell::race::OnceBox;
Expand Down Expand Up @@ -867,7 +867,7 @@ mod race_once_box {
}
}

#[cfg(not(feature = "critical-section"))]
#[cfg(feature = "std")]
#[test]
fn once_box_smoke_test() {
let heap = Heap::default();
Expand Down Expand Up @@ -922,7 +922,7 @@ mod race_once_box {
assert_eq!(heap.total(), 0);
}

#[cfg(not(feature = "critical-section"))]
#[cfg(feature = "std")]
#[test]
fn once_box_first_wins() {
let cell = OnceBox::new();
Expand Down
2 changes: 1 addition & 1 deletion xtask/src/main.rs
Expand Up @@ -34,7 +34,7 @@ fn main() -> xshell::Result<()> {
cmd!(sh, "cargo test --no-default-features --features unstable,alloc --test it").run()?;

cmd!(sh, "cargo test --no-default-features --features critical-section").run()?;
cmd!(sh, "cargo test --no-default-features --features critical-section --release").run()?;
cmd!(sh, "cargo test --features critical-section").run()?;
}

{
Expand Down

0 comments on commit 1faad40

Please sign in to comment.