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
181
182
183
184
185
//! # HeapArray
//! This crate aims to give people better control of how they want to allocate memory,
//! by providing a customizable way to allocate blocks of memory, that optionally contains
//! metadata about the block itself.
//!
//! It provides 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:
//!
//! > (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);
//!
//! print!("{} [", dynamic.get_label());
//! for i in 0..(dynamic.len()-1) {
//! print!("{:?},", dynamic[i]);
//! }
//! println!("{:?}]", dynamic[dynamic.len()-1]);
//! }
//! ```
//!
//! Note that a `Debug` implementation will be available soon, and make
//! the above code much prettier.
//!
//! - **Thin pointer arrays:** in Rust, unsized structs are referenced with
//! pointers that are stored with an associated length; these are called fat
//! pointers. 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
//! - 1-word and 2-word references to arrays
//! - Atomically reference-counted memory blocks of arbitrary size without using a `Vec`
//! - Swap owned objects in and out with `array.insert()`
//! - Arbitrarily sized objects using label and an array of bytes (`u8`)
//! - Atomic pointer comparison for the `heaparray::ArcArray` type.
//!
//! ## 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 14 instances total,
//! not including tests.
//!
//! ## Future Plans
//! Iteration, allocator customization, constant-sized array of arbitrary size,
//! i.e. `CArray`, with sizes managed by the type system (waiting on const
//! generics for this one). See `TODO.md` in the repository for a full
//! list of planned features.
// TODO uncomment this when the alloc crate hits stable
// extern crate alloc;
extern crate containers_rs as containers;
pub use *;
extern crate interloc;
use *;
use *;
use System;
static TEST_MONITOR: TestMonitor = new;
static GLOBAL: = InterAlloc ;