arena_alligator/lib.rs
1#![warn(missing_docs)]
2#![warn(unsafe_op_in_unsafe_fn)]
3
4//! Arena allocator for building [`bytes::Bytes`] without copying the final
5//! payload.
6//!
7//! Write into a [`Buffer`], call [`freeze()`](Buffer::freeze), and get back
8//! `Bytes` backed by arena memory. The slot or block returns to the arena
9//! when the last `Bytes` reference drops.
10//!
11//! # Arena selection
12//!
13//! [`FixedArena`] is the recommended high-throughput path when one slot size
14//! covers the workload. Fixed uses uniform slots and a bitmap claim path.
15//!
16//! [`BuddyArena`] covers variable-size allocation from one shared region.
17//! Requests are rounded up to powers of two, larger blocks split on demand,
18//! and neighbors coalesce on release.
19//!
20//! Both produce the same [`Buffer`] type with identical write and freeze
21//! semantics.
22//!
23//! # Quick start
24//!
25//! ```
26//! use std::num::NonZeroUsize;
27//! use arena_alligator::FixedArena;
28//! use bytes::BufMut;
29//!
30//! let arena = FixedArena::with_slot_capacity(
31//! NonZeroUsize::new(1024).unwrap(),
32//! NonZeroUsize::new(4096).unwrap(),
33//! )
34//! .build()
35//! .unwrap();
36//!
37//! let mut buf = arena.allocate().unwrap();
38//! buf.put_slice(b"hello");
39//! let bytes = buf.freeze();
40//! assert_eq!(&bytes[..], b"hello");
41//! ```
42//!
43//! # Auto-spill
44//!
45//! [`.auto_spill()`](FixedArenaBuilder::auto_spill) changes overflow writes
46//! from panic-on-capacity to heap spill. The arena allocation is released as
47//! soon as the spill happens.
48//!
49//! # Initialization policy
50//!
51//! The default policy is [`InitPolicy::Uninit`], which matches Rust's common
52//! writable-uninitialized-memory model: newly allocated capacity is not
53//! zero-filled, and only the bytes written become visible in the
54//! frozen [`Bytes`](bytes::Bytes).
55//!
56//! [`InitPolicy::Zero`] clears reused arena memory before it is handed back to
57//! a writer. That adds work on every allocation in exchange for a stronger
58//! zero-on-allocate guarantee.
59//!
60//! # Frozen slice retention
61//!
62//! Freezing a buffer transfers ownership of the arena slot (or buddy block)
63//! to the returned `Bytes`. Cloning or slicing that `Bytes` shares the
64//! reference, so the arena memory stays pinned until every clone and slice is
65//! dropped.
66//!
67//! [`BytesExt::into_owned()`] copies frozen bytes into fresh owned mutable
68//! storage.
69//!
70//! # Async allocation
71//!
72//! With the `async-alloc` feature, [`AsyncFixedArena`] and [`AsyncBuddyArena`]
73//! provide `allocate_async()` which waits until capacity is available.
74
75mod allocation;
76mod arena;
77mod bitmap;
78mod buddy;
79mod buffer;
80mod error;
81mod ext;
82mod geometry;
83mod handle;
84mod metrics;
85mod sync;
86
87#[cfg(feature = "async-alloc")]
88mod async_alloc;
89
90pub use arena::{FixedArena, FixedArenaBuilder, InitPolicy, PageSize, Unfaulted};
91pub use buddy::{BuddyArena, BuddyArenaBuilder};
92pub use buffer::Buffer;
93pub use error::{AllocError, BufferFullError, BuildError};
94pub use ext::BytesExt;
95pub use geometry::BuddyGeometry;
96pub use metrics::{BuddyArenaMetrics, FixedArenaMetrics};
97
98#[cfg(feature = "async-alloc")]
99pub use async_alloc::{
100 AsyncBuddyArena, AsyncFixedArena, BuddyWaiter, NotifyWaiters, WaitRegistration, Waiter,
101};