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

publish 1.16.0-pre.1 #203

Merged
merged 1 commit into from Oct 22, 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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,12 @@

-

## 1.16.0-pre.1

- Add `no_std` implementation based on `critical-section`,
[#195](https://github.com/matklad/once_cell/pull/195).
- 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