smallbox/
lib.rs

1//! # SmallBox: Space-Efficient Smart Pointers
2//!
3//! [`SmallBox`] is a space-efficient alternative to [`Box`] that stores small values on the stack
4//! and automatically falls back to heap allocation for larger values. This optimization can
5//! significantly reduce memory allocations and improve performance for applications working with
6//! many small objects.
7//!
8//! ## Core Concept
9//!
10//! Traditional [`Box`] always heap-allocates, even for small values. [`SmallBox`] uses a
11//! configurable inline storage space and only allocates on the heap when the value exceeds
12//! this capacity.
13//!
14//! ## Quick Start
15//!
16//! Add SmallBox to your `Cargo.toml`:
17//!
18//! ```toml
19//! [dependencies]
20//! smallbox = "0.8"
21//! ```
22//!
23//! Basic usage:
24//!
25//! ```rust
26//! use smallbox::SmallBox;
27//! use smallbox::space::S4;
28//!
29//! // Small values are stored on the stack
30//! let small: SmallBox<[u32; 2], S4> = SmallBox::new([1, 2]);
31//! assert!(!small.is_heap());
32//!
33//! // Large values automatically use heap allocation
34//! let large: SmallBox<[u32; 32], S4> = SmallBox::new([0; 32]);
35//! assert!(large.is_heap());
36//!
37//! // Use like a regular Box
38//! println!("Values: {:?} and length {}", *small, large.len());
39//! ```
40//!
41//! ## Configuration
42//!
43//! ### Feature Flags
44//!
45//! - **`std`** (enabled by default)
46//!   - Links to the standard library
47//!   - Disable for `#![no_std]` environments: `default-features = false`
48//!
49//! - **`coerce`** (optional, requires nightly)
50//!   - Enables automatic coercion from `SmallBox<T>` to `SmallBox<dyn Trait>`
51//!   - Allows more ergonomic usage with trait objects
52//!
53//! ### No-std Usage
54//!
55//! SmallBox works in `#![no_std]` environments:
56//!
57//! ```toml
58//! [dependencies]
59//! smallbox = { version = "0.8", default-features = false }
60//! ```
61//!
62//! ### Custom Space Types
63//!
64//! Define custom capacities for specific needs:
65//!
66//! ```rust
67//! use smallbox::SmallBox;
68//!
69//! // Custom 128-byte capacity
70//! type MySpace = [u8; 128];
71//! type MySmallBox<T> = SmallBox<T, MySpace>;
72//!
73//! let value: MySmallBox<[u8; 100]> = SmallBox::new([0; 100]);
74//! assert!(!value.is_heap()); // Fits in custom space
75//! ```
76//!
77//! **Important**: Space alignment matters! If the space alignment is smaller than the value's
78//! required alignment, the value will be heap-allocated regardless of size.
79//!
80//! ## Working with Unsized Types
81//!
82//! SmallBox supports unsized types like trait objects and slices through two approaches:
83//!
84//! ### 1. Using the `smallbox!()` Macro (Stable Rust)
85//!
86//! ```rust
87//! #[macro_use]
88//! extern crate smallbox;
89//!
90//! # fn main() {
91//! use std::any::Any;
92//!
93//! use smallbox::SmallBox;
94//! use smallbox::space::S4;
95//!
96//! // Create trait objects
97//! let values: Vec<SmallBox<dyn Any, S4>> = vec![
98//!     smallbox!(42u32),
99//!     smallbox!("hello world"),
100//!     smallbox!(vec![1, 2, 3]),
101//! ];
102//!
103//! // Create slices
104//! let slice: SmallBox<[i32], S4> = smallbox!([1, 2, 3, 4]);
105//! assert_eq!(slice.len(), 4);
106//! # }
107//! ```
108//!
109//! ### 2. Automatic Coercion (Nightly with `coerce` feature)
110//!
111//! ```rust
112//! # #[cfg(feature = "coerce")]
113//! # {
114//! use std::any::Any;
115//!
116//! use smallbox::SmallBox;
117//! use smallbox::space::S4;
118//!
119//! // Automatic coercion to trait objects
120//! let num: SmallBox<dyn Any, S4> = SmallBox::new(42u32);
121//! let text: SmallBox<dyn Any, S4> = SmallBox::new("hello");
122//!
123//! // Automatic coercion to slices
124//! let slice: SmallBox<[i32], S4> = SmallBox::new([1, 2, 3, 4]);
125//! # }
126//! ```
127//!
128//! ## Advanced Usage
129//!
130//! ### Type Downcasting
131//!
132//! ```rust
133//! #[macro_use]
134//! extern crate smallbox;
135//!
136//! # fn main() {
137//! use std::any::Any;
138//!
139//! use smallbox::SmallBox;
140//! use smallbox::space::S2;
141//!
142//! let value: SmallBox<dyn Any, S2> = smallbox!(42u32);
143//!
144//! match value.downcast::<u32>() {
145//!     Ok(num) => println!("Got number: {}", *num),
146//!     Err(original) => println!("Not a u32, got: {:?}", original.type_id()),
147//! }
148//! # }
149//! ```
150//!
151//! ### Interoperability with `Box`
152//!
153//! Convert between [`SmallBox`] and [`Box`] when needed:
154//!
155//! ```rust
156//! use smallbox::SmallBox;
157//! use smallbox::space::S4;
158//!
159//! // Box -> SmallBox (data stays on heap)
160//! let boxed = Box::new([1, 2, 3, 4]);
161//! let small_box: SmallBox<_, S4> = SmallBox::from_box(boxed);
162//! assert!(small_box.is_heap());
163//!
164//! // SmallBox -> Box (data moves to heap if needed)
165//! let back_to_box: Box<[i32; 4]> = SmallBox::into_box(small_box);
166//! ```
167
168#![cfg_attr(feature = "nightly", feature(strict_provenance, set_ptr_value))]
169#![cfg_attr(feature = "coerce", feature(unsize, coerce_unsized))]
170#![cfg_attr(not(feature = "std"), no_std)]
171#![allow(stable_features)]
172#![deny(missing_docs)]
173#![deny(clippy::as_conversions)]
174
175extern crate alloc;
176
177mod smallbox;
178pub mod space;
179mod sptr;
180
181pub use crate::smallbox::SmallBox;