limited_queue/
lib.rs

1//! # LimitedQueue
2//!
3//! `LimitedQueue<T>` is a limited queue that
4//! overrides the oldest data if trying to
5//! push a data when the queue is full.
6//!
7//! All operations are of `O(1)` complexity,
8//! except the constructor with `O(Vec::with_capacity)`.
9
10use std::{
11    marker::PhantomData,
12    mem::{replace, take},
13};
14
15/// A circular queue that overrides the oldest data
16/// if trying to push data when queue is full.
17///
18/// All operations are of `O(1)` complexity,
19/// except the constructor with `O(Vec::with_capacity)`.
20///
21/// # Example
22///
23/// ```
24/// let mut q = limited_queue::LimitedQueue::with_capacity(5);
25/// // push_ret: [None x 5, 0, 1, ..., 4]
26/// let push_ret = [[None; 5], core::array::from_fn(|i| Some(i))].concat();
27/// for (i, pr) in (0..10).zip(push_ret) {
28///     assert_eq!(q.push(i), pr);
29/// }
30/// for (n, element) in q.iter().enumerate() {
31///     assert_eq!(element.clone(), q[n]); // 5, 6, 7, 8, 9
32///     assert_eq!(element.clone(), n + 5); // 5, 6, 7, 8, 9
33/// }
34/// ```
35///
36/// # Error
37///
38/// For indexing, no bound check will occur, so please check
39/// the size of the queue with `len` method before subscription.
40///
41/// If you need boundary check, please use `get` method.
42#[derive(Debug)]
43pub struct LimitedQueue<T> {
44    q: Vec<Option<T>>,
45    front: usize,
46    rear: usize,
47    sz: usize,
48}
49
50impl<T> LimitedQueue<T> {
51    /// Vec-like constructor
52    ///
53    /// ```
54    /// use limited_queue::LimitedQueue;
55    ///
56    /// let mut q = LimitedQueue::with_capacity(2);
57    ///
58    /// assert_eq!(q.push(1), None);
59    /// assert_eq!(q.push(2), None);
60    ///
61    /// // first element popped since the capacity is 2
62    /// assert_eq!(q.push(3), Some(1));
63    ///
64    /// assert_eq!(q.peek(), Some(&2));
65    /// assert_eq!(q.pop(), Some(2));
66    /// assert_eq!(q.peek(), Some(&3));
67    /// assert_eq!(q.pop(), Some(3));
68    /// ```
69    ///
70    /// @param `cap` Capacity (limit size) of the queue
71    #[inline]
72    pub fn with_capacity(cap: usize) -> LimitedQueue<T> {
73        if cap == 0 {
74            panic!("Cannot create a LimitedQueue with zero capacity");
75        }
76        let mut q = Vec::with_capacity(cap);
77        q.resize_with(cap, Option::default);
78
79        LimitedQueue {
80            q,
81            front: 0usize,
82            rear: 0usize,
83            sz: 0usize,
84        }
85    }
86
87    /// Get the element at position `idx`,
88    /// a.k.a. the position from the start of queue
89    ///
90    /// ```
91    /// use limited_queue::LimitedQueue;
92    ///
93    /// let mut q = LimitedQueue::with_capacity(2);
94    /// q.push(1);
95    /// assert_eq!(q.get(100), None);
96    /// ```
97    #[inline]
98    pub fn get(&self, idx: usize) -> Option<&T> {
99        if idx >= self.sz {
100            None
101        } else {
102            Some(&self[idx])
103        }
104    }
105
106    /// Peek the oldest element at the front of the queue
107    ///
108    /// ```
109    /// use limited_queue::LimitedQueue;
110    ///
111    /// let mut q = LimitedQueue::with_capacity(1);
112    ///
113    /// q.push(1234);
114    /// assert_eq!(q.peek(), Some(&1234));
115    /// assert_eq!(q.pop(), Some(1234));
116    /// assert_eq!(q.peek(), None);
117    /// ```
118    #[inline]
119    pub fn peek(&self) -> Option<&T> {
120        if self.is_empty() {
121            None
122        } else {
123            self.q[self.front].as_ref()
124        }
125    }
126
127    /// Push a new element into queue,
128    /// removing the oldest element if the queue is full
129    #[inline]
130    pub fn push(&mut self, ele: T) -> Option<T> {
131        let mut popped = None;
132        if self.is_full() {
133            // popped = self.pop();
134            // use `replace` so no implicit `Default` will be called
135            popped = replace(&mut self.q[self.rear], Some(ele));
136            // and move forth the front idx to simulate `pop` operation
137            self.front = self.next_idx(self.front);
138        } else {
139            let _ = std::mem::replace(&mut self.q[self.rear], Some(ele));
140            self.sz += 1;
141        }
142        self.rear = self.next_idx(self.rear);
143        popped
144    }
145
146    /// Inner method: next index of the inner vector
147    #[inline]
148    fn next_idx(&self, idx: usize) -> usize {
149        (idx + 1) % self.q.capacity()
150    }
151
152    #[inline]
153    pub fn is_empty(&self) -> bool {
154        self.sz == 0
155    }
156
157    #[inline]
158    pub fn is_full(&self) -> bool {
159        self.sz == self.q.capacity()
160    }
161
162    /// Get queue length
163    ///
164    /// ```
165    /// use limited_queue::LimitedQueue;
166    ///
167    /// let mut q = LimitedQueue::with_capacity(3);
168    ///
169    /// q.push(1234);
170    /// assert_eq!(q.len(), 1);
171    /// q.push(1234);
172    /// assert_eq!(q.len(), 2);
173    /// q.push(1234);
174    /// assert_eq!(q.len(), 3);
175    /// q.push(1234);
176    /// assert_eq!(q.len(), 3);
177    /// ```
178    #[inline]
179    pub fn len(&self) -> usize {
180        self.sz
181    }
182
183    /// To traverse all the elements in
184    /// `LimitedQueue`, for example:
185    ///
186    /// ```
187    /// use limited_queue::LimitedQueue;
188    ///
189    /// let mut q = LimitedQueue::with_capacity(5);
190    /// for i in 0..10 {
191    ///     q.push(i);
192    /// }
193    /// for (&n, element) in q.iter().zip(5usize..=9) {
194    ///     // will be 5, 6, 7, 8, 9 since 0 ~ 4
195    ///     // are popped because the queue is full
196    ///     assert_eq!(element.clone(), n);
197    /// }
198    /// ```
199    #[inline]
200    pub fn iter(&self) -> LimitedQueueIterator<T> {
201        LimitedQueueIterator {
202            lq: self,
203            front_idx: 0,
204            back_idx: self.sz,
205        }
206    }
207
208    /// Returns a mutable iterator over the queue.
209    ///
210    /// # Example
211    ///
212    /// ```
213    /// use limited_queue::LimitedQueue;
214    ///
215    /// let mut q = LimitedQueue::with_capacity(3);
216    /// q.push(1);
217    /// q.push(2);
218    ///
219    /// for element in q.iter_mut() {
220    ///     *element *= 2;
221    /// }
222    ///
223    /// assert_eq!(q.pop(), Some(2));
224    /// assert_eq!(q.pop(), Some(4));
225    /// assert_eq!(q.pop(), None);
226    /// ```
227    #[inline]
228    pub fn iter_mut(&mut self) -> LimitedQueueIteratorMut<T> {
229        let len = self.sz;
230        let cap = self.q.capacity();
231        let front = self.front;
232        let q_ptr = self.q.as_mut_ptr(); // get raw pointer to Vec's buffer
233        LimitedQueueIteratorMut {
234            q_ptr,
235            front,
236            capacity: cap,
237            front_idx: 0,
238            back_idx: len,
239            _marker: PhantomData, // PhantomData for 'a lifetime
240        }
241    }
242
243    /// `O(1)` method to (lazily) clear all the elements
244    ///
245    /// ```
246    /// use limited_queue::LimitedQueue;
247    ///
248    /// let mut q = LimitedQueue::with_capacity(5);
249    /// for i in 0..10 {
250    ///     q.push(i);
251    /// }
252    /// q.clear();
253    /// assert_eq!(q.peek(), None);
254    /// assert_eq!(q.is_empty(), true);
255    /// ```
256    #[inline]
257    pub fn clear(&mut self) {
258        self.front = 0;
259        self.rear = 0;
260        self.sz = 0;
261    }
262
263    /// private method of boundary check and indexing
264    #[inline]
265    fn indexing(&self, idx: usize) -> usize {
266        if idx >= self.sz {
267            panic!("Invalid subscription index: {}", idx)
268        }
269        (idx + self.front) % self.q.capacity()
270    }
271
272    /// Pop the first element from queue,
273    /// will replace the element in queue
274    ///
275    /// ```
276    /// use limited_queue::LimitedQueue;
277    ///
278    /// let mut q = LimitedQueue::with_capacity(1);
279    ///
280    /// q.push(1234);
281    /// assert_eq!(q.pop(), Some(1234));
282    /// assert_eq!(q.pop(), None);
283    /// ```
284    #[inline]
285    pub fn pop(&mut self) -> Option<T> {
286        if self.is_empty() {
287            None
288        } else {
289            let ret = take(&mut self.q[self.front]);
290            self.front = self.next_idx(self.front);
291            self.sz -= 1;
292            ret
293        }
294    }
295}
296
297impl<T> std::ops::Index<usize> for LimitedQueue<T> {
298    type Output = T;
299
300    #[inline]
301    fn index(&self, idx: usize) -> &Self::Output {
302        let real_idx = self.indexing(idx);
303        self.q[real_idx].as_ref().unwrap()
304    }
305}
306
307impl<T> std::ops::IndexMut<usize> for LimitedQueue<T> {
308    #[inline]
309    fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
310        let real_idx = self.indexing(idx);
311        self.q[real_idx].as_mut().unwrap()
312    }
313}
314
315pub struct LimitedQueueIterator<'a, T> {
316    lq: &'a LimitedQueue<T>,
317    front_idx: usize,
318    back_idx: usize,
319}
320
321#[cfg(not(tarpaulin_include))]
322impl<'a, T> Iterator for LimitedQueueIterator<'a, T> {
323    type Item = &'a T;
324
325    fn next(&mut self) -> Option<Self::Item> {
326        if self.front_idx == self.back_idx {
327            None // the end of iteration
328        } else {
329            let cur_idx = self.front_idx;
330            self.front_idx += 1;
331            Some(&self.lq[cur_idx])
332        }
333    }
334}
335
336impl<'a, T> DoubleEndedIterator for LimitedQueueIterator<'a, T> {
337    fn next_back(&mut self) -> Option<Self::Item> {
338        if self.front_idx == self.back_idx {
339            None // the end of iteration
340        } else {
341            self.back_idx -= 1;
342            let cur_idx = self.back_idx;
343            Some(&self.lq[cur_idx])
344        }
345    }
346}
347
348/// A mutable, double-ended iterator over a `LimitedQueue`.
349pub struct LimitedQueueIteratorMut<'a, T> {
350    q_ptr: *mut Option<T>, // raw pointer to the Vec's data
351    front: usize,          // internal Vec's front index
352    capacity: usize,
353    front_idx: usize,                // logical queue index (0..sz)
354    back_idx: usize,                 // logical queue index (0..sz)
355    _marker: PhantomData<&'a mut T>, // marker for 'a lifetime
356}
357
358impl<'a, T> Iterator for LimitedQueueIteratorMut<'a, T> {
359    type Item = &'a mut T;
360
361    fn next(&mut self) -> Option<Self::Item> {
362        if self.front_idx == self.back_idx {
363            None
364        } else {
365            let cur_idx = self.front_idx;
366            self.front_idx += 1;
367            let real_idx = (cur_idx + self.front) % self.capacity;
368
369            unsafe {
370                // get pointer to the real_idx-th element in Vec
371                let elem_ptr = self.q_ptr.add(real_idx);
372
373                // convert raw pointer back to an 'a lifetime mutable reference
374                // this is safe because:
375                // 1. _marker ensures 'a is the lifetime of LimitedQueueMutIterator
376                // 2. we ensure real_idx is within self.q.capacity()
377                // 3. cur_idx < self.sz, so this position must be Some(T)
378                let opt_ref = &mut *elem_ptr;
379
380                // .unwrap() is safe because
381                // logical index (cur_idx) < self.sz,
382                // which means self.q[real_idx] must be Some(T)
383                Some(opt_ref.as_mut().unwrap())
384            }
385        }
386    }
387}
388
389impl<'a, T> DoubleEndedIterator for LimitedQueueIteratorMut<'a, T> {
390    fn next_back(&mut self) -> Option<Self::Item> {
391        if self.front_idx == self.back_idx {
392            None
393        } else {
394            // move index back
395            self.back_idx -= 1;
396            let cur_idx = self.back_idx;
397            let real_idx = (cur_idx + self.front) % self.capacity;
398
399            unsafe {
400                let elem_ptr = self.q_ptr.add(real_idx);
401                let opt_ref = &mut *elem_ptr;
402
403                // .unwrap() is also safe here
404                Some(opt_ref.as_mut().unwrap())
405            }
406        }
407    }
408}
409
410#[cfg(test)]
411mod tests {
412    use std::panic;
413
414    use rand::Rng;
415
416    use crate::LimitedQueue;
417
418    // Helper struct that doesn't implement Default
419    #[derive(Debug, PartialEq, Eq, Clone)]
420    struct NoDefault(i32);
421
422    #[test]
423    fn test_pop_no_default() {
424        let mut q = LimitedQueue::with_capacity(2);
425        q.push(NoDefault(1));
426        q.push(NoDefault(2));
427        assert_eq!(q.push(NoDefault(3)), Some(NoDefault(1)));
428        assert_eq!(q.peek(), Some(&NoDefault(2)));
429        assert_eq!(q.pop(), Some(NoDefault(2)));
430        assert_eq!(q.pop(), Some(NoDefault(3)));
431        assert_eq!(q.pop(), None);
432    }
433
434    #[test]
435    fn test_iter() {
436        let mut q = crate::LimitedQueue::with_capacity(5);
437        // push_ret: [None x 5, 0, 1, ..., 4]
438        let push_ret = [[None; 5], core::array::from_fn(|i| Some(i))].concat();
439        for (i, pr) in (0..10).zip(push_ret) {
440            assert_eq!(q.push(i), pr);
441        }
442        assert_eq!(q.len(), 5);
443        for (n, element) in q.iter().enumerate() {
444            assert_eq!(element.clone(), q[n]); // 5, 6, 7, 8, 9
445            assert_eq!(element.clone(), n + 5); // 5, 6, 7, 8, 9
446        }
447
448        // test DoubleEndedIterator
449        for (n, element) in q.iter().rev().enumerate() {
450            assert_eq!(element.clone(), q[4 - n]); // 5, 6, 7, 8, 9
451            assert_eq!(element.clone(), 9 - n); // 5, 6, 7, 8, 9
452        }
453    }
454
455    #[test]
456    fn test_iter_mut() {
457        let mut q = LimitedQueue::with_capacity(5);
458        for i in 0..5 {
459            q.push(i); // 0, 1, 2, 3, 4
460        }
461
462        for element in q.iter_mut() {
463            *element += 10;
464        }
465
466        // Queue should now contain 10, 11, 12, 13, 14
467        for (n, element) in q.iter().enumerate() {
468            assert_eq!(*element, n + 10);
469        }
470
471        // Test push overflow with modified data
472        assert_eq!(q.push(99), Some(10)); // pops 10
473        assert_eq!(q.peek(), Some(&11));
474    }
475
476    #[test]
477    fn test_double_ended_iter_mut() {
478        let mut q = LimitedQueue::with_capacity(5);
479        for i in 0..5 {
480            q.push(i); // 0, 1, 2, 3, 4
481        }
482
483        // Modify from both ends
484        let mut iter_mut = q.iter_mut();
485        *iter_mut.next().unwrap() = 100; // 0 -> 100
486        *iter_mut.next_back().unwrap() = 400; // 4 -> 400
487        *iter_mut.next().unwrap() = 200; // 1 -> 200
488        *iter_mut.next_back().unwrap() = 300; // 3 -> 300
489                                              // 2 is untouched
490
491        // Check final state
492        let mut iter = q.iter();
493        assert_eq!(iter.next(), Some(&100));
494        assert_eq!(iter.next(), Some(&200));
495        assert_eq!(iter.next(), Some(&2));
496        assert_eq!(iter.next(), Some(&300));
497        assert_eq!(iter.next(), Some(&400));
498        assert_eq!(iter.next(), None);
499    }
500
501    #[test]
502    fn test_change_size() {
503        const MAX_SZ: usize = 25;
504        let mut q: LimitedQueue<i32> = crate::LimitedQueue::with_capacity(MAX_SZ);
505        let mut sz = 0;
506        let mut rng = rand::thread_rng();
507
508        for _ in 0..1000 {
509            let op = rng.gen_range(0..=2);
510            match op {
511                0 => {
512                    if q.push(rng.gen()).is_none() {
513                        sz += 1
514                    };
515                }
516                1 => {
517                    if q.pop().is_some() {
518                        sz -= 1
519                    };
520                }
521                _ => {
522                    assert!(match sz {
523                        0 => q.is_empty() && q.pop().is_none() && q.peek().is_none(),
524                        MAX_SZ => q.is_full(),
525                        _ => sz == q.len() && sz < MAX_SZ,
526                    });
527                }
528            };
529        }
530    }
531
532    #[test]
533    #[should_panic]
534    fn test_zero_len_invalid_indexing() {
535        LimitedQueue::<i32>::with_capacity(0)[0];
536    }
537
538    #[test]
539    fn test_invalid_indexing() {
540        // shadow out panic message for unwind in the loop
541        let old_hook = panic::take_hook();
542        panic::set_hook(Box::new(|_info| {}));
543
544        let mut q = LimitedQueue::with_capacity(5);
545        q.push(1);
546        for i in 5..100 {
547            let invalid_access = || q[i];
548            let should_be_false = panic::catch_unwind(invalid_access).is_err();
549            if !should_be_false {
550                // reset panic hook to show error message
551                panic::set_hook(old_hook);
552                // panic with reason
553                panic!("Indexing with idx: {} cannot trigger panic.", i);
554            }
555        }
556
557        panic::set_hook(old_hook);
558    }
559
560    #[test]
561    fn test_clear() {
562        let mut q = LimitedQueue::with_capacity(10);
563
564        // Test clear on empty
565        q.clear();
566        assert_eq!(q.len(), 0);
567        assert!(q.is_empty());
568
569        // Test clear on partially full
570        for _ in 0..3 {
571            q.push(1);
572        }
573        assert_eq!(q.len(), 3);
574        q.clear();
575        assert_eq!(q.len(), 0);
576        assert_eq!(q.peek(), None);
577        assert!(q.is_empty());
578
579        // Test clear on full
580        for i in 0..10 {
581            q.push(i);
582        }
583        assert!(q.is_full());
584        q.clear();
585        assert!(q.is_empty());
586        assert_eq!(q.len(), 0);
587        assert_eq!(q.peek(), None);
588
589        // Test functionality after clear
590        assert_eq!(q.push(100), None);
591        assert_eq!(q.len(), 1);
592        assert_eq!(q.peek(), Some(&100));
593        assert_eq!(q.pop(), Some(100));
594        assert_eq!(q.len(), 0);
595        assert!(q.is_empty());
596    }
597
598    #[test]
599    fn test_capacity_one() {
600        let mut q = LimitedQueue::with_capacity(1);
601        assert!(q.is_empty());
602        assert_eq!(q.push(1), None);
603        assert!(q.is_full());
604        assert_eq!(q.peek(), Some(&1));
605        assert_eq!(q.push(2), Some(1)); // Overwrite
606        assert!(q.is_full());
607        assert_eq!(q.peek(), Some(&2));
608        assert_eq!(q.pop(), Some(2));
609        assert!(q.is_empty());
610        assert_eq!(q.peek(), None);
611        assert_eq!(q.pop(), None);
612        assert_eq!(q.push(3), None);
613        assert_eq!(q.len(), 1);
614        assert_eq!(q.peek(), Some(&3));
615    }
616
617    #[test]
618    #[should_panic]
619    fn test_capacity_zero_push_panic() {
620        let mut q = LimitedQueue::<i32>::with_capacity(0);
621        q.push(1); // This should panic
622    }
623
624    #[test]
625    fn test_get_method() {
626        let mut q = LimitedQueue::with_capacity(3);
627        assert_eq!(q.get(0), None); // Empty
628        assert_eq!(q.get(1), None);
629
630        q.push(10); // 10
631        q.push(20); // 10, 20
632        assert_eq!(q.get(0), Some(&10));
633        assert_eq!(q.get(1), Some(&20));
634        assert_eq!(q.get(2), None); // Out of bounds (len)
635
636        q.push(30); // 10, 20, 30 (full)
637        assert_eq!(q.get(2), Some(&30));
638        assert_eq!(q.get(3), None);
639
640        q.push(40); // 20, 30, 40 (wrapped)
641        assert_eq!(q.get(0), Some(&20));
642        assert_eq!(q.get(1), Some(&30));
643        assert_eq!(q.get(2), Some(&40));
644        assert_eq!(q.get(3), None); // Out of bounds (len)
645    }
646
647    #[test]
648    fn test_iter_empty() {
649        let mut q = LimitedQueue::<i32>::with_capacity(5);
650        assert_eq!(q.iter().next(), None);
651        assert_eq!(q.iter().next_back(), None);
652        assert_eq!(q.iter_mut().next(), None);
653        assert_eq!(q.iter_mut().next_back(), None);
654    }
655
656    #[test]
657    fn test_iter_mixed() {
658        let mut q = LimitedQueue::with_capacity(5);
659        for i in 0..5 {
660            q.push(i); // 0, 1, 2, 3, 4
661        }
662
663        let mut iter = q.iter();
664        assert_eq!(iter.next(), Some(&0));
665        assert_eq!(iter.next_back(), Some(&4));
666        assert_eq!(iter.next(), Some(&1));
667        assert_eq!(iter.next_back(), Some(&3));
668        assert_eq!(iter.next(), Some(&2));
669        assert_eq!(iter.next(), None);
670        assert_eq!(iter.next_back(), None);
671    }
672
673    #[test]
674    fn test_index_mut() {
675        let mut q = LimitedQueue::with_capacity(3);
676        q.push(1);
677        q.push(2); // q = [1, 2]
678
679        q[0] = 100; // Test IndexMut
680        q[1] = 200;
681
682        assert_eq!(q.get(0), Some(&100));
683        assert_eq!(q.get(1), Some(&200));
684    }
685
686    #[test]
687    fn test_debug_format() {
688        let mut q = LimitedQueue::with_capacity(3);
689        q.push(1);
690        q.push(2);
691
692        // Test whether debug works as expected
693        let formatted = format!("{:?}", q);
694        assert!(formatted.contains("LimitedQueue"));
695        assert!(formatted.contains("Some(1)"));
696        assert!(formatted.contains("Some(2)"));
697    }
698
699    #[test]
700    #[should_panic(expected = "Invalid subscription index: 1")]
701    fn test_indexing_panic_simple() {
702        let mut q = LimitedQueue::with_capacity(3);
703        q.push(1); // sz = 1
704        let _ = q[1]; // Accessing q[1] when sz=1 should panic
705    }
706}