1use super::{DstArray, DstBuf, check_fat_pointer, decompose_pointer, list_push_gen};
11use crate::{ConstInit, MaybeUninit, MemAligned, PhantomData, Ptr};
12
13#[doc = crate::_tags!(data_structure)]
16#[doc = crate::_doc_meta!{location("data/layout/dst")}]
19pub type DstStackUsize<DST , const CAP: usize> = DstStack<DST, DstArray<usize, CAP>>;
28
29#[doc = crate::_tags!(data_structure)]
38#[doc = crate::_doc_meta!{location("data/layout/dst")}]
40pub struct DstStack<DST: ?Sized, BUF: DstBuf> {
44 _pd: PhantomData<*const DST>,
45 next_ofs: usize,
48 data: BUF,
49}
50
51#[doc = crate::_tags!(iterator)]
52#[doc = crate::_doc_meta!{location("data/layout/dst")}]
54#[derive(Debug)]
55pub struct DstStackIter<'a, DST: 'a + ?Sized, BUF: 'a + DstBuf>(&'a DstStack<DST, BUF>, usize);
56
57#[doc = crate::_tags!(iterator)]
58#[doc = crate::_doc_meta!{location("data/layout/dst")}]
60#[derive(Debug)]
61pub struct DstStackIterMut<'a, DST: 'a + ?Sized, BUF: 'a + DstBuf>(
62 &'a mut DstStack<DST, BUF>,
63 usize,
64);
65
66impl<DST: ?Sized, BUF: DstBuf> DstStack<DST, BUF> {
67 #[must_use] #[rustfmt::skip]
69 pub fn new() -> Self where BUF: Default { Self::with_buffer(BUF::default()) }
70
71 #[must_use] #[rustfmt::skip]
73 pub const fn new_const() -> Self where BUF: ConstInit { Self::with_buffer(BUF::INIT) }
74
75 #[must_use] #[rustfmt::skip]
77 pub const fn with_buffer(buffer: BUF) -> Self {
78 DstStack { _pd: PhantomData, next_ofs: 0, data: buffer }
79 }
80
81 #[must_use]
83 pub const fn is_empty(&self) -> bool {
84 self.next_ofs == 0
85 }
86
87 pub fn push<VAL, F: FnOnce(&VAL) -> &DST>(&mut self, v: VAL, f: F) -> Result<(), VAL>
95 where
96 (VAL, BUF::Inner): MemAligned,
97 {
98 <(VAL, BUF::Inner) as MemAligned>::assert_compatibility();
99
100 unsafe {
102 match self.push_inner(check_fat_pointer(&v, f)) {
103 Ok(pii) => {
104 Ptr::write(pii.data.as_mut_ptr() as *mut VAL, v);
105 Ok(())
106 }
107 Err(()) => Err(v),
108 }
109 }
110 }
111
112 #[must_use]
114 pub fn top(&self) -> Option<&DST> {
115 self.top_raw().map(|x| unsafe { &*x })
116 }
117
118 #[must_use]
120 pub fn top_mut(&mut self) -> Option<&mut DST> {
121 self.top_raw_mut().map(|x| unsafe { &mut *x })
122 }
123
124 pub fn pop(&mut self) {
126 if let Some(ptr) = self.top_raw_mut() {
127 assert!(self.next_ofs > 0);
128 let words = unsafe {
130 let size = size_of_val(&*ptr);
131 Ptr::drop_in_place(ptr);
132 BUF::round_to_words(size)
133 };
134 self.next_ofs -= words + Self::meta_words();
135 }
136 }
137
138 #[must_use]
153 pub const fn iter(&self) -> DstStackIter<'_, DST, BUF> {
154 DstStackIter(self, self.next_ofs)
155 }
156
157 #[must_use]
174 pub fn iter_mut(&mut self) -> DstStackIterMut<'_, DST, BUF> {
175 DstStackIterMut(self, self.next_ofs)
176 }
177}
178
179impl<BUF: DstBuf> DstStack<str, BUF> {
180 pub fn push_str(&mut self, string: &str) -> Result<(), ()> {
189 unsafe {
190 self.push_inner(string).map(|pii| {
191 Ptr::copy(
192 string.as_bytes().as_ptr(),
193 pii.data.as_mut_ptr() as *mut u8,
194 string.len(),
195 );
196 })
197 }
198 }
199}
200
201impl<BUF: DstBuf, DST: Clone> DstStack<[DST], BUF>
202where
203 (DST, BUF::Inner): MemAligned,
204{
205 pub fn push_cloned(&mut self, slice: &[DST]) -> Result<(), ()> {
214 <(DST, BUF::Inner) as MemAligned>::assert_compatibility();
215 self.push_from_iter(slice.iter().cloned())
216 }
217 pub fn push_copied(&mut self, slice: &[DST]) -> Result<(), ()>
226 where
227 DST: Copy,
228 {
229 <(DST, BUF::Inner) as MemAligned>::assert_compatibility();
230 unsafe {
232 self.push_inner(slice).map(|pii| {
233 Ptr::copy(
234 slice.as_ptr() as *const u8,
235 pii.data.as_mut_ptr() as *mut u8,
236 size_of_val(slice),
237 );
238 })
239 }
240 }
241}
242
243impl<BUF: DstBuf, DST> DstStack<[DST], BUF>
244where
245 (DST, BUF::Inner): MemAligned,
246{
247 pub fn push_from_iter(
257 &mut self,
258 mut iter: impl ExactSizeIterator<Item = DST>,
259 ) -> Result<(), ()> {
260 <(DST, BUF::Inner) as MemAligned>::assert_compatibility();
261 unsafe {
263 let pii = self.push_inner_raw(iter.len() * size_of::<DST>(), &[0])?;
264 list_push_gen(
265 pii.meta,
266 pii.data,
267 iter.len(),
268 |_| iter.next().unwrap(),
269 pii.reset_slot,
270 pii.reset_value,
271 );
272 Ok(())
273 }
274 }
275}
276
277struct PushInnerInfo<'a, DInner> {
280 data: &'a mut [MaybeUninit<DInner>],
282
283 meta: &'a mut [MaybeUninit<DInner>],
285
286 reset_slot: &'a mut usize,
288 reset_value: usize,
289}
290
291impl<DST: ?Sized, BUF: DstBuf> DstStack<DST, BUF> {
292 #[must_use]
293 fn meta_words() -> usize {
294 BUF::round_to_words(size_of::<&DST>() - size_of::<usize>())
295 }
296
297 #[must_use]
298 unsafe fn raw_at(&self, ofs: usize) -> *mut DST {
299 let dar = self.data.as_ref();
300 let meta = &dar[dar.len() - ofs..];
301 let mw = Self::meta_words();
302 let (meta, data) = meta.split_at(mw);
303 unsafe { super::make_fat_ptr(data.as_ptr() as *mut (), meta) }
305 }
306 #[must_use]
307 unsafe fn raw_at_mut(&mut self, ofs: usize) -> *mut DST {
308 let dar = self.data.as_mut();
309 let ofs = dar.len() - ofs;
310 let meta = &mut dar[ofs..];
311 let mw = Self::meta_words();
312 let (meta, data) = meta.split_at_mut(mw);
313 unsafe { super::make_fat_ptr(data.as_mut_ptr() as *mut (), meta) }
315 }
316 #[must_use]
318 fn top_raw(&self) -> Option<*mut DST> {
319 if self.next_ofs == 0 {
320 None
321 } else {
322 Some(unsafe { self.raw_at(self.next_ofs) })
324 }
325 }
326 #[must_use]
328 fn top_raw_mut(&mut self) -> Option<*mut DST> {
329 if self.next_ofs == 0 {
330 None
331 } else {
332 Some(unsafe { self.raw_at_mut(self.next_ofs) })
334 }
335 }
336
337 unsafe fn push_inner(&mut self, fat_ptr: &DST) -> Result<PushInnerInfo<'_, BUF::Inner>, ()> {
339 let bytes = size_of_val(fat_ptr);
340 let (_data_ptr, len, v) = decompose_pointer(fat_ptr);
341 unsafe { self.push_inner_raw(bytes, &v[..len]) }
343 }
344
345 unsafe fn push_inner_raw(
350 &mut self,
351 bytes: usize,
352 metadata: &[usize],
353 ) -> Result<PushInnerInfo<'_, BUF::Inner>, ()> {
354 assert!(BUF::round_to_words(size_of_val(metadata)) == Self::meta_words());
355 let words = BUF::round_to_words(bytes) + Self::meta_words();
356
357 let req_space = self.next_ofs + words;
358 if req_space > self.data.as_ref().len() {
360 let old_len = self.data.as_ref().len();
361 if self.data.extend(req_space).is_ok() {
362 let new_len = self.data.as_ref().len();
363 self.data.as_mut().rotate_right(new_len - old_len);
364 }
365 }
366
367 if req_space <= self.data.as_ref().len() {
369 let prev_next_ofs = self.next_ofs;
371 self.next_ofs += words;
372 let len = self.data.as_ref().len();
373 let slot = &mut self.data.as_mut()[len - self.next_ofs..][..words];
374 let (meta, rv) = slot.split_at_mut(Self::meta_words());
375
376 super::store_metadata(meta, metadata);
378
379 Ok(PushInnerInfo {
381 meta,
382 data: rv,
383 reset_slot: &mut self.next_ofs,
384 reset_value: prev_next_ofs,
385 })
386 } else {
387 Err(())
388 }
389 }
390}
391
392mod core_impls {
393 use super::{DstBuf, DstStack, DstStackIter, DstStackIterMut};
394 use core::{fmt, iter, ops};
395
396 impl<DST: ?Sized, BUF: DstBuf> ops::Drop for DstStack<DST, BUF> {
397 fn drop(&mut self) {
398 while !self.is_empty() {
399 self.pop();
400 }
401 }
402 }
403 impl<DST: ?Sized, BUF: DstBuf + Default> Default for DstStack<DST, BUF> {
404 fn default() -> Self {
405 DstStack::new()
406 }
407 }
408
409 macro_rules! impl_trait {
410 ( $t:path; $($body:tt)* ) => {
411 impl<BUF: DstBuf, DST: ?Sized> $t for DstStack<DST, BUF> where DST: $t { $( $body )* }
412 }
413 }
414 impl_trait! { fmt::Debug;
416 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
417 f.write_str("[")?;
418 for v in self.iter() {
419 v.fmt(f)?;
420 f.write_str(",")?;
421 }
422 f.write_str("]")?;
423 Ok( () )
424 }
425 }
426
427 impl<'a, DST: 'a + ?Sized, BUF: 'a + DstBuf> iter::Iterator for DstStackIter<'a, DST, BUF> {
430 type Item = &'a DST;
431 fn next(&mut self) -> Option<&'a DST> {
432 if self.1 == 0 {
433 None
434 } else {
435 let rv = unsafe { &*self.0.raw_at(self.1) };
437 self.1 -= DstStack::<DST, BUF>::meta_words() + BUF::round_to_words(size_of_val(rv));
438 Some(rv)
439 }
440 }
441 }
442
443 impl<'a, DST: 'a + ?Sized, BUF: 'a + DstBuf> iter::Iterator for DstStackIterMut<'a, DST, BUF> {
444 type Item = &'a mut DST;
445 fn next(&mut self) -> Option<&'a mut DST> {
446 if self.1 == 0 {
447 None
448 } else {
449 let rv = unsafe { &mut *self.0.raw_at_mut(self.1) };
451 self.1 -= DstStack::<DST, BUF>::meta_words() + BUF::round_to_words(size_of_val(rv));
452 Some(rv)
453 }
454 }
455 }
456}