#![cfg_attr(not(feature = "use_std"), no_std)]
#![cfg_attr(feature = "unstable", feature(const_maybe_uninit_assume_init))]
#![cfg_attr(feature = "unstable", feature(const_maybe_uninit_uninit_array))]
#![cfg_attr(feature = "unstable", feature(const_mut_refs))]
#![cfg_attr(feature = "unstable", feature(const_slice_index))]
#![cfg_attr(feature = "unstable", feature(const_slice_split_at_mut))]
#![cfg_attr(feature = "unstable", feature(const_slice_split_at_not_mut))]
#![cfg_attr(feature = "unstable", feature(const_trait_impl))]
#![cfg_attr(feature = "unstable", feature(maybe_uninit_slice))]
#![cfg_attr(feature = "unstable", feature(maybe_uninit_uninit_array))]
#![cfg_attr(feature = "unstable", feature(maybe_uninit_write_slice))]
#![cfg_attr(feature = "unstable", feature(one_sided_range))]
#![cfg_attr(feature = "unstable", feature(slice_take))]
#![cfg_attr(all(feature = "unstable", feature = "use_std"), feature(new_uninit))]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![warn(pointer_structural_match)]
#![warn(unreachable_pub)]
#![warn(unused_qualifications)]
mod iter;
#[cfg(feature = "use_std")]
mod io;
#[cfg(test)]
mod tests;
use core::cmp::Ordering;
use core::fmt;
use core::hash::Hash;
use core::hash::Hasher;
use core::mem::MaybeUninit;
use core::mem;
use core::ops::Range;
use core::ops::RangeBounds;
use core::ptr;
pub use crate::iter::IntoIter;
pub use crate::iter::Iter;
pub use crate::iter::IterMut;
macro_rules! unstable_const_fn {
(
$( #[ $meta:meta ] )*
$vis:vis const fn $fn:ident $( <{ $( $generics:tt )* }> )? ( $( $arg:tt )* )
$( -> $out:ty )? { $( $tt:tt )* }
) => {
#[cfg(feature = "unstable")]
$(#[$meta])*
$vis const fn $fn $(<$($generics)*>)? ($($arg)*) $(-> $out)? { $($tt)* }
#[cfg(not(feature = "unstable"))]
$(#[$meta])*
$vis fn $fn $(<$($generics)*>)? ($($arg)*) $(-> $out)? { $($tt)* }
}
}
#[cfg(feature = "unstable")]
macro_rules! unstable_const_impl {
(
$( #[ $meta:meta ] )*
impl $( <{ $( $generics:tt )* }> )? const $trait:ident for $type:ty { $( $tt:tt )* }
) => {
$(#[$meta])*
impl $(<$($generics)*>)? const $trait for $type { $($tt)* }
}
}
#[cfg(not(feature = "unstable"))]
macro_rules! unstable_const_impl {
(
$( #[ $meta:meta ] )*
impl $( <{ $( $generics:tt )* }> )? const $trait:ident for $type:ty { $( $tt:tt )* }
) => {
$(#[$meta])*
impl $(<$($generics)*>)? $trait for $type { $($tt)* }
}
}
use unstable_const_fn;
#[inline]
const fn add_mod(x: usize, y: usize, m: usize) -> usize {
debug_assert!(m > 0);
debug_assert!(x <= m);
debug_assert!(y <= m);
let (z, overflow) = x.overflowing_add(y);
(z + (overflow as usize) * (usize::MAX % m + 1)) % m
}
#[inline]
const fn sub_mod(x: usize, y: usize, m: usize) -> usize {
debug_assert!(m > 0);
debug_assert!(x <= m);
debug_assert!(y <= m);
add_mod(x, m - y, m)
}
pub struct CircularBuffer<const N: usize, T> {
size: usize,
start: usize,
items: [MaybeUninit<T>; N],
}
impl<const N: usize, T> CircularBuffer<N, T> {
#[inline]
#[must_use]
pub const fn new() -> Self {
#[cfg(feature = "unstable")]
{
Self {
size: 0,
start: 0,
items: MaybeUninit::uninit_array(),
}
}
#[cfg(not(feature = "unstable"))]
{
Self {
size: 0,
start: 0,
items: unsafe { MaybeUninit::<[MaybeUninit<T>; N]>::uninit().assume_init() },
}
}
}
#[must_use]
#[cfg(feature = "use_std")]
#[cfg(feature = "unstable")]
pub fn boxed() -> Box<Self> {
let mut uninit: Box<MaybeUninit<Self>> = Box::new_uninit();
let ptr = uninit.as_mut_ptr();
unsafe {
std::ptr::addr_of_mut!((*ptr).size).write(0);
std::ptr::addr_of_mut!((*ptr).start).write(0);
uninit.assume_init()
}
}
#[must_use]
#[cfg(feature = "use_std")]
#[cfg(not(feature = "unstable"))]
pub fn boxed() -> Box<Self> {
unsafe {
let layout = std::alloc::Layout::new::<Self>();
let ptr = std::alloc::alloc(layout) as *mut Self;
std::ptr::addr_of_mut!((*ptr).size).write(0);
std::ptr::addr_of_mut!((*ptr).start).write(0);
Box::from_raw(ptr)
}
}
#[inline]
pub const fn len(&self) -> usize {
self.size
}
#[inline]
pub const fn capacity(&self) -> usize {
N
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.size == 0
}
#[inline]
pub const fn is_full(&self) -> bool {
self.size == N
}
unstable_const_fn! {
#[inline]
#[must_use]
pub const fn iter(&self) -> Iter<'_, T> {
Iter::new(self)
}
}
unstable_const_fn! {
#[inline]
#[must_use]
pub const fn iter_mut(&mut self) -> IterMut<'_, T> {
IterMut::new(self)
}
}
#[inline]
#[must_use]
pub fn range<R>(&self, range: R) -> Iter<'_, T>
where R: RangeBounds<usize>
{
Iter::over_range(self, range)
}
#[inline]
#[must_use]
pub fn range_mut<R>(&mut self, range: R) -> IterMut<'_, T>
where R: RangeBounds<usize>
{
IterMut::over_range(self, range)
}
unstable_const_fn! {
#[inline]
pub const fn as_slices(&self) -> (&[T], &[T]) {
if N == 0 || self.size == 0 {
return (&[], &[]);
}
debug_assert!(self.start < N, "start out-of-bounds");
debug_assert!(self.size <= N, "size out-of-bounds");
let start = self.start;
let end = add_mod(self.start, self.size, N);
let (left, right) = if start < end {
(&self.items[start..end], &[][..])
} else {
let (right, left) = self.items.split_at(end);
let left = &left[start - end..];
(left, right)
};
#[cfg(feature = "unstable")]
unsafe {
(MaybeUninit::slice_assume_init_ref(left),
MaybeUninit::slice_assume_init_ref(right))
}
#[cfg(not(feature = "unstable"))]
unsafe {
(&*(left as *const [MaybeUninit<T>] as *const [T]),
&*(right as *const [MaybeUninit<T>] as *const [T]))
}
}
}
unstable_const_fn! {
#[inline]
pub const fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) {
if N == 0 || self.size == 0 {
return (&mut [][..], &mut [][..]);
}
debug_assert!(self.start < N, "start out-of-bounds");
debug_assert!(self.size <= N, "size out-of-bounds");
let start = self.start;
let end = add_mod(self.start, self.size, N);
let (left, right) = if start < end {
(&mut self.items[start..end], &mut [][..])
} else {
let (right, left) = self.items.split_at_mut(end);
let left = &mut left[start - end..];
(left, right)
};
#[cfg(feature = "unstable")]
unsafe {
(MaybeUninit::slice_assume_init_mut(left),
MaybeUninit::slice_assume_init_mut(right))
}
#[cfg(not(feature = "unstable"))]
unsafe {
(&mut *(left as *mut [MaybeUninit<T>] as *mut [T]),
&mut *(right as *mut [MaybeUninit<T>] as *mut [T]))
}
}
}
#[inline]
fn front_maybe_uninit_mut(&mut self) -> &mut MaybeUninit<T> {
debug_assert!(self.size > 0, "empty buffer");
debug_assert!(self.start < N, "start out-of-bounds");
&mut self.items[self.start]
}
#[inline]
const fn front_maybe_uninit(&self) -> &MaybeUninit<T> {
debug_assert!(self.size > 0, "empty buffer");
debug_assert!(self.size <= N, "size out-of-bounds");
debug_assert!(self.start < N, "start out-of-bounds");
&self.items[self.start]
}
#[inline]
const fn back_maybe_uninit(&self) -> &MaybeUninit<T> {
debug_assert!(self.size > 0, "empty buffer");
debug_assert!(self.size <= N, "size out-of-bounds");
debug_assert!(self.start < N, "start out-of-bounds");
let back = add_mod(self.start, self.size - 1, N);
&self.items[back]
}
#[inline]
fn back_maybe_uninit_mut(&mut self) -> &mut MaybeUninit<T> {
debug_assert!(self.size > 0, "empty buffer");
debug_assert!(self.size <= N, "size out-of-bounds");
debug_assert!(self.start < N, "start out-of-bounds");
let back = add_mod(self.start, self.size - 1, N);
&mut self.items[back]
}
#[inline]
const fn get_maybe_uninit(&self, index: usize) -> &MaybeUninit<T> {
debug_assert!(self.size > 0, "empty buffer");
debug_assert!(index < N, "index out-of-bounds");
debug_assert!(self.start < N, "start out-of-bounds");
let index = add_mod(self.start, index, N);
&self.items[index]
}
#[inline]
fn get_maybe_uninit_mut(&mut self, index: usize) -> &mut MaybeUninit<T> {
debug_assert!(self.size > 0, "empty buffer");
debug_assert!(index < N, "index out-of-bounds");
debug_assert!(self.start < N, "start out-of-bounds");
let index = add_mod(self.start, index, N);
&mut self.items[index]
}
#[inline]
fn slices_uninit_mut(&mut self) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>]) {
if N == 0 {
return (&mut [][..], &mut [][..]);
}
debug_assert!(self.start < N, "start out-of-bounds");
debug_assert!(self.size <= N, "size out-of-bounds");
let start = self.start;
let end = add_mod(start, self.size, N);
if end < start {
(&mut self.items[end..start], &mut [][..])
} else {
let (left, right) = self.items.split_at_mut(end);
let left = &mut left[..start];
(right, left)
}
}
#[inline]
fn inc_start(&mut self) {
debug_assert!(self.start < N, "start out-of-bounds");
self.start = add_mod(self.start, 1, N);
}
#[inline]
fn dec_start(&mut self) {
debug_assert!(self.start < N, "start out-of-bounds");
self.start = sub_mod(self.start, 1, N);
}
#[inline]
fn inc_size(&mut self) {
debug_assert!(self.size <= N, "size out-of-bounds");
self.size += 1;
debug_assert!(self.size <= N, "size exceeding capacity");
}
#[inline]
fn dec_size(&mut self) {
debug_assert!(self.size > 0, "size is 0");
self.size -= 1;
}
#[inline]
unsafe fn drop_range(&mut self, range: Range<usize>) {
if range.is_empty() {
return;
}
debug_assert!(self.start < N, "start out-of-bounds");
debug_assert!(self.size <= N, "size out-of-bounds");
debug_assert!(range.end <= self.size, "end of range out-of-bounds");
debug_assert!(range.start == 0 || range.end == self.size,
"range does not include boundary of the buffer");
struct Dropper<'a, T>(&'a mut [MaybeUninit<T>]);
impl<'a, T> Drop for Dropper<'a, T> {
#[inline]
fn drop(&mut self) {
#[cfg(feature = "unstable")]
unsafe { ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(self.0)); }
#[cfg(not(feature = "unstable"))]
unsafe { ptr::drop_in_place(&mut *(self.0 as *mut [MaybeUninit<T>] as *mut [T])); }
}
}
let drop_from = add_mod(self.start, range.start, N);
let drop_to = add_mod(self.start, range.end, N);
let (right, left) = if drop_from < drop_to {
(&mut self.items[drop_from..drop_to], &mut [][..])
} else {
let (left, right) = self.items.split_at_mut(drop_from);
let left = &mut left[..drop_to];
(right, left)
};
let _left = Dropper(left);
let _right = Dropper(right);
}
#[inline]
pub fn back(&self) -> Option<&T> {
if N == 0 || self.size == 0 {
return None;
}
Some(unsafe { self.back_maybe_uninit().assume_init_ref() })
}
#[inline]
pub fn back_mut(&mut self) -> Option<&mut T> {
if N == 0 || self.size == 0 {
return None;
}
Some(unsafe { self.back_maybe_uninit_mut().assume_init_mut() })
}
#[inline]
pub fn front(&self) -> Option<&T> {
if N == 0 || self.size == 0 {
return None;
}
Some(unsafe { self.front_maybe_uninit().assume_init_ref() })
}
#[inline]
pub fn front_mut(&mut self) -> Option<&mut T> {
if N == 0 || self.size == 0 {
return None;
}
Some(unsafe { self.front_maybe_uninit_mut().assume_init_mut() })
}
#[inline]
pub fn get(&self, index: usize) -> Option<&T> {
if N == 0 || index >= self.size {
return None;
}
Some(unsafe { self.get_maybe_uninit(index).assume_init_ref() })
}
#[inline]
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
if N == 0 || index >= self.size {
return None;
}
Some(unsafe { self.get_maybe_uninit_mut(index).assume_init_mut() })
}
pub fn push_back(&mut self, item: T) {
if N == 0 {
return;
}
if self.size >= N {
unsafe { ptr::drop_in_place(self.front_maybe_uninit_mut().as_mut_ptr()); }
self.front_maybe_uninit_mut().write(item);
self.inc_start();
} else {
self.inc_size();
self.back_maybe_uninit_mut().write(item);
}
}
pub fn push_front(&mut self, item: T) {
if N == 0 {
return;
}
if self.size >= N {
unsafe { ptr::drop_in_place(self.back_maybe_uninit_mut().as_mut_ptr()); }
self.back_maybe_uninit_mut().write(item);
self.dec_start();
} else {
self.inc_size();
self.dec_start();
self.front_maybe_uninit_mut().write(item);
}
}
pub fn pop_back(&mut self) -> Option<T> {
if N == 0 || self.size == 0 {
return None;
}
let back = unsafe { self.back_maybe_uninit().assume_init_read() };
self.dec_size();
Some(back)
}
pub fn pop_front(&mut self) -> Option<T> {
if N == 0 || self.size == 0 {
return None;
}
let back = unsafe { self.front_maybe_uninit().assume_init_read() };
self.dec_size();
self.inc_start();
Some(back)
}
pub fn remove(&mut self, index: usize) -> Option<T> {
if N == 0 || index >= self.size {
return None;
}
let index = add_mod(self.start, index, N);
let back_index = add_mod(self.start, self.size - 1, N);
let item = unsafe { self.items[index].assume_init_read() };
unsafe {
let ptr = self.items.as_mut_ptr();
if back_index >= index {
ptr::copy(ptr.add(index).add(1), ptr.add(index), back_index - index);
} else {
ptr::copy(ptr.add(index).add(1), ptr.add(index), N - index);
ptr::copy(ptr, ptr.add(N - 1), 1);
ptr::copy(ptr.add(1), ptr, back_index);
}
}
self.dec_size();
Some(item)
}
pub fn swap(&mut self, i: usize, j: usize) {
assert!(i < self.size, "i index out-of-bounds");
assert!(j < self.size, "j index out-of-bounds");
if i != j {
let i = add_mod(self.start, i, N);
let j = add_mod(self.start, j, N);
unsafe { ptr::swap_nonoverlapping(&mut self.items[i], &mut self.items[j], 1) };
}
}
pub fn swap_remove_back(&mut self, index: usize) -> Option<T> {
if index >= self.size {
return None;
}
self.swap(index, self.size - 1);
self.pop_back()
}
pub fn swap_remove_front(&mut self, index: usize) -> Option<T> {
if index >= self.size {
return None;
}
self.swap(index, 0);
self.pop_front()
}
pub fn truncate_back(&mut self, len: usize) {
if N == 0 || len >= self.size {
return;
}
let drop_range = len..self.size;
unsafe { self.drop_range(drop_range) };
self.size = len;
}
pub fn truncate_front(&mut self, len: usize) {
if N == 0 || len >= self.size {
return;
}
let drop_len = self.size - len;
let drop_range = 0..drop_len;
unsafe { self.drop_range(drop_range) };
self.start = add_mod(self.start, drop_len, N);
self.size = len;
}
#[inline]
pub fn clear(&mut self) {
self.truncate_back(0)
}
}
impl<const N: usize, T> CircularBuffer<N, T>
where T: Clone
{
pub fn extend_from_slice(&mut self, other: &[T]) {
if N == 0 {
return;
}
debug_assert!(self.start < N, "start out-of-bounds");
debug_assert!(self.size <= N, "size out-of-bounds");
#[cfg(not(feature = "unstable"))]
fn write_uninit_slice_cloned<T: Clone>(dst: &mut [MaybeUninit<T>], src: &[T]) {
struct Guard<'a, T> {
dst: &'a mut [MaybeUninit<T>],
initialized: usize,
}
impl<'a, T> Drop for Guard<'a, T> {
fn drop(&mut self) {
let initialized = &mut self.dst[..self.initialized];
unsafe {
let initialized = &mut *(initialized as *mut [MaybeUninit<T>] as *mut [T]);
ptr::drop_in_place(initialized);
}
}
}
debug_assert_eq!(dst.len(), src.len());
let len = dst.len();
let mut guard = Guard { dst, initialized: 0 };
#[allow(clippy::needless_range_loop)]
for i in 0..len {
guard.dst[i].write(src[i].clone());
guard.initialized += 1;
}
mem::forget(guard);
}
if other.len() < N {
let free_size = N - self.size;
let final_size = if other.len() < free_size {
self.size + other.len()
} else {
self.truncate_front(N - other.len());
N
};
let (right, left) = self.slices_uninit_mut();
let write_len = core::cmp::min(right.len(), other.len());
#[cfg(feature = "unstable")]
MaybeUninit::write_slice_cloned(&mut right[..write_len], &other[..write_len]);
#[cfg(not(feature = "unstable"))]
write_uninit_slice_cloned(&mut right[..write_len], &other[..write_len]);
let other = &other[write_len..];
debug_assert!(left.len() >= other.len());
let write_len = other.len();
#[cfg(feature = "unstable")]
MaybeUninit::write_slice_cloned(&mut left[..write_len], other);
#[cfg(not(feature = "unstable"))]
write_uninit_slice_cloned(&mut left[..write_len], other);
self.size = final_size;
} else {
self.clear();
self.start = 0;
let other = &other[other.len() - N..];
debug_assert_eq!(self.items.len(), other.len());
#[cfg(feature = "unstable")]
MaybeUninit::write_slice_cloned(&mut self.items, other);
#[cfg(not(feature = "unstable"))]
write_uninit_slice_cloned(&mut self.items, other);
self.size = N;
}
}
#[must_use]
#[cfg(feature = "use_std")]
pub fn to_vec(&self) -> Vec<T> {
let mut vec = Vec::with_capacity(self.size);
vec.extend(self.iter().cloned());
debug_assert_eq!(vec.len(), self.size);
vec
}
}
unstable_const_impl! {
impl<{const N: usize, T}> const Default for CircularBuffer<N, T> {
#[inline]
fn default() -> Self {
Self::new()
}
}
}
impl<const N: usize, const M: usize, T> From<[T; M]> for CircularBuffer<N, T> {
fn from(mut arr: [T; M]) -> Self {
#[cfg(feature = "unstable")]
let mut elems = MaybeUninit::<T>::uninit_array();
#[cfg(not(feature = "unstable"))]
let mut elems = unsafe { MaybeUninit::<[MaybeUninit<T>; N]>::uninit().assume_init() };
let arr_ptr = &arr as *const T as *const MaybeUninit<T>;
let elems_ptr = &mut elems as *mut MaybeUninit<T>;
let size = if N >= M { M } else { N };
unsafe { ptr::copy_nonoverlapping(arr_ptr.add(M - size), elems_ptr, size); }
unsafe { ptr::drop_in_place(&mut arr[..M - size]); }
mem::forget(arr);
Self { size, start: 0, items: elems }
}
}
impl<const N: usize, T> FromIterator<T> for CircularBuffer<N, T> {
fn from_iter<I>(iter: I) -> Self
where I: IntoIterator<Item = T>
{
let mut buf = Self::new();
iter.into_iter().for_each(|item| buf.push_back(item));
buf
}
}
impl<const N: usize, T> Extend<T> for CircularBuffer<N, T> {
fn extend<I>(&mut self, iter: I)
where I: IntoIterator<Item = T>
{
iter.into_iter().for_each(|item| self.push_back(item));
}
}
impl<'a, const N: usize, T> Extend<&'a T> for CircularBuffer<N, T>
where T: Copy
{
fn extend<I>(&mut self, iter: I)
where I: IntoIterator<Item = &'a T>
{
iter.into_iter().for_each(|item| self.push_back(*item));
}
}
unstable_const_impl! {
impl<{const N: usize, T}> const IntoIterator for CircularBuffer<N, T> {
type Item = T;
type IntoIter = IntoIter<N, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
IntoIter::new(self)
}
}
}
unstable_const_impl! {
impl<{'a, const N: usize, T}> const IntoIterator for &'a CircularBuffer<N, T> {
type Item = &'a T;
type IntoIter = Iter<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
Iter::new(self)
}
}
}
impl<const N: usize, const M: usize, T, U> PartialEq<CircularBuffer<M, U>> for CircularBuffer<N, T>
where T: PartialEq<U>
{
fn eq(&self, other: &CircularBuffer<M, U>) -> bool {
if self.len() != other.len() {
return false;
}
let (a_left, a_right) = self.as_slices();
let (b_left, b_right) = other.as_slices();
match a_left.len().cmp(&b_left.len()) {
Ordering::Less => {
let x = a_left.len();
let y = b_left.len() - x;
a_left[..] == b_left[..x] && a_right[..y] == b_left[x..] && a_right[y..] == b_right[..]
},
Ordering::Greater => {
let x = b_left.len();
let y = a_left.len() - x;
a_left[..x] == b_left[..] && a_right[x..] == b_left[..y] && a_right[..] == b_right[y..]
},
Ordering::Equal => {
debug_assert_eq!(a_left.len(), b_left.len());
debug_assert_eq!(a_right.len(), b_right.len());
a_left == b_left && a_right == b_right
},
}
}
}
impl<const N: usize, T> Eq for CircularBuffer<N, T> where T: Eq {}
impl<const N: usize, T, U> PartialEq<[U]> for CircularBuffer<N, T>
where T: PartialEq<U>
{
fn eq(&self, other: &[U]) -> bool {
if self.len() != other.len() {
return false;
}
let (a_left, a_right) = self.as_slices();
let (b_left, b_right) = other.split_at(a_left.len());
debug_assert_eq!(a_left.len(), b_left.len());
debug_assert_eq!(a_right.len(), b_right.len());
a_left == b_left && a_right == b_right
}
}
impl<const N: usize, const M: usize, T, U> PartialEq<[U; M]> for CircularBuffer<N, T>
where T: PartialEq<U>
{
#[inline]
fn eq(&self, other: &[U; M]) -> bool {
self == &other[..]
}
}
impl<'a, const N: usize, T, U> PartialEq<&'a [U]> for CircularBuffer<N, T>
where T: PartialEq<U>
{
#[inline]
fn eq(&self, other: &&'a [U]) -> bool {
self == *other
}
}
impl<'a, const N: usize, T, U> PartialEq<&'a mut [U]> for CircularBuffer<N, T>
where T: PartialEq<U>
{
#[inline]
fn eq(&self, other: &&'a mut [U]) -> bool {
self == *other
}
}
impl<'a, const N: usize, const M: usize, T, U> PartialEq<&'a [U; M]> for CircularBuffer<N, T>
where T: PartialEq<U>
{
#[inline]
fn eq(&self, other: &&'a [U; M]) -> bool {
self == *other
}
}
impl<'a, const N: usize, const M: usize, T, U> PartialEq<&'a mut [U; M]> for CircularBuffer<N, T>
where T: PartialEq<U>
{
#[inline]
fn eq(&self, other: &&'a mut [U; M]) -> bool {
self == *other
}
}
impl<const N: usize, const M: usize, T, U> PartialOrd<CircularBuffer<M, U>> for CircularBuffer<N, T>
where T: PartialOrd<U>
{
fn partial_cmp(&self, other: &CircularBuffer<M, U>) -> Option<Ordering> {
self.iter().partial_cmp(other.iter())
}
}
impl<const N: usize, T> Ord for CircularBuffer<N, T>
where T: Ord
{
fn cmp(&self, other: &Self) -> Ordering {
self.iter().cmp(other.iter())
}
}
impl<const N: usize, T> Hash for CircularBuffer<N, T>
where T: Hash
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.size.hash(state);
self.iter().for_each(|item| item.hash(state));
}
}
impl<const N: usize, T> Clone for CircularBuffer<N, T>
where T: Clone
{
fn clone(&self) -> Self {
Self::from_iter(self.iter().cloned())
}
fn clone_from(&mut self, other: &Self) {
self.clear();
self.extend(other.iter().cloned());
}
}
impl<const N: usize, T> Drop for CircularBuffer<N, T> {
#[inline]
fn drop(&mut self) {
self.clear();
}
}
impl<const N: usize, T> fmt::Debug for CircularBuffer<N, T>
where T: fmt::Debug
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self).finish()
}
}