diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b79993..d10aeeb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,8 +24,10 @@ jobs: toolchain: stable override: true - run: cargo check --all-targets + - run: cargo check --all-targets --features stats - run: cargo check --all-targets --no-default-features - - run: cargo check --all-targets --all-features + - run: cargo check --all-targets --no-default-features --features crossbeam + - run: cargo check --all-targets --features shuttle test: name: Tests @@ -42,8 +44,9 @@ jobs: override: true - run: cargo test - run: cargo test --no-default-features + - run: cargo test --no-default-features --features crossbeam # no run because of shuttle feature and non-shuttle tests - - run: cargo test --all-features --no-run + - run: cargo test --features shuttle --no-run shuttle-tests: name: Shuttle Tests diff --git a/Cargo.toml b/Cargo.toml index 776f399..208fb2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,11 +14,13 @@ rust-version = "1.71" [features] default = ["ahash", "parking_lot"] +crossbeam = ["dep:crossbeam-utils"] shuttle = ["dep:shuttle"] stats = [] [dependencies] ahash = { optional = true, version = "0.8" } +crossbeam-utils = { optional = true, version = "0.8" } equivalent = "1.0" hashbrown = { version = "0.16", default-features = false, features = ["inline-more"] } parking_lot = { optional = true, version = "0.12" } diff --git a/src/lib.rs b/src/lib.rs index 4ca92d3..e841eb7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,20 +66,26 @@ //! # Synchronization primitives //! //! By default the crate uses [parking_lot](https://crates.io/crates/parking_lot), which is enabled (by default) via -//! a crate feature with the same name. If the `parking_lot` feature is disabled the crate defaults to the std lib -//! implementation instead. +//! a crate feature with the same name. If `parking_lot` is disabled and `crossbeam` is enabled, the crate uses +//! [`crossbeam_utils::sync::ShardedLock`](https://docs.rs/crossbeam-utils/latest/crossbeam_utils/sync/struct.ShardedLock.html) +//! from [crossbeam-utils](https://crates.io/crates/crossbeam-utils) instead. If both are disabled the crate defaults +//! to the std lib implementation. The `parking_lot` and `crossbeam` features are mutually exclusive. //! //! # Cargo Features //! //! | Feature | Default | Description | //! |---------|---------|-------------| //! | `ahash` | ✓ | Use [ahash](https://crates.io/crates/ahash) as the default hasher. When disabled, falls back to std lib's `RandomState` (currently SipHash-1-3). | -//! | `parking_lot` | ✓ | Use [parking_lot](https://crates.io/crates/parking_lot) for synchronization primitives. When disabled, falls back to std lib's `RwLock`. | +//! | `parking_lot` | ✓ | Use [parking_lot](https://crates.io/crates/parking_lot) for synchronization primitives. Mutually exclusive with `crossbeam`. | +//! | `crossbeam` | | Use [`crossbeam_utils::sync::ShardedLock`](https://docs.rs/crossbeam-utils/latest/crossbeam_utils/sync/struct.ShardedLock.html) for synchronization primitives. Mutually exclusive with `parking_lot`. | //! | `shuttle` | | Enable [shuttle](https://crates.io/crates/shuttle) testing support for concurrency testing. | //! | `stats` | | Enable cache statistics tracking via the `hits()` and `misses()` methods. | #![allow(clippy::type_complexity)] #![cfg_attr(docsrs, feature(doc_cfg))] +#[cfg(all(feature = "parking_lot", feature = "crossbeam"))] +compile_error!("features `parking_lot` and `crossbeam` are mutually exclusive"); + #[cfg(not(fuzzing))] mod linked_slab; #[cfg(fuzzing)] diff --git a/src/rw_lock.rs b/src/rw_lock.rs index ba4db95..4bc6ecb 100644 --- a/src/rw_lock.rs +++ b/src/rw_lock.rs @@ -2,17 +2,23 @@ use std::ops::{Deref, DerefMut}; #[cfg(feature = "parking_lot")] type InnerRwLock = parking_lot::RwLock; -#[cfg(not(feature = "parking_lot"))] +#[cfg(all(not(feature = "parking_lot"), feature = "crossbeam"))] +type InnerRwLock = crossbeam_utils::sync::ShardedLock; +#[cfg(all(not(feature = "parking_lot"), not(feature = "crossbeam")))] type InnerRwLock = std::sync::RwLock; #[cfg(feature = "parking_lot")] type InnerRwLockReadGuard<'rwlock, T> = parking_lot::RwLockReadGuard<'rwlock, T>; -#[cfg(not(feature = "parking_lot"))] +#[cfg(all(not(feature = "parking_lot"), feature = "crossbeam"))] +type InnerRwLockReadGuard<'rwlock, T> = crossbeam_utils::sync::ShardedLockReadGuard<'rwlock, T>; +#[cfg(all(not(feature = "parking_lot"), not(feature = "crossbeam")))] type InnerRwLockReadGuard<'rwlock, T> = std::sync::RwLockReadGuard<'rwlock, T>; #[cfg(feature = "parking_lot")] type InnerRwLockWriteGuard<'rwlock, T> = parking_lot::RwLockWriteGuard<'rwlock, T>; -#[cfg(not(feature = "parking_lot"))] +#[cfg(all(not(feature = "parking_lot"), feature = "crossbeam"))] +type InnerRwLockWriteGuard<'rwlock, T> = crossbeam_utils::sync::ShardedLockWriteGuard<'rwlock, T>; +#[cfg(all(not(feature = "parking_lot"), not(feature = "crossbeam")))] type InnerRwLockWriteGuard<'rwlock, T> = std::sync::RwLockWriteGuard<'rwlock, T>; /// A reader-writer lock. @@ -52,6 +58,7 @@ pub struct RwLockReadGuard<'rwlock, T: ?Sized>(InnerRwLockReadGuard<'rwlock, T>) #[must_use = "if unused the RwLock will immediately unlock"] pub struct RwLockWriteGuard<'rwlock, T: ?Sized>(InnerRwLockWriteGuard<'rwlock, T>); +#[cfg(not(feature = "crossbeam"))] impl RwLock { /// Creates a new instance of an `RwLock` which is unlocked. pub const fn new(t: T) -> Self { @@ -59,6 +66,14 @@ impl RwLock { } } +#[cfg(feature = "crossbeam")] +impl RwLock { + /// Creates a new instance of an `RwLock` which is unlocked. + pub fn new(t: T) -> Self { + Self(InnerRwLock::new(t)) + } +} + impl RwLock { /// Locks this `RwLock` with shared read access, blocking the current thread /// until it can be acquired.