redoubt_alloc/
lib.rs

1// Copyright (c) 2025-2026 Federico Hoerth <memparanoid@gmail.com>
2// SPDX-License-Identifier: GPL-3.0-only
3// See LICENSE in the repository root for full license text.
4
5//! Secure allocation containers with automatic zeroization.
6//!
7//! This crate provides four main types:
8//!
9//! - [`AllockedVec`]: Capacity-locked Vec with fallible operations
10//! - [`RedoubtArray`]: Fixed-size array with automatic zeroization
11//! - [`RedoubtVec`]: Auto-growing Vec with safe reallocation (2x growth)
12//! - [`RedoubtString`]: Auto-growing String with safe reallocation (2x growth)
13//!
14//! # Core Guarantees
15//!
16//! - **Controlled capacity**: Once sealed with `reserve_exact()`, that method cannot be called
17//!   again. To change capacity, use `realloc_with_capacity()` which safely zeroizes the old
18//!   allocation before creating a new one.
19//! - **Automatic zeroization**: All data is zeroized on drop via `#[fast_zeroize(drop)]`
20//! - **Fallible operations**: `push()` and `reserve_exact()` fail instead of reallocating,
21//!   preventing unintended copies of data
22//!
23//! # Example: Basic Usage
24//!
25//! ```rust
26//! use redoubt_alloc::{AllockedVec, AllockedVecError};
27//!
28//! fn example() -> Result<(), AllockedVecError> {
29//!     let mut vec = AllockedVec::<u8>::new();
30//!     vec.reserve_exact(10)?;
31//!
32//!     // Now sealed - cannot reserve again
33//!     assert!(vec.reserve_exact(20).is_err());
34//!
35//!     // Push works while capacity allows
36//!     for i in 0u8..10 {
37//!         vec.push(i)?;
38//!     }
39//!
40//!     // Exceeding capacity fails
41//!     assert!(vec.push(42).is_err());
42//!     Ok(())
43//! }
44//! # example().unwrap();
45//! ```
46//!
47//! # Example: Controlled Reallocation
48//!
49//! ```rust
50//! use redoubt_alloc::{AllockedVec, AllockedVecError};
51//!
52//! fn example() -> Result<(), AllockedVecError> {
53//!     let mut vec = AllockedVec::<u8>::with_capacity(5);
54//!     vec.push(1)?;
55//!     vec.push(2)?;
56//!
57//!     // Change capacity with realloc_with_capacity()
58//!     // This zeroizes the old allocation before creating the new one
59//!     vec.realloc_with_capacity(10);
60//!
61//!     for i in 3u8..=10 {
62//!         vec.push(i)?;
63//!     }
64//!
65//!     assert_eq!(vec.len(), 10);
66//!     assert_eq!(vec.capacity(), 10);
67//!     Ok(())
68//! }
69//! # example().unwrap();
70//! ```
71//!
72//! # Test Utilities
73//!
74//! Enable the `test-utils` feature to inject failures for testing error handling paths:
75//!
76//! ```toml
77//! [dev-dependencies]
78//! redoubt-alloc = { version = "*", features = ["test-utils"] }
79//! ```
80//!
81//! Then use [`AllockedVecBehaviour`] to test error scenarios:
82//!
83//! ```rust
84//! // test-utils feature required in dev-dependencies
85//! #[cfg(test)]
86//! mod tests {
87//!     use redoubt_alloc::{AllockedVec, AllockedVecBehaviour};
88//!
89//!     #[test]
90//!     fn test_handles_push_failure() {
91//!         let mut vec = AllockedVec::with_capacity(10);
92//!         vec.change_behaviour(AllockedVecBehaviour::FailAtPush);
93//!
94//!         // Test that your code handles the error correctly
95//!         assert!(vec.push(1u8).is_err());
96//!     }
97//! }
98//! ```
99//!
100//! ## License
101//!
102//! GPL-3.0-only
103
104#![cfg_attr(not(test), no_std)]
105#![warn(missing_docs)]
106#![warn(unsafe_op_in_unsafe_fn)]
107
108extern crate alloc;
109
110mod allocked_vec;
111mod error;
112mod redoubt_array;
113mod redoubt_option;
114mod redoubt_string;
115mod redoubt_vec;
116
117#[cfg(test)]
118mod tests;
119
120pub use allocked_vec::AllockedVec;
121pub use error::{AllockedVecError, RedoubtOptionError};
122pub use redoubt_array::RedoubtArray;
123pub use redoubt_option::RedoubtOption;
124pub use redoubt_string::RedoubtString;
125pub use redoubt_vec::RedoubtVec;
126
127#[cfg(any(test, feature = "test-utils"))]
128pub use allocked_vec::AllockedVecBehaviour;