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-OLD.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Historical Changelog

> Apache Asyncband (Incubating) is an effort undergoing incubation at the Apache Software Foundation (ASF), sponsored by the Apache Incubator PMC. Please read the [DISCLAIMER](DISCLAIMER).

## v0.6.7 (2026-08-13)

* Announce the upcoming `asyncband` rebrand.
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Changelog

> Apache Asyncband (Incubating) is an effort undergoing incubation at the Apache Software Foundation (ASF), sponsored by the Apache Incubator PMC. Please read the [DISCLAIMER](DISCLAIMER).

All notable changes to this project will be documented in this file.

## Unreleased
Expand Down
2 changes: 2 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# History

> Apache Asyncband (Incubating) is an effort undergoing incubation at the Apache Software Foundation (ASF), sponsored by the Apache Incubator PMC. Please read the [DISCLAIMER](DISCLAIMER).

Asyncband collects runtime-agnostic synchronization primitives informed by several existing implementations. Only components that draw on external designs or code are listed here.

- `barrier::Barrier` is inspired by [`std::sync::Barrier`](https://doc.rust-lang.org/std/sync/struct.Barrier.html) and [`tokio::sync::Barrier`](https://docs.rs/tokio/latest/tokio/sync/struct.Barrier.html), with a different implementation based on the internal `WaitSet` primitive.
Expand Down
2 changes: 2 additions & 0 deletions MIGRATE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Migrating from MEA

> Apache Asyncband (Incubating) is an effort undergoing incubation at the Apache Software Foundation (ASF), sponsored by the Apache Incubator PMC. Please read the [DISCLAIMER](DISCLAIMER).

Asyncband continues the codebase formerly published as [`mea`](https://crates.io/crates/mea), but it uses a new Cargo package and Rust crate name. Existing `mea` releases remain available for builds that have not migrated, but they receive no further development.

## Recommended migration path
Expand Down
42 changes: 22 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,25 @@ Asyncband is a runtime-agnostic library providing essential synchronization prim

Each module is an opt-in Cargo feature. The crate enables no primitives by default. Categories describe each primitive's primary purpose; they do not add another module level, so public paths continue to match feature names such as `asyncband::mutex` and `asyncband::mpsc`.

| Category | Primitive | Feature | Purpose |
| --- | --- | --- | --- |
| Shared state | [`Mutex`](https://docs.rs/asyncband/*/asyncband/mutex/struct.Mutex.html) | `mutex` | Protect shared data with asynchronous mutual exclusion. |
| | [`RwLock`](https://docs.rs/asyncband/*/asyncband/rwlock/struct.RwLock.html) | `rwlock` | Allow multiple readers or one writer. |
| | [`Condvar`](https://docs.rs/asyncband/*/asyncband/condvar/struct.Condvar.html) | `condvar` | Wait for notifications while releasing a mutex. |
| One-time initialization | [`Once`](https://docs.rs/asyncband/*/asyncband/once/struct.Once.html) | `once` | Run asynchronous initialization exactly once. |
| | [`OnceCell`](https://docs.rs/asyncband/*/asyncband/once/struct.OnceCell.html) | `once` | Initialize and store one asynchronous value. |
| | [`OnceMap`](https://docs.rs/asyncband/*/asyncband/once/struct.OnceMap.html) | `once` | Initialize and store one value per key. |
| Task coordination | [`Barrier`](https://docs.rs/asyncband/*/asyncband/barrier/struct.Barrier.html) | `barrier` | Wait until all participants reach a synchronization point. |
| | [`Latch`](https://docs.rs/asyncband/*/asyncband/latch/struct.Latch.html) | `latch` | Wait until a one-way countdown completes. |
| | [`WaitGroup`](https://docs.rs/asyncband/*/asyncband/waitgroup/struct.WaitGroup.html) | `waitgroup` | Wait for a dynamic group of tasks to finish. |
| | [`shutdown`](https://docs.rs/asyncband/*/asyncband/shutdown/) | `shutdown` | Coordinate shutdown signals and completion. |
| Channels | [`oneshot::channel`](https://docs.rs/asyncband/*/asyncband/oneshot/fn.channel.html) | `oneshot` | Send one value between two tasks. |
| | [`mpsc::bounded`](https://docs.rs/asyncband/*/asyncband/mpsc/fn.bounded.html) | `mpsc` | Send values from multiple producers through a bounded channel. |
| | [`mpsc::unbounded`](https://docs.rs/asyncband/*/asyncband/mpsc/fn.unbounded.html) | `mpsc` | Send values from multiple producers through an unbounded channel. |
| | [`broadcast::overflow`](https://docs.rs/asyncband/*/asyncband/broadcast/overflow/) | `broadcast` | Broadcast values and report when slow receivers miss overwritten items. |
| Workload control | [`Semaphore`](https://docs.rs/asyncband/*/asyncband/semaphore/struct.Semaphore.html) | `semaphore` | Control concurrent access with permits. |
| | [`FairShare`](https://docs.rs/asyncband/*/asyncband/admission/struct.FairShare.html) | `admission` | Fairly share bounded concurrency across keys. |
| | [`Group`](https://docs.rs/asyncband/*/asyncband/singleflight/struct.Group.html) | `singleflight` | Coalesce concurrent calls for the same key. |
| Category | Primitive | Feature | Purpose |
| ----------------------- | ------------------------------------------------------------------------------------ | -------------- | ----------------------------------------------------------------------- |
| Shared state | [`Mutex`](https://docs.rs/asyncband/*/asyncband/mutex/struct.Mutex.html) | `mutex` | Protect shared data with asynchronous mutual exclusion. |
| | [`RwLock`](https://docs.rs/asyncband/*/asyncband/rwlock/struct.RwLock.html) | `rwlock` | Allow multiple readers or one writer. |
| | [`Condvar`](https://docs.rs/asyncband/*/asyncband/condvar/struct.Condvar.html) | `condvar` | Wait for notifications while releasing a mutex. |
| One-time initialization | [`Once`](https://docs.rs/asyncband/*/asyncband/once/struct.Once.html) | `once` | Run asynchronous initialization exactly once. |
| | [`OnceCell`](https://docs.rs/asyncband/*/asyncband/once/struct.OnceCell.html) | `once` | Initialize and store one asynchronous value. |
| | [`OnceMap`](https://docs.rs/asyncband/*/asyncband/once/struct.OnceMap.html) | `once` | Initialize and store one value per key. |
| Task coordination | [`Barrier`](https://docs.rs/asyncband/*/asyncband/barrier/struct.Barrier.html) | `barrier` | Wait until all participants reach a synchronization point. |
| | [`Latch`](https://docs.rs/asyncband/*/asyncband/latch/struct.Latch.html) | `latch` | Wait until a one-way countdown completes. |
| | [`WaitGroup`](https://docs.rs/asyncband/*/asyncband/waitgroup/struct.WaitGroup.html) | `waitgroup` | Wait for a dynamic group of tasks to finish. |
| | [`shutdown`](https://docs.rs/asyncband/*/asyncband/shutdown/) | `shutdown` | Coordinate shutdown signals and completion. |
| Channels | [`oneshot::channel`](https://docs.rs/asyncband/*/asyncband/oneshot/fn.channel.html) | `oneshot` | Send one value between two tasks. |
| | [`mpsc::bounded`](https://docs.rs/asyncband/*/asyncband/mpsc/fn.bounded.html) | `mpsc` | Send values from multiple producers through a bounded channel. |
| | [`mpsc::unbounded`](https://docs.rs/asyncband/*/asyncband/mpsc/fn.unbounded.html) | `mpsc` | Send values from multiple producers through an unbounded channel. |
| | [`broadcast::overflow`](https://docs.rs/asyncband/*/asyncband/broadcast/overflow/) | `broadcast` | Broadcast values and report when slow receivers miss overwritten items. |
| Workload control | [`Semaphore`](https://docs.rs/asyncband/*/asyncband/semaphore/struct.Semaphore.html) | `semaphore` | Control concurrent access with permits. |
| | [`FairShare`](https://docs.rs/asyncband/*/asyncband/admission/struct.FairShare.html) | `admission` | Fairly share bounded concurrency across keys. |
| | [`Group`](https://docs.rs/asyncband/*/asyncband/singleflight/struct.Group.html) | `singleflight` | Coalesce concurrent calls for the same key. |

Features that build on other primitives enable them automatically: `condvar` enables `mutex`, `once` enables `semaphore`, `shutdown` enables `latch` and `waitgroup`, and `singleflight` enables `once`.

Expand Down Expand Up @@ -110,10 +110,12 @@ This crate is built against the latest stable release, and its minimum supported

The policy is that the minimum Rust version required to use this crate can be increased in minor version updates. For example, if Asyncband 1.0 requires Rust 1.20.0, then Asyncband 1.0.z for all values of z will also require Rust 1.20.0 or newer. However, Asyncband 1.y for y > 0 may require a newer minimum version of Rust.

## License
## License and Trademarks

This project is licensed under [Apache License, Version 2.0](LICENSE).

Apache Asyncband, Asyncband, and Apache are either registered trademarks or trademarks of The Apache Software Foundation in the United States and/or other countries.

## History

See [HISTORY.md](HISTORY.md) for the external implementations that informed Asyncband's primitives.
10 changes: 5 additions & 5 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ The public verification URL is <https://downloads.apache.org/incubator/asyncband

The `asyncband` crate already exists, so a crate owner can configure [crates.io Trusted Publishing](https://crates.io/docs/trusted-publishing) without a bootstrap publication. In the crate's **Settings → Trusted Publishing** page, add a GitHub Actions publisher with these exact values:

| Setting | Value |
| --- | --- |
| Repository owner | `apache` |
| Repository name | `asyncband` |
| Setting | Value |
| ----------------- | ------------- |
| Repository owner | `apache` |
| Repository name | `asyncband` |
| Workflow filename | `release.yml` |
| Environment | `release` |
| Environment | `release` |

The workflow obtains a short-lived OIDC token and keeps no long-lived crates.io token in GitHub. The `release` GitHub environment is managed by `.asf.yaml`: it accepts version tags and requires approval from one of the configured project committers. The person who pushed the tag may approve the deployment.

Expand Down
1 change: 1 addition & 0 deletions asyncband/HISTORY.md
1 change: 1 addition & 0 deletions asyncband/MIGRATE.md
92 changes: 56 additions & 36 deletions asyncband/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,62 +15,82 @@
// specific language governing permissions and limitations
// under the License.

// `doc_cfg` automatically infers feature badges from `cfg` attributes, so individual modules do
// not need matching `doc(cfg(...))` attributes.
#![cfg_attr(docsrs, feature(doc_cfg))]
#![deny(missing_docs)]

//! `asyncband` is a runtime-agnostic library providing essential synchronization primitives for
//! asynchronous Rust programming. The library offers a collection of well-tested, efficient
//! synchronization tools that work with any async runtime.
//! Runtime-agnostic synchronization primitives for asynchronous Rust.
//!
//! # Migrating from MEA
//! `asyncband` provides locks, initialization tools, task coordination, channels, and workload
//! controls without tying an application to a particular async runtime. The primitives use standard
//! futures and wakers, so they can run on Tokio, async-std, smol, or a custom executor.
//!
//! Asyncband continues the project formerly published as `mea`. The old crate is deprecated and no
//! compatibility crate or re-export is provided. Replace the `mea` dependency with `asyncband` and
//! update `mea::` paths to `asyncband::`.
//! # Getting started
//!
//! # Cargo features
//!
//! The crate enables no primitives or utilities by default. Each public module has a same-named
//! opt-in feature, so applications only compile the APIs they use:
//! Public APIs live in top-level modules. Each module is controlled by a same-named Cargo feature,
//! and no features are enabled by default. Enable the modules your application needs:
//!
//! ```toml
//! asyncband = { version = "0.7", features = ["mutex", "oneshot"] }
//! ```
//!
//! Features that build on other primitives enable those dependencies automatically. For example,
//! `condvar` enables `mutex`, while `shutdown` enables `latch` and `waitgroup`.
//! Then use the selected primitives directly:
//!
//! ```
//! # #[tokio::main]
//! # async fn main() {
//! use asyncband::mutex::Mutex;
//!
//! let counter = Mutex::new(0);
//! {
//! let mut value = counter.lock().await;
//! *value += 1;
//! }
//! assert_eq!(*counter.lock().await, 1);
//! # }
//! ```
//!
//! Features that build on other primitives enable their dependencies automatically: `condvar`
//! enables `mutex`, `once` enables `semaphore`, `shutdown` enables `latch` and `waitgroup`, and
//! `singleflight` enables `once`.
//!
//! # API guide
//!
//! | Use case | APIs | Cargo features |
//! | -------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------- |
//! | Protect shared state | [`mutex::Mutex`], [`rwlock::RwLock`], [`condvar::Condvar`] | `mutex`, `rwlock`, `condvar` |
//! | Initialize values once | [`once::Once`], [`once::OnceCell`], [`once::OnceMap`] | `once` |
//! | Coordinate tasks | [`barrier::Barrier`], [`latch::Latch`], [`waitgroup::WaitGroup`], [`shutdown`] | `barrier`, `latch`, `waitgroup`, `shutdown` |
//! | Send values | [`oneshot::channel`], [`mpsc::bounded`], [`mpsc::unbounded`], [`broadcast::overflow`] | `oneshot`, `mpsc`, `broadcast` |
//! | Control workloads | [`semaphore::Semaphore`], [`admission::FairShare`], [`singleflight::Group`] | `semaphore`, `admission`, `singleflight` |
//! | Wait from synchronous code | [`blocking::FutureExt`] | `blocking` |
//!
//! # Primitive categories
//! # Runtime and blocking model
//!
//! The public primitives are grouped by their primary user-facing purpose while their modules
//! remain at the crate root so module paths continue to match Cargo feature names:
//! The async primitives do not start threads, spawn tasks, or require a runtime-specific reactor.
//! Await them inside any executor that polls standard Rust futures.
//!
//! * Shared state: `Mutex`, `RwLock`, and `Condvar`.
//! * One-time initialization: `Once`, `OnceCell`, and `OnceMap`.
//! * Task coordination: `Barrier`, `Latch`, `WaitGroup`, and graceful shutdown.
//! * Channels: oneshot, bounded and unbounded MPSC, and overflowing broadcast channels.
//! * Workload control: `Semaphore`, fair-share admission control, and duplicate-call suppression.
//! Async APIs are the primary interface. The optional [`blocking`] module is a boundary adapter for
//! synchronous callers: its single-future executor parks the calling thread and resumes it through
//! the future's waker. It is not a general-purpose async runtime, and futures that depend on a
//! runtime-specific timer or I/O driver may not make progress. See the module documentation for the
//! full execution constraints.
//!
//! # Synchronous interoperability
//! # Thread safety
//!
//! The optional [`blocking`] module lets synchronous code wait indefinitely or with a timeout on a
//! single runtime-agnostic future. It is an interoperability utility rather than an async primitive
//! or a general-purpose runtime.
//! Primitives and guards implement `Send` and `Sync` only when their protected or transferred
//! values satisfy the required bounds. Consult each type's documentation for its exact contract.
//!
//! # Runtime Agnostic
//! # Disclaimer
//!
//! All synchronization primitives in this library are runtime-agnostic, meaning they can be used
//! with any async runtime like tokio, async-std, or others. This makes the library highly versatile
//! and portable.
//! Apache Asyncband (Incubating) is an effort undergoing incubation at the Apache Software
//! Foundation (ASF), sponsored by the Apache Incubator PMC.
//!
//! # Thread Safety
//! Incubation is required of all newly accepted projects until a further review indicates that the
//! infrastructure, communications, and decision making process have stabilized in a manner
//! consistent with other successful ASF projects.
//!
//! Asyncband primitives and guards implement `Send` and `Sync` only when the protected or
//! transferred value satisfies the necessary bounds. In particular, owned read guards that may move
//! destruction to another thread require the protected value to be `Send` as well as `Sync`. See
//! each type's documentation for its exact bounds.
//! While incubation status is not necessarily a reflection of the completeness or stability of the
//! code, it does indicate that the project has yet to be fully endorsed by the ASF.
#[cfg(any(
feature = "admission",
feature = "barrier",
Expand Down
11 changes: 5 additions & 6 deletions asyncband/src/rwlock/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,11 @@
//! will allow any number of readers to acquire the lock as long as a writer is not holding the
//! lock.
//!
//! The priority policy of Tokio's read-write lock is fair (or [write-preferring]), in order to
//! ensure that readers cannot starve writers. Fairness is ensured using a first-in, first-out queue
//! for the tasks awaiting the lock; if a task that wishes to acquire the write lock is at the head
//! of the queue, read locks will not be given out until the write lock has been released. This is
//! in contrast to the Rust standard library's `std::sync::RwLock`, where the priority policy is
//! dependent on the operating system's implementation.
//! The priority policy of this read-write lock is fair (or [write-preferring]), ensuring that
//! readers cannot starve writers. Fairness is maintained using a first-in, first-out queue for
//! tasks awaiting the lock. If a writer reaches the head of the queue, readers will not acquire
//! the lock until that writer has acquired and released it. In contrast, the priority policy of
//! the Rust standard library's `std::sync::RwLock` depends on the operating system.
//!
//! The type parameter `T` represents the data that this lock protects. It is required that `T`
//! satisfies [`Send`] to be shared across threads. The RAII guards returned from the locking
Expand Down