Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

- Add `crossbeam` feature, enabled by default, to enable `crossbeam-utils` dependency and `AtomicLazy` struct.

## [0.2.0] - 2025-02-13

### Fixed
Expand Down
7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ include = [

[dependencies]
portable-atomic = "1"
crossbeam-utils = { version = "0.8.15", default-features = false }
crossbeam-utils = { version = "0.8.15", default-features = false, optional = true }
serde = { version = "1.0.171", optional = true }

[target.'cfg(loom)'.dependencies]
Expand All @@ -26,5 +26,6 @@ loom = "0.7.0"
serde_json = "1.0.104"

[features]
default = []
serde = ["dep:serde"]
default = ["crossbeam"]
crossbeam = ["dep:crossbeam-utils"]
serde = ["dep:serde"]
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ lock-free (if you know a way, please tell me).
Both types can be used in a non-blocking way, but there are some
blocking calls that should not be used from interrupt handlers or
other contexts where blocking will lead to a deadlock. Blocking is
based on
[`crossbeam::utils::Backoff`](https://docs.rs/crossbeam/latest/crossbeam/utils/struct.Backoff.html),
and will be reduced to a spinlock in `#[no_std]` environments.
based on [`crossbeam::utils::Backoff`] and will be reduced to a spinlock
in `#[no_std]` environments. This is enabled via `crossbeam` feature.

[`crossbeam::utils::Backoff`]: https://docs.rs/crossbeam/latest/crossbeam/utils/struct.Backoff.html,

### Examples
#### `AtomicOnceCell`
Expand Down
29 changes: 19 additions & 10 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
//! Both types can be used in a non-blocking way, but there are some
//! blocking calls that should not be used from interrupt handlers or
//! other contexts where blocking will lead to a deadlock. Blocking is
//! based on
//! [`crossbeam::utils::Backoff`](https://docs.rs/crossbeam/latest/crossbeam/utils/struct.Backoff.html),
//! and will be reduced to a spinlock in `#[no_std]` environments.
//! based on [`crossbeam::utils::Backoff`] and will be reduced to a spinlock
//! in `#[no_std]` environments. This is enabled via `crossbeam` feature.
//!
//! [`crossbeam::utils::Backoff`]: https://docs.rs/crossbeam/latest/crossbeam/utils/struct.Backoff.html,
//!
//! ## Examples
//! ### `AtomicOnceCell`
Expand Down Expand Up @@ -48,13 +49,13 @@

#![no_std]

use core::{
cell::{Cell, UnsafeCell},
fmt,
ops::Deref,
sync::atomic::Ordering,
use core::{cell::UnsafeCell, fmt, sync::atomic::Ordering};

#[cfg(feature = "crossbeam")]
use {
core::{cell::Cell, ops::Deref},
crossbeam_utils::Backoff,
};
use crossbeam_utils::Backoff;

#[cfg(not(loom))]
use portable_atomic::AtomicU8;
Expand Down Expand Up @@ -269,6 +270,7 @@ impl<T> AtomicOnceCell<T> {
/// let value = cell.get_or_init(|| unreachable!());
/// assert_eq!(value, &92);
/// ```
#[cfg(feature = "crossbeam")]
pub fn get_or_init<F>(&self, f: F) -> &T
where
F: FnOnce() -> T,
Expand Down Expand Up @@ -311,6 +313,7 @@ impl<T> AtomicOnceCell<T> {
/// assert_eq!(value, Ok(&92));
/// assert_eq!(cell.get(), Some(&92))
/// ```
#[cfg(feature = "crossbeam")]
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
where
F: FnOnce() -> Result<T, E>,
Expand Down Expand Up @@ -456,12 +459,13 @@ impl<T: Serialize> Serialize for AtomicOnceCell<T> {
/// // asynchronously at some point
/// // [...]
/// }

#[cfg(feature = "crossbeam")]
pub struct AtomicLazy<T, F = fn() -> T> {
cell: AtomicOnceCell<T>,
init: Cell<Option<F>>,
}

#[cfg(feature = "crossbeam")]
impl<T: fmt::Debug, F> fmt::Debug for AtomicLazy<T, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AtomicLazy")
Expand All @@ -471,20 +475,23 @@ impl<T: fmt::Debug, F> fmt::Debug for AtomicLazy<T, F> {
}
}

#[cfg(feature = "crossbeam")]
impl<T: Default> Default for AtomicLazy<T> {
/// Creates a new lazy value using `Default` as the initializing function.
fn default() -> AtomicLazy<T> {
AtomicLazy::new(T::default)
}
}

#[cfg(feature = "crossbeam")]
unsafe impl<T, F> Sync for AtomicLazy<T, F>
where
T: Send + Sync,
F: Send,
{
}

#[cfg(feature = "crossbeam")]
impl<T, F> AtomicLazy<T, F> {
/// Creates a new lazy value with the given initializing function.
///
Expand Down Expand Up @@ -518,6 +525,7 @@ impl<T, F> AtomicLazy<T, F> {
}
}

#[cfg(feature = "crossbeam")]
impl<T, F> AtomicLazy<T, F>
where
F: FnOnce() -> T,
Expand Down Expand Up @@ -585,6 +593,7 @@ where
}
}

#[cfg(feature = "crossbeam")]
impl<T, F> Deref for AtomicLazy<T, F>
where
F: FnOnce() -> T,
Expand Down
Loading