copy_stack_vec/lib.rs
1// This file is part of copy-stack-vec.
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! # `copy-stack-vec`
5//!
6//! A `no_std`, fixed-capacity, stack-based vector type for `Copy` elements,
7//! **with no `unsafe` by default**.
8//!
9//! The core type, [`CopyStackVec<T, N>`], stores `N` elements inline on the stack
10//! and tracks a logical length `len ∈ 0..=N`. It provides
11//! a small, predictable, allocation-free buffer with familiar slice/`Vec`-like
12//! semantics where they make sense.
13//!
14//! ## When to use this crate
15//!
16//! This crate may be useful when:
17//!
18//! - You are in a `no_std` or embedded environment.
19//! - You know capacities at compile time.
20//! - Elements are small and `Copy`.
21//! - You want predictable, allocation-free behavior and can work with a fixed
22//! maximum length.
23//!
24//! It may not be the best fit if:
25//!
26//! - You need very large capacities or large element types.
27//! - You frequently pass vectors by value (moving a `CopyStackVec` copies the
28//! entire `[T; N]` buffer, not just the initialized prefix).
29//! - You don't want to constrain elements to `Copy`.
30//!
31//! See [`CopyStackVec`] for detailed semantics, complexity, and limitations.
32//!
33//! ## Backends and safety
34//!
35//! Two internal backends are selected by the `unsafe-maybe-uninit`
36//! feature flag:
37//!
38//! - **Default backend (safe)**:
39//! - Storage is `[T; N]`.
40//! - The crate is `no_std` and `#![forbid(unsafe_code)]` (outside tests).
41//! - [`Default::default`] / [`CopyStackVec::new`] initialize all `N` elements
42//! with `T::default()`, which is `O(N)` and requires `T: Default`.
43//!
44//! - **`unsafe-maybe-uninit` backend**:
45//! - Storage is `[core::mem::MaybeUninit<T>; N]`.
46//! - A small amount of internal `unsafe` is used to treat only the
47//! `[0..len)` prefix as initialized.
48//! - [`Default::default`] / [`CopyStackVec::new`] avoid constructing `N`
49//! copies of `T` and no longer require `T: Default`. They still conceptually
50//! scale with the capacity `N`, but typically compile down to cheap bulk
51//! initialization of the `MaybeUninit` buffer.
52//!
53//! In both backends, the **public API is fully safe**. The feature only affects
54//! internal representation and trait bounds on some constructors.
55//!
56//! ## Features
57//!
58//! - `serde`
59//! - Enables `Serialize` / `Deserialize` for `CopyStackVec<T, N>`.
60//! - In the safe backend: `T: Deserialize<'de> + Copy + Default`.
61//! - In the `unsafe-maybe-uninit` backend: `T: Deserialize<'de> + Copy`.
62//!
63//! - `unsafe-maybe-uninit`
64//! - Switches the internal storage to `[MaybeUninit<T>; N]`.
65//! - Relaxes some `T: Default` requirements (e.g. `Default` / `try_from_iter`).
66//! - Allows a small amount of internal `unsafe` to avoid touching the
67//! uninitialized tail.
68//!
69//! ## High-level semantics
70//!
71//! - Capacity is fixed at compile time (`CopyStackVec::<T, N>::CAPACITY == N`).
72//! - Length is a logical prefix: only indices `< len` are considered initialized.
73//! - No heap allocations are performed.
74//! - Operations that may exceed capacity come in two flavors:
75//! - **Fallible**: return [`Error::Full`] on overflow and leave the
76//! vector unchanged (e.g. [`CopyStackVec::push`], [`CopyStackVec::extend_from_slice`],
77//! [`CopyStackVec::resize`], [`TryFrom<&[T]>`], [`CopyStackVec::try_from_iter`],
78//! [`CopyStackVec::try_extend_from_iter`], [`CopyStackVec::insert`],
79//! [`CopyStackVec::try_remove`], [`CopyStackVec::try_swap_remove`]).
80//! - **Truncating**: silently ignore extra elements (e.g.
81//! [`CopyStackVec::push_truncated`], [`CopyStackVec::extend_from_slice_truncated`],
82//! [`CopyStackVec::from_slice_truncated`], [`CopyStackVec::from_array_truncated`], [`FromIterator<T>`], and
83//! [`Extend<T>`]).
84//!
85//! ## Range and indexing behavior
86//!
87//! `CopyStackVec` intentionally follows Rust slice and `Vec` semantics for all
88//! **indexing** and **range-based** operations:
89//!
90//! - Indexing (`v[i]`, `v[start..end]`, …) **panics** on out-of-bounds or
91//! inverted ranges, exactly like built-in slices.
92//!
93//! - [`CopyStackVec::drain`](CopyStackVec::drain) behaves like
94//! [`Vec::drain`](alloc::vec::Vec::drain):
95//! - `start > end` or `end > len()` → **panic**
96//! - `start == end` → empty iterator, no change
97//! - valid ranges remove the elements immediately and shift the tail left
98//!
99//! Only **range/index errors** panic.
100//! Capacity-related failures never panic: they return [`Error::Full`] or
101//! silently truncate (depending on the method, see above).
102//!
103//! Collecting into `CopyStackVec<T, N>` (via `FromIterator` / `collect`) takes at most the
104//! first `N` elements from the iterator and stops there, leaving any remaining items
105//! unconsumed.
106//!
107//! ## Example
108//!
109//! ```rust
110//! use copy_stack_vec::CopyStackVec;
111//!
112//! let mut v: CopyStackVec<u8, 4> = CopyStackVec::default();
113//! v.push(1).unwrap();
114//! v.extend_from_slice(&[2, 3]).unwrap();
115//! assert_eq!(v.as_slice(), &[1, 2, 3]);
116//! ```
117//!
118//! See [`CopyStackVec`] for detailed behavior, including indexing semantics,
119//! iterator behavior, and complexity notes.
120
121#![cfg_attr(not(feature = "unsafe-maybe-uninit"), forbid(unsafe_code))]
122#![cfg_attr(not(test), no_std)]
123
124#[cfg(test)]
125extern crate alloc;
126
127// Modules
128mod error;
129mod index;
130mod iter;
131#[cfg(feature = "serde")]
132mod serde;
133mod vec;
134
135// Public exports (crate API surface)
136pub use error::Error;
137pub use iter::IntoIter;
138pub use vec::CopyStackVec;