devela/data/dst/queue/
private.rs

1// devela::data::dst::queue::private
2//
3//! DstQueue private API
4//
5// TOC
6
7use super::super::{decompose_pointer, make_fat_ptr, store_metadata};
8use super::{DstBuf, DstQueue};
9use crate::{MaybeUninit, Ptr};
10
11pub(super) struct PushInnerInfo<'a, I> {
12    // Buffer for value data.
13    pub(super) data: &'a mut [MaybeUninit<I>],
14
15    // Buffer for metadata (length/vtable).
16    pub(super) meta: &'a mut [MaybeUninit<I>],
17
18    // Memory location for resetting the push.
19    pub(super) reset_slot: &'a mut usize,
20    pub(super) reset_value: usize,
21}
22
23impl<DST: ?Sized, BUF: DstBuf> DstQueue<DST, BUF> {
24    /// Pushes an item to the list (setting metadata based on `fat_ptr`).
25    //
26    // SAFETY: Caller must fill the buffer before any potential panic.
27    pub(super) unsafe fn push_inner(
28        &mut self,
29        fat_ptr: &DST,
30    ) -> Result<PushInnerInfo<BUF::Inner>, ()> {
31        let bytes = size_of_val(fat_ptr);
32        let (_data_ptr, len, v) = decompose_pointer(fat_ptr);
33        // SAFETY: caller must ensure safety
34        unsafe { self.push_inner_raw(bytes, &v[..len]) }
35    }
36
37    // SAFETY: TODO
38    pub(super) unsafe fn push_inner_raw(
39        &mut self,
40        bytes: usize,
41        metadata: &[usize],
42    ) -> Result<PushInnerInfo<BUF::Inner>, ()> {
43        let words = BUF::round_to_words(bytes) + Self::meta_words();
44
45        // 1. Check if there's space for the item
46        if self.space_words() < words {
47            // 2. If not, check if compaction would help
48            if self.space_words() + self.read_pos >= words {
49                self.compact();
50            }
51            // 3. Then, try expanding
52            if self.space_words() < words && self.data.extend(self.write_pos + words).is_err() {
53                // if expansion fails, return error
54                return Err(());
55            }
56        }
57        assert!(self.space_words() >= words);
58
59        // Get the base pointer for the new item
60        let slot = &mut self.data.as_mut()[self.write_pos..][..words];
61        let prev_write_pos = self.write_pos;
62        self.write_pos += words;
63        let (meta, rv) = slot.split_at_mut(Self::meta_words());
64
65        // Populate the metadata
66        store_metadata(meta, metadata);
67
68        // Increment offset and return
69        Ok(PushInnerInfo {
70            meta,
71            data: rv,
72            reset_slot: &mut self.write_pos,
73            reset_value: prev_write_pos,
74        })
75    }
76
77    #[must_use]
78    pub(super) fn meta_words() -> usize {
79        BUF::round_to_words(size_of::<&DST>() - size_of::<usize>())
80    }
81
82    #[must_use]
83    fn space_words(&self) -> usize {
84        self.data.as_ref().len() - self.write_pos
85    }
86
87    #[must_use]
88    pub(super) fn front_raw(&self) -> *mut DST {
89        assert!(self.read_pos < self.write_pos);
90        // SAFETY: Internal consistency maintains the metadata validity.
91        unsafe { self.raw_at(self.read_pos) }
92    }
93
94    #[must_use]
95    // SAFETY: Caller must ensure that `pos` is the start of an object.
96    pub(super) unsafe fn raw_at(&self, pos: usize) -> *mut DST {
97        assert!(pos >= self.read_pos);
98        assert!(pos < self.write_pos);
99        let meta = &self.data.as_ref()[pos..];
100        let mw = Self::meta_words();
101        let (meta, data) = meta.split_at(mw);
102        // SAFETY: caller must ensure safety
103        unsafe { make_fat_ptr(data.as_ptr() as *mut (), meta) }
104    }
105
106    #[must_use]
107    pub(super) fn front_raw_mut(&mut self) -> *mut DST {
108        assert!(self.read_pos < self.write_pos);
109        // SAFETY: Internal consistency maintains the metadata validity.
110        unsafe { self.raw_at_mut(self.read_pos) }
111    }
112
113    #[must_use]
114    // SAFETY: Caller must ensure that `pos` is the start of an object.
115    pub(super) unsafe fn raw_at_mut(&mut self, pos: usize) -> *mut DST {
116        assert!(pos >= self.read_pos);
117        assert!(pos < self.write_pos);
118        let meta = &mut self.data.as_mut()[pos..];
119        let mw = Self::meta_words();
120        let (meta, data) = meta.split_at_mut(mw);
121        // SAFETY: caller must ensure safety
122        unsafe { make_fat_ptr(data.as_mut_ptr() as *mut (), meta) }
123    }
124
125    pub(super) fn pop_front_inner(&mut self) {
126        // SAFETY: `front_raw_mut` asserts that there's an item, rest is correct.
127        unsafe {
128            let ptr = &mut *self.front_raw_mut();
129            let len = size_of_val(ptr);
130            Ptr::drop_in_place(ptr);
131            let words = BUF::round_to_words(len);
132            self.read_pos += Self::meta_words() + words;
133        }
134    }
135}