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 168 169 170 171 172 173 174 175 176 177 178 179 180
//! This crate aims to give people better control of how they allocate memory, //! by providing a customizable way to allocate blocks of memory, that optionally //! contains metadata about the block itself. This makes it much easier to implement //! Dynamically-Sized Types (DSTs), and also reduces the number of pointer //! indirections necessary to share data between threads. //! //! It has two main features that provide the foundation for the rest: //! //! - **Storing data next to an array:** From the //! [Rust documentation on exotically sized types](https://doc.rust-lang.org/nomicon/exotic-sizes.html), //! at the end of the section on dynamically-sized types: //! //! > Currently the only properly supported way to create a custom DST is by //! > making your type generic and performing an unsizing coercion //! > ... //! > (Yes, custom DSTs are a largely half-baked feature for now.) //! //! This crate aims to provide *some* of that functionality; the code that //! the docs give is the following: //! //! ```rust //! struct MySuperSliceable<T: ?Sized> { //! info: u32, //! data: T //! } //! //! fn main() { //! let sized: MySuperSliceable<[u8; 8]> = MySuperSliceable { //! info: 17, //! data: [0; 8], //! }; //! //! let dynamic: &MySuperSliceable<[u8]> = &sized; //! //! // prints: "17 [0, 0, 0, 0, 0, 0, 0, 0]" //! println!("{} {:?}", dynamic.info, &dynamic.data); //! } //! ``` //! //! using this crate, the `MySuperSliceable<[u8]>` type would be //! implemented like this: //! //! ```rust //! use heaparray::*; //! //! fn main() { //! let dynamic = HeapArray::<u8,u32>::with_label(17, 8, |_,_| 0); //! println!("{:?}", dynamic); //! } //! ``` //! //! - **Thin pointer arrays:** in Rust, unsized structs are referenced with //! pointers that are stored with an associated length. //! This behavior isn't always desired, so this crate provides //! both thin and fat pointer-referenced arrays, where the length is stored //! with the data instead of with the pointer in the thin pointer variant. //! //! ## Features //! - Arrays are allocated on the heap, with optional extra space allocated for metadata //! - Support for 1-word and 2-word pointers //! - Atomically reference-counted memory blocks of arbitrary size without using a `Vec`; //! this means you can access reference-counted memory with only a single pointer //! indirection. //! - Swap owned objects in and out with `array.insert()` //! - Arbitrarily sized objects using label and an array of bytes (`u8`) //! //! ## Examples //! Creating an array: //! //! ```rust //! use heaparray::*; //! let len = 10; //! let array = HeapArray::new(len, |idx| idx + 3); //! assert!(array[1] == 4); //! ``` //! //! Indexing works as you would expect: //! //! ```rust //! use heaparray::*; //! let mut array = HeapArray::new(10, |_| 0); //! array[3] = 2; //! assert!(array[3] == 2); //! ``` //! //! You can take ownership of objects back from the container: //! //! ```rust //! # use heaparray::*; //! let mut array = HeapArray::new(10, |_| Vec::<u8>::new()); //! let replacement_object = Vec::new(); //! let owned_object = array.insert(0, replacement_object); //! ``` //! //! but you need to give the array a replacement object to fill its slot with. //! //! Additionally, you can customize what information should be stored alongside //! the elements in the array using the `HeapArray::with_label` function: //! //! ```rust //! # use heaparray::*; //! struct MyLabel { //! pub even: usize, //! pub odd: usize, //! } //! //! let mut array = HeapArray::with_label( //! MyLabel { even: 0, odd: 0 }, //! 100, //! |label, index| { //! if index % 2 == 0 { //! label.even += 1; //! index //! } else { //! label.odd += 1; //! index //! } //! }); //! ``` //! ## Use of `unsafe` Keyword //! This library relies heavily on the use of the `unsafe` keyword to do both //! reference counting and atomic operations; there are 40 instances total, //! not including tests. //! //! ## Customizability //! All of the implementation details of this crate are public and documented; //! if you'd like to implement your own version of the tools available through //! this crate, note that you don't need to reinvent the wheel; many of the types in //! this crate are generic over certain traits, so you might not need to do that much. extern crate containers_rs as containers; pub mod alloc_utils; mod api; pub mod base; pub mod mem_block; pub mod naive_rc; mod traits; mod prelude { pub(crate) use super::mem_block::*; #[cfg(test)] pub(crate) use super::test_utils::*; pub use super::traits::*; pub use containers::{Container, CopyMap}; pub(crate) use core::fmt; pub(crate) use core::mem; pub(crate) use core::mem::ManuallyDrop; pub(crate) use core::ops::{Index, IndexMut}; pub(crate) use core::ptr; } pub use api::*; #[cfg(all(test, not(bench)))] extern crate interloc; #[cfg(all(test, not(bench)))] use interloc::*; #[cfg(all(test, not(bench)))] use tests::monitor::*; #[cfg(all(test, not(bench)))] use std::alloc::System; #[cfg(all(test, not(bench)))] static TEST_MONITOR: TestMonitor = TestMonitor::new(); #[cfg(all(test, not(bench)))] #[global_allocator] static GLOBAL: InterAlloc<System, TestMonitor> = InterAlloc { inner: System, monitor: &TEST_MONITOR, }; #[cfg(test)] mod test_utils; #[cfg(test)] mod tests;