Skip to main content

multitude/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
5#![cfg_attr(docsrs, feature(doc_cfg))]
6#![allow(
7    clippy::multiple_unsafe_ops_per_block,
8    clippy::allow_attributes,
9    reason = "throughout this crate, related unsafe operations are intentionally grouped under a single safety invariant; `#[allow]` is preferred over `#[expect]` for attributes that expand inside macro bodies (the lint may or may not fire in any given instantiation)"
10)]
11
12//! Fast and flexible arena-based bump allocator.
13//!
14//! `multitude` is an arena-based bump allocator designed to improve the performance of applications that have **phase-oriented logic**, which
15//! is when groups of related allocations live and die together. Service request handling and parsers are two examples of this pattern which usually
16//! benefit from a bump allocator.
17//!
18//! `multitude` works by accumulating large chunks of memory allocated from the system and then carving out smaller pieces of it for application use
19//! using a fast bump allocation strategy, which is considerably faster than allocating from the system. The downside however is that the individual allocations
20//! can't be freed separately. Instead, memory is reclaimed and returned to the system in bulk when the entire arena is dropped.
21//!
22//! # Why Another Bump Allocator?
23//!
24//! The Rust ecosystem has a few bump allocators, the most popular being [`bumpalo`](https://crates.io/crates/bumpalo).
25//! `multitude` uses a different implementation strategy and has a richer API surface making it suitable for more
26//! use cases. The main features that set `multitude` apart are:
27//!
28//! 1. **Flexibility.** Four allocation styles coexist in the same arena: the
29//!    arena-lifetime owning handle [`Alloc<T>`](Alloc) plus three escape-capable
30//!    smart pointers — the atomic [`Arc`], the non-atomic single-thread [`Rc`],
31//!    and the unique-owner [`Box`] — each available for sized `T`, `str`, and
32//!    `[T]`. See the [comparison table](#flexibility) for how they differ.
33//!
34//! 2. **Early Reclamation.** In many situations, `multitude` can reclaim memory from individual chunks as soon as their reference counts drop to zero,
35//!    without waiting for the entire arena to be dropped. This allows for more efficient memory usage in long-running arenas with many short-lived allocations.
36//!
37//! 3. **Smart Pointers Can Outlive the Arena.** Some of the smart pointers produced by `multitude` can keep their owning chunk alive even after the arena itself has been dropped,
38//!    allowing for more flexible memory management and longer-lived data structures.
39//!
40//! 4. **Drop Support.** `multitude` automatically runs `Drop` for allocated values at the appropriate time.
41//!
42//! 5. **Uniformly Thin Smart Pointers.** `multitude`'s escape-capable smart
43//!    pointers — [`Arc<T>`](Arc), [`Rc<T>`](Rc), and [`Box<T>`](Box) — are
44//!    **8 bytes** on 64-bit for *every* `T`, even DSTs like `str` and `[T]`
45//!    (the metadata lives in a chunk prefix). The arena-lifetime
46//!    [`Alloc<T>`](Alloc) handle is a single word for sized `T`; for `str` /
47//!    `[T]` it is a fat reference (pointer + length), which costs nothing extra
48//!    since it never escapes the arena and isn't stored at scale.
49//!
50//! 6. **Efficient Mutable Strings and Vectors.** `multitude` provides [`String`](strings::String), [`Utf16String`](strings::Utf16String) and [`Vec`](vec::Vec) which are growable collections that live in the arena.
51//!
52//! 7. **Dynamically-Sized Types.** `multitude` supports dynamically-sized types (DSTs) like slices and strings, allowing you to allocate and manage them in the
53//!    arena with the same flexibility as sized types. The [`dst-factory`](https://crates.io/crates/dst-factory) crate is a great companion for building DSTs in the arena.
54//!
55//! 8. **`format!`-style Macro.** `multitude` includes a [`format!`](strings::format!)-style macro that allows you to create formatted strings directly in the arena, avoiding intermediate allocations and copies.
56//!
57//! 9. **UTF-16 Support.** With the `utf16` Cargo feature, `multitude` provides a parallel set of arena-resident UTF-16 string types
58//!    (`Arc<Utf16Str>`, `Box<Utf16Str>`, [`Utf16String`](strings::Utf16String)) and a [`format_utf16!`](strings::format_utf16!) macro for FFI / Windows / JS-engine
59//!    interop without per-call transcoding at every boundary.
60//!
61//! 10. **`#![no_std]` Support.** `multitude` can be used in `#![no_std]` environments, making it suitable for embedded systems and other resource-constrained contexts.
62//!
63//! See [`BUMPALO.md`](https://github.com/microsoft/oxidizer/blob/main/crates/multitude/BUMPALO.md)
64//! for a feature-by-feature comparison with [`bumpalo`](https://crates.io/crates/bumpalo).
65//!
66//! # Example
67//!
68//! ```
69//! use multitude::Arena;
70//!
71//! let arena = Arena::new();
72//!
73//! // Cheap atomic reference-counted allocation of any user type.
74//! struct Point { x: f64, y: f64 }
75//! let p = arena.alloc_arc(Point { x: 3.0, y: 4.0 });
76//! let p2 = p.clone();
77//! assert_eq!(p.x, p2.x);
78//!
79//! // Single-pointer immutable strings.
80//! let name = arena.alloc_str_arc("Alice");
81//! assert_eq!(&*name, "Alice");
82//!
83//! // format! macro returning a String.
84//! let greeting = multitude::strings::format!(in &arena, "Hello, {}!", "world");
85//! assert_eq!(&*greeting, "Hello, world!");
86//! ```
87//! # Flexibility
88//!
89//! `multitude` offers four ways to allocate a value and own it over time. All
90//! four can coexist in the same arena, dereference to the value, and run
91//! `T::drop` **eagerly**; they differ in whether the handle can outlive the
92//! arena, whether ownership is unique or shared, and what (if any) per-handle
93//! reference count they pay. Each is available for sized `T`, `str`, and `[T]`
94//! (and, behind the `dst` feature, arbitrary DSTs).
95//!
96//! | | [`Alloc<T>`](Alloc) | [`Box<T>`](Box) | [`Rc<T>`](Rc) | [`Arc<T>`](Arc) |
97//! |---|:---:|:---:|:---:|:---:|
98//! | **Constructor family** | [`alloc`](Arena::alloc) | [`alloc_box`](Arena::alloc_box) | [`alloc_rc`](Arena::alloc_rc) | [`alloc_arc`](Arena::alloc_arc) |
99//! | **Ownership** | unique | unique | shared (`Clone`) | shared (`Clone`) |
100//! | **`&mut T` access** | ✅ | ✅ | ❌ | ❌ |
101//! | **Can outlive the arena** | ❌ | ✅ | ✅ | ✅ |
102//! | **Per-handle reference count** | none | none | non-atomic | atomic |
103//! | **Cross-thread *sharing*** | ❌ | ❌ | ❌ (`!Send`) | ✅ (`T: Send + Sync`) |
104//! | **Width (64-bit)** | 1 word (sized); fat ref for DSTs | 8 bytes | 8 bytes | 8 bytes |
105//!
106//! The cheapest option is [`Alloc<T>`](Alloc): an owning handle whose lifetime
107//! is tied to the arena — a single word for sized `T` (a fat pointer+length
108//! reference for `str` / `[T]`). It pays no reference count and cannot
109//! outlive the arena, but gives mutable access and runs the destructor when it
110//! is dropped — the fastest way to allocate when the lifetime constraint is
111//! tolerable.
112//!
113//! ```
114//! let arena = multitude::Arena::new();
115//! let mut x = arena.alloc(42);
116//! *x += 1;
117//! assert_eq!(*x, 43);
118//!
119//! // Strings and slices too:
120//! let s = arena.alloc_str("hello");
121//! let v = arena.alloc_slice_copy(&[1, 2, 3]);
122//! assert_eq!(&*s, "hello");
123//! assert_eq!(&*v, &[1, 2, 3]);
124//! ```
125//!
126//! For values that must **outlive the arena**, use one of the three smart
127//! pointers. They behave like the like-named `std` types but are uniformly
128//! **8-byte thin pointers** (even for DSTs) addressing storage inside a chunk,
129//! and they keep that chunk alive until the last handle drops.
130//!
131//! [`Arc`] is reference-counted and shareable across threads:
132//!
133//! ```
134//! use multitude::Arc;
135//!
136//! let p: Arc<u32> = {
137//!     let arena = multitude::Arena::new();
138//!     arena.alloc_arc(42)
139//!     // arena dropped here; `p` keeps its chunk alive
140//! };
141//! assert_eq!(*p, 42);
142//!
143//! let arena = multitude::Arena::new();
144//! let shared = arena.alloc_arc(7_u64);
145//! let h = std::thread::spawn(move || *shared);
146//! assert_eq!(7, h.join().unwrap());
147//! ```
148//!
149//! [`Rc`] is the cheaper single-thread sibling of [`Arc`]: its reference count
150//! is non-atomic, so `clone`/`drop` are cheaper and `str` / `[u8]` pack slightly
151//! tighter. Being [`!Send`](Send)/[`!Sync`](Sync), it places **no** `Send`/`Sync`
152//! bound on `T`, so it can share thread-affine values (e.g. `Rc<RefCell<T>>`)
153//! that [`Arc`] cannot.
154//!
155//! ```
156//! use multitude::Rc;
157//!
158//! let arena = multitude::Arena::new();
159//! let a: Rc<u64> = arena.alloc_rc(42);
160//! let b = a.clone();
161//! assert_eq!(*a, *b);
162//! ```
163//!
164//! [`Box`] is a unique owner that provides `&mut T` access, like
165//! [`alloc::boxed::Box`] but backed by the arena:
166//!
167//! ```
168//! let arena = multitude::Arena::new();
169//! let mut v = arena.alloc_box(vec![1, 2, 3]);
170//! v.push(4);
171//! assert_eq!(*v, vec![1, 2, 3, 4]);
172//! drop(v); // The vec drop runs here, freeing its heap buffer.
173//! ```
174//!
175//! Although [`Arena`] itself is `!Sync`, it is [`Send`]: an arena — along with
176//! any in-flight [`Alloc`] handles and smart pointers — can be moved between
177//! threads. For cross-thread *sharing* of an individual value, allocate an
178//! [`Arc`] and `.clone()` it across threads.
179//!
180//! # Collections
181//!
182//! [`Vec`](vec::Vec), [`String`](strings::String), and [`Utf16String`](strings::Utf16String) are growable collections that live in
183//! the arena.
184//!
185//! Additionally, you can use an arena as
186//! the allocator for any type from the [`allocator-api2`](https://crates.io/crates/allocator-api2) ecosystem
187//! (including `hashbrown::HashMap`).
188//!
189//! ```
190//! use multitude::Arena;
191//! use multitude::vec::{CollectIn, Vec};
192//!
193//! let arena = Arena::new();
194//!
195//! let mut v = arena.alloc_vec::<i32>();
196//! for i in 0..5 {
197//!     v.push(i);
198//! }
199//!
200//! // CollectIn trait for iterator collection.
201//! let squares: Vec<i32, _> = (1..=5).map(|i| i * i).collect_in(&arena);
202//! assert_eq!(squares.as_slice(), &[1, 4, 9, 16, 25]);
203//! ```
204//!
205//! ## Freezing
206//!
207//! [`String`](strings::String) and [`Vec`](vec::Vec) are designed as **transient
208//! builders** — mutable, growable handles meant to be used briefly and then frozen.
209//!
210//! Once you're done building, you can **freeze them** into immutable smart pointers:
211//!
212//! - [`String::into_boxed_str`](strings::String::into_boxed_str) →
213//!   [`Box<str>`](crate::Box) (**8 bytes**, thin), or `Box::from(string)`.
214//!   The freeze is **O(n)** — it copies the bytes into a compact allocation
215//!   that can outlive the arena. (Like any [`Box`], it is `Send`/`Sync` only
216//!   when the allocator `A` is.)
217//! - [`Vec::into_boxed_slice`](vec::Vec::into_boxed_slice) →
218//!   [`Box<[T]>`](crate::Box) (**8 bytes**, thin), or `Box::from(vec)`.
219//!   The freeze is **O(n)** — it moves the elements into a fresh compact
220//!   allocation that can outlive the arena. (Like any [`Box`], it is
221//!   `Send`/`Sync` only when `T` and the allocator `A` are.)
222//! - `Arc::from(vec)` / `Arc::from(string)` → [`Arc<[T]>`](crate::Arc) /
223//!   [`Arc<str>`](crate::Arc), the shared, reference-counted freeze
224//!   (mirroring `std`'s `From<Vec<T>> for Arc<[T]>`).
225//! - [`Vec::leak`](vec::Vec::leak) → `&mut [T]` (or `&*v.leak()` for `&[T]`)
226//!   borrowed for the arena's lifetime. For `T: !Drop`, this freeze is
227//!   **O(1) and allocation-free** — the existing buffer is reinterpreted in
228//!   place. Unlike the `Box`/`Arc` freezes, the slice does not outlive the arena.
229//!
230//! The `Vec` freeze also reclaims any unused capacity left in the
231//! buffer when the conditions allow it, so those bytes become available
232//! for the next allocation.
233//!
234//! ```
235//! use multitude::{Arena, Box};
236//!
237//! let arena = Arena::new();
238//!
239//! // Build phase: 32-byte builder, alive briefly.
240//! let mut builder = arena.alloc_string();
241//! builder.push_str("hello, ");
242//! builder.push_str("world");
243//!
244//! // Freeze for storage: 8-byte single-pointer smart pointer. O(n) — copies the bytes.
245//! let stored: Box<str> = builder.into_boxed_str();
246//! assert_eq!(&*stored, "hello, world");
247//! ```
248//!
249//! Use this pattern whenever you'd be storing many strings or slices
250//! long-term — the per-pointer savings (8 bytes for both strings and
251//! slices) add up quickly across millions of items.
252//!
253//! ## Maps and Sets
254//!
255//! With the `hashbrown` Cargo feature, [`Arena`] can directly back
256//! [`hashbrown`](https://crates.io/crates/hashbrown) collections via
257//! [`Arena::alloc_hash_map`], [`Arena::alloc_hash_map_with_capacity`],
258//! [`Arena::alloc_set`], and [`Arena::alloc_set_with_capacity`]. The returned
259//! `HashMap` / `HashSet` store their entries in arena chunks.
260//!
261//! ```
262//! # #[cfg(feature = "hashbrown")] {
263//! use multitude::Arena;
264//!
265//! let arena = Arena::new();
266//!
267//! let mut map = arena.alloc_hash_map::<u32, &str>();
268//! map.insert(1, "one");
269//! assert_eq!(map.get(&1), Some(&"one"));
270//!
271//! let mut set = arena.alloc_set::<u32>();
272//! set.insert(7);
273//! assert!(set.contains(&7));
274//! # }
275//! ```
276//!
277//! # Strings
278//!
279//! `multitude` provides a family of arena-resident string types in the
280//! [`strings`] module. The model is the same one used for arbitrary
281//! values elsewhere in the crate — bump-allocation backed by a per-chunk
282//! refcount — but specialized for UTF-8 / UTF-16 text and a compact
283//! single-pointer representation.
284//!
285//! There are two roles a string type can play:
286//!
287//! 1. **Smart pointers (immutable / owned).** Compact handles to string
288//!    data already stored in the arena. They use a single-pointer (8
289//!    bytes on 64-bit) layout — half the size of `&str`. They differ in
290//!    how sharing and mutability work:
291//!
292//!    | UTF-8 | UTF-16 | Sharing | Mutable | Notes |
293//!    |---|---|---|---|---|
294//!    | [`Arc<str>`](crate::Arc) | `Arc<Utf16Str>` | atomic refcount; `Clone`, `Send + Sync` | no | cross-thread sharing |
295//!    | [`Box<str>`](crate::Box) | `Box<Utf16Str>` | unique owner; `Send + Sync` (not `Clone`) | yes | drops eagerly |
296//!
297//!    Like the other arena smart pointers, they keep their owning chunk
298//!    alive via a refcount, so they can outlive the [`Arena`] they came
299//!    from.
300//!
301//! 2. **Builders (mutable, growable).** [`String`](strings::String) and
302//!    [`Utf16String`](strings::Utf16String) are transient growable
303//!    buffers — small structs (32 bytes) carrying a data pointer +
304//!    length + capacity + arena reference. You build them up with
305//!    `push_str` / `push` / [`format!`](strings::format!) /
306//!    [`format_utf16!`](strings::format_utf16!), then **freeze** them
307//!    into one of the smart pointers above:
308//!
309//!    | Builder | Freeze method | Result |
310//!    |---|---|---|
311//!    | [`String`](strings::String) | [`into_boxed_str`](strings::String::into_boxed_str) | [`Box<str>`](crate::Box) |
312//!    | [`Utf16String`](strings::Utf16String) | [`into_boxed_utf16_str`](strings::Utf16String::into_boxed_utf16_str) | `Box<Utf16Str>` |
313//!
314//!    The UTF-16 freeze reuses the buffer in place (O(1)) and reclaims any
315//!    unused capacity when it can. The UTF-8 freeze copies the bytes (O(n))
316//!    into a compact allocation, so [`Box<str>`](crate::Box) stays a single,
317//!    `Send`-safe pointer.
318//!
319//! UTF-16 support requires the `utf16` Cargo feature. Strict (validated)
320//! UTF-16 only — lone surrogates are rejected. The UTF-16 types
321//! interoperate with `widestring::Utf16Str` / `widestring::Utf16String`
322//! for I/O and FFI bridging. UTF-16 length and capacity are counted in
323//! `u16` elements (matching `widestring::Utf16Str::len()`).
324//!
325//! ## Example: UTF-8
326//!
327//! ```
328//! use multitude::Arena;
329//! use multitude::Box;
330//!
331//! let arena = Arena::new();
332//!
333//! // Single-pointer immutable strings.
334//! let s = arena.alloc_str_arc("hello, world");
335//! assert_eq!(&*s, "hello, world");
336//!
337//! // Build incrementally and freeze:
338//! let mut b = arena.alloc_string();
339//! b.push_str("abc");
340//! b.push_str("123");
341//! let frozen: Box<str> = b.into_boxed_str();
342//! assert_eq!(&*frozen, "abc123");
343//!
344//! // format!-style:
345//! let name = "Alice";
346//! let greeting = multitude::strings::format!(in &arena, "Hello, {name}!");
347//! assert_eq!(&*greeting, "Hello, Alice!");
348//! ```
349//!
350//! ## Example: UTF-16
351//!
352//! ```
353//! # #[cfg(feature = "utf16")] {
354//! use multitude::Arena;
355//! use widestring::utf16str;
356//!
357//! let arena = Arena::new();
358//!
359//! // From a validated &Utf16Str literal:
360//! let s = arena.alloc_utf16_str_arc(utf16str!("hello, world"));
361//! assert_eq!(&*s, utf16str!("hello, world"));
362//!
363//! // Or transcode from a &str:
364//! let s2 = arena.alloc_utf16_str_arc_from_str("hello");
365//! assert_eq!(&*s2, utf16str!("hello"));
366//!
367//! // Build incrementally and freeze:
368//! let mut b = arena.alloc_utf16_string();
369//! b.push_str(utf16str!("abc"));
370//! b.push_from_str("123");
371//! let frozen = b.into_boxed_utf16_str();
372//! assert_eq!(&*frozen, utf16str!("abc123"));
373//!
374//! // format!-style:
375//! let name = "Alice";
376//! let greeting = multitude::strings::format_utf16!(in &arena, "Hello, {name}!");
377//! assert_eq!(greeting.as_utf16_str(), utf16str!("Hello, Alice!"));
378//! # }
379//! ```
380//!
381//! # Building DSTs
382//!
383//! With the `dst` Cargo feature enabled, [`Arena`] exposes
384//! [`Arena::alloc_dst_arc`] and
385//! [`Arena::alloc_dst_box`] (and their `try_*` siblings) for
386//! constructing values whose layout is only known at runtime (custom
387//! DSTs, fat pointers, trait objects).
388//!
389//! Each of these takes a [`Layout`](core::alloc::Layout), a
390//! pointer-metadata value (e.g. a slice length, a `DynMetadata`), and
391//! a closure that initializes the buffer through a typed fat pointer.
392//! For most users, the [`dst-factory`](https://crates.io/crates/dst-factory) companion crate is the
393//! recommended high-level driver; the low-level interface looks like:
394//!
395//! ```
396//! # #[cfg(feature = "dst")] {
397//! use core::alloc::Layout;
398//!
399//! use multitude::Arena;
400//!
401//! let arena = Arena::new();
402//!
403//! // Allocate a 5-byte slice in the arena as a `Box<[u8]>`.
404//! let layout = Layout::array::<u8>(5).unwrap();
405//! let b: multitude::Box<[u8]> = unsafe {
406//!     arena.alloc_dst_box::<[u8]>(layout, 5, |fat: *mut [u8]| {
407//!         let p = fat.cast::<u8>();
408//!         for i in 0..5 {
409//!             p.add(i).write(i as u8);
410//!         }
411//!     })
412//! };
413//! assert_eq!(&*b, &[0, 1, 2, 3, 4]);
414//! # }
415//! ```
416//!
417//! The same feature also enables eight `Arena::alloc_slice_*_box`
418//! methods that produce `Box<[T]>` directly (mirroring the
419//! existing `_arc` slice methods).
420//!
421//! # Crate Features
422//!
423//! | Feature | Description |
424//! |---------|-------------|
425//! | `std` *(default)* | Enables [`std::io::Write`] on [`Vec<u8>`](vec::Vec) for use with `write!`, `std::io::copy`, `serde_json::to_writer`, and similar. Disable for `#![no_std]` environments (the crate still requires `alloc`). |
426//! | `stats` | Enables runtime instrumentation counters returned by `Arena::stats`. Disable for the tightest allocation throughput when you don't need observability. |
427//! | `serde` | Adds `Serialize` impls for [`Arc<str>`](Arc), [`Box<str>`](Box), [`String`](strings::String), and [`Vec`](vec::Vec). With `serde + utf16`, also adds impls for the UTF-16 types (transcoded to UTF-8 on the wire). |
428//! | `dst` | Enables the `dst` module for constructing true dynamically-sized types and trait objects in the arena via [`Arena::alloc_dst_arc`] / [`Arena::alloc_dst_box`], plus eight `Arena::alloc_slice_*_box` methods. |
429//! | `utf16` | Adds a parallel UTF-16 string surface (`Arc<Utf16Str>`, `Box<Utf16Str>`, [`Utf16String`](strings::Utf16String), and [`format_utf16!`](strings::format_utf16!)) backed by the [`widestring`](https://crates.io/crates/widestring) crate. Lengths are counted in `u16` elements. |
430//! | `zerocopy` | Provides [`ZerocopyView`](zerocopy::ZerocopyView) for safe zero-initialized allocation of types implementing [`zerocopy::FromZeros`](::zerocopy::FromZeros). Access via [`Arena::zerocopy()`]. |
431//! | `bytemuck` | Provides [`BytemuckView`](bytemuck::BytemuckView) for safe zero-initialized allocation of types implementing [`bytemuck::Zeroable`](::bytemuck::Zeroable). Access via [`Arena::bytemuck()`]. |
432//! | `bytes` | Adds [`From`] conversions from [`Arc<[u8]>`](Arc) and [`Arc<str>`](Arc) into [`bytes::Bytes`](::bytes::Bytes), enabling zero-copy integration with the Tokio / Hyper async ecosystem. |
433//! | `bytesbuf` | Implements [`bytesbuf::mem::Memory`](::bytesbuf::mem::Memory) directly on [`Arena`], so that [`BytesBuf`](::bytesbuf::BytesBuf) buffers can be backed by arena chunks. Implies `std`. |
434//! | `hashbrown` | Lets [`Arena`] back [`hashbrown`](https://crates.io/crates/hashbrown) collections via [`Arena::alloc_hash_map`], [`Arena::alloc_hash_map_with_capacity`], [`Arena::alloc_set`], and [`Arena::alloc_set_with_capacity`]. (`&Arena` always implements the `allocator-api2` 0.2 `Allocator` trait so it can back `hashbrown` directly; this feature adds the convenience constructors.) |
435
436#![no_std]
437#![doc(html_logo_url = "https://media.githubusercontent.com/media/microsoft/oxidizer/refs/heads/main/crates/multitude/logo.png")]
438#![doc(html_favicon_url = "https://media.githubusercontent.com/media/microsoft/oxidizer/refs/heads/main/crates/multitude/favicon.ico")]
439
440extern crate alloc;
441#[cfg(any(feature = "std", test))]
442extern crate std;
443
444mod alloc_handle;
445mod allocator_impl;
446mod arc;
447mod arena;
448mod arena_builder;
449#[cfg(feature = "stats")]
450mod arena_stats;
451mod r#box;
452#[cfg(feature = "dst")]
453#[cfg_attr(docsrs, doc(cfg(feature = "dst")))]
454pub mod dst;
455mod from_in;
456mod internal;
457mod rc;
458pub mod strings;
459mod thin_smart_ptr_common;
460pub mod vec;
461
462#[cfg(test)]
463mod tests_support;
464
465// Ecosystem integration modules. Visibility differs by what the
466// integration exposes:
467//   - `bytemuck` / `zerocopy` are `pub` because they introduce types
468//     (`BytemuckView` / `ZerocopyView`) that users need to name in
469//     their own code.
470//   - `bytes` / `bytesbuf` are private because they only add `From`
471//     impls / inherent methods on existing types; nothing in them
472//     needs to be path-addressable from outside.
473#[cfg(feature = "bytemuck")]
474#[cfg_attr(docsrs, doc(cfg(feature = "bytemuck")))]
475pub mod bytemuck;
476#[cfg(feature = "bytes")]
477#[cfg_attr(docsrs, doc(cfg(feature = "bytes")))]
478mod bytes;
479#[cfg(feature = "bytesbuf")]
480#[cfg_attr(docsrs, doc(cfg(feature = "bytesbuf")))]
481mod bytesbuf;
482#[cfg(feature = "zerocopy")]
483#[cfg_attr(docsrs, doc(cfg(feature = "zerocopy")))]
484pub mod zerocopy;
485
486pub use self::alloc_handle::Alloc;
487pub use self::arc::Arc;
488pub use self::arena::Arena;
489pub use self::arena_builder::ArenaBuilder;
490#[cfg(feature = "stats")]
491#[cfg_attr(docsrs, doc(cfg(feature = "stats")))]
492pub use self::arena_stats::ArenaStats;
493pub use self::r#box::Box;
494pub use self::from_in::{FromIn, IntoIn};
495pub use self::rc::Rc;