diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..dad26d9 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +disable_all_formatting = true diff --git a/src/backend.rs b/src/backend.rs new file mode 100644 index 0000000..9ff4212 --- /dev/null +++ b/src/backend.rs @@ -0,0 +1,845 @@ +use core::cmp::Ordering; +use core::ops::RangeBounds; +use core::ptr; +use core::{fmt, ops::Range}; +use core::mem::MaybeUninit; +use core::hash::{Hash, Hasher}; + +use crate::{add_mod, slice_assume_init_ref, slice_assume_init_mut, sub_mod}; +use crate::iter::{Iter, IterMut, IntoIter}; +use crate::drain::Drain; + +pub(crate) struct Backend + where B: AsSlice> +{ + pub(crate) size: usize, + pub(crate) start: usize, + pub(crate) items: B, +} + +impl Backend + where B: AsSlice> +{ + pub(crate) const fn new(items: B) -> Self { + Self { size: 0, start: 0, items } + } + + #[inline] + pub(crate) const fn len(&self) -> usize { + self.size + } + + #[inline] + pub(crate) fn capacity(&self) -> usize { + // TODO: this can be const once const fn in traits are stable + self.items.as_slice().len() + } + + #[inline] + pub(crate) const fn is_empty(&self) -> bool { + self.size == 0 + } + + #[inline] + #[must_use] + pub(crate) fn iter(&self) -> Iter<'_, T> { + Iter::new(self) + } + + #[inline] + #[must_use] + pub(crate) fn iter_mut(&mut self) -> IterMut<'_, T> { + IterMut::new(self) + } + + #[inline] + pub(crate) fn as_slices(&self) -> (&[T], &[T]) { + if self.capacity() == 0 || self.size == 0 { + return (&[], &[]); + } + + debug_assert!(self.start < self.capacity(), "start out-of-bounds"); + debug_assert!(self.size <= self.capacity(), "size out-of-bounds"); + + let start = self.start; + let end = add_mod(self.start, self.size, self.capacity()); + + let (front, back) = if start < end { + (&self.items.as_slice()[start..end], &[][..]) + } else { + let (back, front) = self.items.as_slice().split_at(start); + (front, &back[..end]) + }; + + // SAFETY: The elements in these slices are guaranteed to be initialized + unsafe { + (slice_assume_init_ref(front), slice_assume_init_ref(back)) + } + } + + #[inline] + pub(crate) fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) { + if self.capacity() == 0 || self.size == 0 { + return (&mut [][..], &mut [][..]); + } + + debug_assert!(self.start < self.capacity(), "start out-of-bounds"); + debug_assert!(self.size <= self.capacity(), "size out-of-bounds"); + + let start = self.start; + let end = add_mod(self.start, self.size, self.capacity()); + + let (front, back) = if start < end { + (&mut self.items.as_slice_mut()[start..end], &mut [][..]) + } else { + let (back, front) = self.items.as_slice_mut().split_at_mut(start); + (front, &mut back[..end]) + }; + + // SAFETY: The elements in these slices are guaranteed to be initialized + unsafe { + (slice_assume_init_mut(front), slice_assume_init_mut(back)) + } + } + + #[inline] + #[must_use] + pub(crate) fn range(&self, range: R) -> Iter<'_, T> + where R: RangeBounds + { + Iter::over_range(self, range) + } + + #[inline] + #[must_use] + pub(crate) fn range_mut(&mut self, range: R) -> IterMut<'_, T> + where R: RangeBounds + { + IterMut::over_range(self, range) + } + + #[inline] + #[must_use] + pub(crate) fn drain(&mut self, range: R) -> Drain<'_, T, B> + where R: RangeBounds + { + Drain::over_range(self, range) + } + + pub(crate) fn make_contiguous(&mut self) -> &mut [T] { + if self.capacity() == 0 || self.size == 0 { + return &mut [] + } + + debug_assert!(self.start < self.capacity(), "start out-of-bounds"); + debug_assert!(self.size <= self.capacity(), "size out-of-bounds"); + + let start = self.start; + let end = add_mod(self.start, self.size, self.capacity()); + + let slice = if start < end { + // Already contiguous; nothing to do + &mut self.items.as_slice_mut()[start..end] + } else { + // Not contiguous; need to rotate + self.start = 0; + self.items.as_slice_mut().rotate_left(start); + &mut self.items.as_slice_mut()[..self.size] + }; + + // SAFETY: The elements in the slice are guaranteed to be initialized + unsafe { slice_assume_init_mut(slice) } + } + + #[inline] + pub(crate) fn back(&self) -> Option<&T> { + if self.capacity() == 0 || self.size == 0 { + // Nothing to do + return None; + } + // SAFETY: `size` is non-zero; back element is guaranteed to be initialized + Some(unsafe { self.back_maybe_uninit().assume_init_ref() }) + } + + #[inline] + pub(crate) fn back_mut(&mut self) -> Option<&mut T> { + if self.capacity() == 0 || self.size == 0 { + // Nothing to do + return None; + } + // SAFETY: `size` is non-zero; back element is guaranteed to be initialized + Some(unsafe { self.back_maybe_uninit_mut().assume_init_mut() }) + } + + #[inline] + pub(crate) fn front(&self) -> Option<&T> { + if self.capacity() == 0 || self.size == 0 { + // Nothing to do + return None; + } + // SAFETY: `size` is non-zero; front element is guaranteed to be initialized + Some(unsafe { self.front_maybe_uninit().assume_init_ref() }) + } + + #[inline] + pub(crate) fn front_mut(&mut self) -> Option<&mut T> { + if self.capacity() == 0 || self.size == 0 { + // Nothing to do + return None; + } + // SAFETY: `size` is non-zero; front element is guaranteed to be initialized + Some(unsafe { self.front_maybe_uninit_mut().assume_init_mut() }) + } + + #[inline] + pub(crate) fn get(&self, index: usize) -> Option<&T> { + if self.capacity() == 0 || index >= self.size { + // Nothing to do + return None; + } + // SAFETY: `index` is in a valid range; it is guaranteed to point to an initialized element + Some(unsafe { self.get_maybe_uninit(index).assume_init_ref() }) + } + + #[inline] + pub(crate) fn get_mut(&mut self, index: usize) -> Option<&mut T> { + if self.capacity() == 0 || index >= self.size { + // Nothing to do + return None; + } + // SAFETY: `index` is in a valid range; it is guaranteed to point to an initialized element + Some(unsafe { self.get_maybe_uninit_mut(index).assume_init_mut() }) + } + + pub(crate) fn push_back(&mut self, item: T) { + if self.capacity() == 0 { + // Nothing to do + return; + } + if self.size >= self.capacity() { + // At capacity; need to replace the front item + // + // SAFETY: if size is greater than 0, the front item is guaranteed to be initialized. + unsafe { ptr::drop_in_place(self.front_maybe_uninit_mut().as_mut_ptr()); } + self.front_maybe_uninit_mut().write(item); + self.inc_start(); + } else { + // Some uninitialized slots left; append at the end + self.inc_size(); + self.back_maybe_uninit_mut().write(item); + } + } + + pub(crate) fn try_push_back(&mut self, item: T) -> Result<(), T> { + if self.capacity() == 0 { + // Nothing to do + return Ok(()); + } + if self.size >= self.capacity(){ + // At capacity; return the pushed item as error + Err(item) + } else { + // Some uninitialized slots left; append at the end + self.inc_size(); + self.back_maybe_uninit_mut().write(item); + Ok(()) + } + } + + pub(crate) fn push_front(&mut self, item: T) { + if self.capacity() == 0 { + // Nothing to do + return; + } + if self.size >= self.capacity() { + // At capacity; need to replace the back item + // + // SAFETY: if size is greater than 0, the front item is guaranteed to be initialized. + unsafe { ptr::drop_in_place(self.back_maybe_uninit_mut().as_mut_ptr()); } + self.back_maybe_uninit_mut().write(item); + self.dec_start(); + } else { + // Some uninitialized slots left; insert at the start + self.inc_size(); + self.dec_start(); + self.front_maybe_uninit_mut().write(item); + } + } + + pub(crate) fn try_push_front(&mut self, item: T) -> Result<(), T> { + if self.capacity() == 0 { + // Nothing to do + return Ok(()); + } + if self.size >= self.capacity() { + // At capacity; return the pushed item as error + Err(item) + } else { + // Some uninitialized slots left; insert at the start + self.inc_size(); + self.dec_start(); + self.front_maybe_uninit_mut().write(item); + Ok(()) + } + } + + pub(crate) fn pop_back(&mut self) -> Option { + if self.capacity() == 0 || self.size == 0 { + // Nothing to do + return None; + } + + // SAFETY: if size is greater than 0, the back item is guaranteed to be initialized. + let back = unsafe { self.back_maybe_uninit().assume_init_read() }; + self.dec_size(); + Some(back) + } + + pub(crate) fn pop_front(&mut self) -> Option { + if self.capacity() == 0 || self.size == 0 { + // Nothing to do + return None; + } + + // SAFETY: if size is greater than 0, the front item is guaranteed to be initialized. + let back = unsafe { self.front_maybe_uninit().assume_init_read() }; + self.dec_size(); + self.inc_start(); + Some(back) + } + + pub(crate) fn remove(&mut self, index: usize) -> Option { + if self.capacity() == 0 || index >= self.size { + return None; + } + + let index = add_mod(self.start, index, self.capacity()); + let back_index = add_mod(self.start, self.size - 1, self.capacity()); + + // SAFETY: `index` is in a valid range; the element is guaranteed to be initialized + let item = unsafe { self.items.as_slice()[index].assume_init_read() }; + + // SAFETY: the pointers being moved are in a valid range; the elements behind those + // pointers are guaranteed to be initialized + unsafe { + // TODO: optimize for the case where `index < len - index` (i.e. when copying items to + // the right is cheaper than moving items to the left) + let ptr = self.items.as_slice_mut().as_mut_ptr(); + if back_index >= index { + // Move the values at the right of `index` by 1 position to the left + ptr::copy(ptr.add(index).add(1), ptr.add(index), back_index - index); + } else { + // Move the values at the right of `index` by 1 position to the left + ptr::copy(ptr.add(index).add(1), ptr.add(index), self.capacity() - index); + // Move the leftmost value to the end of the array + ptr::copy(ptr, ptr.add(self.capacity() - 1), 1); + // Move the values at the left of `back_index` by 1 position to the left + ptr::copy(ptr.add(1), ptr, back_index); + } + } + + self.dec_size(); + Some(item) + } + + pub(crate) 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, self.capacity()); + let j = add_mod(self.start, j, self.capacity()); + + let items = self.items.as_slice_mut(); + // SAFETY: these are valid pointers + unsafe { ptr::swap_nonoverlapping(&mut items[i], &mut items[j], 1) }; + } + } + + pub(crate) fn swap_remove_back(&mut self, index: usize) -> Option { + if index >= self.size { + return None; + } + self.swap(index, self.size - 1); + self.pop_back() + } + + pub(crate) fn swap_remove_front(&mut self, index: usize) -> Option { + if index >= self.size { + return None; + } + self.swap(index, 0); + self.pop_front() + } + + pub(crate) fn truncate_back(&mut self, len: usize) { + if self.capacity() == 0 || len >= self.size { + // Nothing to do + return; + } + + let drop_range = len..self.size; + // SAFETY: `drop_range` is a valid range, so elements within are guaranteed to be + // initialized. The `size` of the buffer is shrunk before dropping, so no value will be + // dropped twice in case of panics. + unsafe { self.drop_range(drop_range) }; + self.size = len; + } + + pub(crate) fn truncate_front(&mut self, len: usize) { + if self.capacity() == 0 || len >= self.size { + // Nothing to do + return; + } + + let drop_len = self.size - len; + let drop_range = 0..drop_len; + // SAFETY: `drop_range` is a valid range, so elements within are guaranteed to be + // initialized. The `start` of the buffer is shrunk before dropping, so no value will be + // dropped twice in case of panics. + unsafe { self.drop_range(drop_range) }; + self.start = add_mod(self.start, drop_len, self.capacity()); + self.size = len; + } + + #[inline] + pub(crate) fn clear(&mut self) { + self.truncate_back(0) + } + + #[inline] + fn front_maybe_uninit_mut(&mut self) -> &mut MaybeUninit { + debug_assert!(self.size > 0, "empty buffer"); + debug_assert!(self.start < self.capacity(), "start out-of-bounds"); + &mut self.items.as_slice_mut()[self.start] + } + + #[inline] + fn front_maybe_uninit(&self) -> &MaybeUninit { + debug_assert!(self.size > 0, "empty buffer"); + debug_assert!(self.size <= self.capacity(), "size out-of-bounds"); + debug_assert!(self.start < self.capacity(), "start out-of-bounds"); + &self.items.as_slice()[self.start] + } + + #[inline] + fn back_maybe_uninit(&self) -> &MaybeUninit { + debug_assert!(self.size > 0, "empty buffer"); + debug_assert!(self.size <= self.capacity(), "size out-of-bounds"); + debug_assert!(self.start < self.capacity(), "start out-of-bounds"); + let back = add_mod(self.start, self.size - 1, self.capacity()); + &self.items.as_slice()[back] + } + + #[inline] + fn back_maybe_uninit_mut(&mut self) -> &mut MaybeUninit { + debug_assert!(self.size > 0, "empty buffer"); + debug_assert!(self.size <= self.capacity(), "size out-of-bounds"); + debug_assert!(self.start < self.capacity(), "start out-of-bounds"); + let back = add_mod(self.start, self.size - 1, self.capacity()); + &mut self.items.as_slice_mut()[back] + } + + #[inline] + fn get_maybe_uninit(&self, index: usize) -> &MaybeUninit { + debug_assert!(self.size > 0, "empty buffer"); + debug_assert!(index < self.capacity(), "index out-of-bounds"); + debug_assert!(self.start < self.capacity(), "start out-of-bounds"); + let index = add_mod(self.start, index, self.capacity()); + &self.items.as_slice()[index] + } + + #[inline] + fn get_maybe_uninit_mut(&mut self, index: usize) -> &mut MaybeUninit { + debug_assert!(self.size > 0, "empty buffer"); + debug_assert!(index < self.capacity(), "index out-of-bounds"); + debug_assert!(self.start < self.capacity(), "start out-of-bounds"); + let index = add_mod(self.start, index, self.capacity()); + &mut self.items.as_slice_mut()[index] + } + + #[inline] + fn slices_uninit_mut(&mut self) -> (&mut [MaybeUninit], &mut [MaybeUninit]) { + if self.capacity() == 0 { + return (&mut [][..], &mut [][..]); + } + + debug_assert!(self.start < self.capacity(), "start out-of-bounds"); + debug_assert!(self.size <= self.capacity(), "size out-of-bounds"); + + let start = self.start; + let end = add_mod(start, self.size, self.capacity()); + if end < start { + (&mut self.items.as_slice_mut()[end..start], &mut [][..]) + } else { + let (left, right) = self.items.as_slice_mut().split_at_mut(end); + let left = &mut left[..start]; + (right, left) + } + } + + #[inline] + fn inc_start(&mut self) { + debug_assert!(self.start < self.capacity(), "start out-of-bounds"); + self.start = add_mod(self.start, 1, self.capacity()); + } + + #[inline] + fn dec_start(&mut self) { + debug_assert!(self.start < self.capacity(), "start out-of-bounds"); + self.start = sub_mod(self.start, 1, self.capacity()); + } + + #[inline] + fn inc_size(&mut self) { + debug_assert!(self.size <= self.capacity(), "size out-of-bounds"); + debug_assert!(self.size < self.capacity(), "size at capacity limit"); + self.size += 1; + } + + #[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) { + if range.is_empty() { + return; + } + + debug_assert!(self.start < self.capacity(), "start out-of-bounds"); + debug_assert!(self.size <= self.capacity(), "size out-of-bounds"); + debug_assert!(range.start < self.size, "start of range out-of-bounds"); + debug_assert!(range.end <= self.size, "end of range out-of-bounds"); + debug_assert!(range.start < range.end, "start of range is past its end"); + debug_assert!(range.start == 0 || range.end == self.size, + "range does not include boundary of the buffer"); + + // Drops all the items in the slice when dropped. This is needed to ensure that all + // elements are dropped in case a panic occurs during the drop of a single element. + struct Dropper<'a, T>(&'a mut [MaybeUninit]); + + impl<'a, T> Drop for Dropper<'a, T> { + #[inline] + fn drop(&mut self) { + // SAFETY: the caller of `drop_range` is responsible to check that this slice was + // initialized. + unsafe { ptr::drop_in_place(slice_assume_init_mut(self.0)); } + } + } + + let drop_from = add_mod(self.start, range.start, self.capacity()); + let drop_to = add_mod(self.start, range.end, self.capacity()); + + let (right, left) = if drop_from < drop_to { + (&mut self.items.as_slice_mut()[drop_from..drop_to], &mut [][..]) + } else { + let (left, right) = self.items.as_slice_mut().split_at_mut(drop_from); + let left = &mut left[..drop_to]; + (right, left) + }; + + let _left = Dropper(left); + let _right = Dropper(right); + } +} + +impl Backend + where + T: Clone, + B: AsSlice> +{ + pub(crate) fn extend_from_slice(&mut self, other: &[T]) { + if self.capacity() == 0 { + return; + } + + debug_assert!(self.start < self.capacity(), "start out-of-bounds"); + debug_assert!(self.size <= self.capacity(), "size out-of-bounds"); + + #[cfg(not(feature = "unstable"))] + fn write_uninit_slice_cloned(dst: &mut [MaybeUninit], src: &[T]) { + use core::mem; + + // Each call to `clone()` may panic, therefore we need to track how many elements we + // successfully cloned so that we can drop them in case of panic. This `Guard` struct + // does exactly that: it keeps track of how many items have been successfully cloned + // and drops them if the guard is dropped. + // + // This implementation was highly inspired by the implementation of + // `MaybeUninit::write_slice_cloned` + struct Guard<'a, T> { + dst: &'a mut [MaybeUninit], + initialized: usize, + } + + impl<'a, T> Drop for Guard<'a, T> { + fn drop(&mut self) { + let initialized = &mut self.dst[..self.initialized]; + // SAFETY: this slice contain only initialized objects; `MaybeUninit` has + // the same alignment and size as `T` + unsafe { + let initialized = &mut *(initialized as *mut [MaybeUninit] 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; + } + + // All the `clone()` calls succeded; get rid of the guard without running its `drop()` + // implementation + mem::forget(guard); + } + + if other.len() < self.capacity() { + // All the elements of `other` fit into the buffer + let free_size = self.capacity() - self.size; + let final_size = if other.len() < free_size { + // All the elements of `other` fit at the back of the buffer + self.size + other.len() + } else { + // Some of the elements of `other` need to overwrite the front of the buffer + self.truncate_front(self.capacity() - other.len()); + self.capacity() + }; + + 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 { + // `other` overwrites the whole buffer; get only the last `N` elements from `other` and + // overwrite + self.clear(); + self.start = 0; + + let other = &other[other.len() - self.capacity()..]; + debug_assert_eq!(self.items.as_slice().len(), other.len()); + #[cfg(feature = "unstable")] + MaybeUninit::write_slice_cloned(self.items.as_slice_mut(), other); + #[cfg(not(feature = "unstable"))] + write_uninit_slice_cloned(self.items.as_slice_mut(), other); + + self.size = self.capacity(); + } + } + + #[must_use] + #[cfg(feature = "use_std")] + pub(crate) fn to_vec(&self) -> Vec { + let mut vec = Vec::with_capacity(self.size); + vec.extend(self.iter().cloned()); + debug_assert_eq!(vec.len(), self.size); + vec + } +} + +impl Extend for Backend + where B: AsSlice>, +{ + fn extend(&mut self, iter: I) + where I: IntoIterator + { + // TODO Optimize + iter.into_iter().for_each(|item| self.push_back(item)); + } +} + +impl<'a, T, B> Extend<&'a T> for Backend + where + T: Copy, + B: AsSlice> +{ + fn extend(&mut self, iter: I) + where I: IntoIterator + { + // TODO Optimize + iter.into_iter().for_each(|item| self.push_back(*item)); + } +} + +// TODO const impl? +impl IntoIterator for Backend + where B: AsSlice>, +{ + type Item = T; + type IntoIter = IntoIter; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + IntoIter::new(self) + } +} + +// TODO const impl? +impl<'a, T: 'a, B> IntoIterator for &'a Backend + where B: AsSlice>, +{ + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + Iter::new(self) + } +} + +impl PartialEq> for Backend + where + T: PartialEq, + B1: AsSlice>, + B2: AsSlice>, +{ + fn eq(&self, other: &Backend) -> 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_left[x..] == b_right[..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 PartialEq<[U]> for Backend + where + T: PartialEq, + B: AsSlice>, +{ + 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 Eq for Backend + where + T: Eq, + B: AsSlice> +{} + +impl PartialOrd> for Backend + where + T: PartialOrd, + B1: AsSlice>, + B2: AsSlice>, +{ + fn partial_cmp(&self, other: &Backend) -> Option { + self.iter().partial_cmp(other.iter()) + } +} + +impl Ord for Backend + where + T: Ord, + B: AsSlice> +{ + fn cmp(&self, other: &Self) -> Ordering { + self.iter().cmp(other.iter()) + } +} + +impl Hash for Backend + where + T: Hash, + B: AsSlice> +{ + fn hash(&self, state: &mut H) { + self.size.hash(state); + self.iter().for_each(|item| item.hash(state)); + } +} + +impl Drop for Backend + where B: AsSlice> +{ + #[inline] + fn drop(&mut self) { + // `clear()` will make sure that every element is dropped in a safe way + self.clear(); + } +} + +impl fmt::Debug for Backend + where + T: fmt::Debug, + B: AsSlice>, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self).finish() + } +} + +pub(crate) trait AsSlice { + type Item; + fn as_slice(&self)-> &[Self::Item]; + fn as_slice_mut(&mut self) -> &mut [Self::Item]; +} + +impl AsSlice for [MaybeUninit; N] { + type Item = MaybeUninit; + fn as_slice(&self)-> &[Self::Item] { + &self[..] + } + fn as_slice_mut(&mut self) -> &mut [Self::Item] { + &mut self[..] + } +} + +impl AsSlice for Box<[MaybeUninit]> { + type Item = MaybeUninit; + fn as_slice(&self)-> &[Self::Item] { + &self[..] + } + fn as_slice_mut(&mut self) -> &mut [Self::Item] { + &mut self[..] + } +} \ No newline at end of file diff --git a/src/drain.rs b/src/drain.rs index fef4e2f..6b73ade 100644 --- a/src/drain.rs +++ b/src/drain.rs @@ -6,16 +6,23 @@ use core::ops::Range; use core::ops::RangeBounds; use core::ptr::NonNull; use core::ptr; -use crate::CircularBuffer; use crate::add_mod; +use crate::backend::AsSlice; +use crate::backend::Backend; use crate::iter::Iter; use crate::iter::translate_range_bounds; /// A draining [iterator](std::iter::Iterator) that removes and returns elements from a -/// `CircularBuffer`. +/// `CircularBuffer` or `HeapCircularBuffer`. /// -/// This struct is created by [`CircularBuffer::drain()`]. See its documentation for more details. -pub struct Drain<'a, const N: usize, T> { +/// This struct is created by [`CircularBuffer::drain()`] or +/// [`HeapCircularBuffer::drain()`]. See its documentation for more details. +/// +/// [`CircularBuffer::drain()`]: crate::CircularBuffer::drain +/// [`HeapCircularBuffer::drain()`]: crate::heap::HeapCircularBuffer::drain +pub(crate) struct Drain<'a, T, B> + where B: AsSlice> +{ /// This is a pointer and not a reference (`&'a mut CircularBuffer`) because using a reference /// would make `Drain` an invariant over `CircularBuffer`, but instead we want `Drain` to be /// covariant over `CircularBuffer`. @@ -25,7 +32,7 @@ pub struct Drain<'a, const N: usize, T> { /// buffer, storing them into a vector, and returning an iterable over the vector. /// Equivalently, `Drain` owns the drained elements, so it would be unnecessarily restrictive /// to make this type invariant over `CircularBuffer`. - buf: NonNull>, + buf: NonNull>, /// A backup of the size of the buffer. Necessary because `buf.size` is set to 0 during the /// lifetime of the `Drain` and is restored only during drop. buf_size: usize, @@ -42,9 +49,11 @@ pub struct Drain<'a, const N: usize, T> { phantom: PhantomData<&'a T>, } -impl<'a, const N: usize, T> Drain<'a, N, T> { - pub(crate) fn over_range(buf: &'a mut CircularBuffer, range: R) -> Self - where R: RangeBounds +impl<'a, T, B> Drain<'a, T, B> + where B: AsSlice>, +{ + pub(crate) fn over_range(buf: &'a mut Backend, range: R) -> Self + where R: RangeBounds, { let (start, end) = translate_range_bounds(buf, range); @@ -81,34 +90,34 @@ impl<'a, const N: usize, T> Drain<'a, N, T> { /// the element at `index` must be considered as uninitialized memory and therefore the `index` /// must not be reused. unsafe fn read(&self, index: usize) -> T { - debug_assert!(index < N && index < self.buf_size, + let buf = self.buf.as_ref(); + debug_assert!(index < buf.capacity() && index < self.buf_size, "index out-of-bounds for buffer"); debug_assert!(index >= self.range.start && index < self.range.end, "index out-of-bounds for drain range"); debug_assert!(index < self.iter.start || index >= self.iter.end, "attempt to read an item that may be returned by the iterator"); - let buf = self.buf.as_ref(); - let index = add_mod(buf.start, index, N); - ptr::read(buf.items[index].assume_init_ref()) + let index = add_mod(buf.start, index, buf.capacity()); + ptr::read(buf.items.as_slice()[index].assume_init_ref()) } fn as_slices(&self) -> (&[T], &[T]) { - if N == 0 || self.buf_size == 0 || self.iter.is_empty() { + let buf = unsafe { self.buf.as_ref() }; + if buf.capacity() == 0 || self.buf_size == 0 || self.iter.is_empty() { return (&[][..], &[][..]); } - let buf = unsafe { self.buf.as_ref() }; - debug_assert!(buf.start < N, "start out-of-bounds"); - debug_assert!(self.buf_size <= N, "size out-of-bounds"); + debug_assert!(buf.start < buf.capacity(), "start out-of-bounds"); + debug_assert!(self.buf_size <= buf.capacity(), "size out-of-bounds"); - let start = add_mod(buf.start, self.iter.start, N); - let end = add_mod(buf.start, self.iter.end, N); + let start = add_mod(buf.start, self.iter.start, buf.capacity()); + let end = add_mod(buf.start, self.iter.end, buf.capacity()); let (right, left) = if start < end { - (&buf.items[start..end], &[][..]) + (&buf.items.as_slice()[start..end], &[][..]) } else { - let (left, right) = buf.items.split_at(end); + let (left, right) = buf.items.as_slice().split_at(end); let right = &right[start - end..]; (right, left) }; @@ -127,22 +136,22 @@ impl<'a, const N: usize, T> Drain<'a, N, T> { } fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) { - if N == 0 || self.buf_size == 0 || self.iter.is_empty() { + let buf = unsafe { self.buf.as_mut() }; + if buf.capacity() == 0 || self.buf_size == 0 || self.iter.is_empty() { return (&mut [][..], &mut [][..]); } - let buf = unsafe { self.buf.as_mut() }; - debug_assert!(buf.start < N, "start out-of-bounds"); - debug_assert!(self.buf_size <= N, "size out-of-bounds"); + debug_assert!(buf.start < buf.capacity(), "start out-of-bounds"); + debug_assert!(self.buf_size <= buf.capacity(), "size out-of-bounds"); - let start = add_mod(buf.start, self.iter.start, N); - let end = add_mod(buf.start, self.iter.end, N); + let start = add_mod(buf.start, self.iter.start, buf.capacity()); + let end = add_mod(buf.start, self.iter.end, buf.capacity()); let (right, left) = if start < end { - (&mut buf.items[start..end], &mut [][..]) + (&mut buf.items.as_slice_mut()[start..end], &mut [][..]) } else { - let (left, right) = buf.items.split_at_mut(end); + let (left, right) = buf.items.as_slice_mut().split_at_mut(end); let right = &mut right[start - end..]; (right, left) }; @@ -161,7 +170,9 @@ impl<'a, const N: usize, T> Drain<'a, N, T> { } } -impl<'a, const N: usize, T> Iterator for Drain<'a, N, T> { +impl<'a, T, B> Iterator for Drain<'a, T, B> + where B: AsSlice> +{ type Item = T; #[inline] @@ -176,23 +187,31 @@ impl<'a, const N: usize, T> Iterator for Drain<'a, N, T> { } } -impl<'a, const N: usize, T> ExactSizeIterator for Drain<'a, N, T> { +impl<'a, T, B> ExactSizeIterator for Drain<'a, T, B> + where B: AsSlice> +{ #[inline] fn len(&self) -> usize { self.iter.len() } } -impl<'a, const N: usize, T> FusedIterator for Drain<'a, N, T> {} +impl<'a, T, B> FusedIterator for Drain<'a, T, B> + where B: AsSlice> +{} -impl<'a, const N: usize, T> DoubleEndedIterator for Drain<'a, N, T> { +impl<'a, T, B> DoubleEndedIterator for Drain<'a, T, B> + where B: AsSlice> +{ fn next_back(&mut self) -> Option { // SAFETY: the element at the index is guaranteed to be initialized self.iter.next_back().map(|index| unsafe { self.read(index) }) } } -impl<'a, const N: usize, T> Drop for Drain<'a, N, T> { +impl<'a, T, B> Drop for Drain<'a, T, B> + where B: AsSlice> +{ fn drop(&mut self) { // Drop the items that were not consumed struct Dropper<'a, T>(&'a mut [T]); @@ -270,7 +289,7 @@ impl<'a, const N: usize, T> Drop for Drain<'a, N, T> { let buf = unsafe { self.buf.as_mut() }; let mut remaining = self.buf_size - self.range.end; - let items = CircularSlicePtr::new(&mut buf.items).add(buf.start); + let items = CircularSlicePtr::new(buf.items.as_slice_mut()).add(buf.start); let mut hole = items.add(self.range.start); let mut backfill = items.add(self.range.end); @@ -292,8 +311,11 @@ impl<'a, const N: usize, T> Drop for Drain<'a, N, T> { } } -impl<'a, const N: usize, T> fmt::Debug for Drain<'a, N, T> - where T: fmt::Debug +impl<'a, T, B> fmt::Debug for Drain<'a, T, B> + where + T: fmt::Debug, + B: AsSlice> + { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -360,3 +382,27 @@ impl<'a, T> Clone for CircularSlicePtr<'a, T> { *self } } + + +/// A draining [iterator](std::iter::Iterator) that removes and returns elements +/// from a `CircularBuffer` +/// +/// This struct is created by [`CircularBuffer::drain()`]. See its documentation +/// for more details. +/// +/// [`CircularBuffer::drain()`]: crate::CircularBuffer::drain +#[repr(transparent)] +pub struct StaticDrain<'a, const N: usize, T>(pub(crate) Drain<'a, T, [MaybeUninit; N]>); +super::impl_iter_traits!(<{const N: usize, T}> - StaticDrain<'_, N, T>); + + +/// A draining [iterator](std::iter::Iterator) that removes and returns elements +/// from a `HeapCircularBuffer`. +/// +/// This struct is created by [`HeapCircularBuffer::drain()`]. See its +/// documentation for more details. +/// +/// [`HeapCircularBuffer::drain()`]: crate::heap::HeapCircularBuffer::drain +#[repr(transparent)] +pub struct HeapDrain<'a, T>(pub(crate) Drain<'a, T, Box<[MaybeUninit]>>); +super::impl_iter_traits!(<{T}> - HeapDrain<'_, T>); diff --git a/src/heap.rs b/src/heap.rs new file mode 100644 index 0000000..06afb2a --- /dev/null +++ b/src/heap.rs @@ -0,0 +1,365 @@ +//! This module provides [`HeapCircularBuffer`], a circular buffer variant with +//! runtime determined capacity. This variant is only available in `std` +//! environments under the `use_std` feature. +//! +//! # Examples +//! +//! ``` +//! use circular_buffer::heap::HeapCircularBuffer; +//! +//! // This does _not_ need to be known at compile time. It could +//! // be loaded for example from a file or database query. +//! let capacity = 5; +//! // Initialize a new, empty circular buffer with a capacity of `capacity` elements +//! let mut buf = HeapCircularBuffer::::with_capacity(capacity); +//! +//! // Add a few elements +//! buf.push_back(1); +//! buf.push_back(2); +//! buf.push_back(3); +//! assert_eq!(buf, [1, 2, 3]); +//! +//! // Add more elements to fill the buffer capacity completely +//! buf.push_back(4); +//! buf.push_back(5); +//! assert_eq!(buf, [1, 2, 3, 4, 5]); +//! +//! // Adding more elements than the buffer can contain causes the front elements to be +//! // automatically dropped +//! buf.push_back(6); +//! assert_eq!(buf, [2, 3, 4, 5, 6]); // `1` got dropped to make room for `6` +//! ``` +//! +//! # Interface +//! [`HeapCircularBuffer`] has the same interface as [`CircularBuffer`]. +//! Checkout the [struct documentation] and [crate documentation][Interface] for +//! more details. +//! +//! # Time complexity +//! See the [crate documentation][TimeComplexity] for more details +//! +//! [`CircularBuffer`]: crate::CircularBuffer +//! [struct documentation]: HeapCircularBuffer +//! [Interface]: crate#interface +//! [TimeComplexity]: crate#time-complexity + +use core::{ptr, fmt}; +use core::cmp::Ordering; +use core::mem::{MaybeUninit, self}; +use core::ops::RangeBounds; +use crate::{backend::Backend, Iter, IterMut}; +use crate::unstable_const_impl; + +pub use crate::drain::HeapDrain; +pub use crate::iter::HeapIntoIter; + + +/// A fixed-size circular buffer allocated on the heap. +/// +/// A `HeapCircularBuffer` can be allocted with runtime known capacity. +/// +/// See the [module-level documentation](self) for more details and examples. +#[derive(Ord, Eq, Hash)] +#[repr(transparent)] +pub struct HeapCircularBuffer { + backend: Backend]>>, +} + +impl HeapCircularBuffer { + /// Returns an empty [`HeapCircularBuffer`]. + /// + /// # Examples + /// + /// ``` + /// use circular_buffer::heap::HeapCircularBuffer; + /// let buf = HeapCircularBuffer::::with_capacity(16); + /// assert_eq!(buf, []); + /// ``` + #[inline] + #[must_use] + pub fn with_capacity(cap: usize) -> Self { + let slice = if cap == 0 || mem::size_of::() == 0 { + ptr::slice_from_raw_parts_mut(ptr::NonNull::dangling().as_ptr(), cap) + } else { + let layout = std::alloc::Layout::array::(cap).expect("layout overflow"); + // SAFETY: `T` is not a ZST, and `cap` is not 0 + let ptr = unsafe { std::alloc::alloc(layout) as *mut MaybeUninit }; + if ptr.is_null() { + std::alloc::handle_alloc_error(layout); + } + ptr::slice_from_raw_parts_mut(ptr, cap) + }; + Self { + // SAFETY: "It is valid to convert both ways between a Box and a raw + // pointer allocated with the Global allocator, given that the Layout + // used with the allocator is correct for the type." + // https://doc.rust-lang.org/stable/std/boxed/index.html#memory-layout + backend: unsafe { Backend::new(Box::from_raw(slice)) } + } + } + /// Returns the capacity of the buffer. + /// + /// This is the maximum number of elements that the buffer can hold. + /// + /// # Examples + /// + /// ``` + /// use circular_buffer::heap::HeapCircularBuffer; + /// let mut buf = HeapCircularBuffer::::with_capacity(16); + /// assert_eq!(buf.capacity(), 16); + /// ``` + #[inline] + pub const fn capacity(&self) -> usize { + self.backend.items.len() + } + + /// Removes the specified range from the buffer in bulk, returning the removed elements as an + /// iterator. If the iterator is dropped before being fully consumed, it drops the remaining + /// removed elements. + /// + /// # Panics + /// + /// If the start of the range is greater than the end, or if the end is greater than the length + /// of the buffer. + /// + /// # Leaking + /// + /// If the returned iterator goes out of scope without being dropped (for example, due to + /// calling [`mem::forget()`] on it), the buffer may have lost and leaked arbitrary elements, + /// including elements outside of the range. + /// + /// The current implementation leaks all the elements of the buffer if the iterator is leaked, + /// but this behavior may change in the future. + /// + /// # Examples + /// + /// ``` + /// use circular_buffer::heap::HeapCircularBuffer; + /// + /// let mut buf = HeapCircularBuffer::::with_capacity(6); + /// buf.extend("abcdef".chars()); + /// let drained = buf.drain(3..).collect::>(); + /// + /// assert_eq!(drained, ['d', 'e', 'f']); + /// assert_eq!(buf, ['a', 'b', 'c']); + /// ``` + /// + /// Not consuming the draining iterator still removes the range of elements: + /// + /// ``` + /// use circular_buffer::heap::HeapCircularBuffer; + /// + /// let mut buf = HeapCircularBuffer::::with_capacity(6); + /// buf.extend("abcdef".chars()); + /// let _ = buf.drain(3..); + /// + /// assert_eq!(buf, ['a', 'b', 'c']); + /// ``` + #[inline] + #[must_use] + pub fn drain(&mut self, range: R) -> HeapDrain<'_, T> + where R: RangeBounds + { + HeapDrain(self.backend.drain(range)) + } + + pub(crate) fn into_backend(self) -> Backend]>> { + self.backend + } + + super::impl_buffer!(); +} + +impl HeapCircularBuffer + where T: Clone +{ + /// Clones and appends all the elements from the slice to the back of the buffer. + /// + /// This is an optimized version of [`extend()`](Self::extend) for slices. + /// + /// If slice contains more values than the available capacity, the elements at the front of the + /// buffer are dropped. + /// + /// # Examples + /// + /// ``` + /// use circular_buffer::heap::HeapCircularBuffer; + /// + /// let mut buf: HeapCircularBuffer = HeapCircularBuffer::with_capacity(5); + /// buf.extend([1, 2, 3]); + /// + /// buf.extend_from_slice(&[4, 5, 6, 7]); + /// assert_eq!(buf, [3, 4, 5, 6, 7]); + /// ``` + pub fn extend_from_slice(&mut self, other: &[T]) { + self.backend.extend_from_slice(other) + } + + /// Clones the elements of the buffer into a new [`Vec`], leaving the buffer unchanged. + /// + /// # Examples + /// + /// ``` + /// use circular_buffer::heap::HeapCircularBuffer; + /// + /// let mut buf: HeapCircularBuffer = HeapCircularBuffer::with_capacity(5); + /// buf.extend([1, 2, 3]); + /// let vec: Vec = buf.to_vec(); + /// + /// assert_eq!(buf, [1, 2, 3]); + /// assert_eq!(vec, [1, 2, 3]); + /// ``` + #[must_use] + #[cfg(feature = "use_std")] + pub fn to_vec(&self) -> Vec { + self.backend.to_vec() + } +} + +impl Extend for HeapCircularBuffer { + fn extend(&mut self, iter: I) + where I: IntoIterator + { + self.backend.extend(iter) + } +} + +impl<'a, T> Extend<&'a T> for HeapCircularBuffer + where T: Copy +{ + fn extend(&mut self, iter: I) + where I: IntoIterator + { + self.backend.extend(iter) + } +} + +unstable_const_impl! { + impl<{T}> const IntoIterator for HeapCircularBuffer { + type Item = T; + type IntoIter = HeapIntoIter; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + HeapIntoIter(self.backend.into_iter()) + } + } +} + +unstable_const_impl! { + impl<{'a, T}> const IntoIterator for &'a HeapCircularBuffer { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + Iter::new(&self.backend) + } + } +} + +impl PartialEq> for HeapCircularBuffer + where T: PartialEq +{ + fn eq(&self, other: &HeapCircularBuffer) -> bool { + self.backend.eq(&other.backend) + } +} + +impl PartialEq<[U]> for HeapCircularBuffer + where T: PartialEq +{ + fn eq(&self, other: &[U]) -> bool { + self.backend.eq(other) + } +} + +impl PartialEq<[U; M]> for HeapCircularBuffer + where T: PartialEq +{ + #[inline] + fn eq(&self, other: &[U; M]) -> bool { + self == &other[..] + } +} + +impl<'a, T, U> PartialEq<&'a [U]> for HeapCircularBuffer + where T: PartialEq +{ + #[inline] + fn eq(&self, other: &&'a [U]) -> bool { + self == *other + } +} + +impl<'a, T, U> PartialEq<&'a mut [U]> for HeapCircularBuffer + where T: PartialEq +{ + #[inline] + fn eq(&self, other: &&'a mut [U]) -> bool { + self == *other + } +} + +impl<'a, const M: usize, T, U> PartialEq<&'a [U; M]> for HeapCircularBuffer + where T: PartialEq +{ + #[inline] + fn eq(&self, other: &&'a [U; M]) -> bool { + self == *other + } +} + +impl<'a, const M: usize, T, U> PartialEq<&'a mut [U; M]> for HeapCircularBuffer + where T: PartialEq +{ + #[inline] + fn eq(&self, other: &&'a mut [U; M]) -> bool { + self == *other + } +} + +impl PartialOrd> for HeapCircularBuffer + where T: PartialOrd +{ + fn partial_cmp(&self, other: &HeapCircularBuffer) -> Option { + self.backend.partial_cmp(&other.backend) + } +} + +impl Clone for HeapCircularBuffer + where T: Clone +{ + fn clone(&self) -> Self { + // TODO Optimize + let mut this = Self::with_capacity(self.capacity()); + this.extend(self.iter().cloned()); + this + + } + + fn clone_from(&mut self, other: &Self) { + // TODO Optimize + self.clear(); + self.extend(other.iter().cloned()); + } +} + +impl fmt::Debug for HeapCircularBuffer + where T: fmt::Debug +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.backend.fmt(f) + } +} + +macro_rules! USE { + () => { "use circular_buffer::heap::HeapCircularBuffer;" }; +} + +macro_rules! NEW { + ($N:literal,$ty:ty) => { + concat!("let mut buf = HeapCircularBuffer::<",stringify!($ty),">::with_capacity(",$N,");") + }; +} +use {USE, NEW}; \ No newline at end of file diff --git a/src/io.rs b/src/io.rs index 2250a5e..1832380 100644 --- a/src/io.rs +++ b/src/io.rs @@ -1,6 +1,7 @@ #![cfg(feature = "use_std")] use crate::CircularBuffer; +use crate::heap::HeapCircularBuffer; use std::io::Read; use std::io::Result; use std::io::Write; @@ -27,3 +28,27 @@ impl Read for CircularBuffer { Ok(count) } } + +impl Write for HeapCircularBuffer { + #[inline] + fn write(&mut self, src: &[u8]) -> Result { + self.extend_from_slice(src); + Ok(src.len()) + } + + #[inline] + fn flush(&mut self) -> Result<()> { + Ok(()) + } +} + +impl Read for HeapCircularBuffer { + fn read(&mut self, dst: &mut [u8]) -> Result { + let (mut right, mut left) = self.as_slices(); + let mut count = right.read(dst)?; + count += left.read(&mut dst[count..])?; + self.truncate_front(self.len() - count); + Ok(count) + } +} + diff --git a/src/iter.rs b/src/iter.rs index 8ce7dd9..0ada9ee 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -1,27 +1,68 @@ use core::fmt; use core::iter::FusedIterator; +use core::mem::MaybeUninit; use core::ops::Bound; use core::ops::RangeBounds; -use crate::CircularBuffer; +use crate::backend::AsSlice; +use crate::backend::Backend; -/// An owning [iterator](std::iter::Iterator) over the elements of a [`CircularBuffer`]. +/// An owning [iterator](std::iter::Iterator) over the elements of a [`CircularBuffer`] or [`HeapCircularBuffer`]. /// /// This yields the elements of a `CircularBuffer` from fron to back. /// /// This struct is created when iterating over a `CircularBuffer`. See the documentation for /// [`IntoIterator`] for more details. -#[derive(Clone)] -pub struct IntoIter { - inner: CircularBuffer, +/// +/// [`CircularBuffer`]: crate::CircularBuffer +/// [`HeapCircularBuffer`]: crate::heap::HeapCircularBuffer +pub(crate) struct IntoIter + where B: AsSlice> +{ + inner: Backend, +} + +impl Clone for IntoIter; N]> + where T: Clone, +{ + fn clone(&self) -> Self { + use crate::CircularBuffer; + let buf = CircularBuffer::from_iter(self.inner.iter().cloned()); + Self { inner: buf.into_backend() } + } + + fn clone_from(&mut self, other: &Self) { + self.inner.clear(); + self.inner.extend(other.inner.iter().cloned()); + } } -impl IntoIter { - pub(crate) const fn new(inner: CircularBuffer) -> Self { +impl Clone for IntoIter]>> + where T: Clone, +{ + fn clone(&self) -> Self { + use crate::heap::HeapCircularBuffer; + let mut buf = HeapCircularBuffer::with_capacity(self.inner.capacity()); + buf.extend(self.inner.iter().cloned()); + Self { inner: buf.into_backend() } + } + + fn clone_from(&mut self, other: &Self) { + self.inner.clear(); + self.inner.extend(other.inner.iter().cloned()); + } +} + +impl IntoIter + where B: AsSlice> +{ + pub(crate) const fn new(inner: Backend) -> Self { Self { inner } } } -impl Iterator for IntoIter { +impl Iterator for IntoIter + where B: AsSlice> +{ type Item = T; fn next(&mut self) -> Option { @@ -35,31 +76,68 @@ impl Iterator for IntoIter { } } -impl ExactSizeIterator for IntoIter { +impl ExactSizeIterator for IntoIter + where B: AsSlice> +{ #[inline] fn len(&self) -> usize { self.inner.len() } } -impl FusedIterator for IntoIter {} +impl FusedIterator for IntoIter + where B: AsSlice> +{} -impl DoubleEndedIterator for IntoIter { +impl DoubleEndedIterator for IntoIter + where B: AsSlice> +{ fn next_back(&mut self) -> Option { self.inner.pop_back() } } -impl fmt::Debug for IntoIter - where T: fmt::Debug +impl fmt::Debug for IntoIter + where + T: fmt::Debug, + B: AsSlice> + { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.fmt(f) } } -pub(crate) fn translate_range_bounds(buf: &CircularBuffer, range: R) -> (usize, usize) - where R: RangeBounds +/// An owning [iterator](std::iter::Iterator) over the elements of a +/// [`CircularBuffer`] +/// +/// This yields the elements of a `CircularBuffer` from fron to back. +/// +/// This struct is created when iterating over a `CircularBuffer`. See the +/// documentation for [`IntoIterator`] for more details. +/// +/// [`CircularBuffer`]: crate::CircularBuffer +#[derive(Clone)] +pub struct StaticIntoIter(pub(crate) IntoIter; N]>); +super::impl_iter_traits!(<{const N: usize, T}> - StaticIntoIter); + +/// An owning [iterator](std::iter::Iterator) over the elements of a +/// [`HeapCircularBuffer`]. +/// +/// This yields the elements of a `CircularBuffer` from fron to back. +/// +/// This struct is created when iterating over a `CircularBuffer`. See the +/// documentation for [`IntoIterator`] for more details. +/// +/// [`HeapCircularBuffer`]: crate::heap::HeapCircularBuffer +#[derive(Clone)] +pub struct HeapIntoIter(pub(crate) IntoIter]>>); +super::impl_iter_traits!(<{T}> - HeapIntoIter); + +pub(crate) fn translate_range_bounds(buf: &Backend, range: R) -> (usize, usize) + where + R: RangeBounds, + B: AsSlice> { let start = match range.start_bound() { Bound::Included(x) => *x, @@ -183,10 +261,16 @@ fn slice_take_last_mut<'a, T>(slice: &mut &'a mut [T]) -> Option<&'a mut T> { Some(item) } -/// An [iterator](std::iter::Iterator) over the elements of a `CircularBuffer`. +/// An [iterator](std::iter::Iterator) over the elements of a `CircularBuffer` or `HeapCircularBuffer`. /// -/// This struct is created by [`CircularBuffer::iter()`] and [`CircularBuffer::range()`]. See -/// their documentation for more details. +/// This struct is created by [`CircularBuffer::iter()`], +/// [`CircularBuffer::range()`], [`CircularBuffer::iter()`] and +/// [`CircularBuffer::range()`]. See their documentation for more details. +/// +/// [`CircularBuffer::iter()`]: crate::CircularBuffer::iter +/// [`CircularBuffer::range()`]: crate::CircularBuffer::range +/// [`HeapCircularBuffer::iter()`]: crate::heap::HeapCircularBuffer::iter +/// [`HeapCircularBuffer::range()`]: crate::heap::HeapCircularBuffer::range pub struct Iter<'a, T> { pub(crate) right: &'a [T], pub(crate) left: &'a [T], @@ -197,13 +281,17 @@ impl<'a, T> Iter<'a, T> { Self { right: &[], left: &[] } } - pub(crate) fn new(buf: &'a CircularBuffer) -> Self { + pub(crate) fn new(buf: &'a Backend) -> Self + where B: AsSlice> + { let (right, left) = buf.as_slices(); Self { right, left } } - pub(crate) fn over_range(buf: &'a CircularBuffer, range: R) -> Self - where R: RangeBounds + pub(crate) fn over_range(buf: &'a Backend, range: R) -> Self + where + R: RangeBounds, + B: AsSlice> { let (start, end) = translate_range_bounds(buf, range); if start >= end { @@ -305,10 +393,17 @@ impl<'a, T> fmt::Debug for Iter<'a, T> } } -/// A mutable [iterator](std::iter::Iterator) over the elements of a `CircularBuffer`. +/// A mutable [iterator](std::iter::Iterator) over the elements of a `CircularBuffer` or `HeapCircularBuffer`. /// -/// This struct is created by [`CircularBuffer::iter_mut()`] and [`CircularBuffer::range_mut()`]. -/// See their documentation for more details. +/// This struct is created by [`CircularBuffer::iter_mut()`], +/// [`CircularBuffer::range_mut()`], [`HeapCircularBuffer::iter_mut()`] and +/// [`HeapCircularBuffer::range_mut()`]. See their documentation for more +/// details. +/// +/// [`CircularBuffer::iter_mut()`]: crate::CircularBuffer::iter_mut +/// [`CircularBuffer::range_mut()`]: crate::CircularBuffer::range_mut +/// [`HeapCircularBuffer::iter_mut()`]: crate::heap::HeapCircularBuffer::iter_mut +/// [`HeapCircularBuffer::range_mut()`]: crate::heap::HeapCircularBuffer::range_mut pub struct IterMut<'a, T> { right: &'a mut [T], left: &'a mut [T], @@ -319,13 +414,17 @@ impl<'a, T> IterMut<'a, T> { Self { right: &mut [], left: &mut [] } } - pub(crate) fn new(buf: &'a mut CircularBuffer) -> Self { + pub(crate) fn new(buf: &'a mut Backend) -> Self + where B: AsSlice> + { let (right, left) = buf.as_mut_slices(); Self { right, left } } - pub(crate) fn over_range(buf: &'a mut CircularBuffer, range: R) -> Self - where R: RangeBounds + pub(crate) fn over_range(buf: &'a mut Backend, range: R) -> Self + where + R: RangeBounds, + B: AsSlice> { let (start, end) = translate_range_bounds(buf, range); if start >= end { diff --git a/src/lib.rs b/src/lib.rs index aa38379..7f28242 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,20 @@ //! This crate implements a [circular buffer], also known as cyclic buffer, circular queue or ring. //! -//! The main struct is [`CircularBuffer`]. It can live on the stack and does not require any heap -//! memory allocation. A `CircularBuffer` is sequence of elements with a maximum capacity: elements +//! A `CircularBuffer` is sequence of elements with a maximum capacity: elements //! can be added to the buffer, and once the maximum capacity is reached, the elements at the start //! of the buffer are discarded and overwritten. //! +//! The main struct is [`CircularBuffer`], which can live on the stack and does +//! not require any heap memory allocation. It can also be allocated on the heap +//! using its [`CircularBuffer::boxed()`] constructor in `std` environments, but +//! it still requires a compile-time fixed capacity. +//! +//! As an alternative this crate also provides a heap-only variant +//! [`HeapCircularBuffer`], which has a fixed, but at runtime determined +//! capacity. +//! //! [circular buffer]: https://en.wikipedia.org/wiki/Circular_buffer +//! [`HeapCircularBuffer`]: crate::heap::HeapCircularBuffer //! //! # Examples //! @@ -34,10 +43,10 @@ //! //! # Interface //! -//! [`CircularBuffer`] provides methods akin the ones for the standard +//! [`CircularBuffer`] and [`HeapCircularBuffer`] provide methods akin the ones for the standard //! [`VecDeque`](std::collections::VecDeque) and [`LinkedList`](std::collections::LinkedList). The -//! list below includes the most common methods, but see the -//! [`CircularBuffer` struct documentation](CircularBuffer) to see more. +//! list below includes the most common methods, but see the struct documentation of +//! [`CircularBuffer`] and [`HeapCircularBuffer`] to see more. //! //! ## Adding/removing elements //! @@ -63,10 +72,10 @@ //! //! ## Writing/reading bytes //! -//! For the special case of a `CircularBuffer` containing `u8` elements, bytes can be written and -//! read using the standard [`Write`](std::io::Write) and [`Read`](std::io::Read) traits. Writing -//! past the buffer capacity will overwrite the bytes at the start of the buffer, and reading -//! elements will consume elements from the buffer. +//! For the special case of a `CircularBuffer` or `HeapCircularBuffer` containing `u8` elements, +//! bytes can be written and read using the standard [`Write`](std::io::Write) and +//! [`Read`](std::io::Read) traits. Writing past the buffer capacity will overwrite the bytes +//! at the start of the buffer, and reading elements will consume elements from the buffer. //! //! ``` //! use circular_buffer::CircularBuffer; @@ -90,7 +99,7 @@ //! //! # Time complexity //! -//! Most of the methods implemented by [`CircularBuffer`] run in constant time. Some of the methods +//! Most of the methods implemented by [`CircularBuffer`] and [`HeapCircularBuffer`] run in constant time. Some of the methods //! may run in linear time if the type of the elements implements [`Drop`], as each element needs //! to be deallocated one-by-one. //! @@ -113,7 +122,8 @@ //! This can provide optimal performance for small buffers as memory allocation can be avoided. //! //! For large buffers, or for buffers that need to be passed around often, it can be useful to -//! allocate the buffer on the heap. Use a [`Box`](std::boxed) for that: +//! allocate the buffer on the heap. You can either use a [`Box`](std::boxed) for that, if the +//! capacity is known at compile-time: //! //! ``` //! use circular_buffer::CircularBuffer; @@ -129,6 +139,24 @@ //! buf.truncate_back(128); //! assert_eq!(buf.len(), 128); //! ``` +//! +//! or a [`HeapCircularBuffer`], if the capacity is only known at runtime: +//! +//! ``` +//! use circular_buffer::heap::HeapCircularBuffer; +//! +//! let mut buf = HeapCircularBuffer::::with_capacity(4096); +//! assert_eq!(buf.len(), 0); +//! +//! for i in 0..1024 { +//! buf.push_back(i); +//! } +//! assert_eq!(buf.len(), 1024); +//! +//! buf.truncate_back(128); +//! assert_eq!(buf.len(), 128); +//! ``` +//! //! //! # `no_std` //! @@ -164,6 +192,7 @@ mod drain; mod iter; +mod backend; #[cfg(feature = "use_std")] mod io; @@ -171,18 +200,21 @@ mod io; #[cfg(test)] mod tests; +#[cfg(feature = "use_std")] +pub mod heap; + 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; +use backend::Backend; + -pub use crate::drain::Drain; -pub use crate::iter::IntoIter; +pub use crate::drain::StaticDrain as Drain; +pub use crate::iter::StaticIntoIter as IntoIter; pub use crate::iter::Iter; pub use crate::iter::IterMut; @@ -207,6 +239,52 @@ macro_rules! unstable_const_impl { impl $(<$($generics)*>)? $trait for $type { $($tt)* } } } +pub(crate) use unstable_const_impl; + +macro_rules! impl_iter_traits { + ($( <{ $( $generics:tt )* }> )? - $type:ty) => { + impl $(<$($generics)*>)? Iterator for $type { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + } + + impl $(<$($generics)*>)? ExactSizeIterator for $type { + #[inline] + fn len(&self) -> usize { + self.0.len() + } + } + + impl $(<$($generics)*>)? FusedIterator for $type {} + + impl $(<$($generics)*>)? DoubleEndedIterator for $type { + #[inline] + fn next_back(&mut self) -> Option { + self.0.next_back() + } + } + + + impl $(<$($generics)*>)? fmt::Debug for $type + where T: fmt::Debug + { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } + } + }; +} +pub(crate) use impl_iter_traits; /// Returns `(x + y) % m` without risk of overflows if `x + y` cannot fit in `usize`. /// @@ -253,10 +331,10 @@ unsafe fn slice_assume_init_mut(slice: &mut [MaybeUninit]) -> &mut [T] { /// using [`CircularBuffer::boxed()`] if you need the struct to be heap-allocated. /// /// See the [module-level documentation](self) for more details and examples. +#[derive(Ord, Eq, Hash)] +#[repr(transparent)] pub struct CircularBuffer { - size: usize, - start: usize, - items: [MaybeUninit; N], + backend: Backend; N]>, } impl CircularBuffer { @@ -275,17 +353,21 @@ impl CircularBuffer { #[cfg(feature = "unstable")] { Self { - size: 0, - start: 0, - items: MaybeUninit::uninit_array(), + backend: Backend { + size: 0, + start: 0, + items: MaybeUninit::uninit_array(), + } } } #[cfg(not(feature = "unstable"))] { Self { - size: 0, - start: 0, - items: unsafe { MaybeUninit::<[MaybeUninit; N]>::uninit().assume_init() }, + backend: Backend { + size: 0, + start: 0, + items: unsafe { MaybeUninit::<[MaybeUninit; N]>::uninit().assume_init() }, + }, } } } @@ -309,8 +391,8 @@ impl CircularBuffer { unsafe { // SAFETY: the pointer contains enough memory to contain `Self` and `addr_of_mut` // ensures that the address written to is properly aligned. - std::ptr::addr_of_mut!((*ptr).size).write(0); - std::ptr::addr_of_mut!((*ptr).start).write(0); + std::ptr::addr_of_mut!((*ptr).backend.size).write(0); + std::ptr::addr_of_mut!((*ptr).backend.start).write(0); // SAFETY: `size` and `start` have been properly initialized to 0; `items` does not // need to be initialized if `size` is 0 @@ -337,32 +419,12 @@ impl CircularBuffer { unsafe { let layout = std::alloc::Layout::new::(); 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); + std::ptr::addr_of_mut!((*ptr).backend.size).write(0); + std::ptr::addr_of_mut!((*ptr).backend.start).write(0); Box::from_raw(ptr) } } - /// Returns the number of elements in the buffer. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<16, u32>::new(); - /// assert_eq!(buf.len(), 0); - /// - /// buf.push_back(1); - /// buf.push_back(2); - /// buf.push_back(3); - /// assert_eq!(buf.len(), 3); - /// ``` - #[inline] - pub const fn len(&self) -> usize { - self.size - } - /// Returns the capacity of the buffer. /// /// This is the maximum number of elements that the buffer can hold. @@ -381,190 +443,6 @@ impl CircularBuffer { N } - - /// Returns `true` if the buffer contains 0 elements. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<16, u32>::new(); - /// assert!(buf.is_empty()); - /// - /// buf.push_back(1); - /// assert!(!buf.is_empty()); - /// ``` - #[inline] - pub const fn is_empty(&self) -> bool { - self.size == 0 - } - - /// Returns `true` if the number of elements in the buffer matches the buffer capacity. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<5, u32>::new(); - /// assert!(!buf.is_full()); - /// - /// buf.push_back(1); - /// assert!(!buf.is_full()); - /// - /// buf.push_back(2); - /// buf.push_back(3); - /// buf.push_back(4); - /// buf.push_back(5); - /// assert!(buf.is_full()); - /// ``` - #[inline] - pub const fn is_full(&self) -> bool { - self.size == N - } - - /// Returns an iterator over the elements of the buffer. - /// - /// The iterator advances from front to back. Use [`.rev()`](Iter::rev) to advance from - /// back to front. - /// - /// # Examples - /// - /// Iterate from front to back: - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let buf = CircularBuffer::<5, char>::from_iter("abc".chars()); - /// let mut it = buf.iter(); - /// - /// assert_eq!(it.next(), Some(&'a')); - /// assert_eq!(it.next(), Some(&'b')); - /// assert_eq!(it.next(), Some(&'c')); - /// assert_eq!(it.next(), None); - /// ``` - /// - /// Iterate from back to front: - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let buf = CircularBuffer::<5, char>::from_iter("abc".chars()); - /// let mut it = buf.iter().rev(); - /// - /// assert_eq!(it.next(), Some(&'c')); - /// assert_eq!(it.next(), Some(&'b')); - /// assert_eq!(it.next(), Some(&'a')); - /// assert_eq!(it.next(), None); - /// ``` - #[inline] - #[must_use] - pub fn iter(&self) -> Iter<'_, T> { - Iter::new(self) - } - - /// Returns an iterator over the elements of the buffer that allows modifying each value. - /// - /// The iterator advances from front to back. Use [`.rev()`](Iter::rev) to advance from back to - /// front. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<5, u32>::from([1, 2, 3]); - /// for elem in buf.iter_mut() { - /// *elem += 5; - /// } - /// assert_eq!(buf, [6, 7, 8]); - /// ``` - #[inline] - #[must_use] - pub fn iter_mut(&mut self) -> IterMut<'_, T> { - IterMut::new(self) - } - - /// Returns an iterator over the specified range of elements of the buffer. - /// - /// The iterator advances from front to back. Use [`.rev()`](Iter::rev) to advance from back to - /// front. - /// - /// # Panics - /// - /// If the start of the range is greater than the end, or if the end is greater than the length - /// of the buffer. - /// - /// # Examples - /// - /// Iterate from front to back: - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let buf = CircularBuffer::<16, char>::from_iter("abcdefghi".chars()); - /// let mut it = buf.range(3..6); - /// - /// assert_eq!(it.next(), Some(&'d')); - /// assert_eq!(it.next(), Some(&'e')); - /// assert_eq!(it.next(), Some(&'f')); - /// assert_eq!(it.next(), None); - /// ``` - /// - /// Iterate from back to front: - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let buf = CircularBuffer::<16, char>::from_iter("abcdefghi".chars()); - /// let mut it = buf.range(3..6).rev(); - /// - /// assert_eq!(it.next(), Some(&'f')); - /// assert_eq!(it.next(), Some(&'e')); - /// assert_eq!(it.next(), Some(&'d')); - /// assert_eq!(it.next(), None); - /// ``` - #[inline] - #[must_use] - pub fn range(&self, range: R) -> Iter<'_, T> - where R: RangeBounds - { - Iter::over_range(self, range) - } - - /// Returns an iterator over the specified range of elements of the buffer that allows - /// modifying each value. - /// - /// The iterator advances from front to back. Use [`.rev()`](Iter::rev) to advance from back to - /// front. - /// - /// # Panics - /// - /// If the start of the range is greater than the end, or if the end is greater than the length - /// of the buffer. - /// - /// # Examples - /// - /// Iterate from front to back: - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<16, i32>::from_iter([1, 2, 3, 4, 5, 6]); - /// for elem in buf.range_mut(..3) { - /// *elem *= -1; - /// } - /// assert_eq!(buf, [-1, -2, -3, 4, 5, 6]); - /// ``` - #[inline] - #[must_use] - pub fn range_mut(&mut self, range: R) -> IterMut<'_, T> - where R: RangeBounds - { - IterMut::over_range(self, range) - } - /// Removes the specified range from the buffer in bulk, returning the removed elements as an /// iterator. If the iterator is dropped before being fully consumed, it drops the remaining /// removed elements. @@ -610,925 +488,787 @@ impl CircularBuffer { pub fn drain(&mut self, range: R) -> Drain<'_, N, T> where R: RangeBounds { - Drain::over_range(self, range) + Drain(self.backend.drain(range)) } - /// Rearranges the internal memory of the buffer so that all elements are in a contiguous - /// slice, which is then returned. - /// - /// This method does not allocate and does not change the order of the inserted elements. - /// Because it returns a mutable slice, any [slice methods](slice) may be called on the - /// elements of the buffer, such as sorting methods. - /// - /// Once the internal storage is contiguous, the [`as_slices()`](CircularBuffer::as_slices) and - /// [`as_mut_slices()`](CircularBuffer::as_mut_slices) methods will return the entire contents - /// of the deque in a single slice. Adding new elements to the buffer may make the buffer - /// disjoint (not contiguous). - /// - /// # Complexity - /// - /// If the buffer is disjoint (not contiguous), this method takes *O*(*N*) time, where *N* is - /// the capacity of the buffer. - /// - /// If the buffer is already contiguous, this method takes *O*(1) time. - /// - /// This means that this method may be called multiple times on the same buffer without a - /// performance penalty (provided that no new elements are added to the buffer in between - /// calls). - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// // Create a new buffer, adding more elements than its capacity - /// let mut buf = CircularBuffer::<4, u32>::from_iter([1, 4, 3, 0, 2, 5]); - /// assert_eq!(buf, [3, 0, 2, 5]); - /// - /// // The buffer is disjoint: as_slices() returns two non-empty slices - /// assert_eq!(buf.as_slices(), (&[3, 0][..], &[2, 5][..])); - /// - /// // Make the buffer contiguous - /// assert_eq!(buf.make_contiguous(), &mut [3, 0, 2, 5]); - /// // as_slices() now returns a single non-empty slice - /// assert_eq!(buf.as_slices(), (&[3, 0, 2, 5][..], &[][..])); - /// // The buffer order of the elements in the buffer did not get modified - /// assert_eq!(buf, [3, 0, 2, 5]); - /// - /// // Make the buffer contiguous and sort its elements - /// buf.make_contiguous().sort(); - /// assert_eq!(buf, [0, 2, 3, 5]); - /// ``` - pub fn make_contiguous(&mut self) -> &mut [T] { - if N == 0 || self.size == 0 { - return &mut [] - } + pub(crate) fn into_backend(self) -> Backend; N]> { + self.backend + } - debug_assert!(self.start < N, "start out-of-bounds"); - debug_assert!(self.size <= N, "size out-of-bounds"); + impl_buffer!(); +} - let start = self.start; - let end = add_mod(self.start, self.size, N); +macro_rules! impl_buffer { + () => { + /// Returns the number of elements in the buffer. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(16, u32)] + /// assert_eq!(buf.len(), 0); + /// + /// buf.push_back(1); + /// buf.push_back(2); + /// buf.push_back(3); + /// assert_eq!(buf.len(), 3); + /// ``` + #[inline] + pub const fn len(&self) -> usize { + self.backend.len() + } - let slice = if start < end { - // Already contiguous; nothing to do - &mut self.items[start..end] - } else { - // Not contiguous; need to rotate - self.start = 0; - self.items.rotate_left(start); - &mut self.items[..self.size] - }; + /// Returns `true` if the buffer contains 0 elements. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(16, u32)] + /// assert!(buf.is_empty()); + /// + /// buf.push_back(1); + /// assert!(!buf.is_empty()); + /// ``` + #[inline] + pub const fn is_empty(&self) -> bool { + self.backend.is_empty() + } - // SAFETY: The elements in the slice are guaranteed to be initialized - unsafe { slice_assume_init_mut(slice) } - } + /// Returns `true` if the number of elements in the buffer matches the buffer capacity. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(5, u32)] + /// assert!(!buf.is_full()); + /// + /// buf.push_back(1); + /// assert!(!buf.is_full()); + /// + /// buf.push_back(2); + /// buf.push_back(3); + /// buf.push_back(4); + /// buf.push_back(5); + /// assert!(buf.is_full()); + /// ``` + #[inline] + pub const fn is_full(&self) -> bool { + self.len() == self.capacity() + } - /// Returns a pair of slices which contain the elements of this buffer. - /// - /// The second slice may be empty if the internal buffer is contiguous. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<4, char>::new(); - /// buf.push_back('a'); - /// buf.push_back('b'); - /// buf.push_back('c'); - /// buf.push_back('d'); - /// - /// // Buffer is contiguous; second slice is empty - /// assert_eq!(buf.as_slices(), (&['a', 'b', 'c', 'd'][..], &[][..])); - /// - /// buf.push_back('e'); - /// buf.push_back('f'); - /// - /// // Buffer is disjoint; both slices are non-empty - /// assert_eq!(buf.as_slices(), (&['c', 'd'][..], &['e', 'f'][..])); - /// ``` - #[inline] - pub fn as_slices(&self) -> (&[T], &[T]) { - if N == 0 || self.size == 0 { - return (&[], &[]); + /// Returns an iterator over the elements of the buffer. + /// + /// The iterator advances from front to back. Use [`.rev()`](Iter::rev) to advance from + /// back to front. + /// + /// # Examples + /// + /// Iterate from front to back: + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(5, char)] + /// buf.extend("abc".chars()); + /// let mut it = buf.iter(); + /// + /// assert_eq!(it.next(), Some(&'a')); + /// assert_eq!(it.next(), Some(&'b')); + /// assert_eq!(it.next(), Some(&'c')); + /// assert_eq!(it.next(), None); + /// ``` + /// + /// Iterate from back to front: + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(5, char)] + /// buf.extend("abc".chars()); + /// let mut it = buf.iter().rev(); + /// + /// assert_eq!(it.next(), Some(&'c')); + /// assert_eq!(it.next(), Some(&'b')); + /// assert_eq!(it.next(), Some(&'a')); + /// assert_eq!(it.next(), None); + /// ``` + #[inline] + #[must_use] + pub fn iter(&self) -> Iter<'_, T> { + self.backend.iter() } - debug_assert!(self.start < N, "start out-of-bounds"); - debug_assert!(self.size <= N, "size out-of-bounds"); + /// Returns an iterator over the elements of the buffer that allows modifying each value. + /// + /// The iterator advances from front to back. Use [`.rev()`](Iter::rev) to advance from back to + /// front. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(5, u32)] + /// buf.extend([1, 2, 3]); + /// for elem in buf.iter_mut() { + /// *elem += 5; + /// } + /// assert_eq!(buf, [6, 7, 8]); + /// ``` + #[inline] + #[must_use] + pub fn iter_mut(&mut self) -> IterMut<'_, T> { + self.backend.iter_mut() + } - let start = self.start; - let end = add_mod(self.start, self.size, N); + /// Returns an iterator over the specified range of elements of the buffer. + /// + /// The iterator advances from front to back. Use [`.rev()`](Iter::rev) to advance from back to + /// front. + /// + /// # Panics + /// + /// If the start of the range is greater than the end, or if the end is greater than the length + /// of the buffer. + /// + /// # Examples + /// + /// Iterate from front to back: + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(16, char)] + /// buf.extend("abcdefghi".chars()); + /// let mut it = buf.range(3..6); + /// + /// assert_eq!(it.next(), Some(&'d')); + /// assert_eq!(it.next(), Some(&'e')); + /// assert_eq!(it.next(), Some(&'f')); + /// assert_eq!(it.next(), None); + /// ``` + /// + /// Iterate from back to front: + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(16, char)] + /// buf.extend("abcdefghi".chars()); + /// let mut it = buf.range(3..6).rev(); + /// + /// assert_eq!(it.next(), Some(&'f')); + /// assert_eq!(it.next(), Some(&'e')); + /// assert_eq!(it.next(), Some(&'d')); + /// assert_eq!(it.next(), None); + /// ``` + #[inline] + #[must_use] + pub fn range(&self, range: R) -> Iter<'_, T> + where R: RangeBounds + { + self.backend.range(range) + } - let (front, back) = if start < end { - (&self.items[start..end], &[][..]) - } else { - let (back, front) = self.items.split_at(start); - (front, &back[..end]) - }; + /// Returns an iterator over the specified range of elements of the buffer that allows + /// modifying each value. + /// + /// The iterator advances from front to back. Use [`.rev()`](Iter::rev) to advance from back to + /// front. + /// + /// # Panics + /// + /// If the start of the range is greater than the end, or if the end is greater than the length + /// of the buffer. + /// + /// # Examples + /// + /// Iterate from front to back: + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(16, i32)] + /// buf.extend([1, 2, 3, 4, 5, 6]); + /// for elem in buf.range_mut(..3) { + /// *elem *= -1; + /// } + /// assert_eq!(buf, [-1, -2, -3, 4, 5, 6]); + /// ``` + #[inline] + #[must_use] + pub fn range_mut(&mut self, range: R) -> IterMut<'_, T> + where R: RangeBounds + { + self.backend.range_mut(range) + } - // SAFETY: The elements in these slices are guaranteed to be initialized - unsafe { - (slice_assume_init_ref(front), slice_assume_init_ref(back)) + /// Rearranges the internal memory of the buffer so that all elements are in a contiguous + /// slice, which is then returned. + /// + /// This method does not allocate and does not change the order of the inserted elements. + /// Because it returns a mutable slice, any [slice methods](slice) may be called on the + /// elements of the buffer, such as sorting methods. + /// + /// Once the internal storage is contiguous, the [`as_slices()`](Self::as_slices) and + /// [`as_mut_slices()`](Self::as_mut_slices) methods will return the entire contents + /// of the deque in a single slice. Adding new elements to the buffer may make the buffer + /// disjoint (not contiguous). + /// + /// # Complexity + /// + /// If the buffer is disjoint (not contiguous), this method takes *O*(*N*) time, where *N* is + /// the capacity of the buffer. + /// + /// If the buffer is already contiguous, this method takes *O*(1) time. + /// + /// This means that this method may be called multiple times on the same buffer without a + /// performance penalty (provided that no new elements are added to the buffer in between + /// calls). + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + /// // Create a new buffer, adding more elements than its capacity + #[doc = NEW!(4, u32)] + /// buf.extend([1, 4, 3, 0, 2, 5]); + /// assert_eq!(buf, [3, 0, 2, 5]); + /// + /// // The buffer is disjoint: as_slices() returns two non-empty slices + /// assert_eq!(buf.as_slices(), (&[3, 0][..], &[2, 5][..])); + /// + /// // Make the buffer contiguous + /// assert_eq!(buf.make_contiguous(), &mut [3, 0, 2, 5]); + /// // as_slices() now returns a single non-empty slice + /// assert_eq!(buf.as_slices(), (&[3, 0, 2, 5][..], &[][..])); + /// // The buffer order of the elements in the buffer did not get modified + /// assert_eq!(buf, [3, 0, 2, 5]); + /// + /// // Make the buffer contiguous and sort its elements + /// buf.make_contiguous().sort(); + /// assert_eq!(buf, [0, 2, 3, 5]); + /// ``` + pub fn make_contiguous(&mut self) -> &mut [T] { + self.backend.make_contiguous() } - } - /// Returns a pair of mutable slices which contain the elements of this buffer. - /// - /// These slices can be used to modify or replace the elements in the buffer. - /// - /// The second slice may be empty if the internal buffer is contiguous. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<4, char>::new(); - /// buf.push_back('a'); - /// buf.push_back('b'); - /// buf.push_back('c'); - /// buf.push_back('d'); - /// buf.push_back('e'); - /// buf.push_back('f'); - /// - /// assert_eq!(buf, ['c', 'd', 'e', 'f']); - /// - /// let (left, right) = buf.as_mut_slices(); - /// assert_eq!(left, &mut ['c', 'd'][..]); - /// assert_eq!(right, &mut ['e', 'f'][..]); - /// - /// left[0] = 'z'; - /// - /// assert_eq!(buf, ['z', 'd', 'e', 'f']); - /// ``` - #[inline] - pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) { - if N == 0 || self.size == 0 { - return (&mut [][..], &mut [][..]); + /// Returns a pair of slices which contain the elements of this buffer. + /// + /// The second slice may be empty if the internal buffer is contiguous. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(4, char)] + /// buf.push_back('a'); + /// buf.push_back('b'); + /// buf.push_back('c'); + /// buf.push_back('d'); + /// + /// // Buffer is contiguous; second slice is empty + /// assert_eq!(buf.as_slices(), (&['a', 'b', 'c', 'd'][..], &[][..])); + /// + /// buf.push_back('e'); + /// buf.push_back('f'); + /// + /// // Buffer is disjoint; both slices are non-empty + /// assert_eq!(buf.as_slices(), (&['c', 'd'][..], &['e', 'f'][..])); + /// ``` + #[inline] + pub fn as_slices(&self) -> (&[T], &[T]) { + self.backend.as_slices() } - debug_assert!(self.start < N, "start out-of-bounds"); - debug_assert!(self.size <= N, "size out-of-bounds"); + /// Returns a pair of mutable slices which contain the elements of this buffer. + /// + /// These slices can be used to modify or replace the elements in the buffer. + /// + /// The second slice may be empty if the internal buffer is contiguous. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(4, char)] + /// buf.push_back('a'); + /// buf.push_back('b'); + /// buf.push_back('c'); + /// buf.push_back('d'); + /// buf.push_back('e'); + /// buf.push_back('f'); + /// + /// assert_eq!(buf, ['c', 'd', 'e', 'f']); + /// + /// let (left, right) = buf.as_mut_slices(); + /// assert_eq!(left, &mut ['c', 'd'][..]); + /// assert_eq!(right, &mut ['e', 'f'][..]); + /// + /// left[0] = 'z'; + /// + /// assert_eq!(buf, ['z', 'd', 'e', 'f']); + /// ``` + #[inline] + pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) { + self.backend.as_mut_slices() + } + + /// Returns a reference to the back element, or `None` if the buffer is empty. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(4, char)] + /// assert_eq!(buf.back(), None); + /// + /// buf.push_back('a'); + /// buf.push_back('b'); + /// buf.push_back('c'); + /// assert_eq!(buf.back(), Some(&'c')); + /// ``` + #[inline] + pub fn back(&self) -> Option<&T> { + self.backend.back() + } - let start = self.start; - let end = add_mod(self.start, self.size, N); + /// Returns a mutable reference to the back element, or `None` if the buffer is empty. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(4, char)] + /// assert_eq!(buf.back_mut(), None); + /// + /// buf.push_back('a'); + /// buf.push_back('b'); + /// buf.push_back('c'); + /// match buf.back_mut() { + /// None => (), + /// Some(x) => *x = 'z', + /// } + /// assert_eq!(buf, ['a', 'b', 'z']); + /// ``` + #[inline] + pub fn back_mut(&mut self) -> Option<&mut T> { + self.backend.back_mut() + } - let (front, back) = if start < end { - (&mut self.items[start..end], &mut [][..]) - } else { - let (back, front) = self.items.split_at_mut(start); - (front, &mut back[..end]) - }; + /// Returns a reference to the front element, or `None` if the buffer is empty. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(4, char)] + /// assert_eq!(buf.front(), None); + /// + /// buf.push_back('a'); + /// buf.push_back('b'); + /// buf.push_back('c'); + /// assert_eq!(buf.front(), Some(&'a')); + /// ``` + #[inline] + pub fn front(&self) -> Option<&T> { + self.backend.front() + } - // SAFETY: The elements in these slices are guaranteed to be initialized - unsafe { - (slice_assume_init_mut(front), slice_assume_init_mut(back)) + /// Returns a mutable reference to the front element, or `None` if the buffer is empty. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(4, char)] + /// assert_eq!(buf.front_mut(), None); + /// + /// buf.push_back('a'); + /// buf.push_back('b'); + /// buf.push_back('c'); + /// match buf.front_mut() { + /// None => (), + /// Some(x) => *x = 'z', + /// } + /// assert_eq!(buf, ['z', 'b', 'c']); + /// ``` + #[inline] + pub fn front_mut(&mut self) -> Option<&mut T> { + self.backend.front_mut() } - } - #[inline] - fn front_maybe_uninit_mut(&mut self) -> &mut MaybeUninit { - debug_assert!(self.size > 0, "empty buffer"); - debug_assert!(self.start < N, "start out-of-bounds"); - &mut self.items[self.start] - } + /// Returns a reference to the element at the given index, or `None` if the element does not + /// exist. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(4, char)] + /// assert_eq!(buf.get(1), None); + /// + /// buf.push_back('a'); + /// buf.push_back('b'); + /// buf.push_back('c'); + /// assert_eq!(buf.get(1), Some(&'b')); + /// ``` + #[inline] + pub fn get(&self, index: usize) -> Option<&T> { + self.backend.get(index) + } - #[inline] - const fn front_maybe_uninit(&self) -> &MaybeUninit { - 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] - } + /// Returns a mutable reference to the element at the given index, or `None` if the element + /// does not exist. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(4, char)] + /// assert_eq!(buf.get_mut(1), None); + /// + /// buf.push_back('a'); + /// buf.push_back('b'); + /// buf.push_back('c'); + /// match buf.get_mut(1) { + /// None => (), + /// Some(x) => *x = 'z', + /// } + /// assert_eq!(buf, ['a', 'z', 'c']); + /// ``` + #[inline] + pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { + self.backend.get_mut(index) + } - #[inline] - const fn back_maybe_uninit(&self) -> &MaybeUninit { - 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] - } + /// Appends an element to the back of the buffer. + /// + /// If the buffer is full, the element at the front of the buffer is automatically dropped and + /// overwritten. + /// + /// See also [`try_push_back()`](Self::try_push_back) for a non-overwriting version + /// of this method. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(3, char)] + /// + /// buf.push_back('a'); assert_eq!(buf, ['a']); + /// buf.push_back('b'); assert_eq!(buf, ['a', 'b']); + /// buf.push_back('c'); assert_eq!(buf, ['a', 'b', 'c']); + /// // The buffer is now full; adding more values causes the front elements to be dropped + /// buf.push_back('d'); assert_eq!(buf, ['b', 'c', 'd']); + /// buf.push_back('e'); assert_eq!(buf, ['c', 'd', 'e']); + /// buf.push_back('f'); assert_eq!(buf, ['d', 'e', 'f']); + /// ``` + pub fn push_back(&mut self, item: T) { + self.backend.push_back(item) + } - #[inline] - fn back_maybe_uninit_mut(&mut self) -> &mut MaybeUninit { - 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] - } + /// Appends an element to the back of the buffer. + /// + /// If the buffer is full, the buffer is not modified and the given element is returned as an + /// error. + /// + /// See also [`push_back()`](Self::push_back) for a version of this method that + /// overwrites the front of the buffer when full. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(3, char)] + /// + /// assert_eq!(buf.try_push_back('a'), Ok(())); assert_eq!(buf, ['a']); + /// assert_eq!(buf.try_push_back('b'), Ok(())); assert_eq!(buf, ['a', 'b']); + /// assert_eq!(buf.try_push_back('c'), Ok(())); assert_eq!(buf, ['a', 'b', 'c']); + /// // The buffer is now full; adding more values results in an error + /// assert_eq!(buf.try_push_back('d'), Err('d')) + /// ``` + pub fn try_push_back(&mut self, item: T) -> Result<(), T> { + self.backend.try_push_back(item) + } - #[inline] - const fn get_maybe_uninit(&self, index: usize) -> &MaybeUninit { - 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] - } + /// Appends an element to the front of the buffer. + /// + /// If the buffer is full, the element at the back of the buffer is automatically dropped and + /// overwritten. + /// + /// See also [`try_push_front()`](Self::try_push_front) for a non-overwriting version + /// of this method. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(3, char)] + /// + /// buf.push_front('a'); assert_eq!(buf, ['a']); + /// buf.push_front('b'); assert_eq!(buf, ['b', 'a']); + /// buf.push_front('c'); assert_eq!(buf, ['c', 'b', 'a']); + /// // The buffer is now full; adding more values causes the back elements to be dropped + /// buf.push_front('d'); assert_eq!(buf, ['d', 'c', 'b']); + /// buf.push_front('e'); assert_eq!(buf, ['e', 'd', 'c']); + /// buf.push_front('f'); assert_eq!(buf, ['f', 'e', 'd']); + /// ``` + pub fn push_front(&mut self, item: T) { + self.backend.push_front(item) + } - #[inline] - fn get_maybe_uninit_mut(&mut self, index: usize) -> &mut MaybeUninit { - 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] - } + /// Appends an element to the front of the buffer. + /// + /// If the buffer is full, the buffer is not modified and the given element is returned as an + /// error. + /// + /// See also [`push_front()`](Self::push_front) for a version of this method that + /// overwrites the back of the buffer when full. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(3, char)] + /// + /// assert_eq!(buf.try_push_front('a'), Ok(())); assert_eq!(buf, ['a']); + /// assert_eq!(buf.try_push_front('b'), Ok(())); assert_eq!(buf, ['b', 'a']); + /// assert_eq!(buf.try_push_front('c'), Ok(())); assert_eq!(buf, ['c', 'b', 'a']); + /// // The buffer is now full; adding more values results in an error + /// assert_eq!(buf.try_push_front('d'), Err('d')); + /// ``` + pub fn try_push_front(&mut self, item: T) -> Result<(), T> { + self.backend.try_push_front(item) + } - #[inline] - fn slices_uninit_mut(&mut self) -> (&mut [MaybeUninit], &mut [MaybeUninit]) { - if N == 0 { - return (&mut [][..], &mut [][..]); + /// Removes and returns an element from the back of the buffer. + /// + /// If the buffer is empty, `None` is returned. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(3, char)] + /// buf.extend(['a', 'b', 'c']); + /// + /// assert_eq!(buf.pop_back(), Some('c')); + /// assert_eq!(buf.pop_back(), Some('b')); + /// assert_eq!(buf.pop_back(), Some('a')); + /// assert_eq!(buf.pop_back(), None); + /// ``` + pub fn pop_back(&mut self) -> Option { + self.backend.pop_back() } - 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) + /// Removes and returns an element from the front of the buffer. + /// + /// If the buffer is empty, `None` is returned. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(3, char)] + /// buf.extend(['a', 'b', 'c']); + /// + /// assert_eq!(buf.pop_front(), Some('a')); + /// assert_eq!(buf.pop_front(), Some('b')); + /// assert_eq!(buf.pop_front(), Some('c')); + /// assert_eq!(buf.pop_front(), None); + /// ``` + pub fn pop_front(&mut self) -> Option { + self.backend.pop_front() } - } - #[inline] - fn inc_start(&mut self) { - debug_assert!(self.start < N, "start out-of-bounds"); - self.start = add_mod(self.start, 1, N); - } + /// Removes and returns an element at the specified index. + /// + /// If the index is out of bounds, `None` is returned. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(3, char)] + /// buf.extend(['a', 'b', 'c']); + /// + /// assert_eq!(buf.remove(1), Some('b')); + /// assert_eq!(buf, ['a', 'c']); + /// + /// assert_eq!(buf.remove(5), None); + /// ``` + pub fn remove(&mut self, index: usize) -> Option { + self.backend.remove(index) + } - #[inline] - fn dec_start(&mut self) { - debug_assert!(self.start < N, "start out-of-bounds"); - self.start = sub_mod(self.start, 1, N); - } + /// Swap the element at index `i` with the element at index `j`. + /// + /// # Panics + /// + /// If either `i` or `j` is out of bounds. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(5, char)] + /// buf.extend(['a', 'b', 'c', 'd']); + /// assert_eq!(buf, ['a', 'b', 'c', 'd']); + /// + /// buf.swap(0, 3); + /// assert_eq!(buf, ['d', 'b', 'c', 'a']); + /// ``` + /// + /// Trying to swap an invalid index panics: + /// + /// ```should_panic + #[doc = USE!()] + #[doc = NEW!(5, char)] + /// buf.extend(['a', 'b', 'c', 'd']); + /// buf.swap(0, 7); + /// ``` + pub fn swap(&mut self, i: usize, j: usize) { + self.backend.swap(i, j) + } - #[inline] - fn inc_size(&mut self) { - debug_assert!(self.size <= N, "size out-of-bounds"); - debug_assert!(self.size < N, "size at capacity limit"); - self.size += 1; - } - - #[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) { - 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.start < self.size, "start of range out-of-bounds"); - debug_assert!(range.end <= self.size, "end of range out-of-bounds"); - debug_assert!(range.start < range.end, "start of range is past its end"); - debug_assert!(range.start == 0 || range.end == self.size, - "range does not include boundary of the buffer"); - - // Drops all the items in the slice when dropped. This is needed to ensure that all - // elements are dropped in case a panic occurs during the drop of a single element. - struct Dropper<'a, T>(&'a mut [MaybeUninit]); - - impl<'a, T> Drop for Dropper<'a, T> { - #[inline] - fn drop(&mut self) { - // SAFETY: the caller of `drop_range` is responsible to check that this slice was - // initialized. - unsafe { ptr::drop_in_place(slice_assume_init_mut(self.0)); } - } - } - - 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); - } - - /// Returns a reference to the back element, or `None` if the buffer is empty. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<4, char>::new(); - /// assert_eq!(buf.back(), None); - /// - /// buf.push_back('a'); - /// buf.push_back('b'); - /// buf.push_back('c'); - /// assert_eq!(buf.back(), Some(&'c')); - /// ``` - #[inline] - pub fn back(&self) -> Option<&T> { - if N == 0 || self.size == 0 { - // Nothing to do - return None; - } - // SAFETY: `size` is non-zero; back element is guaranteed to be initialized - Some(unsafe { self.back_maybe_uninit().assume_init_ref() }) - } - - /// Returns a mutable reference to the back element, or `None` if the buffer is empty. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<4, char>::new(); - /// assert_eq!(buf.back_mut(), None); - /// - /// buf.push_back('a'); - /// buf.push_back('b'); - /// buf.push_back('c'); - /// match buf.back_mut() { - /// None => (), - /// Some(x) => *x = 'z', - /// } - /// assert_eq!(buf, ['a', 'b', 'z']); - /// ``` - #[inline] - pub fn back_mut(&mut self) -> Option<&mut T> { - if N == 0 || self.size == 0 { - // Nothing to do - return None; - } - // SAFETY: `size` is non-zero; back element is guaranteed to be initialized - Some(unsafe { self.back_maybe_uninit_mut().assume_init_mut() }) - } - - /// Returns a reference to the front element, or `None` if the buffer is empty. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<4, char>::new(); - /// assert_eq!(buf.front(), None); - /// - /// buf.push_back('a'); - /// buf.push_back('b'); - /// buf.push_back('c'); - /// assert_eq!(buf.front(), Some(&'a')); - /// ``` - #[inline] - pub fn front(&self) -> Option<&T> { - if N == 0 || self.size == 0 { - // Nothing to do - return None; - } - // SAFETY: `size` is non-zero; front element is guaranteed to be initialized - Some(unsafe { self.front_maybe_uninit().assume_init_ref() }) - } - - /// Returns a mutable reference to the front element, or `None` if the buffer is empty. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<4, char>::new(); - /// assert_eq!(buf.front_mut(), None); - /// - /// buf.push_back('a'); - /// buf.push_back('b'); - /// buf.push_back('c'); - /// match buf.front_mut() { - /// None => (), - /// Some(x) => *x = 'z', - /// } - /// assert_eq!(buf, ['z', 'b', 'c']); - /// ``` - #[inline] - pub fn front_mut(&mut self) -> Option<&mut T> { - if N == 0 || self.size == 0 { - // Nothing to do - return None; - } - // SAFETY: `size` is non-zero; front element is guaranteed to be initialized - Some(unsafe { self.front_maybe_uninit_mut().assume_init_mut() }) - } - - /// Returns a reference to the element at the given index, or `None` if the element does not - /// exist. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<4, char>::new(); - /// assert_eq!(buf.get(1), None); - /// - /// buf.push_back('a'); - /// buf.push_back('b'); - /// buf.push_back('c'); - /// assert_eq!(buf.get(1), Some(&'b')); - /// ``` - #[inline] - pub fn get(&self, index: usize) -> Option<&T> { - if N == 0 || index >= self.size { - // Nothing to do - return None; - } - // SAFETY: `index` is in a valid range; it is guaranteed to point to an initialized element - Some(unsafe { self.get_maybe_uninit(index).assume_init_ref() }) - } - - /// Returns a mutable reference to the element at the given index, or `None` if the element - /// does not exist. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<4, char>::new(); - /// assert_eq!(buf.get_mut(1), None); - /// - /// buf.push_back('a'); - /// buf.push_back('b'); - /// buf.push_back('c'); - /// match buf.get_mut(1) { - /// None => (), - /// Some(x) => *x = 'z', - /// } - /// assert_eq!(buf, ['a', 'z', 'c']); - /// ``` - #[inline] - pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { - if N == 0 || index >= self.size { - // Nothing to do - return None; + /// Removes the element at `index` and returns it, replacing it with the back of the buffer. + /// + /// Returns `None` if `index` is out-of-bounds. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(5, char)] + /// buf.extend(['a', 'b', 'c', 'd']); + /// assert_eq!(buf, ['a', 'b', 'c', 'd']); + /// + /// assert_eq!(buf.swap_remove_back(2), Some('c')); + /// assert_eq!(buf, ['a', 'b', 'd']); + /// + /// assert_eq!(buf.swap_remove_back(7), None); + /// ``` + pub fn swap_remove_back(&mut self, index: usize) -> Option { + self.backend.swap_remove_back(index) } - // SAFETY: `index` is in a valid range; it is guaranteed to point to an initialized element - Some(unsafe { self.get_maybe_uninit_mut(index).assume_init_mut() }) - } - /// Appends an element to the back of the buffer. - /// - /// If the buffer is full, the element at the front of the buffer is automatically dropped and - /// overwritten. - /// - /// See also [`try_push_back()`](CircularBuffer::try_push_back) for a non-overwriting version - /// of this method. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<3, char>::new(); - /// - /// buf.push_back('a'); assert_eq!(buf, ['a']); - /// buf.push_back('b'); assert_eq!(buf, ['a', 'b']); - /// buf.push_back('c'); assert_eq!(buf, ['a', 'b', 'c']); - /// // The buffer is now full; adding more values causes the front elements to be dropped - /// buf.push_back('d'); assert_eq!(buf, ['b', 'c', 'd']); - /// buf.push_back('e'); assert_eq!(buf, ['c', 'd', 'e']); - /// buf.push_back('f'); assert_eq!(buf, ['d', 'e', 'f']); - /// ``` - pub fn push_back(&mut self, item: T) { - if N == 0 { - // Nothing to do - return; - } - if self.size >= N { - // At capacity; need to replace the front item - // - // SAFETY: if size is greater than 0, the front item is guaranteed to be initialized. - unsafe { ptr::drop_in_place(self.front_maybe_uninit_mut().as_mut_ptr()); } - self.front_maybe_uninit_mut().write(item); - self.inc_start(); - } else { - // Some uninitialized slots left; append at the end - self.inc_size(); - self.back_maybe_uninit_mut().write(item); + /// Removes the element at `index` and returns it, replacing it with the front of the buffer. + /// + /// Returns `None` if `index` is out-of-bounds. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(5, char)] + /// buf.extend(['a', 'b', 'c', 'd']); + /// assert_eq!(buf, ['a', 'b', 'c', 'd']); + /// + /// assert_eq!(buf.swap_remove_front(2), Some('c')); + /// assert_eq!(buf, ['b', 'a', 'd']); + /// + /// assert_eq!(buf.swap_remove_front(7), None); + /// ``` + pub fn swap_remove_front(&mut self, index: usize) -> Option { + self.backend.swap_remove_front(index) } - } - /// Appends an element to the back of the buffer. - /// - /// If the buffer is full, the buffer is not modified and the given element is returned as an - /// error. - /// - /// See also [`push_back()`](CircularBuffer::push_back) for a version of this method that - /// overwrites the front of the buffer when full. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<3, char>::new(); - /// - /// assert_eq!(buf.try_push_back('a'), Ok(())); assert_eq!(buf, ['a']); - /// assert_eq!(buf.try_push_back('b'), Ok(())); assert_eq!(buf, ['a', 'b']); - /// assert_eq!(buf.try_push_back('c'), Ok(())); assert_eq!(buf, ['a', 'b', 'c']); - /// // The buffer is now full; adding more values results in an error - /// assert_eq!(buf.try_push_back('d'), Err('d')) - /// ``` - pub fn try_push_back(&mut self, item: T) -> Result<(), T> { - if N == 0 { - // Nothing to do - return Ok(()); - } - if self.size >= N { - // At capacity; return the pushed item as error - Err(item) - } else { - // Some uninitialized slots left; append at the end - self.inc_size(); - self.back_maybe_uninit_mut().write(item); - Ok(()) + /// Shortens the buffer, keeping only the front `len` elements and dropping the rest. + /// + /// If `len` is equal or greater to the buffer's current length, this has no effect. + /// + /// Calling `truncate_back(0)` is equivalent to [`clear()`](Self::clear). + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(4, u32)] + /// buf.extend([10, 20, 30]); + /// + /// buf.truncate_back(1); + /// assert_eq!(buf, [10]); + /// + /// // Truncating to a length that is greater than the buffer's length has no effect + /// buf.truncate_back(8); + /// assert_eq!(buf, [10]); + /// ``` + pub fn truncate_back(&mut self, len: usize) { + self.backend.truncate_back(len) } - } - /// Appends an element to the front of the buffer. - /// - /// If the buffer is full, the element at the back of the buffer is automatically dropped and - /// overwritten. - /// - /// See also [`try_push_front()`](CircularBuffer::try_push_front) for a non-overwriting version - /// of this method. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<3, char>::new(); - /// - /// buf.push_front('a'); assert_eq!(buf, ['a']); - /// buf.push_front('b'); assert_eq!(buf, ['b', 'a']); - /// buf.push_front('c'); assert_eq!(buf, ['c', 'b', 'a']); - /// // The buffer is now full; adding more values causes the back elements to be dropped - /// buf.push_front('d'); assert_eq!(buf, ['d', 'c', 'b']); - /// buf.push_front('e'); assert_eq!(buf, ['e', 'd', 'c']); - /// buf.push_front('f'); assert_eq!(buf, ['f', 'e', 'd']); - /// ``` - pub fn push_front(&mut self, item: T) { - if N == 0 { - // Nothing to do - return; - } - if self.size >= N { - // At capacity; need to replace the back item - // - // SAFETY: if size is greater than 0, the front item is guaranteed to be initialized. - unsafe { ptr::drop_in_place(self.back_maybe_uninit_mut().as_mut_ptr()); } - self.back_maybe_uninit_mut().write(item); - self.dec_start(); - } else { - // Some uninitialized slots left; insert at the start - self.inc_size(); - self.dec_start(); - self.front_maybe_uninit_mut().write(item); - } - } - - /// Appends an element to the front of the buffer. - /// - /// If the buffer is full, the buffer is not modified and the given element is returned as an - /// error. - /// - /// See also [`push_front()`](CircularBuffer::push_front) for a version of this method that - /// overwrites the back of the buffer when full. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<3, char>::new(); - /// - /// assert_eq!(buf.try_push_front('a'), Ok(())); assert_eq!(buf, ['a']); - /// assert_eq!(buf.try_push_front('b'), Ok(())); assert_eq!(buf, ['b', 'a']); - /// assert_eq!(buf.try_push_front('c'), Ok(())); assert_eq!(buf, ['c', 'b', 'a']); - /// // The buffer is now full; adding more values results in an error - /// assert_eq!(buf.try_push_front('d'), Err('d')); - /// ``` - pub fn try_push_front(&mut self, item: T) -> Result<(), T> { - if N == 0 { - // Nothing to do - return Ok(()); - } - if self.size >= N { - // At capacity; return the pushed item as error - Err(item) - } else { - // Some uninitialized slots left; insert at the start - self.inc_size(); - self.dec_start(); - self.front_maybe_uninit_mut().write(item); - Ok(()) + /// Shortens the buffer, keeping only the back `len` elements and dropping the rest. + /// + /// If `len` is equal or greater to the buffer's current length, this has no effect. + /// + /// Calling `truncate_front(0)` is equivalent to [`clear()`](Self::clear). + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(4, u32)] + /// buf.extend([10, 20, 30]); + /// + /// buf.truncate_front(1); + /// assert_eq!(buf, [30]); + /// + /// // Truncating to a length that is greater than the buffer's length has no effect + /// buf.truncate_front(8); + /// assert_eq!(buf, [30]); + /// ``` + pub fn truncate_front(&mut self, len: usize) { + self.backend.truncate_front(len) } - } - /// Removes and returns an element from the back of the buffer. - /// - /// If the buffer is empty, `None` is returned. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<3, char>::from(['a', 'b', 'c']); - /// - /// assert_eq!(buf.pop_back(), Some('c')); - /// assert_eq!(buf.pop_back(), Some('b')); - /// assert_eq!(buf.pop_back(), Some('a')); - /// assert_eq!(buf.pop_back(), None); - /// ``` - pub fn pop_back(&mut self) -> Option { - if N == 0 || self.size == 0 { - // Nothing to do - return None; - } - - // SAFETY: if size is greater than 0, the back item is guaranteed to be initialized. - let back = unsafe { self.back_maybe_uninit().assume_init_read() }; - self.dec_size(); - Some(back) - } - - /// Removes and returns an element from the front of the buffer. - /// - /// If the buffer is empty, `None` is returned. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<3, char>::from(['a', 'b', 'c']); - /// - /// assert_eq!(buf.pop_front(), Some('a')); - /// assert_eq!(buf.pop_front(), Some('b')); - /// assert_eq!(buf.pop_front(), Some('c')); - /// assert_eq!(buf.pop_front(), None); - /// ``` - pub fn pop_front(&mut self) -> Option { - if N == 0 || self.size == 0 { - // Nothing to do - return None; - } - - // SAFETY: if size is greater than 0, the front item is guaranteed to be initialized. - let back = unsafe { self.front_maybe_uninit().assume_init_read() }; - self.dec_size(); - self.inc_start(); - Some(back) - } - - /// Removes and returns an element at the specified index. - /// - /// If the index is out of bounds, `None` is returned. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<3, char>::from(['a', 'b', 'c']); - /// - /// assert_eq!(buf.remove(1), Some('b')); - /// assert_eq!(buf, ['a', 'c']); - /// - /// assert_eq!(buf.remove(5), None); - /// ``` - pub fn remove(&mut self, index: usize) -> Option { - 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); - - // SAFETY: `index` is in a valid range; the element is guaranteed to be initialized - let item = unsafe { self.items[index].assume_init_read() }; - - // SAFETY: the pointers being moved are in a valid range; the elements behind those - // pointers are guaranteed to be initialized - unsafe { - // TODO: optimize for the case where `index < len - index` (i.e. when copying items to - // the right is cheaper than moving items to the left) - let ptr = self.items.as_mut_ptr(); - if back_index >= index { - // Move the values at the right of `index` by 1 position to the left - ptr::copy(ptr.add(index).add(1), ptr.add(index), back_index - index); - } else { - // Move the values at the right of `index` by 1 position to the left - ptr::copy(ptr.add(index).add(1), ptr.add(index), N - index); - // Move the leftmost value to the end of the array - ptr::copy(ptr, ptr.add(N - 1), 1); - // Move the values at the left of `back_index` by 1 position to the left - ptr::copy(ptr.add(1), ptr, back_index); - } - } - - self.dec_size(); - Some(item) - } - - /// Swap the element at index `i` with the element at index `j`. - /// - /// # Panics - /// - /// If either `i` or `j` is out of bounds. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<5, char>::from(['a', 'b', 'c', 'd']); - /// assert_eq!(buf, ['a', 'b', 'c', 'd']); - /// - /// buf.swap(0, 3); - /// assert_eq!(buf, ['d', 'b', 'c', 'a']); - /// ``` - /// - /// Trying to swap an invalid index panics: - /// - /// ```should_panic - /// use circular_buffer::CircularBuffer; - /// let mut buf = CircularBuffer::<5, char>::from(['a', 'b', 'c', 'd']); - /// buf.swap(0, 7); - /// ``` - 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); - // SAFETY: these are valid pointers - unsafe { ptr::swap_nonoverlapping(&mut self.items[i], &mut self.items[j], 1) }; - } - } - - /// Removes the element at `index` and returns it, replacing it with the back of the buffer. - /// - /// Returns `None` if `index` is out-of-bounds. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<5, char>::from(['a', 'b', 'c', 'd']); - /// assert_eq!(buf, ['a', 'b', 'c', 'd']); - /// - /// assert_eq!(buf.swap_remove_back(2), Some('c')); - /// assert_eq!(buf, ['a', 'b', 'd']); - /// - /// assert_eq!(buf.swap_remove_back(7), None); - /// ``` - pub fn swap_remove_back(&mut self, index: usize) -> Option { - if index >= self.size { - return None; - } - self.swap(index, self.size - 1); - self.pop_back() - } - - /// Removes the element at `index` and returns it, replacing it with the front of the buffer. - /// - /// Returns `None` if `index` is out-of-bounds. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<5, char>::from(['a', 'b', 'c', 'd']); - /// assert_eq!(buf, ['a', 'b', 'c', 'd']); - /// - /// assert_eq!(buf.swap_remove_front(2), Some('c')); - /// assert_eq!(buf, ['b', 'a', 'd']); - /// - /// assert_eq!(buf.swap_remove_front(7), None); - /// ``` - pub fn swap_remove_front(&mut self, index: usize) -> Option { - if index >= self.size { - return None; - } - self.swap(index, 0); - self.pop_front() - } - - /// Shortens the buffer, keeping only the front `len` elements and dropping the rest. - /// - /// If `len` is equal or greater to the buffer's current length, this has no effect. - /// - /// Calling `truncate_back(0)` is equivalent to [`clear()`](Self::clear). - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<4, u32>::from([10, 20, 30]); - /// - /// buf.truncate_back(1); - /// assert_eq!(buf, [10]); - /// - /// // Truncating to a length that is greater than the buffer's length has no effect - /// buf.truncate_back(8); - /// assert_eq!(buf, [10]); - /// ``` - pub fn truncate_back(&mut self, len: usize) { - if N == 0 || len >= self.size { - // Nothing to do - return; - } - - let drop_range = len..self.size; - // SAFETY: `drop_range` is a valid range, so elements within are guaranteed to be - // initialized. The `size` of the buffer is shrunk before dropping, so no value will be - // dropped twice in case of panics. - unsafe { self.drop_range(drop_range) }; - self.size = len; - } - - /// Shortens the buffer, keeping only the back `len` elements and dropping the rest. - /// - /// If `len` is equal or greater to the buffer's current length, this has no effect. - /// - /// Calling `truncate_front(0)` is equivalent to [`clear()`](Self::clear). - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<4, u32>::from([10, 20, 30]); - /// - /// buf.truncate_front(1); - /// assert_eq!(buf, [30]); - /// - /// // Truncating to a length that is greater than the buffer's length has no effect - /// buf.truncate_front(8); - /// assert_eq!(buf, [30]); - /// ``` - pub fn truncate_front(&mut self, len: usize) { - if N == 0 || len >= self.size { - // Nothing to do - return; + /// Drops all the elements in the buffer. + /// + /// # Examples + /// + /// ``` + #[doc = USE!()] + /// + #[doc = NEW!(4, u32)] + /// buf.extend([10, 20, 30]); + /// assert_eq!(buf, [10, 20, 30]); + /// buf.clear(); + /// assert_eq!(buf, []); + /// ``` + #[inline] + pub fn clear(&mut self) { + self.backend.clear() } - - let drop_len = self.size - len; - let drop_range = 0..drop_len; - // SAFETY: `drop_range` is a valid range, so elements within are guaranteed to be - // initialized. The `start` of the buffer is shrunk before dropping, so no value will be - // dropped twice in case of panics. - unsafe { self.drop_range(drop_range) }; - self.start = add_mod(self.start, drop_len, N); - self.size = len; - } - - /// Drops all the elements in the buffer. - /// - /// # Examples - /// - /// ``` - /// use circular_buffer::CircularBuffer; - /// - /// let mut buf = CircularBuffer::<4, u32>::from([10, 20, 30]); - /// assert_eq!(buf, [10, 20, 30]); - /// buf.clear(); - /// assert_eq!(buf, []); - /// ``` - #[inline] - pub fn clear(&mut self) { - self.truncate_back(0) } } +pub(crate) use impl_buffer; impl CircularBuffer where T: Clone @@ -1550,97 +1290,7 @@ impl CircularBuffer /// assert_eq!(buf, [3, 4, 5, 6, 7]); /// ``` 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(dst: &mut [MaybeUninit], src: &[T]) { - // Each call to `clone()` may panic, therefore we need to track how many elements we - // successfully cloned so that we can drop them in case of panic. This `Guard` struct - // does exactly that: it keeps track of how many items have been successfully cloned - // and drops them if the guard is dropped. - // - // This implementation was highly inspired by the implementation of - // `MaybeUninit::write_slice_cloned` - struct Guard<'a, T> { - dst: &'a mut [MaybeUninit], - initialized: usize, - } - - impl<'a, T> Drop for Guard<'a, T> { - fn drop(&mut self) { - let initialized = &mut self.dst[..self.initialized]; - // SAFETY: this slice contain only initialized objects; `MaybeUninit` has - // the same alignment and size as `T` - unsafe { - let initialized = &mut *(initialized as *mut [MaybeUninit] 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; - } - - // All the `clone()` calls succeded; get rid of the guard without running its `drop()` - // implementation - mem::forget(guard); - } - - if other.len() < N { - // All the elements of `other` fit into the buffer - let free_size = N - self.size; - let final_size = if other.len() < free_size { - // All the elements of `other` fit at the back of the buffer - self.size + other.len() - } else { - // Some of the elements of `other` need to overwrite the front of the buffer - 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 { - // `other` overwrites the whole buffer; get only the last `N` elements from `other` and - // overwrite - 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; - } + self.backend.extend_from_slice(other) } /// Clones the elements of the buffer into a new [`Vec`], leaving the buffer unchanged. @@ -1659,10 +1309,7 @@ impl CircularBuffer #[must_use] #[cfg(feature = "use_std")] pub fn to_vec(&self) -> Vec { - let mut vec = Vec::with_capacity(self.size); - vec.extend(self.iter().cloned()); - debug_assert_eq!(vec.len(), self.size); - vec + self.backend.to_vec() } } @@ -1700,7 +1347,8 @@ impl From<[T; M]> for CircularBuffer { unsafe { ptr::drop_in_place(&mut arr[..M - size]); } mem::forget(arr); - Self { size, start: 0, items: elems } + let backend = Backend { size, start: 0, items: elems }; + Self { backend } } } @@ -1719,8 +1367,7 @@ impl Extend for CircularBuffer { fn extend(&mut self, iter: I) where I: IntoIterator { - // TODO Optimize - iter.into_iter().for_each(|item| self.push_back(item)); + self.backend.extend(iter) } } @@ -1730,8 +1377,7 @@ impl<'a, const N: usize, T> Extend<&'a T> for CircularBuffer fn extend(&mut self, iter: I) where I: IntoIterator { - // TODO Optimize - iter.into_iter().for_each(|item| self.push_back(*item)); + self.backend.extend(iter) } } @@ -1742,7 +1388,7 @@ unstable_const_impl! { #[inline] fn into_iter(self) -> Self::IntoIter { - IntoIter::new(self) + IntoIter(self.backend.into_iter()) } } } @@ -1754,7 +1400,7 @@ unstable_const_impl! { #[inline] fn into_iter(self) -> Self::IntoIter { - Iter::new(self) + Iter::new(&self.backend) } } } @@ -1763,49 +1409,15 @@ impl PartialEq> for C where T: PartialEq { fn eq(&self, other: &CircularBuffer) -> 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_left[x..] == b_right[..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 - }, - } + self.backend.eq(&other.backend) } } -impl Eq for CircularBuffer where T: Eq {} - impl PartialEq<[U]> for CircularBuffer where T: PartialEq { 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 + self.backend.eq(other) } } @@ -1858,24 +1470,7 @@ impl PartialOrd> for where T: PartialOrd { fn partial_cmp(&self, other: &CircularBuffer) -> Option { - self.iter().partial_cmp(other.iter()) - } -} - -impl Ord for CircularBuffer - where T: Ord -{ - fn cmp(&self, other: &Self) -> Ordering { - self.iter().cmp(other.iter()) - } -} - -impl Hash for CircularBuffer - where T: Hash -{ - fn hash(&self, state: &mut H) { - self.size.hash(state); - self.iter().for_each(|item| item.hash(state)); + self.backend.partial_cmp(&other.backend) } } @@ -1894,18 +1489,20 @@ impl Clone for CircularBuffer } } -impl Drop for CircularBuffer { - #[inline] - fn drop(&mut self) { - // `clear()` will make sure that every element is dropped in a safe way - self.clear(); - } -} - impl fmt::Debug for CircularBuffer where T: fmt::Debug { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self).finish() + self.backend.fmt(f) } } + +macro_rules! USE { + () => { "use circular_buffer::CircularBuffer;" }; +} +macro_rules! NEW { + ($N:literal,$ty:ty) => { + concat!("let mut buf = CircularBuffer::<",$N,", ",stringify!($ty),">::new();") + }; +} +use {USE, NEW}; \ No newline at end of file diff --git a/src/tests.rs b/src/tests.rs index 0307a58..0c376dd 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,6 +1,6 @@ #![cfg(test)] -use crate::CircularBuffer; +use crate::{CircularBuffer, heap::HeapCircularBuffer}; use drop_tracker::DropItem; use drop_tracker::DropTracker; use std::collections::hash_map::DefaultHasher; @@ -10,11 +10,6 @@ use std::io::Read; use std::io::Write; use std::ops::Bound; -fn is_contiguous(buf: &CircularBuffer) -> bool { - let slices = buf.as_slices(); - slices.1.is_empty() -} - macro_rules! assert_buf_eq { ( $buf:ident , [] $( as [ $( $arrtyp:tt )* ] )? ) => { let expected = [] $(as [ $($arrtyp)* ])?; @@ -55,1637 +50,1663 @@ macro_rules! assert_buf_slices_eq { } } -#[test] -fn attrs() { - let mut buf = CircularBuffer::<4, u32>::new(); - assert_eq!(buf.len(), 0); - assert!(buf.is_empty()); - assert!(!buf.is_full()); - - buf.push_back(1); - assert_eq!(buf.len(), 1); - assert!(!buf.is_empty()); - assert!(!buf.is_full()); - - buf.push_back(2); - assert_eq!(buf.len(), 2); - assert!(!buf.is_empty()); - assert!(!buf.is_full()); - - buf.push_back(3); - assert_eq!(buf.len(), 3); - assert!(!buf.is_empty()); - assert!(!buf.is_full()); - - buf.push_back(4); - assert_eq!(buf.len(), 4); - assert!(!buf.is_empty()); - assert!(buf.is_full()); - - buf.push_back(5); - assert_eq!(buf.len(), 4); - assert!(!buf.is_empty()); - assert!(buf.is_full()); - - buf.push_back(6); - assert_eq!(buf.len(), 4); - assert!(!buf.is_empty()); - assert!(buf.is_full()); - - buf.clear(); - assert_eq!(buf.len(), 0); - assert!(buf.is_empty()); - assert!(!buf.is_full()); -} +macro_rules! tests { + () => { + #[test] + fn attrs() { + let mut buf = new::<4, u32>(); + assert_eq!(buf.len(), 0); + assert!(buf.is_empty()); + assert!(!buf.is_full()); + + buf.push_back(1); + assert_eq!(buf.len(), 1); + assert!(!buf.is_empty()); + assert!(!buf.is_full()); + + buf.push_back(2); + assert_eq!(buf.len(), 2); + assert!(!buf.is_empty()); + assert!(!buf.is_full()); + + buf.push_back(3); + assert_eq!(buf.len(), 3); + assert!(!buf.is_empty()); + assert!(!buf.is_full()); + + buf.push_back(4); + assert_eq!(buf.len(), 4); + assert!(!buf.is_empty()); + assert!(buf.is_full()); + + buf.push_back(5); + assert_eq!(buf.len(), 4); + assert!(!buf.is_empty()); + assert!(buf.is_full()); + + buf.push_back(6); + assert_eq!(buf.len(), 4); + assert!(!buf.is_empty()); + assert!(buf.is_full()); + + buf.clear(); + assert_eq!(buf.len(), 0); + assert!(buf.is_empty()); + assert!(!buf.is_full()); + } -#[test] -fn push_back() { - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<4, DropItem>::new(); - assert_buf_eq!(buf, [] as [i32; 0]); - - buf.push_back(tracker.track(1)); - assert_buf_eq!(buf, [1]); - tracker.assert_all_alive([1]); - tracker.assert_fully_alive(); - - buf.push_back(tracker.track(2)); - assert_buf_eq!(buf, [1, 2]); - tracker.assert_all_alive([1, 2]); - tracker.assert_fully_alive(); - - buf.push_back(tracker.track(3)); - assert_buf_eq!(buf, [1, 2, 3]); - tracker.assert_all_alive([1, 2, 3]); - tracker.assert_fully_alive(); - - buf.push_back(tracker.track(4)); - assert_buf_eq!(buf, [1, 2, 3, 4]); - tracker.assert_all_alive([1, 2, 3, 4]); - tracker.assert_fully_alive(); - - buf.push_back(tracker.track(5)); - assert_buf_eq!(buf, [2, 3, 4, 5]); - tracker.assert_all_alive([2, 3, 4, 5]); - tracker.assert_all_dropped([1]); - - buf.push_back(tracker.track(6)); - assert_buf_eq!(buf, [3, 4, 5, 6]); - tracker.assert_all_alive([3, 4, 5, 6]); - tracker.assert_all_dropped([1, 2]); - - buf.push_back(tracker.track(7)); - assert_buf_eq!(buf, [4, 5, 6, 7]); - tracker.assert_all_alive([4, 5, 6, 7]); - tracker.assert_all_dropped([1, 2, 3]); - - buf.push_back(tracker.track(8)); - assert_buf_eq!(buf, [5, 6, 7, 8]); - tracker.assert_all_alive([5, 6, 7, 8]); - tracker.assert_all_dropped([1, 2, 3, 4]); -} + #[test] + fn push_back() { + let mut tracker = DropTracker::new(); + let mut buf = new::<4, DropItem>(); + assert_buf_eq!(buf, [] as [i32; 0]); + + buf.push_back(tracker.track(1)); + assert_buf_eq!(buf, [1]); + tracker.assert_all_alive([1]); + tracker.assert_fully_alive(); + + buf.push_back(tracker.track(2)); + assert_buf_eq!(buf, [1, 2]); + tracker.assert_all_alive([1, 2]); + tracker.assert_fully_alive(); + + buf.push_back(tracker.track(3)); + assert_buf_eq!(buf, [1, 2, 3]); + tracker.assert_all_alive([1, 2, 3]); + tracker.assert_fully_alive(); + + buf.push_back(tracker.track(4)); + assert_buf_eq!(buf, [1, 2, 3, 4]); + tracker.assert_all_alive([1, 2, 3, 4]); + tracker.assert_fully_alive(); + + buf.push_back(tracker.track(5)); + assert_buf_eq!(buf, [2, 3, 4, 5]); + tracker.assert_all_alive([2, 3, 4, 5]); + tracker.assert_all_dropped([1]); + + buf.push_back(tracker.track(6)); + assert_buf_eq!(buf, [3, 4, 5, 6]); + tracker.assert_all_alive([3, 4, 5, 6]); + tracker.assert_all_dropped([1, 2]); + + buf.push_back(tracker.track(7)); + assert_buf_eq!(buf, [4, 5, 6, 7]); + tracker.assert_all_alive([4, 5, 6, 7]); + tracker.assert_all_dropped([1, 2, 3]); + + buf.push_back(tracker.track(8)); + assert_buf_eq!(buf, [5, 6, 7, 8]); + tracker.assert_all_alive([5, 6, 7, 8]); + tracker.assert_all_dropped([1, 2, 3, 4]); + } -#[test] -fn push_front() { - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<4, DropItem>::new(); - assert_buf_eq!(buf, [] as [i32; 0]); - - buf.push_front(tracker.track(1)); - assert_buf_eq!(buf, [1]); - tracker.assert_all_alive([1]); - tracker.assert_fully_alive(); - - buf.push_front(tracker.track(2)); - assert_buf_eq!(buf, [2, 1]); - tracker.assert_all_alive([1, 2]); - tracker.assert_fully_alive(); - - buf.push_front(tracker.track(3)); - assert_buf_eq!(buf, [3, 2, 1]); - tracker.assert_all_alive([1, 2, 3]); - tracker.assert_fully_alive(); - - buf.push_front(tracker.track(4)); - assert_buf_eq!(buf, [4, 3, 2, 1]); - tracker.assert_all_alive([1, 2, 3, 4]); - tracker.assert_fully_alive(); - - buf.push_front(tracker.track(5)); - assert_buf_eq!(buf, [5, 4, 3, 2]); - tracker.assert_all_alive([2, 3, 4, 5]); - tracker.assert_all_dropped([1]); - - buf.push_front(tracker.track(6)); - assert_buf_eq!(buf, [6, 5, 4, 3]); - tracker.assert_all_alive([3, 4, 5, 6]); - tracker.assert_all_dropped([1, 2]); - - buf.push_front(tracker.track(7)); - assert_buf_eq!(buf, [7, 6, 5, 4]); - tracker.assert_all_alive([4, 5, 6, 7]); - tracker.assert_all_dropped([1, 2, 3]); - - buf.push_front(tracker.track(8)); - assert_buf_eq!(buf, [8, 7, 6, 5]); - tracker.assert_all_alive([5, 6, 7, 8]); - tracker.assert_all_dropped([1, 2, 3, 4]); -} + #[test] + fn push_front() { + let mut tracker = DropTracker::new(); + let mut buf = new::<4, DropItem>(); + assert_buf_eq!(buf, [] as [i32; 0]); + + buf.push_front(tracker.track(1)); + assert_buf_eq!(buf, [1]); + tracker.assert_all_alive([1]); + tracker.assert_fully_alive(); + + buf.push_front(tracker.track(2)); + assert_buf_eq!(buf, [2, 1]); + tracker.assert_all_alive([1, 2]); + tracker.assert_fully_alive(); + + buf.push_front(tracker.track(3)); + assert_buf_eq!(buf, [3, 2, 1]); + tracker.assert_all_alive([1, 2, 3]); + tracker.assert_fully_alive(); + + buf.push_front(tracker.track(4)); + assert_buf_eq!(buf, [4, 3, 2, 1]); + tracker.assert_all_alive([1, 2, 3, 4]); + tracker.assert_fully_alive(); + + buf.push_front(tracker.track(5)); + assert_buf_eq!(buf, [5, 4, 3, 2]); + tracker.assert_all_alive([2, 3, 4, 5]); + tracker.assert_all_dropped([1]); + + buf.push_front(tracker.track(6)); + assert_buf_eq!(buf, [6, 5, 4, 3]); + tracker.assert_all_alive([3, 4, 5, 6]); + tracker.assert_all_dropped([1, 2]); + + buf.push_front(tracker.track(7)); + assert_buf_eq!(buf, [7, 6, 5, 4]); + tracker.assert_all_alive([4, 5, 6, 7]); + tracker.assert_all_dropped([1, 2, 3]); + + buf.push_front(tracker.track(8)); + assert_buf_eq!(buf, [8, 7, 6, 5]); + tracker.assert_all_alive([5, 6, 7, 8]); + tracker.assert_all_dropped([1, 2, 3, 4]); + } -#[test] -fn pop_back() { - let mut buf = CircularBuffer::<4, u32>::new(); - assert_buf_eq!(buf, [] as [u32; 0]); - - assert_eq!(buf.pop_back(), None); assert_buf_eq!(buf, [] as [u32; 0]); - - buf.push_back(1); assert_buf_eq!(buf, [1]); - assert_eq!(buf.pop_back(), Some(1)); assert_buf_eq!(buf, [] as [u32; 0]); - assert_eq!(buf.pop_back(), None); assert_buf_eq!(buf, [] as [u32; 0]); - - buf.push_back(2); assert_buf_eq!(buf, [2]); - buf.push_back(3); assert_buf_eq!(buf, [2, 3]); - assert_eq!(buf.pop_back(), Some(3)); assert_buf_eq!(buf, [2]); - assert_eq!(buf.pop_back(), Some(2)); assert_buf_eq!(buf, [] as [u32; 0]); - assert_eq!(buf.pop_back(), None); assert_buf_eq!(buf, [] as [u32; 0]); - - buf.push_back(4); assert_buf_eq!(buf, [4]); - buf.push_back(5); assert_buf_eq!(buf, [4, 5]); - buf.push_back(6); assert_buf_eq!(buf, [4, 5, 6]); - buf.push_back(7); assert_buf_eq!(buf, [4, 5, 6, 7]); - buf.push_back(8); assert_buf_eq!(buf, [5, 6, 7, 8]); - assert_eq!(buf.pop_back(), Some(8)); assert_buf_eq!(buf, [5, 6, 7]); - assert_eq!(buf.pop_back(), Some(7)); assert_buf_eq!(buf, [5, 6]); - assert_eq!(buf.pop_back(), Some(6)); assert_buf_eq!(buf, [5]); - assert_eq!(buf.pop_back(), Some(5)); assert_buf_eq!(buf, [] as [u32; 0]); - assert_eq!(buf.pop_back(), None); assert_buf_eq!(buf, [] as [u32; 0]); -} + #[test] + fn pop_back() { + let mut buf = new::<4, u32>(); + assert_buf_eq!(buf, [] as [u32; 0]); + + assert_eq!(buf.pop_back(), None); assert_buf_eq!(buf, [] as [u32; 0]); + + buf.push_back(1); assert_buf_eq!(buf, [1]); + assert_eq!(buf.pop_back(), Some(1)); assert_buf_eq!(buf, [] as [u32; 0]); + assert_eq!(buf.pop_back(), None); assert_buf_eq!(buf, [] as [u32; 0]); + + buf.push_back(2); assert_buf_eq!(buf, [2]); + buf.push_back(3); assert_buf_eq!(buf, [2, 3]); + assert_eq!(buf.pop_back(), Some(3)); assert_buf_eq!(buf, [2]); + assert_eq!(buf.pop_back(), Some(2)); assert_buf_eq!(buf, [] as [u32; 0]); + assert_eq!(buf.pop_back(), None); assert_buf_eq!(buf, [] as [u32; 0]); + + buf.push_back(4); assert_buf_eq!(buf, [4]); + buf.push_back(5); assert_buf_eq!(buf, [4, 5]); + buf.push_back(6); assert_buf_eq!(buf, [4, 5, 6]); + buf.push_back(7); assert_buf_eq!(buf, [4, 5, 6, 7]); + buf.push_back(8); assert_buf_eq!(buf, [5, 6, 7, 8]); + assert_eq!(buf.pop_back(), Some(8)); assert_buf_eq!(buf, [5, 6, 7]); + assert_eq!(buf.pop_back(), Some(7)); assert_buf_eq!(buf, [5, 6]); + assert_eq!(buf.pop_back(), Some(6)); assert_buf_eq!(buf, [5]); + assert_eq!(buf.pop_back(), Some(5)); assert_buf_eq!(buf, [] as [u32; 0]); + assert_eq!(buf.pop_back(), None); assert_buf_eq!(buf, [] as [u32; 0]); + } -#[test] -fn pop_front() { - let mut buf = CircularBuffer::<4, u32>::new(); - assert_buf_eq!(buf, [] as [u32; 0]); - - assert_eq!(buf.pop_front(), None); assert_buf_eq!(buf, [] as [u32; 0]); - - buf.push_front(1); assert_buf_eq!(buf, [1]); - assert_eq!(buf.pop_front(), Some(1)); assert_buf_eq!(buf, [] as [u32; 0]); - assert_eq!(buf.pop_front(), None); assert_buf_eq!(buf, [] as [u32; 0]); - - buf.push_front(2); assert_buf_eq!(buf, [2]); - buf.push_front(3); assert_buf_eq!(buf, [3, 2]); - assert_eq!(buf.pop_front(), Some(3)); assert_buf_eq!(buf, [2]); - assert_eq!(buf.pop_front(), Some(2)); assert_buf_eq!(buf, [] as [u32; 0]); - assert_eq!(buf.pop_front(), None); assert_buf_eq!(buf, [] as [u32; 0]); - - buf.push_front(4); assert_buf_eq!(buf, [4]); - buf.push_front(5); assert_buf_eq!(buf, [5, 4]); - buf.push_front(6); assert_buf_eq!(buf, [6, 5, 4]); - buf.push_front(7); assert_buf_eq!(buf, [7, 6, 5, 4]); - buf.push_front(8); assert_buf_eq!(buf, [8, 7, 6, 5]); - assert_eq!(buf.pop_front(), Some(8)); assert_buf_eq!(buf, [7, 6, 5]); - assert_eq!(buf.pop_front(), Some(7)); assert_buf_eq!(buf, [6, 5]); - assert_eq!(buf.pop_front(), Some(6)); assert_buf_eq!(buf, [5]); - assert_eq!(buf.pop_front(), Some(5)); assert_buf_eq!(buf, [] as [u32; 0]); - assert_eq!(buf.pop_front(), None); assert_buf_eq!(buf, [] as [u32; 0]); -} + #[test] + fn pop_front() { + let mut buf = new::<4, u32>(); + assert_buf_eq!(buf, [] as [u32; 0]); + + assert_eq!(buf.pop_front(), None); assert_buf_eq!(buf, [] as [u32; 0]); + + buf.push_front(1); assert_buf_eq!(buf, [1]); + assert_eq!(buf.pop_front(), Some(1)); assert_buf_eq!(buf, [] as [u32; 0]); + assert_eq!(buf.pop_front(), None); assert_buf_eq!(buf, [] as [u32; 0]); + + buf.push_front(2); assert_buf_eq!(buf, [2]); + buf.push_front(3); assert_buf_eq!(buf, [3, 2]); + assert_eq!(buf.pop_front(), Some(3)); assert_buf_eq!(buf, [2]); + assert_eq!(buf.pop_front(), Some(2)); assert_buf_eq!(buf, [] as [u32; 0]); + assert_eq!(buf.pop_front(), None); assert_buf_eq!(buf, [] as [u32; 0]); + + buf.push_front(4); assert_buf_eq!(buf, [4]); + buf.push_front(5); assert_buf_eq!(buf, [5, 4]); + buf.push_front(6); assert_buf_eq!(buf, [6, 5, 4]); + buf.push_front(7); assert_buf_eq!(buf, [7, 6, 5, 4]); + buf.push_front(8); assert_buf_eq!(buf, [8, 7, 6, 5]); + assert_eq!(buf.pop_front(), Some(8)); assert_buf_eq!(buf, [7, 6, 5]); + assert_eq!(buf.pop_front(), Some(7)); assert_buf_eq!(buf, [6, 5]); + assert_eq!(buf.pop_front(), Some(6)); assert_buf_eq!(buf, [5]); + assert_eq!(buf.pop_front(), Some(5)); assert_buf_eq!(buf, [] as [u32; 0]); + assert_eq!(buf.pop_front(), None); assert_buf_eq!(buf, [] as [u32; 0]); + } -#[test] -fn remove() { - let mut buf = CircularBuffer::<4, u32>::new(); - assert_buf_eq!(buf, [] as [u32; 0]); - - assert_eq!(buf.remove(0), None); - assert_eq!(buf.remove(1), None); - assert_eq!(buf.remove(2), None); - assert_eq!(buf.remove(3), None); - assert_eq!(buf.remove(4), None); - assert_eq!(buf.remove(5), None); - assert_buf_eq!(buf, [] as [u32; 0]); - - buf.push_back(1); assert_buf_eq!(buf, [1]); - assert_eq!(buf.remove(0), Some(1)); assert_buf_eq!(buf, [] as [u32; 0]); - - buf.push_back(2); assert_buf_eq!(buf, [2]); - buf.push_back(3); assert_buf_eq!(buf, [2, 3]); - buf.push_back(4); assert_buf_eq!(buf, [2, 3, 4]); - assert_eq!(buf.remove(1), Some(3)); assert_buf_eq!(buf, [2, 4]); - - buf.push_back(5); assert_buf_eq!(buf, [2, 4, 5]); - buf.push_back(6); assert_buf_eq!(buf, [2, 4, 5, 6]); - buf.push_back(7); assert_buf_eq!(buf, [4, 5, 6, 7]); - buf.push_back(8); assert_buf_eq!(buf, [5, 6, 7, 8]); - assert_eq!(buf.remove(2), Some(7)); assert_buf_eq!(buf, [5, 6, 8]); - assert_eq!(buf.remove(2), Some(8)); assert_buf_eq!(buf, [5, 6]); - assert_eq!(buf.remove(1), Some(6)); assert_buf_eq!(buf, [5]); - assert_eq!(buf.remove(0), Some(5)); assert_buf_eq!(buf, [] as [u32; 0]); -} + #[test] + fn remove() { + let mut buf = new::<4, u32>(); + assert_buf_eq!(buf, [] as [u32; 0]); + + assert_eq!(buf.remove(0), None); + assert_eq!(buf.remove(1), None); + assert_eq!(buf.remove(2), None); + assert_eq!(buf.remove(3), None); + assert_eq!(buf.remove(4), None); + assert_eq!(buf.remove(5), None); + assert_buf_eq!(buf, [] as [u32; 0]); + + buf.push_back(1); assert_buf_eq!(buf, [1]); + assert_eq!(buf.remove(0), Some(1)); assert_buf_eq!(buf, [] as [u32; 0]); + + buf.push_back(2); assert_buf_eq!(buf, [2]); + buf.push_back(3); assert_buf_eq!(buf, [2, 3]); + buf.push_back(4); assert_buf_eq!(buf, [2, 3, 4]); + assert_eq!(buf.remove(1), Some(3)); assert_buf_eq!(buf, [2, 4]); + + buf.push_back(5); assert_buf_eq!(buf, [2, 4, 5]); + buf.push_back(6); assert_buf_eq!(buf, [2, 4, 5, 6]); + buf.push_back(7); assert_buf_eq!(buf, [4, 5, 6, 7]); + buf.push_back(8); assert_buf_eq!(buf, [5, 6, 7, 8]); + assert_eq!(buf.remove(2), Some(7)); assert_buf_eq!(buf, [5, 6, 8]); + assert_eq!(buf.remove(2), Some(8)); assert_buf_eq!(buf, [5, 6]); + assert_eq!(buf.remove(1), Some(6)); assert_buf_eq!(buf, [5]); + assert_eq!(buf.remove(0), Some(5)); assert_buf_eq!(buf, [] as [u32; 0]); + } -#[test] -fn truncate_back() { - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<4, DropItem>::new(); - assert_buf_eq!(buf, [] as [i32; 0]); - - buf.push_back(tracker.track(1)); - buf.push_back(tracker.track(2)); - buf.push_back(tracker.track(3)); - buf.push_back(tracker.track(4)); - assert_buf_eq!(buf, [1, 2, 3, 4]); - tracker.assert_all_alive([1, 2, 3, 4]); - tracker.assert_fully_alive(); - - buf.truncate_back(2); - assert_buf_eq!(buf, [1, 2]); - tracker.assert_all_alive([1, 2]); - tracker.assert_all_dropped([3, 4]); - - buf.truncate_back(0); - assert_buf_eq!(buf, [] as [i32; 0]); - tracker.assert_fully_dropped(); - tracker.assert_all_dropped([1, 2, 3, 4]); - - // Explicitly drop `buf` here to avoid an early implicit drop - drop(buf); -} + #[test] + fn truncate_back() { + let mut tracker = DropTracker::new(); + let mut buf = new::<4, DropItem>(); + assert_buf_eq!(buf, [] as [i32; 0]); + + buf.push_back(tracker.track(1)); + buf.push_back(tracker.track(2)); + buf.push_back(tracker.track(3)); + buf.push_back(tracker.track(4)); + assert_buf_eq!(buf, [1, 2, 3, 4]); + tracker.assert_all_alive([1, 2, 3, 4]); + tracker.assert_fully_alive(); + + buf.truncate_back(2); + assert_buf_eq!(buf, [1, 2]); + tracker.assert_all_alive([1, 2]); + tracker.assert_all_dropped([3, 4]); + + buf.truncate_back(0); + assert_buf_eq!(buf, [] as [i32; 0]); + tracker.assert_fully_dropped(); + tracker.assert_all_dropped([1, 2, 3, 4]); + + // Explicitly drop `buf` here to avoid an early implicit drop + drop(buf); + } -#[test] -fn truncate_front() { - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<4, DropItem>::new(); - assert_buf_eq!(buf, [] as [i32; 0]); - - buf.push_back(tracker.track(1)); - buf.push_back(tracker.track(2)); - buf.push_back(tracker.track(3)); - buf.push_back(tracker.track(4)); - assert_buf_eq!(buf, [1, 2, 3, 4]); - tracker.assert_all_alive([1, 2, 3, 4]); - tracker.assert_fully_alive(); - - buf.truncate_front(2); - assert_buf_eq!(buf, [3, 4]); - tracker.assert_all_alive([3, 4]); - tracker.assert_all_dropped([1, 2]); - - buf.truncate_front(0); - assert_buf_eq!(buf, [] as [i32; 0]); - tracker.assert_fully_dropped(); - tracker.assert_all_dropped([1, 2, 3, 4]); - - // Explicitly drop `buf` here to avoid an early implicit drop - drop(buf); -} + #[test] + fn truncate_front() { + let mut tracker = DropTracker::new(); + let mut buf = new::<4, DropItem>(); + assert_buf_eq!(buf, [] as [i32; 0]); + + buf.push_back(tracker.track(1)); + buf.push_back(tracker.track(2)); + buf.push_back(tracker.track(3)); + buf.push_back(tracker.track(4)); + assert_buf_eq!(buf, [1, 2, 3, 4]); + tracker.assert_all_alive([1, 2, 3, 4]); + tracker.assert_fully_alive(); + + buf.truncate_front(2); + assert_buf_eq!(buf, [3, 4]); + tracker.assert_all_alive([3, 4]); + tracker.assert_all_dropped([1, 2]); + + buf.truncate_front(0); + assert_buf_eq!(buf, [] as [i32; 0]); + tracker.assert_fully_dropped(); + tracker.assert_all_dropped([1, 2, 3, 4]); + + // Explicitly drop `buf` here to avoid an early implicit drop + drop(buf); + } -#[test] -fn get() { - let mut buf = CircularBuffer::<4, u32>::new(); - assert_buf_eq!(buf, [] as [u32; 0]); - - assert_eq!(buf.get(0), None); - assert_eq!(buf.get(1), None); - assert_eq!(buf.get(2), None); - assert_eq!(buf.get(3), None); - assert_eq!(buf.get(4), None); - assert_eq!(buf.get(5), None); - - buf.push_back(1); assert_buf_eq!(buf, [1]); - assert_eq!(buf.get(0), Some(&1)); - assert_eq!(buf.get(1), None); - - buf.push_back(2); assert_buf_eq!(buf, [1, 2]); - assert_eq!(buf.get(0), Some(&1)); - assert_eq!(buf.get(1), Some(&2)); - assert_eq!(buf.get(2), None); - - buf.push_back(3); assert_buf_eq!(buf, [1, 2, 3]); - assert_eq!(buf.get(0), Some(&1)); - assert_eq!(buf.get(1), Some(&2)); - assert_eq!(buf.get(2), Some(&3)); - assert_eq!(buf.get(3), None); - - buf.push_back(4); assert_buf_eq!(buf, [1, 2, 3, 4]); - assert_eq!(buf.get(0), Some(&1)); - assert_eq!(buf.get(1), Some(&2)); - assert_eq!(buf.get(2), Some(&3)); - assert_eq!(buf.get(3), Some(&4)); - assert_eq!(buf.get(4), None); - - buf.push_back(5); assert_buf_eq!(buf, [2, 3, 4, 5]); - assert_eq!(buf.get(0), Some(&2)); - assert_eq!(buf.get(1), Some(&3)); - assert_eq!(buf.get(2), Some(&4)); - assert_eq!(buf.get(3), Some(&5)); - assert_eq!(buf.get(4), None); - - buf.push_back(6); assert_buf_eq!(buf, [3, 4, 5, 6]); - assert_eq!(buf.get(0), Some(&3)); - assert_eq!(buf.get(1), Some(&4)); - assert_eq!(buf.get(2), Some(&5)); - assert_eq!(buf.get(3), Some(&6)); - assert_eq!(buf.get(5), None); - - buf.push_back(7); assert_buf_eq!(buf, [4, 5, 6, 7]); - assert_eq!(buf.get(0), Some(&4)); - assert_eq!(buf.get(1), Some(&5)); - assert_eq!(buf.get(2), Some(&6)); - assert_eq!(buf.get(3), Some(&7)); - assert_eq!(buf.get(4), None); - - buf.push_back(8); assert_buf_eq!(buf, [5, 6, 7, 8]); - assert_eq!(buf.get(0), Some(&5)); - assert_eq!(buf.get(1), Some(&6)); - assert_eq!(buf.get(2), Some(&7)); - assert_eq!(buf.get(3), Some(&8)); - assert_eq!(buf.get(4), None); + #[test] + fn get() { + let mut buf = new::<4, u32>(); + assert_buf_eq!(buf, [] as [u32; 0]); + + assert_eq!(buf.get(0), None); + assert_eq!(buf.get(1), None); + assert_eq!(buf.get(2), None); + assert_eq!(buf.get(3), None); + assert_eq!(buf.get(4), None); + assert_eq!(buf.get(5), None); + + buf.push_back(1); assert_buf_eq!(buf, [1]); + assert_eq!(buf.get(0), Some(&1)); + assert_eq!(buf.get(1), None); + + buf.push_back(2); assert_buf_eq!(buf, [1, 2]); + assert_eq!(buf.get(0), Some(&1)); + assert_eq!(buf.get(1), Some(&2)); + assert_eq!(buf.get(2), None); + + buf.push_back(3); assert_buf_eq!(buf, [1, 2, 3]); + assert_eq!(buf.get(0), Some(&1)); + assert_eq!(buf.get(1), Some(&2)); + assert_eq!(buf.get(2), Some(&3)); + assert_eq!(buf.get(3), None); + + buf.push_back(4); assert_buf_eq!(buf, [1, 2, 3, 4]); + assert_eq!(buf.get(0), Some(&1)); + assert_eq!(buf.get(1), Some(&2)); + assert_eq!(buf.get(2), Some(&3)); + assert_eq!(buf.get(3), Some(&4)); + assert_eq!(buf.get(4), None); + + buf.push_back(5); assert_buf_eq!(buf, [2, 3, 4, 5]); + assert_eq!(buf.get(0), Some(&2)); + assert_eq!(buf.get(1), Some(&3)); + assert_eq!(buf.get(2), Some(&4)); + assert_eq!(buf.get(3), Some(&5)); + assert_eq!(buf.get(4), None); + + buf.push_back(6); assert_buf_eq!(buf, [3, 4, 5, 6]); + assert_eq!(buf.get(0), Some(&3)); + assert_eq!(buf.get(1), Some(&4)); + assert_eq!(buf.get(2), Some(&5)); + assert_eq!(buf.get(3), Some(&6)); + assert_eq!(buf.get(5), None); + + buf.push_back(7); assert_buf_eq!(buf, [4, 5, 6, 7]); + assert_eq!(buf.get(0), Some(&4)); + assert_eq!(buf.get(1), Some(&5)); + assert_eq!(buf.get(2), Some(&6)); + assert_eq!(buf.get(3), Some(&7)); + assert_eq!(buf.get(4), None); + + buf.push_back(8); assert_buf_eq!(buf, [5, 6, 7, 8]); + assert_eq!(buf.get(0), Some(&5)); + assert_eq!(buf.get(1), Some(&6)); + assert_eq!(buf.get(2), Some(&7)); + assert_eq!(buf.get(3), Some(&8)); + assert_eq!(buf.get(4), None); -} + } -#[test] -fn iter() { - let buf = CircularBuffer::<8, u32>::new(); - let mut iter = buf.iter(); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, u32>::from([1, 2, 3, 4]); - let mut iter = buf.iter(); - assert_eq!(iter.next(), Some(&1)); - assert_eq!(iter.next(), Some(&2)); - assert_eq!(iter.next(), Some(&3)); - assert_eq!(iter.next(), Some(&4)); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, u32>::from([1, 2, 3, 4, 5, 6, 7, 8]); - let mut iter = buf.iter(); - assert_eq!(iter.next(), Some(&1)); - assert_eq!(iter.next(), Some(&2)); - assert_eq!(iter.next(), Some(&3)); - assert_eq!(iter.next(), Some(&4)); - assert_eq!(iter.next(), Some(&5)); - assert_eq!(iter.next(), Some(&6)); - assert_eq!(iter.next(), Some(&7)); - assert_eq!(iter.next(), Some(&8)); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); -} + #[test] + fn iter() { + let buf = new::<8, u32>(); + let mut iter = buf.iter(); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = new_from_iter::<8, u32, _>([1, 2, 3, 4]); + let mut iter = buf.iter(); + assert_eq!(iter.next(), Some(&1)); + assert_eq!(iter.next(), Some(&2)); + assert_eq!(iter.next(), Some(&3)); + assert_eq!(iter.next(), Some(&4)); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = new_from_iter::<8, u32, _>([1, 2, 3, 4, 5, 6, 7, 8]); + let mut iter = buf.iter(); + assert_eq!(iter.next(), Some(&1)); + assert_eq!(iter.next(), Some(&2)); + assert_eq!(iter.next(), Some(&3)); + assert_eq!(iter.next(), Some(&4)); + assert_eq!(iter.next(), Some(&5)); + assert_eq!(iter.next(), Some(&6)); + assert_eq!(iter.next(), Some(&7)); + assert_eq!(iter.next(), Some(&8)); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + } -#[test] -fn iter_rev() { - let buf = CircularBuffer::<8, u32>::new(); - let mut iter = buf.iter().rev(); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, u32>::from([1, 2, 3, 4]); - let mut iter = buf.iter().rev(); - assert_eq!(iter.next(), Some(&4)); - assert_eq!(iter.next(), Some(&3)); - assert_eq!(iter.next(), Some(&2)); - assert_eq!(iter.next(), Some(&1)); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, u32>::from([1, 2, 3, 4, 5, 6, 7, 8]); - let mut iter = buf.iter().rev(); - assert_eq!(iter.next(), Some(&8)); - assert_eq!(iter.next(), Some(&7)); - assert_eq!(iter.next(), Some(&6)); - assert_eq!(iter.next(), Some(&5)); - assert_eq!(iter.next(), Some(&4)); - assert_eq!(iter.next(), Some(&3)); - assert_eq!(iter.next(), Some(&2)); - assert_eq!(iter.next(), Some(&1)); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); -} + #[test] + fn iter_rev() { + let buf = new::<8, u32>(); + let mut iter = buf.iter().rev(); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = new_from_iter::<8, u32, _>([1, 2, 3, 4]); + let mut iter = buf.iter().rev(); + assert_eq!(iter.next(), Some(&4)); + assert_eq!(iter.next(), Some(&3)); + assert_eq!(iter.next(), Some(&2)); + assert_eq!(iter.next(), Some(&1)); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = new_from_iter::<8, u32, _>([1, 2, 3, 4, 5, 6, 7, 8]); + let mut iter = buf.iter().rev(); + assert_eq!(iter.next(), Some(&8)); + assert_eq!(iter.next(), Some(&7)); + assert_eq!(iter.next(), Some(&6)); + assert_eq!(iter.next(), Some(&5)); + assert_eq!(iter.next(), Some(&4)); + assert_eq!(iter.next(), Some(&3)); + assert_eq!(iter.next(), Some(&2)); + assert_eq!(iter.next(), Some(&1)); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + } -#[test] -fn into_iter() { - let buf = CircularBuffer::<8, u32>::new(); - let mut iter = buf.into_iter(); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, u32>::from([1, 2, 3, 4]); - let mut iter = buf.into_iter(); - assert_eq!(iter.next(), Some(1)); - assert_eq!(iter.next(), Some(2)); - assert_eq!(iter.next(), Some(3)); - assert_eq!(iter.next(), Some(4)); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, u32>::from([1, 2, 3, 4, 5, 6, 7, 8]); - let mut iter = buf.into_iter(); - assert_eq!(iter.next(), Some(1)); - assert_eq!(iter.next(), Some(2)); - assert_eq!(iter.next(), Some(3)); - assert_eq!(iter.next(), Some(4)); - assert_eq!(iter.next(), Some(5)); - assert_eq!(iter.next(), Some(6)); - assert_eq!(iter.next(), Some(7)); - assert_eq!(iter.next(), Some(8)); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); -} + #[test] + fn into_iter() { + let buf = new::<8, u32>(); + let mut iter = buf.into_iter(); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = new_from_iter::<8, u32, _>([1, 2, 3, 4]); + let mut iter = buf.into_iter(); + assert_eq!(iter.next(), Some(1)); + assert_eq!(iter.next(), Some(2)); + assert_eq!(iter.next(), Some(3)); + assert_eq!(iter.next(), Some(4)); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = new_from_iter::<8, u32, _>([1, 2, 3, 4, 5, 6, 7, 8]); + let mut iter = buf.into_iter(); + assert_eq!(iter.next(), Some(1)); + assert_eq!(iter.next(), Some(2)); + assert_eq!(iter.next(), Some(3)); + assert_eq!(iter.next(), Some(4)); + assert_eq!(iter.next(), Some(5)); + assert_eq!(iter.next(), Some(6)); + assert_eq!(iter.next(), Some(7)); + assert_eq!(iter.next(), Some(8)); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + } -#[test] -fn into_iter_rev() { - let buf = CircularBuffer::<8, u32>::new(); - let mut iter = buf.into_iter().rev(); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, u32>::from([1, 2, 3, 4]); - let mut iter = buf.into_iter().rev(); - assert_eq!(iter.next(), Some(4)); - assert_eq!(iter.next(), Some(3)); - assert_eq!(iter.next(), Some(2)); - assert_eq!(iter.next(), Some(1)); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, u32>::from([1, 2, 3, 4, 5, 6, 7, 8]); - let mut iter = buf.into_iter().rev(); - assert_eq!(iter.next(), Some(8)); - assert_eq!(iter.next(), Some(7)); - assert_eq!(iter.next(), Some(6)); - assert_eq!(iter.next(), Some(5)); - assert_eq!(iter.next(), Some(4)); - assert_eq!(iter.next(), Some(3)); - assert_eq!(iter.next(), Some(2)); - assert_eq!(iter.next(), Some(1)); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); -} + #[test] + fn into_iter_rev() { + let buf = new::<8, u32>(); + let mut iter = buf.into_iter().rev(); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = new_from_iter::<8, u32, _>([1, 2, 3, 4]); + let mut iter = buf.into_iter().rev(); + assert_eq!(iter.next(), Some(4)); + assert_eq!(iter.next(), Some(3)); + assert_eq!(iter.next(), Some(2)); + assert_eq!(iter.next(), Some(1)); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = new_from_iter::<8, u32, _>([1, 2, 3, 4, 5, 6, 7, 8]); + let mut iter = buf.into_iter().rev(); + assert_eq!(iter.next(), Some(8)); + assert_eq!(iter.next(), Some(7)); + assert_eq!(iter.next(), Some(6)); + assert_eq!(iter.next(), Some(5)); + assert_eq!(iter.next(), Some(4)); + assert_eq!(iter.next(), Some(3)); + assert_eq!(iter.next(), Some(2)); + assert_eq!(iter.next(), Some(1)); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + } -#[test] -fn iter_mut() { - let mut buf = CircularBuffer::<8, u32>::new(); - let mut iter = buf.iter_mut(); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut buf = CircularBuffer::<8, u32>::from([1, 2, 3, 4]); - let mut iter = buf.iter_mut(); - assert_eq!(iter.next(), Some(&mut 1)); - assert_eq!(iter.next(), Some(&mut 2)); - assert_eq!(iter.next(), Some(&mut 3)); - assert_eq!(iter.next(), Some(&mut 4)); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut buf = CircularBuffer::<8, u32>::from([1, 2, 3, 4, 5, 6, 7, 8]); - let mut iter = buf.iter_mut(); - assert_eq!(iter.next(), Some(&mut 1)); - assert_eq!(iter.next(), Some(&mut 2)); - assert_eq!(iter.next(), Some(&mut 3)); - assert_eq!(iter.next(), Some(&mut 4)); - assert_eq!(iter.next(), Some(&mut 5)); - assert_eq!(iter.next(), Some(&mut 6)); - assert_eq!(iter.next(), Some(&mut 7)); - assert_eq!(iter.next(), Some(&mut 8)); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); -} + #[test] + fn iter_mut() { + let mut buf = new::<8, u32>(); + let mut iter = buf.iter_mut(); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut buf = new_from_iter::<8, u32, _>([1, 2, 3, 4]); + let mut iter = buf.iter_mut(); + assert_eq!(iter.next(), Some(&mut 1)); + assert_eq!(iter.next(), Some(&mut 2)); + assert_eq!(iter.next(), Some(&mut 3)); + assert_eq!(iter.next(), Some(&mut 4)); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut buf = new_from_iter::<8, u32, _>([1, 2, 3, 4, 5, 6, 7, 8]); + let mut iter = buf.iter_mut(); + assert_eq!(iter.next(), Some(&mut 1)); + assert_eq!(iter.next(), Some(&mut 2)); + assert_eq!(iter.next(), Some(&mut 3)); + assert_eq!(iter.next(), Some(&mut 4)); + assert_eq!(iter.next(), Some(&mut 5)); + assert_eq!(iter.next(), Some(&mut 6)); + assert_eq!(iter.next(), Some(&mut 7)); + assert_eq!(iter.next(), Some(&mut 8)); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + } -#[test] -fn iter_mut_rev() { - let mut buf = CircularBuffer::<8, u32>::new(); - let mut iter = buf.iter_mut().rev(); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut buf = CircularBuffer::<8, u32>::from([1, 2, 3, 4]); - let mut iter = buf.iter_mut().rev(); - assert_eq!(iter.next(), Some(&mut 4)); - assert_eq!(iter.next(), Some(&mut 3)); - assert_eq!(iter.next(), Some(&mut 2)); - assert_eq!(iter.next(), Some(&mut 1)); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut buf = CircularBuffer::<8, u32>::from([1, 2, 3, 4, 5, 6, 7, 8]); - let mut iter = buf.iter_mut().rev(); - assert_eq!(iter.next(), Some(&mut 8)); - assert_eq!(iter.next(), Some(&mut 7)); - assert_eq!(iter.next(), Some(&mut 6)); - assert_eq!(iter.next(), Some(&mut 5)); - assert_eq!(iter.next(), Some(&mut 4)); - assert_eq!(iter.next(), Some(&mut 3)); - assert_eq!(iter.next(), Some(&mut 2)); - assert_eq!(iter.next(), Some(&mut 1)); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); -} + #[test] + fn iter_mut_rev() { + let mut buf = new::<8, u32>(); + let mut iter = buf.iter_mut().rev(); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut buf = new_from_iter::<8, u32, _>([1, 2, 3, 4]); + let mut iter = buf.iter_mut().rev(); + assert_eq!(iter.next(), Some(&mut 4)); + assert_eq!(iter.next(), Some(&mut 3)); + assert_eq!(iter.next(), Some(&mut 2)); + assert_eq!(iter.next(), Some(&mut 1)); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut buf = new_from_iter::<8, u32, _>([1, 2, 3, 4, 5, 6, 7, 8]); + let mut iter = buf.iter_mut().rev(); + assert_eq!(iter.next(), Some(&mut 8)); + assert_eq!(iter.next(), Some(&mut 7)); + assert_eq!(iter.next(), Some(&mut 6)); + assert_eq!(iter.next(), Some(&mut 5)); + assert_eq!(iter.next(), Some(&mut 4)); + assert_eq!(iter.next(), Some(&mut 3)); + assert_eq!(iter.next(), Some(&mut 2)); + assert_eq!(iter.next(), Some(&mut 1)); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + } -#[test] -fn range() { - let buf = CircularBuffer::<8, char>::new(); - let mut iter = buf.range(..); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range(..); - assert_eq!(iter.next(), Some(&'a')); - assert_eq!(iter.next(), Some(&'b')); - assert_eq!(iter.next(), Some(&'c')); - assert_eq!(iter.next(), Some(&'d')); - assert_eq!(iter.next(), Some(&'e')); - assert_eq!(iter.next(), Some(&'f')); - assert_eq!(iter.next(), Some(&'g')); - assert_eq!(iter.next(), Some(&'h')); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range(5..); - assert_eq!(iter.next(), Some(&'f')); - assert_eq!(iter.next(), Some(&'g')); - assert_eq!(iter.next(), Some(&'h')); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range(..3); - assert_eq!(iter.next(), Some(&'a')); - assert_eq!(iter.next(), Some(&'b')); - assert_eq!(iter.next(), Some(&'c')); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range(..=2); - assert_eq!(iter.next(), Some(&'a')); - assert_eq!(iter.next(), Some(&'b')); - assert_eq!(iter.next(), Some(&'c')); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range(3..6); - assert_eq!(iter.next(), Some(&'d')); - assert_eq!(iter.next(), Some(&'e')); - assert_eq!(iter.next(), Some(&'f')); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range(3..=5); - assert_eq!(iter.next(), Some(&'d')); - assert_eq!(iter.next(), Some(&'e')); - assert_eq!(iter.next(), Some(&'f')); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range(0..0); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range((Bound::Excluded(4), Bound::Unbounded)); - assert_eq!(iter.next(), Some(&'f')); - assert_eq!(iter.next(), Some(&'g')); - assert_eq!(iter.next(), Some(&'h')); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range((Bound::Excluded(2), Bound::Excluded(6))); - assert_eq!(iter.next(), Some(&'d')); - assert_eq!(iter.next(), Some(&'e')); - assert_eq!(iter.next(), Some(&'f')); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range((Bound::Excluded(2), Bound::Included(5))); - assert_eq!(iter.next(), Some(&'d')); - assert_eq!(iter.next(), Some(&'e')); - assert_eq!(iter.next(), Some(&'f')); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range((Bound::Excluded(2), Bound::Excluded(3))); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range((Bound::Excluded(2), Bound::Included(2))); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let buf = CircularBuffer::<8, char>::from_iter("abcdefghijkl".chars()); - let mut iter = buf.range(2..6); - assert_eq!(iter.next(), Some(&'g')); - assert_eq!(iter.next(), Some(&'h')); - assert_eq!(iter.next(), Some(&'i')); - assert_eq!(iter.next(), Some(&'j')); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); -} + #[test] + fn range() { + let buf = new::<8, char>(); + let mut iter = buf.range(..); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range(..); + assert_eq!(iter.next(), Some(&'a')); + assert_eq!(iter.next(), Some(&'b')); + assert_eq!(iter.next(), Some(&'c')); + assert_eq!(iter.next(), Some(&'d')); + assert_eq!(iter.next(), Some(&'e')); + assert_eq!(iter.next(), Some(&'f')); + assert_eq!(iter.next(), Some(&'g')); + assert_eq!(iter.next(), Some(&'h')); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range(5..); + assert_eq!(iter.next(), Some(&'f')); + assert_eq!(iter.next(), Some(&'g')); + assert_eq!(iter.next(), Some(&'h')); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range(..3); + assert_eq!(iter.next(), Some(&'a')); + assert_eq!(iter.next(), Some(&'b')); + assert_eq!(iter.next(), Some(&'c')); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range(..=2); + assert_eq!(iter.next(), Some(&'a')); + assert_eq!(iter.next(), Some(&'b')); + assert_eq!(iter.next(), Some(&'c')); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range(3..6); + assert_eq!(iter.next(), Some(&'d')); + assert_eq!(iter.next(), Some(&'e')); + assert_eq!(iter.next(), Some(&'f')); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range(3..=5); + assert_eq!(iter.next(), Some(&'d')); + assert_eq!(iter.next(), Some(&'e')); + assert_eq!(iter.next(), Some(&'f')); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range(0..0); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range((Bound::Excluded(4), Bound::Unbounded)); + assert_eq!(iter.next(), Some(&'f')); + assert_eq!(iter.next(), Some(&'g')); + assert_eq!(iter.next(), Some(&'h')); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range((Bound::Excluded(2), Bound::Excluded(6))); + assert_eq!(iter.next(), Some(&'d')); + assert_eq!(iter.next(), Some(&'e')); + assert_eq!(iter.next(), Some(&'f')); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range((Bound::Excluded(2), Bound::Included(5))); + assert_eq!(iter.next(), Some(&'d')); + assert_eq!(iter.next(), Some(&'e')); + assert_eq!(iter.next(), Some(&'f')); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range((Bound::Excluded(2), Bound::Excluded(3))); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range((Bound::Excluded(2), Bound::Included(2))); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let buf = CircularBuffer::<8, char>::from_iter("abcdefghijkl".chars()); + let mut iter = buf.range(2..6); + assert_eq!(iter.next(), Some(&'g')); + assert_eq!(iter.next(), Some(&'h')); + assert_eq!(iter.next(), Some(&'i')); + assert_eq!(iter.next(), Some(&'j')); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + } -#[test] -fn range_mut() { - let mut buf = CircularBuffer::<8, char>::new(); - let mut iter = buf.range_mut(..); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range_mut(..); - assert_eq!(iter.next(), Some(&mut 'a')); - assert_eq!(iter.next(), Some(&mut 'b')); - assert_eq!(iter.next(), Some(&mut 'c')); - assert_eq!(iter.next(), Some(&mut 'd')); - assert_eq!(iter.next(), Some(&mut 'e')); - assert_eq!(iter.next(), Some(&mut 'f')); - assert_eq!(iter.next(), Some(&mut 'g')); - assert_eq!(iter.next(), Some(&mut 'h')); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range_mut(5..); - assert_eq!(iter.next(), Some(&mut 'f')); - assert_eq!(iter.next(), Some(&mut 'g')); - assert_eq!(iter.next(), Some(&mut 'h')); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range_mut(..3); - assert_eq!(iter.next(), Some(&mut 'a')); - assert_eq!(iter.next(), Some(&mut 'b')); - assert_eq!(iter.next(), Some(&mut 'c')); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range_mut(..=2); - assert_eq!(iter.next(), Some(&mut 'a')); - assert_eq!(iter.next(), Some(&mut 'b')); - assert_eq!(iter.next(), Some(&mut 'c')); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range_mut(3..6); - assert_eq!(iter.next(), Some(&mut 'd')); - assert_eq!(iter.next(), Some(&mut 'e')); - assert_eq!(iter.next(), Some(&mut 'f')); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range_mut(3..=5); - assert_eq!(iter.next(), Some(&mut 'd')); - assert_eq!(iter.next(), Some(&mut 'e')); - assert_eq!(iter.next(), Some(&mut 'f')); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range_mut(0..0); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range_mut((Bound::Excluded(4), Bound::Unbounded)); - assert_eq!(iter.next(), Some(&mut 'f')); - assert_eq!(iter.next(), Some(&mut 'g')); - assert_eq!(iter.next(), Some(&mut 'h')); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range_mut((Bound::Excluded(2), Bound::Excluded(6))); - assert_eq!(iter.next(), Some(&mut 'd')); - assert_eq!(iter.next(), Some(&mut 'e')); - assert_eq!(iter.next(), Some(&mut 'f')); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range_mut((Bound::Excluded(2), Bound::Included(5))); - assert_eq!(iter.next(), Some(&mut 'd')); - assert_eq!(iter.next(), Some(&mut 'e')); - assert_eq!(iter.next(), Some(&mut 'f')); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range_mut((Bound::Excluded(2), Bound::Excluded(3))); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut buf = CircularBuffer::<8, char>::from_iter("abcdefgh".chars()); - let mut iter = buf.range_mut((Bound::Excluded(2), Bound::Included(2))); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut buf = CircularBuffer::<8, char>::from_iter("abcdefghijkl".chars()); - let mut iter = buf.range_mut(2..6); - assert_eq!(iter.next(), Some(&mut 'g')); - assert_eq!(iter.next(), Some(&mut 'h')); - assert_eq!(iter.next(), Some(&mut 'i')); - assert_eq!(iter.next(), Some(&mut 'j')); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); -} + #[test] + fn range_mut() { + let mut buf = new::<8, char>(); + let mut iter = buf.range_mut(..); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range_mut(..); + assert_eq!(iter.next(), Some(&mut 'a')); + assert_eq!(iter.next(), Some(&mut 'b')); + assert_eq!(iter.next(), Some(&mut 'c')); + assert_eq!(iter.next(), Some(&mut 'd')); + assert_eq!(iter.next(), Some(&mut 'e')); + assert_eq!(iter.next(), Some(&mut 'f')); + assert_eq!(iter.next(), Some(&mut 'g')); + assert_eq!(iter.next(), Some(&mut 'h')); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range_mut(5..); + assert_eq!(iter.next(), Some(&mut 'f')); + assert_eq!(iter.next(), Some(&mut 'g')); + assert_eq!(iter.next(), Some(&mut 'h')); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range_mut(..3); + assert_eq!(iter.next(), Some(&mut 'a')); + assert_eq!(iter.next(), Some(&mut 'b')); + assert_eq!(iter.next(), Some(&mut 'c')); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range_mut(..=2); + assert_eq!(iter.next(), Some(&mut 'a')); + assert_eq!(iter.next(), Some(&mut 'b')); + assert_eq!(iter.next(), Some(&mut 'c')); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range_mut(3..6); + assert_eq!(iter.next(), Some(&mut 'd')); + assert_eq!(iter.next(), Some(&mut 'e')); + assert_eq!(iter.next(), Some(&mut 'f')); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range_mut(3..=5); + assert_eq!(iter.next(), Some(&mut 'd')); + assert_eq!(iter.next(), Some(&mut 'e')); + assert_eq!(iter.next(), Some(&mut 'f')); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range_mut(0..0); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range_mut((Bound::Excluded(4), Bound::Unbounded)); + assert_eq!(iter.next(), Some(&mut 'f')); + assert_eq!(iter.next(), Some(&mut 'g')); + assert_eq!(iter.next(), Some(&mut 'h')); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range_mut((Bound::Excluded(2), Bound::Excluded(6))); + assert_eq!(iter.next(), Some(&mut 'd')); + assert_eq!(iter.next(), Some(&mut 'e')); + assert_eq!(iter.next(), Some(&mut 'f')); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range_mut((Bound::Excluded(2), Bound::Included(5))); + assert_eq!(iter.next(), Some(&mut 'd')); + assert_eq!(iter.next(), Some(&mut 'e')); + assert_eq!(iter.next(), Some(&mut 'f')); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range_mut((Bound::Excluded(2), Bound::Excluded(3))); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut buf = new_from_iter::<8, char, _>("abcdefgh".chars()); + let mut iter = buf.range_mut((Bound::Excluded(2), Bound::Included(2))); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut buf = CircularBuffer::<8, char>::from_iter("abcdefghijkl".chars()); + let mut iter = buf.range_mut(2..6); + assert_eq!(iter.next(), Some(&mut 'g')); + assert_eq!(iter.next(), Some(&mut 'h')); + assert_eq!(iter.next(), Some(&mut 'i')); + assert_eq!(iter.next(), Some(&mut 'j')); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + } -#[test] -fn zero_capacity() { - fn run_assertions(buf: &CircularBuffer::<0, u32>) { - assert_eq!(*buf, []); - assert_eq!(buf.len(), 0); - assert_eq!(buf.capacity(), 0); - assert_eq!(buf.to_vec(), []); - assert!(buf.is_empty()); - assert!(buf.is_full()); - } + #[test] + fn zero_capacity() { + fn run_assertions(buf: &Buffer<0, u32>) { + assert_eq!(*buf, []); + assert_eq!(buf.len(), 0); + assert_eq!(buf.capacity(), 0); + assert_eq!(buf.to_vec(), []); + assert!(buf.is_empty()); + assert!(buf.is_full()); + } - let mut buf = CircularBuffer::<0, u32>::new(); - run_assertions(&buf); - - buf.push_back(1); run_assertions(&buf); - assert_eq!(buf.pop_back(), None); run_assertions(&buf); - buf.push_front(1); run_assertions(&buf); - assert_eq!(buf.pop_front(), None); run_assertions(&buf); - assert_eq!(buf.remove(0), None); run_assertions(&buf); - buf.extend(&[1, 2, 3]); run_assertions(&buf); - buf.extend_from_slice(&[1, 2, 3]); run_assertions(&buf); - buf.truncate_back(10); run_assertions(&buf); - buf.truncate_back(0); run_assertions(&buf); - buf.truncate_front(10); run_assertions(&buf); - buf.truncate_front(0); run_assertions(&buf); - buf.clear(); run_assertions(&buf); -} + let mut buf = new::<0, u32>(); + run_assertions(&buf); + + buf.push_back(1); run_assertions(&buf); + assert_eq!(buf.pop_back(), None); run_assertions(&buf); + buf.push_front(1); run_assertions(&buf); + assert_eq!(buf.pop_front(), None); run_assertions(&buf); + assert_eq!(buf.remove(0), None); run_assertions(&buf); + buf.extend(&[1, 2, 3]); run_assertions(&buf); + buf.extend_from_slice(&[1, 2, 3]); run_assertions(&buf); + buf.truncate_back(10); run_assertions(&buf); + buf.truncate_back(0); run_assertions(&buf); + buf.truncate_front(10); run_assertions(&buf); + buf.truncate_front(0); run_assertions(&buf); + buf.clear(); run_assertions(&buf); + } -#[test] -fn remove_on_empty() { - fn run_assertions(buf: &CircularBuffer::<10, u32>) { - assert_eq!(*buf, []); - assert_eq!(buf.len(), 0); - assert_eq!(buf.to_vec(), []); - assert!(buf.is_empty()); - } + #[test] + fn remove_on_empty() { + fn run_assertions(buf: &Buffer<10, u32>) { + assert_eq!(*buf, []); + assert_eq!(buf.len(), 0); + assert_eq!(buf.to_vec(), []); + assert!(buf.is_empty()); + } - let mut buf = CircularBuffer::<10, u32>::new(); - run_assertions(&buf); - - assert_eq!(buf.pop_back(), None); run_assertions(&buf); - assert_eq!(buf.pop_front(), None); run_assertions(&buf); - assert_eq!(buf.remove(0), None); run_assertions(&buf); - buf.truncate_back(10); run_assertions(&buf); - buf.truncate_back(0); run_assertions(&buf); - buf.truncate_front(10); run_assertions(&buf); - buf.truncate_front(0); run_assertions(&buf); - buf.clear(); run_assertions(&buf); -} + let mut buf = new::<10, u32>(); + run_assertions(&buf); + + assert_eq!(buf.pop_back(), None); run_assertions(&buf); + assert_eq!(buf.pop_front(), None); run_assertions(&buf); + assert_eq!(buf.remove(0), None); run_assertions(&buf); + buf.truncate_back(10); run_assertions(&buf); + buf.truncate_back(0); run_assertions(&buf); + buf.truncate_front(10); run_assertions(&buf); + buf.truncate_front(0); run_assertions(&buf); + buf.clear(); run_assertions(&buf); + } -#[test] -fn swap() { - let mut buf: CircularBuffer<4, u32> = [1, 2, 3, 4].into_iter().collect(); - - buf.swap(0, 3); assert_buf_eq!(buf, [4, 2, 3, 1]); - buf.swap(1, 2); assert_buf_eq!(buf, [4, 3, 2, 1]); - buf.pop_front(); assert_buf_eq!(buf, [3, 2, 1]); - buf.push_back(4); assert_buf_eq!(buf, [3, 2, 1, 4]); - assert!(!is_contiguous(&buf)); - buf.swap(0, 1); assert_buf_eq!(buf, [2, 3, 1, 4]); - buf.swap(1, 2); assert_buf_eq!(buf, [2, 1, 3, 4]); - buf.swap(2, 3); assert_buf_eq!(buf, [2, 1, 4, 3]); - buf.swap(3, 0); assert_buf_eq!(buf, [3, 1, 4, 2]); -} + #[test] + fn swap() { + let mut buf = new_from_iter::<4, u32, _>([1, 2, 3, 4]); + + buf.swap(0, 3); assert_buf_eq!(buf, [4, 2, 3, 1]); + buf.swap(1, 2); assert_buf_eq!(buf, [4, 3, 2, 1]); + buf.pop_front(); assert_buf_eq!(buf, [3, 2, 1]); + buf.push_back(4); assert_buf_eq!(buf, [3, 2, 1, 4]); + assert!(!is_contiguous(&buf)); + buf.swap(0, 1); assert_buf_eq!(buf, [2, 3, 1, 4]); + buf.swap(1, 2); assert_buf_eq!(buf, [2, 1, 3, 4]); + buf.swap(2, 3); assert_buf_eq!(buf, [2, 1, 4, 3]); + buf.swap(3, 0); assert_buf_eq!(buf, [3, 1, 4, 2]); + } -#[test] -fn drop_contiguous() { - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<4, DropItem>::new(); - assert_buf_eq!(buf, [] as [i32; 0]); + #[test] + fn drop_contiguous() { + let mut tracker = DropTracker::new(); + let mut buf = new::<4, DropItem>(); + assert_buf_eq!(buf, [] as [i32; 0]); - buf.push_back(tracker.track(1)); - buf.push_back(tracker.track(2)); - assert_buf_eq!(buf, [1, 2]); - assert!(is_contiguous(&buf)); - tracker.assert_all_alive([1, 2]); - tracker.assert_fully_alive(); + buf.push_back(tracker.track(1)); + buf.push_back(tracker.track(2)); + assert_buf_eq!(buf, [1, 2]); + assert!(is_contiguous(&buf)); + tracker.assert_all_alive([1, 2]); + tracker.assert_fully_alive(); - drop(buf); + drop(buf); - tracker.assert_fully_dropped(); - tracker.assert_all_dropped([1, 2]); -} + tracker.assert_fully_dropped(); + tracker.assert_all_dropped([1, 2]); + } -#[test] -fn drop_full_contiguous() { - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<4, DropItem>::new(); - assert_buf_eq!(buf, [] as [i32; 0]); - - buf.push_back(tracker.track(1)); - buf.push_back(tracker.track(2)); - buf.push_back(tracker.track(3)); - buf.push_back(tracker.track(4)); - assert_buf_eq!(buf, [1, 2, 3, 4]); - assert!(is_contiguous(&buf)); - tracker.assert_all_alive([1, 2, 3, 4]); - tracker.assert_fully_alive(); - - drop(buf); - - tracker.assert_fully_dropped(); - tracker.assert_all_dropped([1, 2, 3, 4]); -} + #[test] + fn drop_full_contiguous() { + let mut tracker = DropTracker::new(); + let mut buf = new::<4, DropItem>(); + assert_buf_eq!(buf, [] as [i32; 0]); + + buf.push_back(tracker.track(1)); + buf.push_back(tracker.track(2)); + buf.push_back(tracker.track(3)); + buf.push_back(tracker.track(4)); + assert_buf_eq!(buf, [1, 2, 3, 4]); + assert!(is_contiguous(&buf)); + tracker.assert_all_alive([1, 2, 3, 4]); + tracker.assert_fully_alive(); + + drop(buf); + + tracker.assert_fully_dropped(); + tracker.assert_all_dropped([1, 2, 3, 4]); + } -#[test] -fn drop_full_disjoint() { - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<4, DropItem>::new(); - assert_buf_eq!(buf, [] as [i32; 0]); - - buf.push_back(tracker.track(1)); - buf.push_back(tracker.track(2)); - buf.push_back(tracker.track(3)); - buf.push_back(tracker.track(4)); - buf.push_back(tracker.track(5)); - buf.push_back(tracker.track(6)); - assert_buf_eq!(buf, [3, 4, 5, 6]); - assert!(!is_contiguous(&buf)); - tracker.assert_all_alive([3, 4, 5, 6]); - tracker.assert_all_dropped([1, 2]); - - drop(buf); - - tracker.assert_fully_dropped(); - tracker.assert_all_dropped([1, 2, 3, 4, 5, 6]); -} + #[test] + fn drop_full_disjoint() { + let mut tracker = DropTracker::new(); + let mut buf = new::<4, DropItem>(); + assert_buf_eq!(buf, [] as [i32; 0]); + + buf.push_back(tracker.track(1)); + buf.push_back(tracker.track(2)); + buf.push_back(tracker.track(3)); + buf.push_back(tracker.track(4)); + buf.push_back(tracker.track(5)); + buf.push_back(tracker.track(6)); + assert_buf_eq!(buf, [3, 4, 5, 6]); + assert!(!is_contiguous(&buf)); + tracker.assert_all_alive([3, 4, 5, 6]); + tracker.assert_all_dropped([1, 2]); + + drop(buf); + + tracker.assert_fully_dropped(); + tracker.assert_all_dropped([1, 2, 3, 4, 5, 6]); + } -#[test] -fn drop_disjoint() { - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<4, DropItem>::new(); - assert_buf_eq!(buf, [] as [i32; 0]); - - buf.push_back(tracker.track(1)); - buf.push_back(tracker.track(2)); - buf.push_back(tracker.track(3)); - buf.push_back(tracker.track(4)); - buf.push_back(tracker.track(5)); - buf.push_back(tracker.track(6)); - buf.pop_back(); - assert_buf_eq!(buf, [3, 4, 5]); - assert!(!is_contiguous(&buf)); - tracker.assert_all_alive([3, 4, 5]); - tracker.assert_all_dropped([1, 2, 6]); - - drop(buf); - - tracker.assert_fully_dropped(); - tracker.assert_all_dropped([1, 2, 3, 4, 5, 6]); -} + #[test] + fn drop_disjoint() { + let mut tracker = DropTracker::new(); + let mut buf = new::<4, DropItem>(); + assert_buf_eq!(buf, [] as [i32; 0]); + + buf.push_back(tracker.track(1)); + buf.push_back(tracker.track(2)); + buf.push_back(tracker.track(3)); + buf.push_back(tracker.track(4)); + buf.push_back(tracker.track(5)); + buf.push_back(tracker.track(6)); + buf.pop_back(); + assert_buf_eq!(buf, [3, 4, 5]); + assert!(!is_contiguous(&buf)); + tracker.assert_all_alive([3, 4, 5]); + tracker.assert_all_dropped([1, 2, 6]); + + drop(buf); + + tracker.assert_fully_dropped(); + tracker.assert_all_dropped([1, 2, 3, 4, 5, 6]); + } -#[test] -fn drain_front() { - // Fully consume the drain - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<10, _>::from_iter( - tracker.track_many([1, 2, 3, 4, 5, 6, 7]) - ); - let mut drain = buf.drain(..4); - assert_eq!(drain.next().unwrap(), 1); - assert_eq!(drain.next().unwrap(), 2); - assert_eq!(drain.next().unwrap(), 3); - assert_eq!(drain.next().unwrap(), 4); - assert_eq!(drain.next(), None); - assert_eq!(drain.next(), None); - assert_eq!(drain.next(), None); - drop(drain); - assert_buf_eq!(buf, [5, 6, 7]); - tracker.assert_all_alive([5, 6, 7]); - tracker.assert_all_dropped([1, 2, 3, 4]); - - // Partially consume the drain - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<10, _>::from_iter( - tracker.track_many([1, 2, 3, 4, 5, 6, 7]) - ); - let mut drain = buf.drain(..4); - assert_eq!(drain.next().unwrap(), 1); - assert_eq!(drain.next().unwrap(), 2); - drop(drain); - assert_buf_eq!(buf, [5, 6, 7]); - tracker.assert_all_alive([5, 6, 7]); - tracker.assert_all_dropped([1, 2, 3, 4]); - - // Do not consume the drain - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<10, _>::from_iter( - tracker.track_many([1, 2, 3, 4, 5, 6, 7]) - ); - let _ = buf.drain(..4); - assert_buf_eq!(buf, [5, 6, 7]); - tracker.assert_all_alive([5, 6, 7]); - tracker.assert_all_dropped([1, 2, 3, 4]); -} + #[test] + fn drain_front() { + // Fully consume the drain + let mut tracker = DropTracker::new(); + let mut buf = new_from_iter::<10, _, _>(tracker.track_many([1, 2, 3, 4, 5, 6, 7])); + let mut drain = buf.drain(..4); + assert_eq!(drain.next().unwrap(), 1); + assert_eq!(drain.next().unwrap(), 2); + assert_eq!(drain.next().unwrap(), 3); + assert_eq!(drain.next().unwrap(), 4); + assert_eq!(drain.next(), None); + assert_eq!(drain.next(), None); + assert_eq!(drain.next(), None); + drop(drain); + assert_buf_eq!(buf, [5, 6, 7]); + tracker.assert_all_alive([5, 6, 7]); + tracker.assert_all_dropped([1, 2, 3, 4]); + + // Partially consume the drain + let mut tracker = DropTracker::new(); + let mut buf = new_from_iter::<10, _, _>(tracker.track_many([1, 2, 3, 4, 5, 6, 7])); + let mut drain = buf.drain(..4); + assert_eq!(drain.next().unwrap(), 1); + assert_eq!(drain.next().unwrap(), 2); + drop(drain); + assert_buf_eq!(buf, [5, 6, 7]); + tracker.assert_all_alive([5, 6, 7]); + tracker.assert_all_dropped([1, 2, 3, 4]); + + // Do not consume the drain + let mut tracker = DropTracker::new(); + let mut buf = new_from_iter::<10, _, _>(tracker.track_many([1, 2, 3, 4, 5, 6, 7])); + let _ = buf.drain(..4); + assert_buf_eq!(buf, [5, 6, 7]); + tracker.assert_all_alive([5, 6, 7]); + tracker.assert_all_dropped([1, 2, 3, 4]); + } -#[test] -fn drain_back() { - // Fully consume the drain - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<10, _>::from_iter( - tracker.track_many([1, 2, 3, 4, 5, 6, 7]) - ); - let mut drain = buf.drain(3..); - assert_eq!(drain.next().unwrap(), 4); - assert_eq!(drain.next().unwrap(), 5); - assert_eq!(drain.next().unwrap(), 6); - assert_eq!(drain.next().unwrap(), 7); - assert_eq!(drain.next(), None); - assert_eq!(drain.next(), None); - assert_eq!(drain.next(), None); - drop(drain); - assert_buf_eq!(buf, [1, 2, 3]); - tracker.assert_all_alive([1, 2, 3]); - tracker.assert_all_dropped([4, 5, 6, 7]); - - // Partially consume the drain - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<10, _>::from_iter( - tracker.track_many([1, 2, 3, 4, 5, 6, 7]) - ); - let mut drain = buf.drain(3..); - assert_eq!(drain.next().unwrap(), 4); - assert_eq!(drain.next().unwrap(), 5); - drop(drain); - assert_buf_eq!(buf, [1, 2, 3]); - tracker.assert_all_alive([1, 2, 3]); - tracker.assert_all_dropped([4, 5, 6, 7]); - - // Do not consume the drain - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<10, _>::from_iter( - tracker.track_many([1, 2, 3, 4, 5, 6, 7]) - ); - let _ = buf.drain(3..); - assert_buf_eq!(buf, [1, 2, 3]); - tracker.assert_all_alive([1, 2, 3]); - tracker.assert_all_dropped([4, 5, 6, 7]); -} + #[test] + fn drain_back() { + // Fully consume the drain + let mut tracker = DropTracker::new(); + let mut buf = new_from_iter::<10, _, _>(tracker.track_many([1, 2, 3, 4, 5, 6, 7])); + let mut drain = buf.drain(3..); + assert_eq!(drain.next().unwrap(), 4); + assert_eq!(drain.next().unwrap(), 5); + assert_eq!(drain.next().unwrap(), 6); + assert_eq!(drain.next().unwrap(), 7); + assert_eq!(drain.next(), None); + assert_eq!(drain.next(), None); + assert_eq!(drain.next(), None); + drop(drain); + assert_buf_eq!(buf, [1, 2, 3]); + tracker.assert_all_alive([1, 2, 3]); + tracker.assert_all_dropped([4, 5, 6, 7]); + + // Partially consume the drain + let mut tracker = DropTracker::new(); + let mut buf = new_from_iter::<10, _, _>(tracker.track_many([1, 2, 3, 4, 5, 6, 7])); + let mut drain = buf.drain(3..); + assert_eq!(drain.next().unwrap(), 4); + assert_eq!(drain.next().unwrap(), 5); + drop(drain); + assert_buf_eq!(buf, [1, 2, 3]); + tracker.assert_all_alive([1, 2, 3]); + tracker.assert_all_dropped([4, 5, 6, 7]); + + // Do not consume the drain + let mut tracker = DropTracker::new(); + let mut buf = new_from_iter::<10, _, _>(tracker.track_many([1, 2, 3, 4, 5, 6, 7])); + let _ = buf.drain(3..); + assert_buf_eq!(buf, [1, 2, 3]); + tracker.assert_all_alive([1, 2, 3]); + tracker.assert_all_dropped([4, 5, 6, 7]); + } -#[test] -fn drain_middle_contiguous() { - // Fully consume the drain - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<10, _>::from_iter( - tracker.track_many([1, 2, 3, 4, 5, 6, 7]) - ); - assert!(is_contiguous(&buf)); - let mut drain = buf.drain(2..5); - assert_eq!(drain.next().unwrap(), 3); - assert_eq!(drain.next().unwrap(), 4); - assert_eq!(drain.next().unwrap(), 5); - assert_eq!(drain.next(), None); - assert_eq!(drain.next(), None); - assert_eq!(drain.next(), None); - drop(drain); - assert_buf_eq!(buf, [1, 2, 6, 7]); - tracker.assert_all_alive([1, 2, 6, 7]); - tracker.assert_all_dropped([3, 4, 5]); - - // Partially consume the drain - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<10, _>::from_iter( - tracker.track_many([1, 2, 3, 4, 5, 6, 7]) - ); - assert!(is_contiguous(&buf)); - let mut drain = buf.drain(2..5); - assert_eq!(drain.next().unwrap(), 3); - assert_eq!(drain.next().unwrap(), 4); - drop(drain); - assert_buf_eq!(buf, [1, 2, 6, 7]); - tracker.assert_all_alive([1, 2, 6, 7]); - tracker.assert_all_dropped([3, 4, 5]); - - // Do not consume the drain - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<10, _>::from_iter( - tracker.track_many([1, 2, 3, 4, 5, 6, 7]) - ); - assert!(is_contiguous(&buf)); - let _ = buf.drain(2..5); - assert_buf_eq!(buf, [1, 2, 6, 7]); - tracker.assert_all_alive([1, 2, 6, 7]); - tracker.assert_all_dropped([3, 4, 5]); -} + #[test] + fn drain_middle_contiguous() { + // Fully consume the drain + let mut tracker = DropTracker::new(); + let mut buf = new_from_iter::<10, _, _>(tracker.track_many([1, 2, 3, 4, 5, 6, 7])); + assert!(is_contiguous(&buf)); + let mut drain = buf.drain(2..5); + assert_eq!(drain.next().unwrap(), 3); + assert_eq!(drain.next().unwrap(), 4); + assert_eq!(drain.next().unwrap(), 5); + assert_eq!(drain.next(), None); + assert_eq!(drain.next(), None); + assert_eq!(drain.next(), None); + drop(drain); + assert_buf_eq!(buf, [1, 2, 6, 7]); + tracker.assert_all_alive([1, 2, 6, 7]); + tracker.assert_all_dropped([3, 4, 5]); + + // Partially consume the drain + let mut tracker = DropTracker::new(); + let mut buf = new_from_iter::<10, _, _>(tracker.track_many([1, 2, 3, 4, 5, 6, 7])); + assert!(is_contiguous(&buf)); + let mut drain = buf.drain(2..5); + assert_eq!(drain.next().unwrap(), 3); + assert_eq!(drain.next().unwrap(), 4); + drop(drain); + assert_buf_eq!(buf, [1, 2, 6, 7]); + tracker.assert_all_alive([1, 2, 6, 7]); + tracker.assert_all_dropped([3, 4, 5]); + + // Do not consume the drain + let mut tracker = DropTracker::new(); + let mut buf = new_from_iter::<10, _, _>(tracker.track_many([1, 2, 3, 4, 5, 6, 7])); + assert!(is_contiguous(&buf)); + let _ = buf.drain(2..5); + assert_buf_eq!(buf, [1, 2, 6, 7]); + tracker.assert_all_alive([1, 2, 6, 7]); + tracker.assert_all_dropped([3, 4, 5]); + } -#[test] -fn drain_middle_disjoint() { - // Fully consume the drain - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<10, _>::from_iter( - tracker.track_many([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) - ); - assert!(!is_contiguous(&buf)); - let mut drain = buf.drain(3..7); - assert_eq!(drain.next().unwrap(), 9); - assert_eq!(drain.next().unwrap(), 10); - assert_eq!(drain.next().unwrap(), 11); - assert_eq!(drain.next().unwrap(), 12); - assert_eq!(drain.next(), None); - assert_eq!(drain.next(), None); - assert_eq!(drain.next(), None); - drop(drain); - assert_buf_eq!(buf, [6, 7, 8, 13, 14, 15]); - tracker.assert_all_alive([6, 7, 8, 13, 14, 15]); - tracker.assert_all_dropped([9, 10, 11, 12]); - - // Partially consume the drain - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<10, _>::from_iter( - tracker.track_many([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) - ); - assert!(!is_contiguous(&buf)); - let mut drain = buf.drain(3..7); - assert_eq!(drain.next().unwrap(), 9); - assert_eq!(drain.next().unwrap(), 10); - drop(drain); - assert_buf_eq!(buf, [6, 7, 8, 13, 14, 15]); - tracker.assert_all_alive([6, 7, 8, 13, 14, 15]); - tracker.assert_all_dropped([9, 10, 11, 12]); - - // Do not consume the drain - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<10, _>::from_iter( - tracker.track_many([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) - ); - assert!(!is_contiguous(&buf)); - let _ = buf.drain(3..7); - assert_buf_eq!(buf, [6, 7, 8, 13, 14, 15]); - tracker.assert_all_alive([6, 7, 8, 13, 14, 15]); - tracker.assert_all_dropped([9, 10, 11, 12]); -} + #[test] + fn drain_middle_disjoint() { + // Fully consume the drain + let mut tracker = DropTracker::new(); + let mut buf = new_from_iter::<10, _, _>( + tracker.track_many([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + ); + assert!(!is_contiguous(&buf)); + let mut drain = buf.drain(3..7); + assert_eq!(drain.next().unwrap(), 9); + assert_eq!(drain.next().unwrap(), 10); + assert_eq!(drain.next().unwrap(), 11); + assert_eq!(drain.next().unwrap(), 12); + assert_eq!(drain.next(), None); + assert_eq!(drain.next(), None); + assert_eq!(drain.next(), None); + drop(drain); + assert_buf_eq!(buf, [6, 7, 8, 13, 14, 15]); + tracker.assert_all_alive([6, 7, 8, 13, 14, 15]); + tracker.assert_all_dropped([9, 10, 11, 12]); + + // Partially consume the drain + let mut tracker = DropTracker::new(); + let mut buf = new_from_iter::<10, _, _>( + tracker.track_many([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + ); + assert!(!is_contiguous(&buf)); + let mut drain = buf.drain(3..7); + assert_eq!(drain.next().unwrap(), 9); + assert_eq!(drain.next().unwrap(), 10); + drop(drain); + assert_buf_eq!(buf, [6, 7, 8, 13, 14, 15]); + tracker.assert_all_alive([6, 7, 8, 13, 14, 15]); + tracker.assert_all_dropped([9, 10, 11, 12]); + + // Do not consume the drain + let mut tracker = DropTracker::new(); + let mut buf = new_from_iter::<10, _, _>( + tracker.track_many([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + ); + assert!(!is_contiguous(&buf)); + let _ = buf.drain(3..7); + assert_buf_eq!(buf, [6, 7, 8, 13, 14, 15]); + tracker.assert_all_alive([6, 7, 8, 13, 14, 15]); + tracker.assert_all_dropped([9, 10, 11, 12]); + } -#[test] -fn drain_full() { - // Fully consume the drain - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<10, _>::from_iter( - tracker.track_many([1, 2, 3, 4]) - ); - let mut drain = buf.drain(..); - assert_eq!(drain.next().unwrap(), 1); - assert_eq!(drain.next().unwrap(), 2); - assert_eq!(drain.next().unwrap(), 3); - assert_eq!(drain.next().unwrap(), 4); - assert_eq!(drain.next(), None); - assert_eq!(drain.next(), None); - assert_eq!(drain.next(), None); - drop(drain); - assert_buf_eq!(buf, [] as [i32; 0]); - tracker.assert_fully_dropped(); - - // Partially consume the drain - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<10, _>::from_iter( - tracker.track_many([1, 2, 3, 4]) - ); - let mut drain = buf.drain(..); - assert_eq!(drain.next().unwrap(), 1); - assert_eq!(drain.next().unwrap(), 2); - drop(drain); - assert_buf_eq!(buf, [] as [i32; 0]); - tracker.assert_fully_dropped(); - - // Do not consume the drain - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<10, _>::from_iter( - tracker.track_many([1, 2, 3, 4]) - ); - let _ = buf.drain(..); - assert_buf_eq!(buf, [] as [i32; 0]); - tracker.assert_fully_dropped(); -} + #[test] + fn drain_full() { + // Fully consume the drain + let mut tracker = DropTracker::new(); + let mut buf = new_from_iter::<10, _, _>(tracker.track_many([1, 2, 3, 4])); + let mut drain = buf.drain(..); + assert_eq!(drain.next().unwrap(), 1); + assert_eq!(drain.next().unwrap(), 2); + assert_eq!(drain.next().unwrap(), 3); + assert_eq!(drain.next().unwrap(), 4); + assert_eq!(drain.next(), None); + assert_eq!(drain.next(), None); + assert_eq!(drain.next(), None); + drop(drain); + assert_buf_eq!(buf, [] as [i32; 0]); + tracker.assert_fully_dropped(); + + // Partially consume the drain + let mut tracker = DropTracker::new(); + let mut buf = new_from_iter::<10, _, _>(tracker.track_many([1, 2, 3, 4])); + let mut drain = buf.drain(..); + assert_eq!(drain.next().unwrap(), 1); + assert_eq!(drain.next().unwrap(), 2); + drop(drain); + assert_buf_eq!(buf, [] as [i32; 0]); + tracker.assert_fully_dropped(); + + // Do not consume the drain + let mut tracker = DropTracker::new(); + let mut buf = new_from_iter::<10, _, _>(tracker.track_many([1, 2, 3, 4])); + let _ = buf.drain(..); + assert_buf_eq!(buf, [] as [i32; 0]); + tracker.assert_fully_dropped(); + } -#[test] -fn drain_empty() { - let mut tracker = DropTracker::new(); - let mut buf = CircularBuffer::<10, _>::from_iter( - tracker.track_many([1, 2, 3, 4]) - ); - let mut drain = buf.drain(0..0); - assert_eq!(drain.next(), None); - assert_eq!(drain.next(), None); - assert_eq!(drain.next(), None); - drop(drain); - assert_buf_eq!(buf, [1, 2, 3, 4]); - tracker.assert_fully_alive(); -} + #[test] + fn drain_empty() { + let mut tracker = DropTracker::new(); + let mut buf = new_from_iter::<10, _, _>(tracker.track_many([1, 2, 3, 4])); + let mut drain = buf.drain(0..0); + assert_eq!(drain.next(), None); + assert_eq!(drain.next(), None); + assert_eq!(drain.next(), None); + drop(drain); + assert_buf_eq!(buf, [1, 2, 3, 4]); + tracker.assert_fully_alive(); + } -#[test] -fn eq_contiguous() { - let mut buf1 = CircularBuffer::<5, _>::from_iter([1, 2, 3]); - let mut buf2 = CircularBuffer::<5, _>::from_iter([1, 2, 3]); - assert!(is_contiguous(&buf1)); - assert!(is_contiguous(&buf2)); - assert_eq!(buf1, buf2); - - buf1.push_back(4); - assert!(is_contiguous(&buf1)); - assert!(is_contiguous(&buf2)); - assert_ne!(buf1, buf2); - - buf2.push_back(4); - assert!(is_contiguous(&buf1)); - assert!(is_contiguous(&buf2)); - assert_eq!(buf1, buf2); -} + #[test] + fn eq_contiguous() { + let mut buf1 = new_from_iter::<5, _, _>([1, 2, 3]); + let mut buf2 = new_from_iter::<5, _, _>([1, 2, 3]); + assert!(is_contiguous(&buf1)); + assert!(is_contiguous(&buf2)); + assert_eq!(buf1, buf2); + + buf1.push_back(4); + assert!(is_contiguous(&buf1)); + assert!(is_contiguous(&buf2)); + assert_ne!(buf1, buf2); + + buf2.push_back(4); + assert!(is_contiguous(&buf1)); + assert!(is_contiguous(&buf2)); + assert_eq!(buf1, buf2); + } -#[test] -fn eq_disjoint() { - let mut buf1 = CircularBuffer::<5, _>::from_iter([1, 2, 3, 4, 5]); - let mut buf2 = CircularBuffer::<5, _>::from_iter([0, 1, 2, 3, 4]); - - buf1.push_back(6); - buf2.push_back(5); - assert!(!is_contiguous(&buf1)); - assert!(!is_contiguous(&buf2)); - assert_ne!(buf1, buf2); - - buf2.push_back(6); - assert!(!is_contiguous(&buf1)); - assert!(!is_contiguous(&buf2)); - assert_eq!(buf1, buf2); - - buf1.push_back(7); - buf2.push_back(7); - assert!(!is_contiguous(&buf1)); - assert!(!is_contiguous(&buf2)); - assert_eq!(buf1, buf2); - - buf1.push_back(8); - buf2.push_back(8); - assert!(!is_contiguous(&buf1)); - assert!(!is_contiguous(&buf2)); - assert_eq!(buf1, buf2); - - buf1.push_back(9); - buf2.push_back(9); - assert!(!is_contiguous(&buf1)); - assert!(is_contiguous(&buf2)); - assert_eq!(buf1, buf2); - - buf1.push_back(10); - buf2.push_back(10); - assert!(is_contiguous(&buf1)); - assert!(!is_contiguous(&buf2)); - assert_eq!(buf1, buf2); -} + #[test] + fn eq_disjoint() { + let mut buf1 = new_from_iter::<5, _, _>([1, 2, 3, 4, 5]); + let mut buf2 = new_from_iter::<5, _, _>([0, 1, 2, 3, 4]); + + buf1.push_back(6); + buf2.push_back(5); + assert!(!is_contiguous(&buf1)); + assert!(!is_contiguous(&buf2)); + assert_ne!(buf1, buf2); + + buf2.push_back(6); + assert!(!is_contiguous(&buf1)); + assert!(!is_contiguous(&buf2)); + assert_eq!(buf1, buf2); + + buf1.push_back(7); + buf2.push_back(7); + assert!(!is_contiguous(&buf1)); + assert!(!is_contiguous(&buf2)); + assert_eq!(buf1, buf2); + + buf1.push_back(8); + buf2.push_back(8); + assert!(!is_contiguous(&buf1)); + assert!(!is_contiguous(&buf2)); + assert_eq!(buf1, buf2); + + buf1.push_back(9); + buf2.push_back(9); + assert!(!is_contiguous(&buf1)); + assert!(is_contiguous(&buf2)); + assert_eq!(buf1, buf2); + + buf1.push_back(10); + buf2.push_back(10); + assert!(is_contiguous(&buf1)); + assert!(!is_contiguous(&buf2)); + assert_eq!(buf1, buf2); + } -#[test] -fn write() { - let mut buf = CircularBuffer::<4, u8>::new(); - assert_buf_eq!(buf, [] as [u8; 0]); + #[test] + fn write() { + let mut buf = new::<4, u8>(); + assert_buf_eq!(buf, [] as [u8; 0]); - assert!(write!(&mut buf, "hello").is_ok()); assert_buf_eq!(buf, [b'e', b'l', b'l', b'o']); - assert!(write!(&mut buf, "world").is_ok()); assert_buf_eq!(buf, [b'o', b'r', b'l', b'd']); -} + assert!(write!(&mut buf, "hello").is_ok()); assert_buf_eq!(buf, [b'e', b'l', b'l', b'o']); + assert!(write!(&mut buf, "world").is_ok()); assert_buf_eq!(buf, [b'o', b'r', b'l', b'd']); + } -#[test] -fn read() { - fn read_all(mut buf: R) -> Vec { - let mut vec = Vec::new(); - buf.read_to_end(&mut vec).expect("read failed"); - vec - } + #[test] + fn read() { + fn read_all(mut buf: R) -> Vec { + let mut vec = Vec::new(); + buf.read_to_end(&mut vec).expect("read failed"); + vec + } - let mut buf = CircularBuffer::<4, u8>::new(); - assert_buf_eq!(buf, [] as [u8; 0]); - assert_eq!(read_all(&mut buf), []); - assert_buf_eq!(buf, [] as [u8; 0]); - - buf.push_back(b'a'); - buf.push_back(b'b'); - assert_buf_eq!(buf, [b'a', b'b']); - assert_eq!(read_all(&mut buf), [b'a', b'b']); - assert_buf_eq!(buf, [] as [u8; 0]); - - buf.push_back(b'c'); - buf.push_back(b'd'); - buf.push_back(b'e'); - buf.push_back(b'f'); - assert_buf_eq!(buf, [b'c', b'd', b'e', b'f']); - assert_eq!(read_all(&mut buf), [b'c', b'd', b'e', b'f']); - assert_buf_eq!(buf, [] as [u8; 0]); -} + let mut buf = new::<4, u8>(); + assert_buf_eq!(buf, [] as [u8; 0]); + assert_eq!(read_all(&mut buf), []); + assert_buf_eq!(buf, [] as [u8; 0]); + + buf.push_back(b'a'); + buf.push_back(b'b'); + assert_buf_eq!(buf, [b'a', b'b']); + assert_eq!(read_all(&mut buf), [b'a', b'b']); + assert_buf_eq!(buf, [] as [u8; 0]); + + buf.push_back(b'c'); + buf.push_back(b'd'); + buf.push_back(b'e'); + buf.push_back(b'f'); + assert_buf_eq!(buf, [b'c', b'd', b'e', b'f']); + assert_eq!(read_all(&mut buf), [b'c', b'd', b'e', b'f']); + assert_buf_eq!(buf, [] as [u8; 0]); + } -#[test] -fn from_array() { - let arr = []; - let buf = CircularBuffer::<4, i32>::from(arr); - assert_buf_eq!(buf, [] as [i32; 0]); - - let mut tracker = DropTracker::new(); - let arr = [tracker.track(1), tracker.track(2)]; - let buf = CircularBuffer::<4, DropItem>::from(arr); - assert_buf_eq!(buf, [1, 2]); - tracker.assert_all_alive([1, 2]); - tracker.assert_fully_alive(); - - let mut tracker = DropTracker::new(); - let arr = [tracker.track(1), tracker.track(2), - tracker.track(3), tracker.track(4)]; - let buf = CircularBuffer::<4, DropItem>::from(arr); - assert_buf_eq!(buf, [1, 2, 3, 4]); - tracker.assert_all_alive([1, 2, 3, 4]); - tracker.assert_fully_alive(); - - let mut tracker = DropTracker::new(); - let arr = [tracker.track(1), tracker.track(2), - tracker.track(3), tracker.track(4), - tracker.track(5), tracker.track(6)]; - let buf = CircularBuffer::<4, DropItem>::from(arr); - assert_buf_eq!(buf, [3, 4, 5, 6]); - tracker.assert_all_alive([3, 4, 5, 6]); - tracker.assert_all_dropped([1, 2]); - - let mut tracker = DropTracker::new(); - let arr = [tracker.track(1), tracker.track(2), - tracker.track(3), tracker.track(4), - tracker.track(5), tracker.track(6), - tracker.track(7), tracker.track(8)]; - let buf = CircularBuffer::<4, DropItem>::from(arr); - assert_buf_eq!(buf, [5, 6, 7, 8]); - tracker.assert_all_alive([5, 6, 7, 8]); - tracker.assert_all_dropped([1, 2, 3, 4]); -} + #[test] + fn from_array() { + let arr = []; + let buf = new_from_iter::<4, i32, _>(arr); + assert_buf_eq!(buf, [] as [i32; 0]); + + let mut tracker = DropTracker::new(); + let arr = [tracker.track(1), tracker.track(2)]; + let buf = new_from_iter::<4, DropItem, _>(arr); + assert_buf_eq!(buf, [1, 2]); + tracker.assert_all_alive([1, 2]); + tracker.assert_fully_alive(); + + let mut tracker = DropTracker::new(); + let arr = [tracker.track(1), tracker.track(2), + tracker.track(3), tracker.track(4)]; + let buf = CircularBuffer::<4, DropItem>::from(arr); + assert_buf_eq!(buf, [1, 2, 3, 4]); + tracker.assert_all_alive([1, 2, 3, 4]); + tracker.assert_fully_alive(); + + let mut tracker = DropTracker::new(); + let arr = [tracker.track(1), tracker.track(2), + tracker.track(3), tracker.track(4), + tracker.track(5), tracker.track(6)]; + let buf = new_from_iter::<4, DropItem, _>(arr); + assert_buf_eq!(buf, [3, 4, 5, 6]); + tracker.assert_all_alive([3, 4, 5, 6]); + tracker.assert_all_dropped([1, 2]); + + let mut tracker = DropTracker::new(); + let arr = [tracker.track(1), tracker.track(2), + tracker.track(3), tracker.track(4), + tracker.track(5), tracker.track(6), + tracker.track(7), tracker.track(8)]; + let buf = new_from_iter::<4, DropItem, _>(arr); + assert_buf_eq!(buf, [5, 6, 7, 8]); + tracker.assert_all_alive([5, 6, 7, 8]); + tracker.assert_all_dropped([1, 2, 3, 4]); + } -#[test] -fn from_iter() { - let vec = vec![]; - let buf = CircularBuffer::<4, i32>::from_iter(vec); - assert_buf_eq!(buf, [] as [i32; 0]); - - let mut tracker = DropTracker::new(); - let vec = vec![tracker.track(1), tracker.track(2)]; - let buf = CircularBuffer::<4, DropItem>::from_iter(vec); - assert_buf_eq!(buf, [1, 2]); - tracker.assert_all_alive([1, 2]); - tracker.assert_fully_alive(); - - let mut tracker = DropTracker::new(); - let vec = vec![tracker.track(1), tracker.track(2), - tracker.track(3), tracker.track(4)]; - let buf = CircularBuffer::<4, DropItem>::from_iter(vec); - assert_buf_eq!(buf, [1, 2, 3, 4]); - tracker.assert_all_alive([1, 2, 3, 4]); - tracker.assert_fully_alive(); - - let mut tracker = DropTracker::new(); - let vec = vec![tracker.track(1), tracker.track(2), - tracker.track(3), tracker.track(4), - tracker.track(5), tracker.track(6)]; - let buf = CircularBuffer::<4, DropItem>::from_iter(vec); - assert_buf_eq!(buf, [3, 4, 5, 6]); - tracker.assert_all_alive([3, 4, 5, 6]); - tracker.assert_all_dropped([1, 2]); - - let mut tracker = DropTracker::new(); - let vec = vec![tracker.track(1), tracker.track(2), - tracker.track(3), tracker.track(4), - tracker.track(5), tracker.track(6), - tracker.track(7), tracker.track(8)]; - let buf = CircularBuffer::<4, DropItem>::from_iter(vec); - assert_buf_eq!(buf, [5, 6, 7, 8]); - tracker.assert_all_alive([5, 6, 7, 8]); - tracker.assert_all_dropped([1, 2, 3, 4]); -} + #[test] + fn from_iter() { + let vec = vec![]; + let buf = new_from_iter::<4, i32, _>(vec); + assert_buf_eq!(buf, [] as [i32; 0]); + + let mut tracker = DropTracker::new(); + let vec = vec![tracker.track(1), tracker.track(2)]; + let buf = new_from_iter::<4, DropItem, _>(vec); + assert_buf_eq!(buf, [1, 2]); + tracker.assert_all_alive([1, 2]); + tracker.assert_fully_alive(); + + let mut tracker = DropTracker::new(); + let vec = vec![tracker.track(1), tracker.track(2), + tracker.track(3), tracker.track(4)]; + let buf = new_from_iter::<4, DropItem, _>(vec); + assert_buf_eq!(buf, [1, 2, 3, 4]); + tracker.assert_all_alive([1, 2, 3, 4]); + tracker.assert_fully_alive(); + + let mut tracker = DropTracker::new(); + let vec = vec![tracker.track(1), tracker.track(2), + tracker.track(3), tracker.track(4), + tracker.track(5), tracker.track(6)]; + let buf = new_from_iter::<4, DropItem, _>(vec); + assert_buf_eq!(buf, [3, 4, 5, 6]); + tracker.assert_all_alive([3, 4, 5, 6]); + tracker.assert_all_dropped([1, 2]); + + let mut tracker = DropTracker::new(); + let vec = vec![tracker.track(1), tracker.track(2), + tracker.track(3), tracker.track(4), + tracker.track(5), tracker.track(6), + tracker.track(7), tracker.track(8)]; + let buf = new_from_iter::<4, DropItem, _>(vec); + assert_buf_eq!(buf, [5, 6, 7, 8]); + tracker.assert_all_alive([5, 6, 7, 8]); + tracker.assert_all_dropped([1, 2, 3, 4]); + } -#[test] -fn extend() { - let mut buf = CircularBuffer::<4, u32>::new(); - assert_buf_eq!(buf, [] as [u32; 0]); - - buf.extend([] as [u32; 0]); assert_buf_eq!(buf, [] as [u32; 0]); - buf.extend([1]); assert_buf_eq!(buf, [1]); - buf.extend([2, 3]); assert_buf_eq!(buf, [1, 2, 3]); - buf.extend([4, 5, 6]); assert_buf_eq!(buf, [3, 4, 5, 6]); - buf.extend([7, 8, 9, 10]); assert_buf_eq!(buf, [7, 8, 9, 10]); - buf.extend([11, 12, 13, 14, 15]); assert_buf_eq!(buf, [12, 13, 14, 15]); -} + #[test] + fn extend() { + let mut buf = new::<4, u32>(); + assert_buf_eq!(buf, [] as [u32; 0]); + + buf.extend([] as [u32; 0]); assert_buf_eq!(buf, [] as [u32; 0]); + buf.extend([1]); assert_buf_eq!(buf, [1]); + buf.extend([2, 3]); assert_buf_eq!(buf, [1, 2, 3]); + buf.extend([4, 5, 6]); assert_buf_eq!(buf, [3, 4, 5, 6]); + buf.extend([7, 8, 9, 10]); assert_buf_eq!(buf, [7, 8, 9, 10]); + buf.extend([11, 12, 13, 14, 15]); assert_buf_eq!(buf, [12, 13, 14, 15]); + } -#[test] -fn extend_ref() { - let mut buf = CircularBuffer::<4, u32>::new(); - assert_buf_eq!(buf, [] as [u32; 0]); - - buf.extend([].iter()); assert_buf_eq!(buf, [] as [u32; 0]); - buf.extend([1].iter()); assert_buf_eq!(buf, [1]); - buf.extend([2, 3].iter()); assert_buf_eq!(buf, [1, 2, 3]); - buf.extend([4, 5, 6].iter()); assert_buf_eq!(buf, [3, 4, 5, 6]); - buf.extend([7, 8, 9, 10].iter()); assert_buf_eq!(buf, [7, 8, 9, 10]); - buf.extend([11, 12, 13, 14, 15].iter()); assert_buf_eq!(buf, [12, 13, 14, 15]); -} + #[test] + fn extend_ref() { + let mut buf = new::<4, u32>(); + assert_buf_eq!(buf, [] as [u32; 0]); + + buf.extend([].iter()); assert_buf_eq!(buf, [] as [u32; 0]); + buf.extend([1].iter()); assert_buf_eq!(buf, [1]); + buf.extend([2, 3].iter()); assert_buf_eq!(buf, [1, 2, 3]); + buf.extend([4, 5, 6].iter()); assert_buf_eq!(buf, [3, 4, 5, 6]); + buf.extend([7, 8, 9, 10].iter()); assert_buf_eq!(buf, [7, 8, 9, 10]); + buf.extend([11, 12, 13, 14, 15].iter()); assert_buf_eq!(buf, [12, 13, 14, 15]); + } -#[test] -fn extend_from_slice() { - let mut buf = CircularBuffer::<4, u32>::new(); - assert_buf_eq!(buf, [] as [u32; 0]); - - buf.extend_from_slice(&[][..]); assert_buf_eq!(buf, [] as [u32; 0]); - buf.extend_from_slice(&[1][..]); assert_buf_eq!(buf, [1]); - buf.extend_from_slice(&[2, 3][..]); assert_buf_eq!(buf, [1, 2, 3]); - buf.extend_from_slice(&[4, 5, 6][..]); assert_buf_eq!(buf, [3, 4, 5, 6]); - buf.extend_from_slice(&[7, 8, 9, 10][..]); assert_buf_eq!(buf, [7, 8, 9, 10]); - buf.extend_from_slice(&[11, 12, 13, 14, 15][..]); assert_buf_eq!(buf, [12, 13, 14, 15]); -} + #[test] + fn extend_from_slice() { + let mut buf = new::<4, u32>(); + assert_buf_eq!(buf, [] as [u32; 0]); + + buf.extend_from_slice(&[][..]); assert_buf_eq!(buf, [] as [u32; 0]); + buf.extend_from_slice(&[1][..]); assert_buf_eq!(buf, [1]); + buf.extend_from_slice(&[2, 3][..]); assert_buf_eq!(buf, [1, 2, 3]); + buf.extend_from_slice(&[4, 5, 6][..]); assert_buf_eq!(buf, [3, 4, 5, 6]); + buf.extend_from_slice(&[7, 8, 9, 10][..]); assert_buf_eq!(buf, [7, 8, 9, 10]); + buf.extend_from_slice(&[11, 12, 13, 14, 15][..]); assert_buf_eq!(buf, [12, 13, 14, 15]); + } -#[test] -fn extend_from_slice_unwind_safety() { - // This needs to be `static` to be used in `fn clone()` below - static mut TRACKER: Option> = None; + #[test] + fn extend_from_slice_unwind_safety() { + // This needs to be `static` to be used in `fn clone()` below + static mut TRACKER: Option> = None; - // SAFETY: the assumption is that this test function will be called only once - unsafe { TRACKER.replace(DropTracker::new()); } + // SAFETY: the assumption is that this test function will be called only once + unsafe { TRACKER.replace(DropTracker::new()); } - fn tracker() -> &'static DropTracker { - unsafe { TRACKER.as_ref().unwrap() } - } + fn tracker() -> &'static DropTracker { + unsafe { TRACKER.as_ref().unwrap() } + } - fn tracker_mut() -> &'static mut DropTracker { - unsafe { TRACKER.as_mut().unwrap() } - } + fn tracker_mut() -> &'static mut DropTracker { + unsafe { TRACKER.as_mut().unwrap() } + } - #[derive(PartialEq, Eq, Hash)] - struct FaultyClonable { - drop_item: DropItem, - panic_on_clone: bool, - } + #[derive(PartialEq, Eq, Hash)] + struct FaultyClonable { + drop_item: DropItem, + panic_on_clone: bool, + } - impl Clone for FaultyClonable { - fn clone(&self) -> Self { - if self.panic_on_clone { - panic!("clone failed :("); - } else { - Self { - drop_item: tracker_mut().track(format!("clone of {}", self.drop_item)), - panic_on_clone: false, + impl Clone for FaultyClonable { + fn clone(&self) -> Self { + if self.panic_on_clone { + panic!("clone failed :("); + } else { + Self { + drop_item: tracker_mut().track(format!("clone of {}", self.drop_item)), + panic_on_clone: false, + } + } } } + + let array = [ + FaultyClonable { drop_item: tracker_mut().track("a".to_string()), panic_on_clone: false }, + FaultyClonable { drop_item: tracker_mut().track("b".to_string()), panic_on_clone: false }, + FaultyClonable { drop_item: tracker_mut().track("c".to_string()), panic_on_clone: true }, + FaultyClonable { drop_item: tracker_mut().track("d".to_string()), panic_on_clone: false }, + ]; + + let mut buf = new::<4, FaultyClonable>(); + + let res = std::panic::catch_unwind(move || buf.extend_from_slice(&array)); + assert!(res.is_err()); + + tracker().assert_dropped("clone of a"); + tracker().assert_dropped("clone of b"); + assert!(!tracker().is_tracked("clone of c")); + assert!(!tracker().is_tracked("clone of d")); } - } - let array = [ - FaultyClonable { drop_item: tracker_mut().track("a".to_string()), panic_on_clone: false }, - FaultyClonable { drop_item: tracker_mut().track("b".to_string()), panic_on_clone: false }, - FaultyClonable { drop_item: tracker_mut().track("c".to_string()), panic_on_clone: true }, - FaultyClonable { drop_item: tracker_mut().track("d".to_string()), panic_on_clone: false }, - ]; + #[test] + fn make_contiguous_full() { + let mut buf: CircularBuffer<4, u32> = [1, 2, 3, 4].into_iter().collect(); + assert_buf_slices_eq!(buf, [1, 2, 3, 4], []); + + assert_eq!(buf.make_contiguous(), &mut [1, 2, 3, 4]); + assert_buf_slices_eq!(buf, [1, 2, 3, 4], []); + assert_buf_eq!(buf, [1, 2, 3, 4]); + + buf.push_back(5); + assert_buf_slices_eq!(buf, [2, 3, 4], [5]); + assert_eq!(buf.make_contiguous(), &mut [2, 3, 4, 5]); + assert_buf_slices_eq!(buf, [2, 3, 4, 5], []); + assert_buf_eq!(buf, [2, 3, 4, 5]); + + buf.extend([6, 7]); + assert_buf_slices_eq!(buf, [4, 5], [6, 7]); + assert_eq!(buf.make_contiguous(), &mut [4, 5, 6, 7]); + assert_buf_slices_eq!(buf, [4, 5, 6, 7], []); + assert_buf_eq!(buf, [4, 5, 6, 7]); + + buf.extend([8, 9, 10]); + assert_buf_slices_eq!(buf, [7], [8, 9, 10]); + assert_eq!(buf.make_contiguous(), &mut [7, 8, 9, 10]); + assert_buf_slices_eq!(buf, [7, 8, 9, 10], []); + assert_buf_eq!(buf, [7, 8, 9, 10]); + } - let mut buf = CircularBuffer::<4, FaultyClonable>::new(); + #[test] + fn make_contiguous_not_full() { + let mut buf: CircularBuffer<4, u32> = [1, 2].into_iter().collect(); + assert_buf_slices_eq!(buf, [1, 2], []); + + assert_eq!(buf.make_contiguous(), &mut [1, 2]); + assert_buf_slices_eq!(buf, [1, 2], []); + assert_buf_eq!(buf, [1, 2]); + + buf.extend([3, 4, 5]); + buf.truncate_front(2); + assert_buf_slices_eq!(buf, [4], [5]); + assert_eq!(buf.make_contiguous(), &mut [4, 5]); + assert_buf_slices_eq!(buf, [4, 5], []); + assert_buf_eq!(buf, [4, 5]); + } - let res = std::panic::catch_unwind(move || buf.extend_from_slice(&array)); - assert!(res.is_err()); - tracker().assert_dropped("clone of a"); - tracker().assert_dropped("clone of b"); - assert!(!tracker().is_tracked("clone of c")); - assert!(!tracker().is_tracked("clone of d")); -} + #[test] + fn clone() { + let mut buf = new::<4, u32>(); + assert_eq!(buf, buf.clone()); -#[test] -fn make_contiguous_full() { - let mut buf: CircularBuffer<4, u32> = [1, 2, 3, 4].into_iter().collect(); - assert_buf_slices_eq!(buf, [1, 2, 3, 4], []); - - assert_eq!(buf.make_contiguous(), &mut [1, 2, 3, 4]); - assert_buf_slices_eq!(buf, [1, 2, 3, 4], []); - assert_buf_eq!(buf, [1, 2, 3, 4]); - - buf.push_back(5); - assert_buf_slices_eq!(buf, [2, 3, 4], [5]); - assert_eq!(buf.make_contiguous(), &mut [2, 3, 4, 5]); - assert_buf_slices_eq!(buf, [2, 3, 4, 5], []); - assert_buf_eq!(buf, [2, 3, 4, 5]); - - buf.extend([6, 7]); - assert_buf_slices_eq!(buf, [4, 5], [6, 7]); - assert_eq!(buf.make_contiguous(), &mut [4, 5, 6, 7]); - assert_buf_slices_eq!(buf, [4, 5, 6, 7], []); - assert_buf_eq!(buf, [4, 5, 6, 7]); - - buf.extend([8, 9, 10]); - assert_buf_slices_eq!(buf, [7], [8, 9, 10]); - assert_eq!(buf.make_contiguous(), &mut [7, 8, 9, 10]); - assert_buf_slices_eq!(buf, [7, 8, 9, 10], []); - assert_buf_eq!(buf, [7, 8, 9, 10]); -} + buf.extend_from_slice(&[][..]); assert_eq!(buf, buf.clone()); + buf.extend_from_slice(&[1][..]); assert_eq!(buf, buf.clone()); + buf.extend_from_slice(&[2, 3][..]); assert_eq!(buf, buf.clone()); + buf.extend_from_slice(&[4, 5, 6][..]); assert_eq!(buf, buf.clone()); + buf.extend_from_slice(&[7, 8, 9, 10][..]); assert_eq!(buf, buf.clone()); + buf.extend_from_slice(&[11, 12, 13, 14, 15][..]); assert_eq!(buf, buf.clone()); + } -#[test] -fn make_contiguous_not_full() { - let mut buf: CircularBuffer<4, u32> = [1, 2].into_iter().collect(); - assert_buf_slices_eq!(buf, [1, 2], []); - - assert_eq!(buf.make_contiguous(), &mut [1, 2]); - assert_buf_slices_eq!(buf, [1, 2], []); - assert_buf_eq!(buf, [1, 2]); - - buf.extend([3, 4, 5]); - buf.truncate_front(2); - assert_buf_slices_eq!(buf, [4], [5]); - assert_eq!(buf.make_contiguous(), &mut [4, 5]); - assert_buf_slices_eq!(buf, [4, 5], []); - assert_buf_eq!(buf, [4, 5]); -} + #[test] + fn hash() { + fn hash(buf: &Buffer) -> u64 { + let mut hasher = DefaultHasher::new(); + buf.hash(&mut hasher); + hasher.finish() + } + let hash_empty = hash::<0, _>(&new::<0, u32>()); + assert_eq!(hash_empty, hash::<0, _>(&new::<0, u32>())); + assert_eq!(hash_empty, hash::<2, _>(&new::<2, u32>())); + assert_eq!(hash_empty, hash::<4, _>(&new::<4, u32>())); + assert_eq!(hash_empty, hash::<8, _>(&new::<8, u32>())); + + let hash_1 = hash::<1, _>(&new_from_iter::<1, u32, _>([1])); + assert_ne!(hash_1, hash_empty); + assert_eq!(hash_1, hash::<2, _>(&new_from_iter::<2, u32, _>([1]))); + assert_eq!(hash_1, hash::<4, _>(&new_from_iter::<4, u32, _>([1]))); + assert_eq!(hash_1, hash::<8, _>(&new_from_iter::<8, u32, _>([1]))); + + let hash_2 = hash::<2, _>(&new_from_iter::<2, u32, _>([1, 2])); + assert_ne!(hash_2, hash_empty); + assert_ne!(hash_2, hash_1); + assert_eq!(hash_2, hash::<4, _>(&new_from_iter::<4, u32, _>([1, 2]))); + assert_eq!(hash_2, hash::<8, _>(&new_from_iter::<8, u32, _>([1, 2]))); + + let hash_4 = hash::<4, _>(&new_from_iter::<4, u32, _>([1, 2, 3, 4])); + assert_ne!(hash_4, hash_empty); + assert_ne!(hash_4, hash_1); + assert_ne!(hash_4, hash_2); + assert_eq!(hash_4, hash::<4, _>(&new_from_iter::<4, u32, _>([1, 2, 3, 4]))); + assert_eq!(hash_4, hash::<8, _>(&new_from_iter::<8, u32, _>([1, 2, 3, 4]))); + } + + #[test] + fn debug() { + let mut buf = new::<4, u32>(); + assert_buf_eq!(buf, [] as [u32; 0]); + assert_eq!(format!("{:?}", buf), "[]"); + assert_eq!(format!("{:x?}", buf), "[]"); + assert_eq!(format!("{:X?}", buf), "[]"); + + buf.push_back(10); + assert_buf_eq!(buf, [10]); + assert_eq!(format!("{:?}", buf), "[10]"); + assert_eq!(format!("{:x?}", buf), "[a]"); + assert_eq!(format!("{:X?}", buf), "[A]"); + + buf.push_back(20); + assert_buf_eq!(buf, [10, 20]); + assert_eq!(format!("{:?}", buf), "[10, 20]"); + assert_eq!(format!("{:x?}", buf), "[a, 14]"); + assert_eq!(format!("{:X?}", buf), "[A, 14]"); + + buf.push_back(30); + assert_buf_eq!(buf, [10, 20, 30]); + assert_eq!(format!("{:?}", buf), "[10, 20, 30]"); + assert_eq!(format!("{:x?}", buf), "[a, 14, 1e]"); + assert_eq!(format!("{:X?}", buf), "[A, 14, 1E]"); + + buf.push_back(40); + assert_buf_eq!(buf, [10, 20, 30, 40]); + assert_eq!(format!("{:?}", buf), "[10, 20, 30, 40]"); + assert_eq!(format!("{:x?}", buf), "[a, 14, 1e, 28]"); + assert_eq!(format!("{:X?}", buf), "[A, 14, 1E, 28]"); + + buf.push_back(50); + assert_buf_eq!(buf, [20, 30, 40, 50]); + assert_eq!(format!("{:?}", buf), "[20, 30, 40, 50]"); + assert_eq!(format!("{:x?}", buf), "[14, 1e, 28, 32]"); + assert_eq!(format!("{:X?}", buf), "[14, 1E, 28, 32]"); + + buf.push_back(60); + assert_buf_eq!(buf, [30, 40, 50, 60]); + assert_eq!(format!("{:?}", buf), "[30, 40, 50, 60]"); + assert_eq!(format!("{:x?}", buf), "[1e, 28, 32, 3c]"); + assert_eq!(format!("{:X?}", buf), "[1E, 28, 32, 3C]"); + } -#[test] -fn clone() { - let mut buf = CircularBuffer::<4, u32>::new(); - assert_eq!(buf, buf.clone()); + macro_rules! assert_add_mod_eq { + ( $expected:expr , crate :: add_mod ( $x:expr , $y:expr , $m:expr ) ) => { + let x = $x; + let y = $y; + let m = $m; + let expected = $expected; + let result = crate::add_mod(x, y, m); + assert_eq!(result, expected, "add_mod({x}, {y}, {m}) returned {result}; expected: {expected}"); + } + } - buf.extend_from_slice(&[][..]); assert_eq!(buf, buf.clone()); - buf.extend_from_slice(&[1][..]); assert_eq!(buf, buf.clone()); - buf.extend_from_slice(&[2, 3][..]); assert_eq!(buf, buf.clone()); - buf.extend_from_slice(&[4, 5, 6][..]); assert_eq!(buf, buf.clone()); - buf.extend_from_slice(&[7, 8, 9, 10][..]); assert_eq!(buf, buf.clone()); - buf.extend_from_slice(&[11, 12, 13, 14, 15][..]); assert_eq!(buf, buf.clone()); + #[test] + fn add_mod() { + assert_eq!(0, crate::add_mod(0, 0, 1)); + assert_eq!(0, crate::add_mod(0, 1, 1)); + assert_eq!(0, crate::add_mod(1, 0, 1)); + assert_eq!(0, crate::add_mod(1, 1, 1)); + + assert_eq!(0, crate::add_mod(0, 0, 2)); + assert_eq!(1, crate::add_mod(0, 1, 2)); + assert_eq!(0, crate::add_mod(0, 2, 2)); + assert_eq!(1, crate::add_mod(1, 0, 2)); + assert_eq!(0, crate::add_mod(1, 1, 2)); + assert_eq!(1, crate::add_mod(1, 2, 2)); + assert_eq!(0, crate::add_mod(2, 0, 2)); + assert_eq!(1, crate::add_mod(2, 1, 2)); + assert_eq!(0, crate::add_mod(2, 2, 2)); + + for m in [3, 4, 5, 6, 7, 8, + usize::MAX >> 1, + (usize::MAX >> 1) + 1, + usize::MAX - 2, + usize::MAX - 1, + usize::MAX] + { + assert_add_mod_eq!(0, crate::add_mod(0, 0, m)); + assert_add_mod_eq!(0, crate::add_mod(0, m, m)); + assert_add_mod_eq!(0, crate::add_mod(m, 0, m)); + assert_add_mod_eq!(0, crate::add_mod(m, m, m)); + + assert_add_mod_eq!(1, crate::add_mod(1, m, m)); + assert_add_mod_eq!(2, crate::add_mod(2, m, m)); + assert_add_mod_eq!(m - 2, crate::add_mod(m - 2, m, m)); + assert_add_mod_eq!(m - 1, crate::add_mod(m - 1, m, m)); + } + } + }; } -#[test] -fn hash() { - fn hash(buf: &CircularBuffer) -> u64 { - let mut hasher = DefaultHasher::new(); - buf.hash(&mut hasher); - hasher.finish() +mod fixed { + use super::*; + + type Buffer = CircularBuffer; + + fn new() -> CircularBuffer { + CircularBuffer::new() } - let hash_empty = hash(&CircularBuffer::<0, u32>::new()); - assert_eq!(hash_empty, hash(&CircularBuffer::<0, u32>::new())); - assert_eq!(hash_empty, hash(&CircularBuffer::<2, u32>::new())); - assert_eq!(hash_empty, hash(&CircularBuffer::<4, u32>::new())); - assert_eq!(hash_empty, hash(&CircularBuffer::<8, u32>::new())); - - let hash_1 = hash(&CircularBuffer::<1, u32>::from([1])); - assert_ne!(hash_1, hash_empty); - assert_eq!(hash_1, hash(&CircularBuffer::<2, u32>::from([1]))); - assert_eq!(hash_1, hash(&CircularBuffer::<4, u32>::from([1]))); - assert_eq!(hash_1, hash(&CircularBuffer::<8, u32>::from([1]))); - - let hash_2 = hash(&CircularBuffer::<2, u32>::from([1, 2])); - assert_ne!(hash_2, hash_empty); - assert_ne!(hash_2, hash_1); - assert_eq!(hash_2, hash(&CircularBuffer::<4, u32>::from([1, 2]))); - assert_eq!(hash_2, hash(&CircularBuffer::<8, u32>::from([1, 2]))); - - let hash_4 = hash(&CircularBuffer::<4, u32>::from([1, 2, 3, 4])); - assert_ne!(hash_4, hash_empty); - assert_ne!(hash_4, hash_1); - assert_ne!(hash_4, hash_2); - assert_eq!(hash_4, hash(&CircularBuffer::<4, u32>::from([1, 2, 3, 4]))); - assert_eq!(hash_4, hash(&CircularBuffer::<8, u32>::from([1, 2, 3, 4]))); -} + fn new_from_iter>( + iter: I, + ) -> CircularBuffer { + CircularBuffer::from_iter(iter) + } + + fn is_contiguous(buf: &CircularBuffer) -> bool { + let slices = buf.as_slices(); + slices.1.is_empty() + } -#[test] -fn debug() { - let mut buf = CircularBuffer::<4, u32>::new(); - assert_buf_eq!(buf, [] as [u32; 0]); - assert_eq!(format!("{:?}", buf), "[]"); - assert_eq!(format!("{:x?}", buf), "[]"); - assert_eq!(format!("{:X?}", buf), "[]"); - - buf.push_back(10); - assert_buf_eq!(buf, [10]); - assert_eq!(format!("{:?}", buf), "[10]"); - assert_eq!(format!("{:x?}", buf), "[a]"); - assert_eq!(format!("{:X?}", buf), "[A]"); - - buf.push_back(20); - assert_buf_eq!(buf, [10, 20]); - assert_eq!(format!("{:?}", buf), "[10, 20]"); - assert_eq!(format!("{:x?}", buf), "[a, 14]"); - assert_eq!(format!("{:X?}", buf), "[A, 14]"); - - buf.push_back(30); - assert_buf_eq!(buf, [10, 20, 30]); - assert_eq!(format!("{:?}", buf), "[10, 20, 30]"); - assert_eq!(format!("{:x?}", buf), "[a, 14, 1e]"); - assert_eq!(format!("{:X?}", buf), "[A, 14, 1E]"); - - buf.push_back(40); - assert_buf_eq!(buf, [10, 20, 30, 40]); - assert_eq!(format!("{:?}", buf), "[10, 20, 30, 40]"); - assert_eq!(format!("{:x?}", buf), "[a, 14, 1e, 28]"); - assert_eq!(format!("{:X?}", buf), "[A, 14, 1E, 28]"); - - buf.push_back(50); - assert_buf_eq!(buf, [20, 30, 40, 50]); - assert_eq!(format!("{:?}", buf), "[20, 30, 40, 50]"); - assert_eq!(format!("{:x?}", buf), "[14, 1e, 28, 32]"); - assert_eq!(format!("{:X?}", buf), "[14, 1E, 28, 32]"); - - buf.push_back(60); - assert_buf_eq!(buf, [30, 40, 50, 60]); - assert_eq!(format!("{:?}", buf), "[30, 40, 50, 60]"); - assert_eq!(format!("{:x?}", buf), "[1e, 28, 32, 3c]"); - assert_eq!(format!("{:X?}", buf), "[1E, 28, 32, 3C]"); + tests!(); } -macro_rules! assert_add_mod_eq { - ( $expected:expr , crate :: add_mod ( $x:expr , $y:expr , $m:expr ) ) => { - let x = $x; - let y = $y; - let m = $m; - let expected = $expected; - let result = crate::add_mod(x, y, m); - assert_eq!(result, expected, "add_mod({x}, {y}, {m}) returned {result}; expected: {expected}"); +mod heap { + use super::*; + + type Buffer = HeapCircularBuffer; + + fn new() -> HeapCircularBuffer { + HeapCircularBuffer::with_capacity(N) } -} -#[test] -fn add_mod() { - assert_eq!(0, crate::add_mod(0, 0, 1)); - assert_eq!(0, crate::add_mod(0, 1, 1)); - assert_eq!(0, crate::add_mod(1, 0, 1)); - assert_eq!(0, crate::add_mod(1, 1, 1)); - - assert_eq!(0, crate::add_mod(0, 0, 2)); - assert_eq!(1, crate::add_mod(0, 1, 2)); - assert_eq!(0, crate::add_mod(0, 2, 2)); - assert_eq!(1, crate::add_mod(1, 0, 2)); - assert_eq!(0, crate::add_mod(1, 1, 2)); - assert_eq!(1, crate::add_mod(1, 2, 2)); - assert_eq!(0, crate::add_mod(2, 0, 2)); - assert_eq!(1, crate::add_mod(2, 1, 2)); - assert_eq!(0, crate::add_mod(2, 2, 2)); - - for m in [3, 4, 5, 6, 7, 8, - usize::MAX >> 1, - (usize::MAX >> 1) + 1, - usize::MAX - 2, - usize::MAX - 1, - usize::MAX] - { - assert_add_mod_eq!(0, crate::add_mod(0, 0, m)); - assert_add_mod_eq!(0, crate::add_mod(0, m, m)); - assert_add_mod_eq!(0, crate::add_mod(m, 0, m)); - assert_add_mod_eq!(0, crate::add_mod(m, m, m)); - - assert_add_mod_eq!(1, crate::add_mod(1, m, m)); - assert_add_mod_eq!(2, crate::add_mod(2, m, m)); - assert_add_mod_eq!(m - 2, crate::add_mod(m - 2, m, m)); - assert_add_mod_eq!(m - 1, crate::add_mod(m - 1, m, m)); + fn new_from_iter>( + iter: I, + ) -> HeapCircularBuffer { + let mut buf = HeapCircularBuffer::with_capacity(N); + buf.extend(iter); + buf } -} + + fn is_contiguous(buf: &HeapCircularBuffer) -> bool { + let slices = buf.as_slices(); + slices.1.is_empty() + } + + tests!(); +} \ No newline at end of file diff --git a/tests/covariance.rs b/tests/covariance.rs index 4ce7930..c50fb8f 100644 --- a/tests/covariance.rs +++ b/tests/covariance.rs @@ -7,6 +7,7 @@ use circular_buffer::CircularBuffer; use circular_buffer::Iter; use circular_buffer::Drain; +use circular_buffer::heap::{HeapCircularBuffer, HeapDrain}; /// Verify that `CircularBuffer` is covariant over `T` #[test] @@ -15,6 +16,13 @@ fn circular_buffer<'a>() { let _: CircularBuffer::<1, &'a str> = buf; } +/// Verify that `HeapCircularBuffer` is covariant over `T` +#[test] +fn heap_circular_buffer<'a>() { + let buf = HeapCircularBuffer::<&'static str>::with_capacity(1); + let _: HeapCircularBuffer::<&'a str> = buf; +} + /// Verify that `Iter<'_, T>` is covariant over `T` #[test] fn iter<'a>() { @@ -23,6 +31,14 @@ fn iter<'a>() { let _: Iter<'_, &'a str> = iter; } +/// Verify that `Iter<'_, T>` is covariant over `T` +#[test] +fn heap_iter<'a>() { + let buf = HeapCircularBuffer::<&'static str>::with_capacity(1); + let iter: Iter<'_, &'static str> = buf.iter(); + let _: Iter<'_, &'a str> = iter; +} + // `IterMut<'a, T>` is invariant over `T` because it holds a mutable reference to the elements of // the buffer. // @@ -42,3 +58,11 @@ fn drain<'a>() { let drain: Drain<'_, 1, &'static str> = buf.drain(..); let _: Drain<'_, 1, &'a str> = drain; } + +/// Verify that `Drain<'_, N, T>` is covariant over `T` +#[test] +fn heap_drain<'a>() { + let mut buf = HeapCircularBuffer::<&'static str>::with_capacity(1); + let drain: HeapDrain<'_, &'static str> = buf.drain(..); + let _: HeapDrain<'_, &'a str> = drain; +} diff --git a/tests/large.rs b/tests/large.rs index 7bcc564..f8c75d7 100644 --- a/tests/large.rs +++ b/tests/large.rs @@ -1,4 +1,4 @@ -use circular_buffer::CircularBuffer; +use circular_buffer::{CircularBuffer, heap::HeapCircularBuffer}; #[cfg(not(miri))] const SIZE: usize = 2 * 1024 * 1024; // 2 MiB @@ -42,3 +42,40 @@ fn large_boxed() { assert_eq!(buf.as_slices().1, &vec[SIZE..]); } } + +#[test] +fn large_heap() { + let chunk = b"abcdefghijklmnopqrstuvxyz0123456789"; + let mut buf = HeapCircularBuffer::::with_capacity(SIZE); + let mut vec = Vec::new(); + + assert_ne!(SIZE % chunk.len(), 0); + + assert_eq!(buf.len(), 0); + assert!(buf.is_empty()); + assert!(!buf.is_full()); + assert_eq!(buf.as_slices().0, &[][..]); + assert_eq!(buf.as_slices().1, &[][..]); + + for _ in 0..(SIZE / chunk.len()) { + buf.extend_from_slice(&chunk[..]); + vec.extend_from_slice(&chunk[..]); + + assert_eq!(buf.len(), vec.len()); + assert!(!buf.is_empty()); + assert!(!buf.is_full()); + assert_eq!(buf.as_slices().0, &vec[..]); + assert_eq!(buf.as_slices().1, &[][..]); + } + + for _ in 0..(SIZE / chunk.len()) { + buf.extend_from_slice(&chunk[..]); + vec.extend_from_slice(&chunk[..]); + + assert_eq!(buf.len(), SIZE); + assert!(!buf.is_empty()); + assert!(buf.is_full()); + assert_eq!(buf.as_slices().0, &vec[vec.len() - SIZE..SIZE]); + assert_eq!(buf.as_slices().1, &vec[SIZE..]); + } +} \ No newline at end of file diff --git a/tests/randomized.rs b/tests/randomized.rs index 645e631..8974312 100644 --- a/tests/randomized.rs +++ b/tests/randomized.rs @@ -1,3 +1,4 @@ +#![cfg(not(miri))] /// Compare the correctness of `CircularBuffer` against a reference implementation (that is assumed /// to be fully correct). /// @@ -6,6 +7,7 @@ /// action. The reference implementation currently is based on top of `VecDeque`. use circular_buffer::CircularBuffer; +use circular_buffer::heap::HeapCircularBuffer; use drop_tracker::DropItem; use drop_tracker::DropTracker; use rand::Rng; @@ -238,6 +240,41 @@ impl Perform for CircularBuffer } } +impl Perform for HeapCircularBuffer +where + T: Clone, +{ + fn perform(&mut self, action: Action) -> Result { + match action { + Action::BackMut(elem) => { *self.back_mut().unwrap() = elem; Result::None }, + Action::FrontMut(elem) => { *self.front_mut().unwrap() = elem; Result::None }, + Action::GetMut(index, elem) => { *self.get_mut(index).unwrap() = elem; Result::None }, + Action::PushBack(elem) => { self.push_back(elem); Result::None }, + Action::PushFront(elem) => { self.push_front(elem); Result::None }, + Action::PopBack => self.pop_back().into(), + Action::PopFront => self.pop_front().into(), + Action::Remove(index) => self.remove(index).into(), + Action::Swap(x, y) => { self.swap(x, y); Result::None }, + Action::SwapRemoveBack(index) => { self.swap_remove_back(index); Result::None }, + Action::SwapRemoveFront(index) => { self.swap_remove_front(index); Result::None }, + Action::TruncateBack(index) => { self.truncate_back(index); Result::None }, + Action::TruncateFront(index) => { self.truncate_front(index); Result::None }, + Action::Clear => { self.clear(); Result::None }, + Action::Extend(elems) => { self.extend(elems); Result::None }, + Action::ExtendFromSlice(elems) => { self.extend_from_slice(&elems[..]); Result::None }, + Action::RangeMut(range, elems) => { + self.range_mut(range) + .zip(elems) + .map(|(elem, replacement)| *elem = replacement) + .count(); + Result::None + }, + Action::Drain(range) => { self.drain(range).collect() }, + Action::MakeContiguous => { self.make_contiguous().iter().cloned().collect() }, + } + } +} + impl Perform for VecDeque where T: Clone { @@ -300,108 +337,222 @@ impl Perform for Reference } } -fn test() - where T: Clone + PartialEq + fmt::Debug, - Standard: Distribution -{ - let mut reference = Reference::::new(N); - let mut buffer = CircularBuffer::::boxed(); - let mut rng = rand::thread_rng(); - - for _ in 0..200_000 { - // Generate a random action - let action: Action = if reference.is_empty() { - >>::sample(&Standard, &mut rng) - } else { - Uniform::from(0..reference.len()).sample(&mut rng) - }; - - println!("{action:?}"); - - // Perform the action on both the reference implementation and the CircularBuffer - let expected = reference.perform(action.clone()); - let actual = buffer.perform(action); - - // Compare the return value of both implementations - assert_eq!(expected, actual); - - // Compare the state of both implementations - let expected_items = reference.iter() - .cloned() - .collect::>(); - #[allow(clippy::eq_op)] - { assert_eq!(buffer, buffer); } - assert_eq!(*buffer, &expected_items[..]); - assert_eq!(buffer.to_vec(), expected_items); - - assert_eq!(reference.len(), buffer.len()); - assert_eq!(reference.is_empty(), buffer.is_empty()); +mod fixed { + use super::*; - assert_eq!(reference.iter().collect::>(), - buffer.iter().collect::>()); - assert_eq!(reference.iter_mut().collect::>(), - buffer.iter_mut().collect::>()); - - assert_eq!(reference.iter().rev().collect::>(), - buffer.iter().rev().collect::>()); - assert_eq!(reference.iter_mut().rev().collect::>(), - buffer.iter_mut().rev().collect::>()); + fn test() + where T: Clone + PartialEq + fmt::Debug, + Standard: Distribution + { + let mut reference = Reference::::new(N); + let mut buffer = CircularBuffer::::boxed(); + let mut rng = rand::thread_rng(); + + for _ in 0..200_000 { + // Generate a random action + let action: Action = if reference.is_empty() { + >>::sample(&Standard, &mut rng) + } else { + Uniform::from(0..reference.len()).sample(&mut rng) + }; + + println!("{action:?}"); + + // Perform the action on both the reference implementation and the CircularBuffer + let expected = reference.perform(action.clone()); + let actual = buffer.perform(action); + + // Compare the return value of both implementations + assert_eq!(expected, actual); + + // Compare the state of both implementations + let expected_items = reference.iter() + .cloned() + .collect::>(); + #[allow(clippy::eq_op)] + { assert_eq!(buffer, buffer); } + assert_eq!(*buffer, &expected_items[..]); + assert_eq!(buffer.to_vec(), expected_items); + + assert_eq!(reference.len(), buffer.len()); + assert_eq!(reference.is_empty(), buffer.is_empty()); + + assert_eq!(reference.iter().collect::>(), + buffer.iter().collect::>()); + assert_eq!(reference.iter_mut().collect::>(), + buffer.iter_mut().collect::>()); + + assert_eq!(reference.iter().rev().collect::>(), + buffer.iter().rev().collect::>()); + assert_eq!(reference.iter_mut().rev().collect::>(), + buffer.iter_mut().rev().collect::>()); + } + } + + #[test] + fn zero() { + test::<0, u64>(); + } + + #[test] + fn small() { + test::<10, u64>(); + } + + #[test] + fn medium() { + test::<1_000, u64>(); + } + + #[test] + fn large() { + test::<1_000_000, u64>(); + } + + #[test] + fn largest_with_zero_sized_struct() { + type Zst = (); + assert_eq!(mem::size_of::(), 0); + test::<{ usize::MAX }, Zst>(); + } + + #[test] + fn drop() { + static mut TRACKER: Option> = None; + + // SAFETY: the assumption is that this test function will be called only once + unsafe { TRACKER.replace(DropTracker::new()); } + + fn tracker() -> &'static DropTracker { + unsafe { TRACKER.as_ref().unwrap() } + } + + fn tracker_mut() -> &'static mut DropTracker { + unsafe { TRACKER.as_mut().unwrap() } + } + + #[derive(Clone, PartialEq, Eq, Debug)] + struct Item(Rc>); + + impl Distribution for Standard { + fn sample(&self, rng: &mut R) -> Item { + let n = rng.gen(); + Item(Rc::new(tracker_mut().track(n))) + } + } + + test::<100, Item>(); + + tracker().assert_fully_dropped(); } } -#[test] -fn zero() { - test::<0, u64>(); -} - -#[test] -fn small() { - test::<10, u64>(); -} - -#[test] -fn medium() { - test::<1_000, u64>(); -} - -#[test] -fn large() { - test::<1_000_000, u64>(); -} - -#[test] -fn largest_with_zero_sized_struct() { - type Zst = (); - assert_eq!(mem::size_of::(), 0); - test::<{ usize::MAX }, Zst>(); -} - -#[test] -fn drop() { - static mut TRACKER: Option> = None; +mod heap { + use super::*; - // SAFETY: the assumption is that this test function will be called only once - unsafe { TRACKER.replace(DropTracker::new()); } - - fn tracker() -> &'static DropTracker { - unsafe { TRACKER.as_ref().unwrap() } + fn test() + where T: Clone + PartialEq + fmt::Debug, + Standard: Distribution + { + let mut reference = Reference::::new(N); + let mut buffer = HeapCircularBuffer::::with_capacity(N); + let mut rng = rand::thread_rng(); + + for _ in 0..200_000 { + // Generate a random action + let action: Action = if reference.is_empty() { + >>::sample(&Standard, &mut rng) + } else { + Uniform::from(0..reference.len()).sample(&mut rng) + }; + + println!("{action:?}"); + + // Perform the action on both the reference implementation and the CircularBuffer + let expected = reference.perform(action.clone()); + let actual = buffer.perform(action); + + // Compare the return value of both implementations + assert_eq!(expected, actual); + + // Compare the state of both implementations + let expected_items = reference.iter() + .cloned() + .collect::>(); + #[allow(clippy::eq_op)] + { assert_eq!(buffer, buffer); } + assert_eq!(buffer, &expected_items[..]); + assert_eq!(buffer.to_vec(), expected_items); + + assert_eq!(reference.len(), buffer.len()); + assert_eq!(reference.is_empty(), buffer.is_empty()); + + assert_eq!(reference.iter().collect::>(), + buffer.iter().collect::>()); + assert_eq!(reference.iter_mut().collect::>(), + buffer.iter_mut().collect::>()); + + assert_eq!(reference.iter().rev().collect::>(), + buffer.iter().rev().collect::>()); + assert_eq!(reference.iter_mut().rev().collect::>(), + buffer.iter_mut().rev().collect::>()); + } } - - fn tracker_mut() -> &'static mut DropTracker { - unsafe { TRACKER.as_mut().unwrap() } + + #[test] + fn zero() { + test::<0, u64>(); } - - #[derive(Clone, PartialEq, Eq, Debug)] - struct Item(Rc>); - - impl Distribution for Standard { - fn sample(&self, rng: &mut R) -> Item { - let n = rng.gen(); - Item(Rc::new(tracker_mut().track(n))) + + #[test] + fn small() { + test::<10, u64>(); + } + + #[test] + fn medium() { + test::<1_000, u64>(); + } + + #[test] + fn large() { + test::<1_000_000, u64>(); + } + + #[test] + fn largest_with_zero_sized_struct() { + type Zst = (); + assert_eq!(mem::size_of::(), 0); + test::<{ usize::MAX }, Zst>(); + } + + #[test] + fn drop() { + static mut TRACKER: Option> = None; + + // SAFETY: the assumption is that this test function will be called only once + unsafe { TRACKER.replace(DropTracker::new()); } + + fn tracker() -> &'static DropTracker { + unsafe { TRACKER.as_ref().unwrap() } } + + fn tracker_mut() -> &'static mut DropTracker { + unsafe { TRACKER.as_mut().unwrap() } + } + + #[derive(Clone, PartialEq, Eq, Debug)] + struct Item(Rc>); + + impl Distribution for Standard { + fn sample(&self, rng: &mut R) -> Item { + let n = rng.gen(); + Item(Rc::new(tracker_mut().track(n))) + } + } + + test::<100, Item>(); + + tracker().assert_fully_dropped(); } - - test::<100, Item>(); - - tracker().assert_fully_dropped(); -} +} \ No newline at end of file