devela/data/dst/queue/
methods.rs

1//
2//
3//!
4//
5// TOC
6
7use super::super::{check_fat_pointer, list_push_gen, make_fat_ptr};
8use super::{DstBuf, DstQueue, DstQueueIter, DstQueueIterMut, DstQueuePopHandle};
9use crate::{
10    MemAligned,
11    _core::{marker, ptr},
12};
13
14impl<DST: ?Sized, BUF: DstBuf> DstQueue<DST, BUF> {
15    /// Constructs a new (empty) queue.
16    #[must_use] #[rustfmt::skip]
17    pub fn new() -> Self where BUF: Default { Self::with_buffer(BUF::default()) }
18
19    /// Constructs a new (empty) queue using the given `buffer`.
20    #[must_use] #[rustfmt::skip]
21    pub fn with_buffer(data: BUF) -> Self {
22        DstQueue { _pd: marker::PhantomData, read_pos: 0, write_pos: 0, data }
23    }
24
25    /// Pushes a value to the end of the queue.
26    pub fn push_back<VAL, F>(&mut self, value: VAL, f: F) -> Result<(), VAL>
27    where
28        F: FnOnce(&VAL) -> &DST,
29        (VAL, BUF::Inner): MemAligned,
30    {
31        <(VAL, BUF::Inner) as MemAligned>::assert_compatibility();
32
33        // SAFETY: Destination address is valid.
34        unsafe {
35            match self.push_inner(check_fat_pointer(&value, f)) {
36                Ok(pii) => {
37                    ptr::write(pii.data.as_mut_ptr() as *mut VAL, value);
38                    Ok(())
39                }
40                Err(()) => Err(value),
41            }
42        }
43    }
44
45    /// Compacts the queue (moving the read position to zero).
46    pub fn compact(&mut self) {
47        if self.read_pos != 0 {
48            self.data.as_mut().rotate_left(self.read_pos);
49            self.write_pos -= self.read_pos;
50            self.read_pos = 0;
51        }
52    }
53
54    /// Returns `true` if the queue is empty.
55    #[must_use]
56    pub const fn empty(&self) -> bool {
57        self.read_pos == self.write_pos
58    }
59
60    /// Removes an item from the front of the queue.
61    #[must_use]
62    pub fn pop_front(&mut self) -> Option<DstQueuePopHandle<DST, BUF>> {
63        if self.read_pos == self.write_pos {
64            None
65        } else {
66            Some(DstQueuePopHandle { parent: self })
67        }
68    }
69
70    /// Returns an exclusive reference to the front element.
71    #[must_use]
72    pub fn front_mut(&mut self) -> Option<&mut DST> {
73        if self.read_pos == self.write_pos {
74            None
75        } else {
76            // SAFETY: TODO
77            Some(unsafe { &mut *self.front_raw_mut() })
78        }
79    }
80
81    /// Returns a shared reference to the front element.
82    #[must_use]
83    pub fn front(&self) -> Option<&DST> {
84        if self.read_pos == self.write_pos {
85            None
86        } else {
87            // SAFETY: TODO
88            Some(unsafe { &*self.front_raw() })
89        }
90    }
91
92    /// Returns an immutable iterator
93    /// (yields references to items, in insertion order).
94    ///
95    /// # Examples
96    /// ```
97    /// # use devela::{DstArray, DstQueue};
98    /// let mut list = DstQueue::<str, DstArray<usize, 8>>::new();
99    /// list.push_back_str("Hello");
100    /// list.push_back_str("world");
101    /// let mut it = list.iter();
102    /// assert_eq!(it.next(), Some("Hello"));
103    /// assert_eq!(it.next(), Some("world"));
104    /// assert_eq!(it.next(), None);
105    /// ```
106    #[must_use]
107    pub const fn iter(&self) -> DstQueueIter<DST, BUF> {
108        DstQueueIter(self, self.read_pos)
109    }
110
111    /// Returns a mutable iterator.
112    ///
113    /// # Examples
114    /// ```
115    /// # use devela::{DstArray, DstQueue};
116    /// let mut list = DstQueue::<[u8], DstArray<usize, 8>>::new();
117    /// list.push_copied(&[1,2,3]);
118    /// list.push_copied(&[9]);
119    /// for v in list.iter_mut() {
120    ///     v[0] -= 1;
121    /// }
122    /// let mut it = list.iter();
123    /// assert_eq!(it.next(), Some(&[0,2,3][..]));
124    /// assert_eq!(it.next(), Some(&[8][..]));
125    /// assert_eq!(it.next(), None);
126    /// ```
127    #[must_use]
128    pub fn iter_mut(&mut self) -> DstQueueIterMut<DST, BUF> {
129        DstQueueIterMut(self, self.read_pos)
130    }
131    // NOTE: No into_iter, not possible due to unsized types.
132    // Could make a `drain` that returns read handles (pops as it goes).
133
134    /// Removes any items that don't meet a predicate.
135    ///
136    /// # Examples
137    /// ```
138    /// # use {devela::{DstArray, DstQueue}, core::{any::Any, fmt::Debug}};
139    /// trait DebugAny: 'static + Any + Debug { fn as_any(&self) -> &dyn Any; }
140    /// impl<DST: Debug + Any + 'static> DebugAny for DST { fn as_any(&self) -> &dyn Any { self } }
141    /// let mut list = {
142    ///     let mut list: DstQueue<dyn DebugAny, DstArray<usize, 8>> = DstQueue::new();
143    ///     list.push_back(1234, |v| v);
144    ///     list.push_back(234.5f32, |v| v);
145    ///     list.push_back(5678, |v| v);
146    ///     list.push_back(0.5f32, |v| v);
147    ///     list
148    /// };
149    /// list.retain(|v| (*v).as_any().downcast_ref::<f32>().is_some());
150    /// let mut it = list.iter().map(|v| format!("{:?}", v));
151    /// assert_eq!(it.next(), Some("234.5".to_owned()));
152    /// assert_eq!(it.next(), Some("0.5".to_owned()));
153    /// assert_eq!(it.next(), None);
154    /// ```
155    pub fn retain<Cb>(&mut self, mut cb: Cb)
156    where
157        Cb: FnMut(&mut DST) -> bool,
158    {
159        let orig_write_pos = self.write_pos;
160        self.write_pos = self.read_pos;
161        let mut ofs = self.read_pos;
162        let mut writeback_pos = ofs;
163        while ofs < orig_write_pos {
164            // SAFETY: TODO
165            let v: &mut DST = unsafe {
166                let meta = &mut self.data.as_mut()[ofs..];
167                let mw = Self::meta_words();
168                let (meta, data) = meta.split_at_mut(mw);
169                &mut *make_fat_ptr(data.as_mut_ptr() as *mut (), meta)
170            };
171            let words = Self::meta_words() + BUF::round_to_words(size_of_val(v));
172            if cb(v) {
173                if writeback_pos != ofs {
174                    let d = self.data.as_mut();
175                    // writeback is always before `ofs`, so this ordering is correct.
176                    for i in 0..words {
177                        let (a, b) = d.split_at_mut(ofs + i);
178                        a[writeback_pos + i] = b[0];
179                    }
180                }
181                writeback_pos += words;
182            } else {
183                // Don't update `writeback_pos`.
184                // SAFETY: Valid pointer, won't be accessed again.
185                unsafe {
186                    ptr::drop_in_place(v);
187                }
188            }
189            ofs += words;
190        }
191        assert!(ofs == orig_write_pos);
192        self.write_pos = writeback_pos;
193    }
194}
195
196impl<BUF: DstBuf, DST> DstQueue<[DST], BUF>
197where
198    (DST, BUF::Inner): MemAligned,
199{
200    /// Pushes a set of items (cloning out of the input `slice`).
201    ///
202    /// # Examples
203    /// ```
204    /// # use devela::{DstArray, DstQueue};
205    /// let mut queue = DstQueue::<[String], DstArray<usize, 8>>::new();
206    /// queue.push_cloned(&["1".to_owned()]);
207    /// ```
208    pub fn push_cloned(&mut self, slice: &[DST]) -> Result<(), ()>
209    where
210        DST: Clone,
211    {
212        <(DST, BUF::Inner) as MemAligned>::assert_compatibility();
213        self.push_from_iter(slice.iter().cloned())
214    }
215
216    /// Pushes a set of items (copying out of the input `slice`).
217    ///
218    /// # Examples
219    /// ```
220    /// # use devela::{DstArray, DstQueue};
221    /// let mut queue = DstQueue::<[usize], DstArray<usize, 8>>::new();
222    /// queue.push_copied(&[1]);
223    /// ```
224    pub fn push_copied(&mut self, slice: &[DST]) -> Result<(), ()>
225    where
226        DST: Copy,
227    {
228        <(DST, BUF::Inner) as MemAligned>::assert_compatibility();
229        // SAFETY: Carefully constructed to maintain consistency.
230        unsafe {
231            self.push_inner(slice).map(|pii| {
232                ptr::copy(
233                    slice.as_ptr() as *const u8,
234                    pii.data.as_mut_ptr() as *mut u8,
235                    size_of_val(slice),
236                );
237            })
238        }
239    }
240
241    /// Pushes an item, populated from an exact-sized iterator.
242    ///
243    /// # Examples
244    /// ```
245    /// # use devela::{DstArray, DstQueue};
246    /// let mut stack = DstQueue::<[u8], DstArray<usize, 8>>::new();
247    /// stack.push_from_iter(0..10);
248    /// assert_eq!(stack.front().unwrap(), &[0,1,2,3,4,5,6,7,8,9]);
249    /// ```
250    pub fn push_from_iter(
251        &mut self,
252        mut iter: impl ExactSizeIterator<Item = DST>,
253    ) -> Result<(), ()> {
254        <(DST, BUF::Inner) as MemAligned>::assert_compatibility();
255        // SAFETY: API used correctly.
256        unsafe {
257            let pii = self.push_inner_raw(iter.len() * size_of::<DST>(), &[0])?;
258            list_push_gen(
259                pii.meta,
260                pii.data,
261                iter.len(),
262                |_| iter.next().unwrap(),
263                pii.reset_slot,
264                pii.reset_value,
265            );
266            Ok(())
267        }
268    }
269}
270
271impl<BUF: DstBuf> DstQueue<str, BUF> {
272    /// Pushes the contents of a `string` slice as an item onto the stack.
273    pub fn push_back_str(&mut self, string: &str) -> Result<(), ()> {
274        // SAFETY TODO
275        unsafe {
276            self.push_inner(string).map(|pii| {
277                ptr::copy(
278                    string.as_bytes().as_ptr(),
279                    pii.data.as_mut_ptr() as *mut u8,
280                    string.len(),
281                );
282            })
283        }
284    }
285}