1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
//! Arena allocator for building [`bytes::Bytes`] without copying the final
//! payload.
//!
//! Write into a [`Buffer`], call [`freeze()`](Buffer::freeze), and get back
//! `Bytes` backed by arena memory. The slot or block returns to the arena
//! when the last `Bytes` reference drops.
//!
//! # Arena selection
//!
//! [`FixedArena`] is the recommended high-throughput path when one slot size
//! covers the workload. Fixed uses uniform slots and a bitmap claim path.
//!
//! [`BuddyArena`] covers variable-size allocation from one shared region.
//! Requests are rounded up to powers of two, larger blocks split on demand,
//! and neighbors coalesce on release.
//!
//! Both produce the same [`Buffer`] type with identical write and freeze
//! semantics.
//!
//! # Quick start
//!
//! ```
//! use core::num::NonZeroUsize;
//! use arena_alligator::FixedArena;
//! use bytes::BufMut;
//!
//! let arena = FixedArena::with_slot_capacity(
//! NonZeroUsize::new(1024).unwrap(),
//! NonZeroUsize::new(4096).unwrap(),
//! )
//! .build()
//! .unwrap();
//!
//! let mut buf = arena.allocate().unwrap();
//! buf.put_slice(b"hello");
//! let bytes = buf.freeze();
//! assert_eq!(&bytes[..], b"hello");
//! ```
//!
//! # Auto-spill
//!
//! [`.auto_spill()`](FixedArenaBuilder::auto_spill) changes overflow writes
//! from panic-on-capacity to heap spill. The arena allocation is released as
//! soon as the spill happens.
//!
//! # Initialization policy
//!
//! The default policy is [`InitPolicy::Uninit`], which matches Rust's common
//! writable-uninitialized-memory model: newly allocated capacity is not
//! zero-filled, and only the bytes written become visible in the
//! frozen [`Bytes`](bytes::Bytes).
//!
//! [`InitPolicy::Zero`] zeroes memory on return to the arena and on first
//! allocation. Returned slots and blocks are scrubbed before being marked
//! free, preventing data leaks between callers. First allocations (cold
//! memory, never returned) are zeroed on the alloc path. Memory that has
//! been through a return-scrub cycle is no longer cold and the alloc-path
//! zero is skipped. All zeroing uses the [`zeroize`] crate
//! (compiler-guaranteed not elided).
//!
//! # Frozen slice retention
//!
//! Freezing a buffer transfers ownership of the arena slot (or buddy block)
//! to the returned `Bytes`. Cloning or slicing that `Bytes` shares the
//! reference, so the arena memory stays pinned until every clone and slice is
//! dropped.
//!
//! [`BytesExt::into_owned()`] copies frozen bytes into fresh owned mutable
//! storage.
//!
//! # Preallocated memory handoff
//!
//! [`FixedArena::from_raw()`] and [`BuddyArena::from_raw()`] let callers hand
//! pre-existing memory to the arena. This is for mmap'd regions, shared
//! memory, static buffers, and similar cases where the backing storage is
//! provisioned elsewhere.
//!
//! For `&'static mut` buffers, prefer the safe
//! [`FixedArena::from_static()`] and [`BuddyArena::from_static()`]
//! wrappers. Use `from_raw()` for pointer/length regions and custom
//! deallocation strategies.
//!
//! These constructors are `unsafe` because the arena cannot validate pointer
//! provenance, exclusivity, or deallocation correctness. On the safe side of
//! the boundary, the resulting arenas use the same allocation, freeze, and
//! retention rules as the ordinary builder paths.
//!
//! Use [`NoDealloc`] when the caller retains responsibility for freeing the
//! backing region. Use [`HeapDealloc`] when the region came from
//! [`alloc::alloc::alloc`].
//!
//! # Async allocation
//!
//! With the `async-alloc` feature, [`AsyncFixedArena`] and [`AsyncBuddyArena`]
//! provide `allocate_async()`, which parks until capacity is available. The
//! buddy variant returns a `Result` and fails fast with
//! [`AllocError::RequestTooLarge`] for a request larger than the arena could
//! ever satisfy, rather than parking forever.
//!
//! # `no_std`
//!
//! This crate is `#![no_std]` by default and depends only on `alloc` and
//! `core`. It works on targets with a global allocator and pointer-width
//! atomics, including embedded systems.
//!
//! ## Feature flags
//!
//! | Feature | Default | What it enables |
//! | ------- | ------- | --------------- |
//! | `std` | yes | Standard-library integrations and dependency features; required by `async-alloc` |
//! | `libc` | yes | Page size detection via `sysconf` on Unix |
//! | `async-alloc` | no | [`AsyncFixedArena`] / [`AsyncBuddyArena`] via tokio (implies `std`) |
//! | `hazmat-raw-access` | no | Raw pointer access to arena memory |
//!
//! For `no_std` usage, disable default features:
//!
//! ```toml
//! [dependencies]
//! arena-alligator = { version = "0.6", default-features = false }
//! ```
extern crate alloc;
extern crate std;
pub use ;
pub use ;
pub use ;
pub use Buffer;
pub use ;
pub use ;
pub use HazmatRaw;
pub use BytesExt;
pub use BuddyGeometry;
pub use ;
pub use ;
pub use ;