1#![doc = include_str!("../readme.md")]
2#![feature(ptr_metadata, unsize)]
4
5pub mod iter;
6
7use core::{
8 fmt::Debug,
9 marker::Unsize,
10 mem,
11 ops::{Index, IndexMut},
12 ptr::{self, DynMetadata, Pointee},
13};
14use iter::{Iter, IterMut};
15use std::alloc;
16use std::{alloc::Layout, ptr::NonNull};
17
18#[repr(align(16))]
19struct DefaultBuffer;
20
21pub struct TraitStack<T: ?Sized + Pointee<Metadata = DynMetadata<T>>> {
22 buf: NonNull<u8>,
23 buf_layout: Layout,
24 buf_occupied: usize,
25
26 table: Vec<(usize, DynMetadata<T>)>,
27}
28
29impl<T: ?Sized + Pointee<Metadata = DynMetadata<T>>> TraitStack<T> {
30 pub const DEFAULT_ALIGN: usize = mem::align_of::<DefaultBuffer>();
31
32 pub const fn new() -> Self {
33 Self {
34 buf: NonNull::<DefaultBuffer>::dangling().cast(),
35 buf_layout: Layout::new::<DefaultBuffer>(),
36 buf_occupied: 0,
37 table: Vec::new(),
38 }
39 }
40
41 pub const fn buf_layout(&self) -> Layout {
42 self.buf_layout
43 }
44
45 #[inline]
46 pub fn table_capacity(&self) -> usize {
47 self.table.capacity()
48 }
49
50 #[inline]
51 pub fn len(&self) -> usize {
52 self.table.len()
53 }
54
55 #[inline]
56 pub fn is_empty(&self) -> bool {
57 self.table.is_empty()
58 }
59
60 #[inline]
61 pub fn buf_ptr(&self) -> *const u8 {
62 self.buf.as_ptr().cast_const()
63 }
64
65 #[inline]
66 pub fn get(&self, index: usize) -> Option<&T> {
67 unsafe { Some(&*self.get_ptr(index)?) }
69 }
70
71 #[inline]
72 pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
73 unsafe { Some(&mut *(self.get_ptr(index)? as *mut T)) }
75 }
76
77 #[inline]
78 unsafe fn get_ptr(&self, index: usize) -> Option<*const T> {
79 let (offset, metadata) = *self.table.get(index)?;
80
81 Some(self.dyn_ptr_from(offset, metadata))
82 }
83
84 #[inline]
85 unsafe fn dyn_ptr_from(&self, offset: usize, metadata: DynMetadata<T>) -> *const T {
86 ptr::from_raw_parts(self.buf.as_ptr().add(offset) as _, metadata)
87 }
88
89 fn reserve_space_for(&mut self, value_layout: Layout) -> usize {
90 let padding = self.buf_occupied % value_layout.align();
91 let offset = self.buf_occupied + padding;
92
93 let new_buf_layout = Layout::from_size_align(
94 (self.buf_occupied + padding + value_layout.size()).next_power_of_two(),
95 self.buf_layout.align().max(value_layout.align()),
96 )
97 .unwrap();
98
99 if self.buf_layout != new_buf_layout {
100 let new_buf = unsafe {
101 if self.buf_layout.size() == 0 {
102 alloc::alloc(new_buf_layout)
103 } else if self.buf_layout.align() != new_buf_layout.align() {
104 alloc::dealloc(self.buf.as_ptr(), self.buf_layout);
105 alloc::alloc(new_buf_layout)
106 } else {
107 alloc::realloc(self.buf.as_ptr(), self.buf_layout, new_buf_layout.size())
108 }
109 };
110
111 self.buf = NonNull::new(new_buf).unwrap();
112 self.buf_layout = new_buf_layout;
113 }
114 self.buf_occupied += padding + value_layout.size();
115
116 return offset;
117 }
118
119 pub fn push<I: Unsize<T>>(&mut self, mut item: I) {
120 let (data, metadata) = (&mut item as *mut T).to_raw_parts();
121
122 let item_layout = Layout::new::<I>();
123 let offset = self.reserve_space_for(item_layout);
124
125 unsafe {
127 ptr::copy_nonoverlapping(
128 data as *mut u8,
129 self.buf.as_ptr().add(offset),
130 item_layout.size(),
131 )
132 };
133 mem::forget(item);
134
135 self.table.push((offset, metadata));
136 self.buf_occupied += item_layout.size();
137 }
138
139 pub fn pop(&mut self) -> Option<()> {
140 let (offset, metadata) = self.table.pop()?;
141 let data = unsafe { self.dyn_ptr_from(offset, metadata) };
142
143 unsafe { ptr::drop_in_place(data as *mut T) };
145 self.buf_occupied = offset;
146
147 Some(())
148 }
149
150 pub fn truncate(&mut self, len: usize) {
151 if len >= self.table.len() {
152 return;
153 }
154
155 let data_start_offset = self.table[len].0;
156
157 for i in len..self.len() {
158 let (offset, metadata) = self.table[i];
159
160 unsafe {
162 let data = self.dyn_ptr_from(offset, metadata);
163 ptr::drop_in_place(data as *mut T)
164 };
165 }
166
167 self.table.truncate(len);
168 self.buf_occupied = data_start_offset;
169 }
170
171 #[inline]
172 pub fn last(&self) -> Option<&T> {
173 self.get(self.len() - 1)
174 }
175
176 #[inline]
177 pub fn last_mut(&mut self) -> Option<&mut T> {
178 self.get_mut(self.len() - 1)
179 }
180
181 #[inline]
182 pub fn iter(&self) -> Iter<T> {
183 Iter {
184 ptr: self.buf.as_ptr(),
185 table_iter: self.table.iter(),
186 }
187 }
188
189 #[inline]
190 pub fn iter_mut(&mut self) -> IterMut<T> {
191 IterMut {
192 ptr: self.buf.as_ptr(),
193 table_iter: self.table.iter(),
194 }
195 }
196
197 pub fn clear(&mut self) {
198 for (offset, metadata) in &self.table {
199 unsafe {
201 ptr::drop_in_place(self.dyn_ptr_from(*offset, *metadata) as *mut T);
202 }
203 }
204
205 self.table.clear();
206 self.buf_occupied = 0;
207 }
208}
209
210impl<T: ?Sized + Pointee<Metadata = DynMetadata<T>>> Drop for TraitStack<T> {
211 fn drop(&mut self) {
212 for (offset, metadata) in &self.table {
213 unsafe {
215 ptr::drop_in_place(self.dyn_ptr_from(*offset, *metadata) as *mut T);
216 }
217 }
218
219 if self.buf_layout.size() > 0 {
220 unsafe {
221 alloc::dealloc(self.buf.as_ptr(), self.buf_layout);
222 }
223 }
224 }
225}
226
227impl<T: ?Sized + Pointee<Metadata = DynMetadata<T>>> Default for TraitStack<T> {
228 fn default() -> Self {
229 Self::new()
230 }
231}
232
233impl<T: ?Sized + Pointee<Metadata = DynMetadata<T>>> Index<usize> for TraitStack<T> {
234 type Output = T;
235
236 fn index(&self, index: usize) -> &Self::Output {
237 self.get(index).unwrap()
238 }
239}
240
241impl<T: ?Sized + Pointee<Metadata = DynMetadata<T>>> IndexMut<usize> for TraitStack<T> {
242 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
243 self.get_mut(index).unwrap()
244 }
245}
246
247unsafe impl<T: ?Sized + Pointee<Metadata = DynMetadata<T>> + Send> Send for TraitStack<T> {}
249
250unsafe impl<T: ?Sized + Pointee<Metadata = DynMetadata<T>> + Sync> Sync for TraitStack<T> {}
252
253impl<'a, T: ?Sized + Pointee<Metadata = DynMetadata<T>>> IntoIterator for &'a TraitStack<T> {
254 type Item = &'a T;
255
256 type IntoIter = Iter<'a, T>;
257
258 fn into_iter(self) -> Self::IntoIter {
259 self.iter()
260 }
261}
262
263impl<'a, T: ?Sized + Pointee<Metadata = DynMetadata<T>>> IntoIterator for &'a mut TraitStack<T> {
264 type Item = &'a mut T;
265
266 type IntoIter = IterMut<'a, T>;
267
268 fn into_iter(self) -> Self::IntoIter {
269 self.iter_mut()
270 }
271}
272
273impl<T: ?Sized + Pointee<Metadata = DynMetadata<T>> + Debug> Debug for TraitStack<T> {
274 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
275 f.debug_list().entries(self).finish()
276 }
277}