Releases: al8n/wg
v1.0.0 — first stable release
First stable release. Significant breaking changes from 0.9.x — see Migration
from 0.9 below before upgrading.
The crate now commits to Semantic Versioning: breaking
changes to the public API or a bump of the declared MSRV will require a major
version bump.
Breaking changes
-
done()now returns the remaining count, not the previous value. In
0.9.x,future::WaitGroup::done()/no_std::WaitGroup::done()returned the
counter value before the decrement, which contradicted the documented
behaviour. It now consistently returns the count after decrementing. The
blockingWaitGroupwas already correct. -
waitings()renamed toremaining()on all variants. The new name
reads naturally (if wg.remaining() > 0 { … }) and is consistent across
variants. -
Old
no_stdmodule replaced byspin. The lock-free, atomic-counter
variant now lives atwg::spin::WaitGroup. Inno_stdbuilds,
wg::WaitGroupis a re-export ofwg::spin::WaitGroup(backward-compatible
forno_stdusers). -
future::AsyncWaitGrouprenamed tofuture::WaitGroup. Use the
module-qualified name:wg::future::WaitGroup. -
The
allocfeature no longer pulls incrossbeam-utils; the spin backoff is
now inlined into the crate.
Fixed
- Busy-loop in
future::WaitGroup::poll. The previousPendingbranch
calledwake_by_ref()before returningPending, causing the executor to
re-poll the future continuously and burn 100% CPU untildone()reached
zero. The waker is now only registered once (via the listener) and the
future properly yields. - Wrong return value from
done()(see breaking changes above). std::sync::Mutexpoisoning no longer panics. The blockingWaitGroup
now recovers the guard on poisoning viaPoisonError::into_inner— a
poisoned counter is not a memory-safety concern, and cascading panics
across every thread touching the group were an over-reaction.- Redundant
notify(usize::MAX)on everydone(). The async variant now
only notifies waiters when the counter actually reaches zero, instead of
on every decrement. crossbeam_utils::Backoff::new()was being reset inside the wait loop,
so it never escalated past its first spin budget. Replaced with an inline
adaptive backoff that spins and — onstd— yields the OS thread once the
spin budget is exhausted.- Silent over-done no longer triggers the misleading
assert_eq!(x, 0).
Callingdone()on a zero counter remains a silent no-op returning0. - The
required-features = ["tokio"]ontests/future.rspointed at a
non-existent feature, so the integration test never ran in CI. Fixed to
required-features = ["future"], and the CI job now exercises it.
Changed
- Memory ordering tightened:
addusesRelease,doneusesAcqRel/
Acquire,remaining/waitloads useAcquire. The previousSeqCst
everywhere was unnecessarily strong —Release/Acquireprovides the
required happens-before edges for this structure. #![forbid(unsafe_code)]is now enforced at the crate level.
Added
wg::spin::WaitGroup— a lock-free, atomic-counter WaitGroup available on
bothstdandno_std. Uses an inline adaptive backoff that yields the OS
thread onstdand spins on pureno_std.- Dedicated integration tests for each variant.
- Compile-time
Send + Syncassertions for all three variants. - Declared MSRV (
rust-version = "1.76.0", driven byparking_lotand
triomphefloor requirements).
Migration from 0.9
- Replace
wg::AsyncWaitGroupwithwg::future::WaitGroup. - Replace
.waitings()with.remaining(). - If you relied on
done()returning the pre-decrement value on the async /
no_std variants, adjust your code — it now returns the post-decrement value,
matching the blocking variant and the documented contract. required-features = ["tokio"]in consumer code should be
required-features = ["future"].