use std::mem::MaybeUninit;
use std::fmt::Debug;
use std::ptr;
pub struct Queue<T, const N: usize>
where
T: Debug,
{
queue: [MaybeUninit<T>; N],
front: usize,
rear: usize,
}
impl<T, const N: usize> Queue<T, N>
where
T: Debug,
{
pub fn new() -> Self {
Self {
queue: unsafe { MaybeUninit::uninit().assume_init() },
front: 0,
rear: 0,
}
}
pub fn is_empty(&self) -> bool {
self.front == self.rear
}
fn is_full(&self) -> bool {
(self.rear + 1) % N == self.front
}
pub fn capacity(&self) -> usize {
N - 1
}
pub fn push(&mut self, data: T) -> Result<(), &'_ str> {
if self.is_full() {
return Err("queue is full");
}
self.queue[self.rear].write(data);
self.rear = (self.rear + 1) % N;
Ok(())
}
pub fn pop(&mut self) -> Option<T> {
if self.is_empty() {
return None;
}
let data = unsafe {
let data = ptr::read(self.queue[self.front].as_ptr());
self.queue[self.front] = MaybeUninit::uninit();
data
};
self.front = (self.front + 1) % N;
Some(data)
}
}
impl<T, const N: usize> Drop for Queue<T, N>
where
T: Debug,
{
fn drop(&mut self) {
let mut idx = self.front;
while idx != self.rear {
unsafe {
ptr::drop_in_place(self.queue[idx].as_mut_ptr());
}
idx = (idx + 1) % N;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_queue_operations() {
let mut queue: Queue<i32, 3> = Queue::new();
assert!(queue.is_empty());
assert_eq!(queue.pop(), None);
assert_eq!(queue.capacity(), 2);
assert!(queue.push(1).is_ok());
assert!(!queue.is_empty());
assert!(queue.push(2).is_ok());
assert!(queue.push(3).is_err());
assert_eq!(queue.pop(), Some(1));
assert_eq!(queue.pop(), Some(2));
assert!(queue.pop().is_none());
assert!(queue.push(3).is_ok());
assert!(queue.push(4).is_ok());
assert!(queue.push(5).is_err());
assert_eq!(queue.pop(), Some(3));
assert_eq!(queue.pop(), Some(4));
assert!(queue.pop().is_none());
assert!(queue.is_empty());
}
#[test]
fn test_queue_full_and_empty() {
let mut queue: Queue<i32, 2> = Queue::new();
assert!(queue.push(1).is_ok());
assert!(queue.push(2).is_err());
assert_eq!(queue.pop(), Some(1));
assert!(queue.pop().is_none());
assert!(queue.push(4).is_ok());
assert!(queue.push(5).is_err());
}
}