Subject
futures-util is the main utility layer of the futures-rs ecosystem. It provides combinators for Future (map, then, flatten, select, join, shared), combinators for Stream and Sink, the FuturesUnordered concurrent task set, the FuturesOrdered stream, async-aware locking primitives (BiLock, Mutex), IO adapters wrapping AsyncRead/AsyncWrite (buffering, read-to-end, lines, copy, split), and compatibility shims between futures 0.1 and 0.3 APIs. The crate is approximately 26 000 lines of Rust across ~180 files with 135 unsafe occurrences.
Methodology
The published .crate contents were compared against the upstream Git repository at the commit recorded in .cargo_vcs_info.json using diff. Differences are limited to standard cargo manifest normalisation and the presence of a generated Cargo.lock and .cargo_vcs_info.json in the published artifact — no code-file divergence was found.
All 22 files containing unsafe were identified with grep -rn "unsafe" src/ -l and read in full. The review focused on:
- Pin projection soundness:
pin_mut!, MaybeDone, TryMaybeDone, JoinAll/iter_pin_mut, BufWriter::write_to_buffer_unchecked, the Shared future, and FlattenUnordered (via pin_project_lite).
FuturesUnordered internals: the intrusive doubly-linked all-tasks list, the 1024cores MPSC ready-to-run queue (ReadyToRunQueue), Task Send/Sync impl, the custom waker_ref bypassing 'static, and the Bomb panic-safety guard.
BiLock synchronisation: the AtomicPtr<Waker> state machine and Box::from_raw discipline.
Mutex and MappedMutexGuard: UnsafeCell access under lock, mem::forget discipline in MutexGuard::map.
- The futures 0.1 compat layer:
UnsafeNotify01 implementation and Box::from_raw on waker pointers.
The repository VCS checkout was used to survey CI configuration and test coverage. has-unit-tests: inline unit tests are present in src/lock/mutex.rs. has-integration-tests is false; has-fuzz-tests is false; has-property-tests is false. The futures workspace has integration-style tests under futures/tests/ covering FuturesUnordered, Mutex, and IO combinators, but these are part of a separate crate. No loom or sanitizer-based testing was found for the concurrent primitives, so unsafe-tested and concurrency-impl-tested are false. grep was used for pattern searches.
Results
The published crate contents match the VCS at the recorded commit. No binary artifacts are present, justifying has-binaries. There is no build.rs, justifying has-build-exec and has-install-exec. The crate is is-benign.
The codebase makes no network or filesystem calls and does not spawn child processes or read environment variables, justifying uses-network, uses-filesystem, uses-exec, uses-environment, uses-crypto, uses-jit, uses-interpreter. It uses-concurrency (atomic primitives, Arc, Mutex) and uses-unsafe.
The crate implements no cryptographic algorithms, parsers, protocols, interpreters, or JIT compilers, justifying impl-crypto, impl-parser, impl-protocol, impl-interpreter, impl-jit, impl-algorithm. It does implement concurrency primitives (impl-concurrency: FuturesUnordered, BiLock, Mutex, Shared) and a data structure (impl-datastructure: FuturesUnordered's intrusive linked list and MPSC queue). The concurrency API surface is documented per type with thread-safety guarantees, justifying concurrency-documented and concurrency-impl-documented. The public API correctly documents Send/Sync bounds, justifying concurrency-safe. Operations on the data structures meet their documented complexity, justifying datastructure-impl-bounds. datastructure-impl-tested and concurrency-impl-tested are false (no loom/sanitizer coverage).
Pin projection (unsafe-safe, unsafe-documented, unsafe-minimal): All Pin::new_unchecked and get_unchecked_mut calls were reviewed. In MaybeDone/TryMaybeDone, the enum is self-pinned: the Future variant is structurally pinned, while Done and Gone hold Unpin data and are safe to replace via mem::replace after get_unchecked_mut. The JoinAll::iter_pin_mut helper correctly projects a Pin<&mut [T]> into per-element Pin<&mut T>, relying on the slice itself not being moved (it is heap-allocated in Box). BufWriter uses get_unchecked_mut only within pin_project_lite-generated projections and a bounds-checked write_to_buffer_unchecked helper with a debug assertion. All uses carry inline safety comments. The pin_mut! macro follows the standard shadow-binding stack-pinning pattern. Overall, unsafe-safe, unsafe-documented, and unsafe-minimal hold.
FuturesUnordered (impl-datastructure, impl-concurrency, concurrency-impl-safe, datastructure-impl-safe, datastructure-impl-correct, concurrency-impl-correct): The all-tasks list is a lock-free singly-linked list accessed with AcqRel swaps on head_all. A pending_next_all sentinel (the stub node pointer) allows insertion to proceed in two steps — the spin_next_all loop handles the window where next_all has not been written yet. The ready-to-run queue is the classic 1024cores MPSC algorithm with AcqRel/Release/Acquire orderings matching the reference. dequeue requires exclusive access, enforced by the &mut Self receiver on poll_next. The Task Send/Sync impls are sound because the future inside UnsafeCell is only accessed from the FuturesUnordered owner thread. The custom waker_ref forgoing 'static is safe: the Arc keeping Task alive is owned by the FuturesUnordered list and the Bomb guard, both of which outlive the waker. Panic safety is handled via the Bomb drop guard. The FIXME comment on enqueue (missing explicit safety preconditions) is recorded as FINDING-1.
BiLock (concurrency-impl-safe, concurrency-impl-correct): The AtomicPtr<Waker> state machine correctly tracks three states (null, 1, heap pointer). Box::from_raw is always called on the previous pointer when swapping in a new waker, preventing leaks. The invalid_ptr helper creates a strict-provenance-compatible sentinel.
Shared (concurrency-impl-safe): The UnsafeCell<FutureOrOutput<Fut>> is protected by the POLLING atomic state that allows at most one concurrent poll. The Reset guard sets POISONED on panic, after which no further access to the cell occurs.
One quality finding (FINDING-1) was recorded for the missing safety preconditions on enqueue.
Conclusion
The unsafe code in this crate is voluminous but structurally sound. The Pin-projection patterns are standard and correctly applied throughout. FuturesUnordered's lock-free implementation follows a well-known algorithm with appropriate memory orderings. BiLock and Mutex are straightforward with correct UnsafeCell discipline. The main gap is the absence of loom or sanitizer-based concurrency testing for the concurrent primitives (unsafe-tested, concurrency-impl-tested).