alloc-checked

Fallible Rust collections that return Result instead of panicking on allocation failure.

Library
Cargo
v0.1.3
3stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
21/100Needs Attention
Development Activity12
Maintenance20
Community8
Maturity44
Momentum0

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
69/100Good
Architecture72
Code Quality78
Innovation62
Learning Curve65

alloc-checked is a Rust crate maintained by QuestDB that provides drop-in-style wrapper types for the standard library’s collections — currently Vec and VecDeque — built around an explicit Allocator and a Result-first API. Instead of panicking when an allocation fails, every operation that could allocate (push, extend, reserve, resize, with_capacity_in) returns Result<_, TryReserveError>, so allocation failure becomes an ordinary error a caller has to handle rather than an abort.

The crate targets code that genuinely cannot tolerate an unplanned panic from a collection growing under it: embedded and no_std environments, database internals, and other systems software where memory pressure is a real operating condition rather than an edge case. It layers a Claim marker trait (for types that are guaranteed not to panic on clone) and a TryClone trait for fallible cloning on top of the collection types, so higher-level fallible operations compose the same way the standard library’s infallible ones do.

Because it wraps alloc’s existing try_reserve/try_with_capacity_in machinery rather than reimplementing allocation from scratch, the API surface stays close to std::vec::Vec and std::collections::VecDeque, which keeps migration mostly mechanical: swap the import, then work through the compiler errors where a former panic site now needs a ? or explicit match.

What You Get

  • A vec::Vec<T, A> wrapper over alloc::vec::Vec where push, extend, reserve, resize, resize_with, and with_capacity_in all return Result<_, TryReserveError> instead of panicking
  • A vec_deque::VecDeque<T, A> wrapper with the equivalent fallible API surface, built on top of the checked Vec
  • A Claim marker trait identifying types whose Clone implementation is guaranteed not to allocate/panic, used to gate fallible-clone-based methods like extend_from_slice
  • A TryClone trait providing a fallible counterpart to Clone, with a default try_clone_from implementation
  • Full no_std compatibility via a no_std Cargo feature, relying only on alloc and core
  • Deref/DerefMut to [T], Index/IndexMut, Debug, and cross-type PartialEq implementations so the wrapper types behave like slices in most call sites

Common Use Cases

  • Embedded firmware or other no_std targets where an allocation failure must be handled as a recoverable error rather than triggering a panic/abort
  • Database or storage engine internals (the crate originates from QuestDB) that need predictable behavior under memory pressure instead of process-ending panics
  • Long-running services where an unbounded or attacker-influenced allocation size should surface as an error path, not a crash
  • Migrating existing std::vec::Vec-based code toward explicit, checked error handling for every growth operation, using the compiler to find every panic-capable call site

Under The Hood

Architecture The crate is organized around a single wrapper pattern applied twice: vec::Vec<T, A> wraps alloc::vec::Vec<T, A> and reimplements each growth-related method (push, extend, reserve, resize, resize_with, with_capacity_in) as reserve-then-write instead of the standard library’s allocate-or-panic path, using try_reserve under the hood and unsafe pointer writes only after capacity is confirmed. vec_deque::VecDeque<T, A> is built directly on top of the checked Vec rather than reimplementing the same logic against alloc::collections::VecDeque, so the two container types share one source of truth for allocation-fallibility behavior. Two small supporting modules, claim and try_clone, define marker/utility traits (Claim, TryClone) with macro-generated blanket implementations for primitive and standard smart-pointer types, keeping the fallible-clone story orthogonal to the collection implementations themselves. There is no dynamic dispatch or plugin surface — the design is a thin, generic-parameterized shim, so anything that changes the panic-vs-Result contract of the underlying alloc collections would ripple through both wrapper types directly.

Tech Stack The crate has zero external dependencies — its Cargo.toml declares only the package metadata, a no_std feature flag, and a docs.rs rustdoc configuration, relying entirely on alloc and core from the Rust distribution. It requires the nightly toolchain (pinned via rust-toolchain.toml) because it depends on the unstable allocator_api feature (#![feature(allocator_api)]) to be generic over custom allocators. Build/test tooling is the standard Cargo test harness with no additional build system.

Code Quality Testing is extensive relative to the crate’s size: vec.rs and vec_deque.rs together carry roughly 50 #[test] functions, exercising push/reserve/extend/truncate/resize/equality/AsRef/AsMut/try_clone paths. A custom testing module implements a WatermarkAllocator that enforces an exact byte budget and asserts allocation/deallocation balance, letting tests assert precisely when an operation should fail with TryReserveError rather than only checking the happy path. A GitHub Actions workflow (.github/workflows/ci.yml) runs against the pinned nightly toolchain. Error handling is explicit throughout — Result<_, TryReserveError> rather than unwrap/expect in the library code itself — and unsafe blocks are narrowly scoped with SAFETY comments justifying each one.

API Design The core design choice is collapsing the standard library’s split between panicking and try_-prefixed non-panicking APIs (e.g. Vec::with_capacity vs Vec::try_with_capacity_in) into a single, always-fallible surface, so there is exactly one method name to reach for and it always returns Result. This keeps the public API close enough to std::vec::Vec/VecDeque (via Deref<Target = [T]>, Index, symmetric PartialEq) that migrating existing code is largely mechanical, while the Claim/TryClone traits extend the same fallibility guarantee to cloning. The scope is intentionally narrow — only Vec and VecDeque are implemented so far, per the README’s stated ‘per-need basis’ philosophy — which keeps the API surface small and consistent rather than broad.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search