#[cfg(feature = "unsafe_init")]
use core::{
mem::{self, MaybeUninit},
ptr,
};
use super::{Array, Queue, QueueIter};
use crate::{
error::{LadataError as Error, LadataResult as Result},
mem::Storage,
};
#[cfg(feature = "alloc")]
use {
crate::mem::Boxed,
alloc::{vec, vec::Vec},
};
impl<T: Clone, const CAP: usize> Queue<T, (), CAP> {
pub fn new(element: T) -> Self {
Self {
array: Array::<T, (), CAP>::with(element),
front: 0,
back: 0,
len: 0,
}
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "alloc")))]
impl<T: Clone, const CAP: usize> Queue<T, Boxed, CAP> {
pub fn new(element: T) -> Self {
Self {
array: Array::<T, Boxed, CAP>::with(element),
front: 0,
back: 0,
len: 0,
}
}
}
impl<T, S: Storage, const CAP: usize> Queue<T, S, CAP> {
#[inline(always)]
pub(super) const fn idx_front(&self, nth: usize) -> usize {
(self.front + nth) % CAP
}
pub fn from_array(arr: [T; CAP]) -> Queue<T, S, CAP> {
Self {
array: Array::new(arr),
front: 0,
back: 0,
len: CAP,
}
}
#[inline]
pub const fn len(&self) -> usize {
self.len
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub const fn is_full(&self) -> bool {
self.len() == CAP
}
#[inline]
pub const fn capacity(&self) -> usize {
CAP
}
#[inline]
pub const fn remaining_capacity(&self) -> usize {
CAP - self.len()
}
pub fn iter(&self) -> QueueIter<'_, T, S, CAP> {
QueueIter {
queue: self,
idx: 0,
}
}
pub fn extend<I>(&mut self, iterator: I) -> Result<()>
where
I: IntoIterator<Item = T>,
{
let mut iter = iterator.into_iter();
while !self.is_full() {
if let Some(e) = iter.next() {
self.push_unchecked(e);
} else {
return Ok(());
}
}
Err(Error::NotEnoughSpace(None))
}
#[inline]
pub fn push(&mut self, element: T) -> Result<()> {
if self.is_full() {
Err(Error::NotEnoughSpace(Some(1)))
} else {
self.array[self.back] = element;
self.back = (self.back + 1) % CAP;
self.len += 1;
Ok(())
}
}
#[inline(always)]
pub fn enqueue(&mut self, element: T) -> Result<()> {
self.push(element)
}
#[inline]
pub fn push_unchecked(&mut self, element: T) {
self.array[self.back] = element;
self.back = (self.back + 1) % CAP;
self.len += 1;
}
#[inline]
pub fn peek(&self) -> Result<&T> {
if self.is_empty() {
Err(Error::NotEnoughElements(1))
} else {
let fi = self.idx_front(0);
Ok(&self.array[fi])
}
}
#[inline]
pub fn peek_mut(&mut self) -> Result<&mut T> {
if self.is_empty() {
Err(Error::NotEnoughElements(1))
} else {
let fi = self.idx_front(0);
Ok(&mut self.array[fi])
}
}
#[inline]
pub fn peek_nth(&self, nth: usize) -> Result<&T> {
if self.len() <= nth {
Err(Error::NotEnoughElements(nth))
} else {
let bi = self.idx_front(nth);
Ok(&self.array[bi])
}
}
#[inline]
pub fn peek_nth_mut(&mut self, nth: usize) -> Result<&mut T> {
if self.len() <= nth {
Err(Error::NotEnoughElements(nth))
} else {
let bi = self.idx_front(nth);
Ok(&mut self.array[bi])
}
}
pub fn clear(&mut self) {
self.front = 0;
self.back = 0;
self.len = 0;
}
#[inline]
#[cfg(feature = "unsafe_pop")]
pub fn pop(&mut self) -> Result<T> {
if self.is_empty() {
Err(Error::NotEnoughElements(1))
} else {
let e = unsafe { ptr::read((self.array.get_unchecked(self.front)) as *const T) };
self.front = (self.front + 1) % CAP;
self.len -= 1;
Ok(e)
}
}
#[inline(always)]
#[cfg(feature = "unsafe_pop")]
pub fn dequeue(&mut self) -> Result<T> {
self.pop()
}
}
impl<T: Clone, S: Storage, const CAP: usize> Queue<T, S, CAP> {
#[inline]
#[cfg(not(feature = "unsafe_pop"))]
pub fn pop(&mut self) -> Result<T> {
if self.is_empty() {
Err(Error::NotEnoughElements(1))
} else {
let e = self.array[self.front].clone();
self.front = (self.front + 1) % CAP;
self.len -= 1;
Ok(e)
}
}
#[inline(always)]
#[cfg(not(feature = "unsafe_pop"))]
pub fn dequeue(&mut self) -> Result<T> {
self.pop()
}
#[cfg(feature = "alloc")]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "alloc")))]
pub fn to_vec(&self) -> Vec<T> {
if self.is_empty() {
vec![]
} else {
let mut vec = Vec::new();
let mut index = self.front;
vec.push(self.array[index].clone());
index = (index + 1) % CAP;
while index != self.back {
vec.push(self.array[index].clone());
index = (index + 1) % CAP;
}
vec
}
}
pub fn to_array<const LEN: usize>(&self) -> Option<[T; LEN]> {
if self.is_empty() || LEN > self.len() || LEN == 0 {
None
} else {
#[cfg(feature = "unsafe_init")]
let arr = {
let mut unarr: [MaybeUninit<T>; LEN] =
unsafe { MaybeUninit::uninit().assume_init() };
for (n, i) in unarr.iter_mut().enumerate().take(LEN) {
let index = (self.front + n) % CAP;
let _ = i.write(self.array[index].clone());
}
unsafe { mem::transmute_copy::<_, [T; LEN]>(&unarr) }
};
#[cfg(not(feature = "unsafe_init"))]
let arr = core::array::from_fn(|n| {
let index = (self.front + n) % CAP;
self.array[index].clone()
});
Some(arr)
}
}
}
impl<T: PartialEq, S: Storage, const CAP: usize> Queue<T, S, CAP> {
pub fn contains(&self, element: &T) -> bool {
self.iter().any(|n| n == element)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn idx() {
let q = Queue::<_, (), 5>::from([1, 2, 3]);
assert_eq![0, q.idx_front(0)];
assert_eq![1, q.idx_front(1)];
assert_eq![2, q.idx_front(2)];
assert_eq![3, q.idx_front(3)];
assert_eq![4, q.idx_front(4)];
assert_eq![0, q.idx_front(5)];
}
}