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}