reusable_memory/
lib.rs

1//! ## Basic usage
2//! 
3//! ```rust
4//! use reusable_memory::ReusableMemory;
5//! 
6//! let mut memory: ReusableMemory<u8> = ReusableMemory::new();
7//! 
8//! {
9//! 	// The memory can then be borrowed as a different type:
10//! 	let mut borrowed_memory = memory.borrow_mut_as::<usize>(std::num::NonZeroUsize::new(3).unwrap());
11//! 
12//! 	// Now `borrowed_memory` holds a pointer to enough memory to store 3 properly-aligned `usize`s inside the memory allocated in `memory`.
13//! 	borrowed_memory.push(1).unwrap();
14//! 	borrowed_memory.push(2).unwrap();
15//! 	borrowed_memory.push(std::usize::MAX).unwrap();
16//! 	// `push` will return an `Err` if the pushed value would not fit into the capacity of the borrowed memory.
17//! 
18//! 	assert_eq!(borrowed_memory.as_slice(), &[1, 2, std::usize::MAX]);
19//! 
20//! 	// values can also be `pop`ed or `drain`ed as with `Vec`:
21//! 	assert_eq!(borrowed_memory.pop(), Some(std::usize::MAX));
22//! 	assert_eq!(borrowed_memory.drain(..).collect::<Vec<usize>>().as_slice(), &[1, 2]);
23//! 	assert_eq!(borrowed_memory.pop(), None);
24//! }
25//! // The borrowed memory is automatically returned when the object is dropped, and the pushed values are dropped as well.
26//! 
27//! // Now the memory can be reused, even as multiple different types (current limit is 5 because the code is generated by a macro):
28//! {
29//! 	let (mut borrow_t, mut borrow_u) = memory.borrow_mut_two_as::<usize, u8>(
30//! 		[
31//! 			std::num::NonZeroUsize::new(1).unwrap(),
32//! 			std::num::NonZeroUsize::new(2).unwrap()
33//! 		]
34//! 	);
35//! 
36//! 	borrow_t.push(0usize).unwrap();
37//! 	
38//! 	borrow_u.push(1u8).unwrap();
39//! 	borrow_u.push(2u8).unwrap();
40//! 
41//! 	assert_eq!(borrow_t.as_slice(), &[0usize]);
42//! 
43//! 	assert_eq!(borrow_u.as_slice(), &[1u8, 2u8]);
44//! }
45//! ```
46
47mod base;
48pub mod borrow;
49
50pub use base::*;
51
52#[cfg(test)]
53mod tests {
54	use std::num::NonZeroUsize;
55
56	use super::{borrow::*, *};
57
58	/// Tests borrow of `u8` from base of `u8`.
59	#[test]
60	fn same_type() {
61		let mut rm: ReusableMemory<u16> = ReusableMemory::new();
62		{
63			let mut borrow = rm.borrow_mut_as::<u16>(NonZeroUsize::new(3).unwrap());
64			borrow.push(1).unwrap();
65			borrow.push(std::u16::MAX).unwrap();
66
67			assert_eq!(borrow.as_ptr().align_offset(std::mem::align_of::<u16>()), 0);
68			assert_eq!(borrow.len(), 2);
69		}
70	}
71
72	/// Tests borrow of `i16` from base of `u16`.
73	#[test]
74	fn same_align_type() {
75		let mut rm: ReusableMemory<u16> = ReusableMemory::new();
76		{
77			let mut borrow = rm.borrow_mut_as::<i16>(NonZeroUsize::new(3).unwrap());
78			borrow.push(1).unwrap();
79			borrow.push(std::i16::MAX).unwrap();
80
81			assert_eq!(borrow.as_ptr().align_offset(std::mem::align_of::<i16>()), 0);
82			assert_eq!(borrow.len(), 2);
83		}
84	}
85
86	/// Tests borrow of `usize` from base of `u8`.
87	///
88	/// This fails on Miri because it cannot align the pointers (yet?)
89	#[test]
90	fn different_align() {
91		let mut rm: ReusableMemory<u8> = ReusableMemory::new();
92		{
93			let mut borrow = rm.borrow_mut_as::<usize>(NonZeroUsize::new(3).unwrap());
94			borrow.push(1).unwrap();
95			borrow.push(std::usize::MAX).unwrap();
96
97			assert_eq!(borrow.as_ptr().align_offset(std::mem::align_of::<usize>()), 0);
98			assert_eq!(borrow.len(), 2);
99		}
100	}
101
102	#[test]
103	fn borrow_two_same_type() {
104		let mut rm: ReusableMemory<u16> = ReusableMemory::new();
105		{
106			let (mut borrow_a, mut borrow_b) = rm.borrow_mut_two_as::<u16, i16>([
107				NonZeroUsize::new(6).unwrap(),
108				NonZeroUsize::new(3).unwrap()
109			]);
110
111			borrow_a.push(1).unwrap();
112			borrow_a.push(2).unwrap();
113			borrow_a.push(std::u16::MAX).unwrap();
114
115			borrow_b.push(-1).unwrap();
116			borrow_b.push(-2).unwrap();
117			borrow_b.push(std::i16::MIN).unwrap();
118
119			assert_eq!(borrow_a.as_ptr().align_offset(std::mem::align_of::<u16>()), 0);
120			assert_eq!(borrow_b.as_ptr().align_offset(std::mem::align_of::<i16>()), 0);
121
122			assert_eq!(borrow_a.as_slice(), &[1, 2, std::u16::MAX]);
123			assert_eq!(borrow_b.as_slice(), &[-1, -2, std::i16::MIN]);
124		}
125	}
126
127	/// Tests borrow of `u64`,`u32` and `u16` from base of `u8`.
128	///
129	/// This fails on Miri because it cannot align the pointers (yet?)
130	#[test]
131	fn borrow_three_different_align() {
132		let mut rm: ReusableMemory<u8> = ReusableMemory::new();
133		{
134			let (mut borrow_u64, mut borrow_u32, mut borrow_u16) = rm
135				.borrow_mut_three_as::<u64, u32, u16>([
136					NonZeroUsize::new(1).unwrap(),
137					NonZeroUsize::new(2).unwrap(),
138					NonZeroUsize::new(4).unwrap()
139				]);
140
141			borrow_u64.push(1).unwrap();
142
143			borrow_u32.push(1).unwrap();
144			borrow_u32.push(2).unwrap();
145
146			borrow_u16.push(1).unwrap();
147			borrow_u16.push(2).unwrap();
148			borrow_u16.push(3).unwrap();
149			borrow_u16.push(4).unwrap();
150
151			assert_eq!(borrow_u64.as_ptr().align_offset(std::mem::align_of::<u64>()), 0);
152			assert_eq!(borrow_u32.as_ptr().align_offset(std::mem::align_of::<u32>()), 0);
153			assert_eq!(borrow_u16.as_ptr().align_offset(std::mem::align_of::<u16>()), 0);
154
155			assert_eq!(borrow_u64.as_slice(), &[1u64]);
156			assert_eq!(borrow_u32.as_slice(), &[1u32, 2u32]);
157			assert_eq!(borrow_u16.as_slice(), &[1u16, 2u16, 3u16, 4u16]);
158		}
159	}
160
161	#[test]
162	fn push_iter() {
163		let mut rm: ReusableMemory<u8> = ReusableMemory::new();
164		{
165			let mut borrow = rm.borrow_mut_as::<u8>(NonZeroUsize::new(6).unwrap());
166			let iter = (0 .. 5u8).into_iter();
167
168			borrow.push_from_iter(iter).unwrap();
169			assert_eq!(borrow.as_slice(), &[0, 1, 2, 3, 4]);
170		}
171	}
172
173	#[test]
174	fn push_iter_fill_up() {
175		let mut rm: ReusableMemory<u8> = ReusableMemory::new();
176		{
177			let mut borrow = rm.borrow_mut_as::<u8>(NonZeroUsize::new(5).unwrap());
178			let iter = (0 .. 5u8).into_iter();
179
180			let mut iter = borrow.push_from_iter(iter).unwrap_err();
181			assert_eq!(borrow.as_slice(), &[0, 1, 2, 3, 4]);
182			assert_eq!(iter.next(), None);
183		}
184	}
185
186	#[test]
187	fn push_iter_fill_up_peekable() {
188		let mut rm: ReusableMemory<u8> = ReusableMemory::new();
189		{
190			let mut borrow = rm.borrow_mut_as::<u8>(NonZeroUsize::new(5).unwrap());
191			let iter = (0 .. 5u8).into_iter();
192
193			borrow.push_from_iter_peeking(iter).unwrap();
194			assert_eq!(borrow.as_slice(), &[0, 1, 2, 3, 4]);
195		}
196	}
197
198	#[test]
199	fn push_iter_over_capacity() {
200		let mut rm: ReusableMemory<u8> = ReusableMemory::new();
201		{
202			let mut borrow = rm.borrow_mut_as::<u8>(NonZeroUsize::new(4).unwrap());
203			let iter = (0 .. 5u8).into_iter();
204
205			let mut iter = borrow.push_from_iter(iter).unwrap_err();
206			assert_eq!(borrow.as_slice(), &[0, 1, 2, 3]);
207			assert_eq!(iter.next(), Some(4));
208		}
209	}
210
211	/// Tests that borrow can push from ExactSizeIterator.
212	#[test]
213	fn push_exact_iter() {
214		let mut rm: ReusableMemory<u8> = ReusableMemory::new();
215		{
216			let mut borrow = rm.borrow_mut_as::<u8>(NonZeroUsize::new(3).unwrap());
217			let iter = vec![1, std::u8::MAX].into_iter();
218
219			borrow.push_from_exact_iter(iter).unwrap();
220			assert_eq!(borrow.as_ptr().align_offset(std::mem::align_of::<u8>()), 0);
221			assert_eq!(borrow.len(), 2);
222		}
223	}
224
225	/// Tests that pushing from an iterator beyond capacity returns an error.
226	#[test]
227	fn push_exact_iter_over_capacity() {
228		let mut rm: ReusableMemory<u8> = ReusableMemory::new();
229		{
230			let capacity = NonZeroUsize::new(1).unwrap();
231			let mut borrow = rm.borrow_mut_as::<u8>(capacity);
232			let iter = vec![1, std::u8::MAX].into_iter();
233
234			match borrow.push_from_exact_iter(iter.clone()) {
235				Err(err_iter) if err_iter.as_slice() == iter.as_slice() => (),
236				_ => panic!("Expected Err(iter)")
237			}
238		}
239	}
240
241	#[test]
242	fn pop() {
243		let mut rm: ReusableMemory<u8> = ReusableMemory::new();
244		{
245			let capacity = NonZeroUsize::new(1).unwrap();
246			let mut borrow = rm.borrow_mut_as::<u8>(capacity);
247
248			borrow.push(1).unwrap();
249
250			assert_eq!(borrow.pop(), Some(1));
251			assert_eq!(borrow.pop(), None);
252		}
253	}
254
255	#[test]
256	fn drain() {
257		let mut rm: ReusableMemory<u8> = ReusableMemory::new();
258		{
259			let mut borrow = rm.borrow_mut_as::<u8>(NonZeroUsize::new(5).unwrap());
260			borrow.push_from_exact_iter(0 ..= 4).unwrap();
261
262			{
263				let mut drain = borrow.drain(1 ..= 3);
264				assert_eq!(drain.next(), Some(1));
265				assert_eq!(drain.next_back(), Some(3));
266			}
267
268			assert_eq!(borrow.as_slice(), &[0, 4]);
269		}
270	}
271
272	/// Tests that values are dropped on clear.
273	#[test]
274	fn clear() {
275		static mut DROP_COUNTER: usize = 0;
276		struct DropCounter {
277			_value: u8
278		}
279		impl DropCounter {
280			pub fn new(value: u8) -> Self {
281				unsafe {
282					DROP_COUNTER += 1;
283				}
284
285				DropCounter { _value: value }
286			}
287		}
288		impl Drop for DropCounter {
289			fn drop(&mut self) {
290				unsafe {
291					DROP_COUNTER -= 1;
292				}
293			}
294		}
295
296		let mut rm: ReusableMemory<u8> = ReusableMemory::new();
297		{
298			let mut borrow = rm.borrow_mut_as::<DropCounter>(NonZeroUsize::new(2).unwrap());
299
300			borrow.push(DropCounter::new(1)).unwrap();
301			borrow.push(DropCounter::new(std::u8::MAX)).unwrap();
302
303			unsafe {
304				assert_eq!(DROP_COUNTER, 2);
305			}
306
307			borrow.clear();
308
309			unsafe {
310				assert_eq!(DROP_COUNTER, 0);
311			}
312		}
313	}
314
315	/// Tests that values are dropped on `Drop`.
316	#[test]
317	fn drop() {
318		static mut DROP_COUNTER: usize = 0;
319		struct DropCounter {
320			_value: u8
321		}
322		impl DropCounter {
323			pub fn new(value: u8) -> Self {
324				unsafe {
325					DROP_COUNTER += 1;
326				}
327
328				DropCounter { _value: value }
329			}
330		}
331		impl Drop for DropCounter {
332			fn drop(&mut self) {
333				unsafe {
334					DROP_COUNTER -= 1;
335				}
336			}
337		}
338
339		let mut rm: ReusableMemory<u8> = ReusableMemory::new();
340		{
341			let mut borrow = rm.borrow_mut_as::<DropCounter>(NonZeroUsize::new(2).unwrap());
342
343			borrow.push(DropCounter::new(1)).unwrap();
344			borrow.push(DropCounter::new(std::u8::MAX)).unwrap();
345
346			unsafe {
347				assert_eq!(DROP_COUNTER, 2);
348			}
349		}
350
351		unsafe {
352			assert_eq!(DROP_COUNTER, 0);
353		}
354	}
355
356	/// Tests that pushing beyond capacity returns an error.
357	#[test]
358	fn not_enough_capacity() {
359		let mut rm: ReusableMemory<u8> = ReusableMemory::new();
360		{
361			let capacity = NonZeroUsize::new(1).unwrap();
362			let mut borrow = rm.borrow_mut_as::<u8>(capacity);
363			borrow.push(1).unwrap();
364
365			match borrow.push(1) {
366				Err(ReusableMemoryBorrowError::NotEnoughCapacity(c)) if c == capacity => (),
367				_ => panic!("Expected Err(ReusableMemoryBorrowError::NotEnoughCapacity)")
368			}
369		}
370	}
371}