1use std::{mem, num::NonZeroUsize, ptr};
2
3use super::borrow::ReusableMemoryBorrow;
4
5const fn align_up(base: usize, align: usize) -> usize {
19 base.wrapping_add(align.wrapping_sub(1)) & !align.wrapping_sub(1)
20}
21macro_rules! impl_borrow_mut_X_as {
22 (
23 pub fn $capacity_name: ident;
24 pub fn $name: ident<$($gen_name: ident),+>[$count: literal];
25 ) => {
26 pub fn $capacity_name<$($gen_name),+>(
27 &self, capacity: [NonZeroUsize; $count]
28 ) -> usize {
29 let align_of: [usize; $count] = [$(mem::align_of::<$gen_name>()),+];
30
31 $(
32 assert_ne!(mem::size_of::<$gen_name>(), 0);
33 )+
34
35 let needed_bytes = 0;
36 let counter = 0;
37
38 $(
39 #[allow(non_snake_case)]
41 let $gen_name: (usize, usize) = (align_up(needed_bytes, mem::align_of::<$gen_name>()), counter);
42 let needed_bytes = $gen_name.0 + mem::size_of::<$gen_name>() * capacity[counter].get();
44
45 #[allow(unused_variables)]
46 let counter = counter + 1;
47 )+
48
49 let align_bump = if mem::align_of::<B>() >= mem::align_of::<T>() {
51 0
52 } else {
53 align_of[0] - 1
54 };
55 let needed_bytes = needed_bytes + align_bump;
57 let needed_length = (needed_bytes + mem::size_of::<B>() - 1) / mem::size_of::<B>();
58
59 needed_length
60 }
61
62 pub fn $name<'mem, $($gen_name),+>(
63 &'mem mut self, capacity: [NonZeroUsize; $count]
64 ) ->( $(ReusableMemoryBorrow<'mem, $gen_name>),+ ) {
65 let align_of: [usize; $count] = [$(mem::align_of::<$gen_name>()),+];
66
67 $(
68 assert_ne!(mem::size_of::<$gen_name>(), 0);
69 )+
70
71 let needed_bytes = 0;
72 let counter = 0;
73
74 $(
75 #[allow(non_snake_case)]
77 let $gen_name: (usize, usize) = (align_up(needed_bytes, mem::align_of::<$gen_name>()), counter);
78 let needed_bytes = $gen_name.0 + mem::size_of::<$gen_name>() * capacity[counter].get();
80
81 #[allow(unused_variables)]
82 let counter = counter + 1;
83 )+
84
85 let align_bump = if mem::align_of::<B>() >= mem::align_of::<T>() {
87 0
88 } else {
89 align_of[0] - 1
90 };
91 let needed_bytes = needed_bytes + align_bump;
93 let needed_length = (needed_bytes + mem::size_of::<B>() - 1) / mem::size_of::<B>();
94
95 self.vec.reserve(needed_length);
97 let memory_ptr = self.vec.as_mut_ptr();
98
99 let align_offset = memory_ptr.align_offset(align_of[0]);
101 if align_offset == std::usize::MAX {
102 panic!("Could not align pointer");
103 }
104
105 unsafe {
106 (
107 $(
108 ReusableMemoryBorrow::from_raw_parts(
109 ptr::NonNull::new_unchecked(
110 (memory_ptr.add(align_offset) as *mut u8).add($gen_name.0) as *mut $gen_name
111 ),
112 capacity[$gen_name.1]
113 )
114 ),+
115 )
116 }
117 }
118 }
119}
120
121#[derive(Debug, Clone)]
128pub struct ReusableMemory<B = u8> {
129 vec: Vec<B>
130}
131impl<B> ReusableMemory<B> {
132 impl_borrow_mut_X_as!(
133 pub fn needed_capacity_for_two;
134 pub fn borrow_mut_two_as<T, U>[2];
135 );
136
137 impl_borrow_mut_X_as!(
138 pub fn needed_capacity_for_three;
139 pub fn borrow_mut_three_as<T, U, V>[3];
140 );
141
142 impl_borrow_mut_X_as!(
143 pub fn needed_capacity_for_four;
144 pub fn borrow_mut_four_as<T, U, V, W>[4];
145 );
146
147 impl_borrow_mut_X_as!(
148 pub fn needed_capacity_for_five;
149 pub fn borrow_mut_five_as<T, U, V, W, X>[5];
150 );
151
152 pub const unsafe fn new_unchecked() -> Self { ReusableMemory { vec: Vec::new() } }
160
161 pub fn new() -> Self { Self::with_capacity(0) }
163
164 pub fn with_capacity(len: usize) -> Self {
168 assert_ne!(mem::size_of::<B>(), 0);
169
170 ReusableMemory { vec: Vec::with_capacity(len) }
171 }
172
173 pub fn needed_capacity_for<T>(&self, count: NonZeroUsize) -> usize {
174 assert_ne!(mem::size_of::<T>(), 0);
175
176 let align_bump =
178 if mem::align_of::<B>() >= mem::align_of::<T>() { 0 } else { mem::align_of::<T>() - 1 };
179
180 let needed_length = {
182 let needed_bytes = mem::size_of::<T>() * count.get() + align_bump;
183
184 (needed_bytes + mem::size_of::<B>() - 1) / mem::size_of::<B>()
186 };
187
188 needed_length
189 }
190
191 pub fn borrow_mut_as<'mem, T>(
198 &'mem mut self, capacity: NonZeroUsize
199 ) -> ReusableMemoryBorrow<'mem, T> {
200 let needed_length = self.needed_capacity_for::<T>(capacity);
201
202 self.vec.reserve(needed_length);
204 let memory_ptr = self.vec.as_mut_ptr();
205
206 let align_offset = memory_ptr.align_offset(mem::align_of::<T>());
208 if align_offset == std::usize::MAX {
209 panic!("Could not align pointer");
210 }
211
212 unsafe {
213 ReusableMemoryBorrow::from_raw_parts(
214 ptr::NonNull::new_unchecked(memory_ptr.add(align_offset) as *mut T),
215 capacity
216 )
217 }
218 }
219}