static_queue/
lib.rs

1#![no_std]
2
3#[derive(Clone)]
4/// A queue holding **N-1** elements.
5///
6/// Why N-1? Because [T; N+1] isn't supported, and ringbuffers/circular buffers
7/// generally waste 1 element in an optimal implementation.
8/// https://github.com/rust-lang/rust/issues/76560
9pub struct Queue<T, const N: usize> {
10    array: [T; N],
11    read: usize,
12    write: usize,
13}
14
15impl<T, const N: usize> Queue<T, N>
16where
17    T: Default + Copy,
18{
19    pub fn new() -> Self {
20        Self {
21            array: [T::default(); N],
22            read: 0,
23            write: 0,
24        }
25    }
26
27    pub fn pop(&mut self) -> Option<T> {
28        if self.read == self.write {
29            return None;
30        }
31        let val = core::mem::take(&mut self.array[self.read]);
32        self.read = self.inc_wrap(self.read);
33        Some(val)
34    }
35}
36
37impl<T, const N: usize> Default for Queue<T, N>
38where
39    T: Default + Copy,
40{
41    fn default() -> Self {
42        Self::new()
43    }
44}
45
46impl<T, const N: usize> Queue<T, N> {
47    fn inc_wrap(&self, n: usize) -> usize {
48        (n + 1) % N
49    }
50
51    pub fn push(&mut self, val: T) -> bool {
52        let new_write = self.inc_wrap(self.write);
53        if new_write == self.read {
54            return false;
55        }
56        self.array[self.write] = val;
57        self.write = new_write;
58        true
59    }
60
61    pub fn pop_into(&mut self, out_val: &mut T) -> bool {
62        if self.read == self.write {
63            return false;
64        }
65        core::mem::swap(out_val, &mut self.array[self.read]);
66        self.read = self.inc_wrap(self.read);
67        true
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn test_push_pop() {
77        let mut q: Queue<u32, 4> = Queue::new();
78        assert_eq!(q.pop(), None);
79        assert!(q.push(1));
80        assert!(q.push(2));
81        assert!(q.push(3));
82        // Should be full now, next push should fail
83        assert!(!q.push(4));
84        assert_eq!(q.pop(), Some(1));
85        assert_eq!(q.pop(), Some(2));
86        assert!(q.push(4));
87        assert_eq!(q.pop(), Some(3));
88        assert_eq!(q.pop(), Some(4));
89        assert_eq!(q.pop(), None);
90    }
91
92    #[test]
93    fn test_pop_into() {
94        let mut q: Queue<u8, 3> = Queue::new();
95        assert!(q.push(10));
96        assert!(q.push(20));
97        let mut out = 0;
98        assert!(q.pop_into(&mut out));
99        assert_eq!(out, 10);
100        assert!(q.pop_into(&mut out));
101        assert_eq!(out, 20);
102        assert!(!q.pop_into(&mut out));
103    }
104
105    #[test]
106    fn test_wrap_around() {
107        let mut q: Queue<u16, 3> = Queue::new();
108        assert!(q.push(100));
109        assert!(q.push(200));
110        assert_eq!(q.pop(), Some(100));
111        assert!(q.push(300));
112        assert_eq!(q.pop(), Some(200));
113        assert_eq!(q.pop(), Some(300));
114        assert_eq!(q.pop(), None);
115    }
116
117    #[test]
118    fn test_default() {
119        let mut q: Queue<u32, 3> = Queue::default();
120        assert!(q.push(100));
121        assert!(q.push(200));
122        assert_eq!(q.pop(), Some(100));
123        assert!(q.push(300));
124        assert_eq!(q.pop(), Some(200));
125        assert_eq!(q.pop(), Some(300));
126        assert_eq!(q.pop(), None);
127    }
128
129    #[test]
130    fn test_push_into_full() {
131        let mut q: Queue<u32, 2> = Queue::new();
132        assert!(q.push(1));
133        assert!(q.pop().is_some());
134        assert!(q.push(1));
135        assert!(!q.push(1));
136    }
137
138    #[test]
139    fn test_pop_from_empty() {
140        let mut q: Queue<u32, 5> = Queue::new();
141        assert!(q.pop().is_none());
142    }
143}