Skip to content

Commit

Permalink
add iterator wrappter types
Browse files Browse the repository at this point in the history
  • Loading branch information
Icxolu committed Dec 2, 2023
1 parent fecc76f commit 80e573f
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 19 deletions.
4 changes: 3 additions & 1 deletion src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use core::{fmt, ops::Range};
use core::mem::MaybeUninit;
use core::hash::{Hash, Hasher};

use crate::{Iter, IterMut, add_mod, slice_assume_init_ref, slice_assume_init_mut, sub_mod, IntoIter, Drain};
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<T, B>
where B: AsSlice<Item = MaybeUninit<T>>
Expand Down
26 changes: 25 additions & 1 deletion src/drain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::iter::translate_range_bounds;
///
/// [`CircularBuffer::drain()`]: crate::CircularBuffer::drain
/// [`HeapCircularBuffer::drain()`]: crate::heap::HeapCircularBuffer::drain
pub struct Drain<'a, T, B>
pub(crate) struct Drain<'a, T, B>
where B: AsSlice<Item = MaybeUninit<T>>
{
/// This is a pointer and not a reference (`&'a mut CircularBuffer`) because using a reference
Expand Down Expand Up @@ -382,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<T>; 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<T>]>>);
super::impl_iter_traits!(<{T}> - HeapDrain<'_, T>);
17 changes: 12 additions & 5 deletions src/heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ use core::{ptr, fmt};
use core::cmp::Ordering;
use core::mem::{MaybeUninit, self};
use core::ops::RangeBounds;
use crate::{backend::Backend, Iter, IntoIter, IterMut, Drain};
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.
///
Expand Down Expand Up @@ -109,10 +112,14 @@ impl <T> HeapCircularBuffer<T> {
/// ```
#[inline]
#[must_use]
pub fn drain<R>(&mut self, range: R) -> Drain<'_, T, Box<[MaybeUninit<T>]>>
pub fn drain<R>(&mut self, range: R) -> HeapDrain<'_, T>
where R: RangeBounds<usize>
{
self.backend.drain(range)
HeapDrain(self.backend.drain(range))
}

pub(crate) fn into_backend(self) -> Backend<T, Box<[MaybeUninit<T>]>> {
self.backend
}

super::impl_buffer!();
Expand Down Expand Up @@ -185,11 +192,11 @@ impl<'a, T> Extend<&'a T> for HeapCircularBuffer<T>
unstable_const_impl! {
impl<{T}> const IntoIterator for HeapCircularBuffer<T> {
type Item = T;
type IntoIter = IntoIter<T, Box<[MaybeUninit<T>]>>;
type IntoIter = HeapIntoIter<T>;

#[inline]
fn into_iter(self) -> Self::IntoIter {
IntoIter::new(self.backend)
HeapIntoIter(self.backend.into_iter())
}
}
}
Expand Down
59 changes: 58 additions & 1 deletion src/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,43 @@ use crate::backend::Backend;
///
/// [`CircularBuffer`]: crate::CircularBuffer
/// [`HeapCircularBuffer`]: crate::heap::HeapCircularBuffer
pub struct IntoIter<T, B>
pub(crate) struct IntoIter<T, B>
where B: AsSlice<Item = MaybeUninit<T>>
{
inner: Backend<T, B>,
}

impl<const N: usize, T> Clone for IntoIter<T, [MaybeUninit<T>; 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<T> Clone for IntoIter<T, Box<[MaybeUninit<T>]>>
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<T, B> IntoIter<T, B>
where B: AsSlice<Item = MaybeUninit<T>>
{
Expand Down Expand Up @@ -77,6 +108,32 @@ impl<T, B> fmt::Debug for IntoIter<T, B>
}
}

/// 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<const N: usize, T>(pub(crate) IntoIter<T, [MaybeUninit<T>; N]>);
super::impl_iter_traits!(<{const N: usize, T}> - StaticIntoIter<N, T>);

/// 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<T>(pub(crate) IntoIter<T, Box<[MaybeUninit<T>]>>);
super::impl_iter_traits!(<{T}> - HeapIntoIter<T>);

pub(crate) fn translate_range_bounds<T, B, R>(buf: &Backend<T, B>, range: R) -> (usize, usize)
where
R: RangeBounds<usize>,
Expand Down
61 changes: 55 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,8 @@ 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;

Expand All @@ -213,6 +213,51 @@ macro_rules! unstable_const_impl {
}
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::Item> {
self.0.next()
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
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::Item> {
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`.
///
/// `x` and `y` are expected to be less than, or equal to `m`.
Expand Down Expand Up @@ -410,10 +455,14 @@ impl<const N: usize, T> CircularBuffer<N, T> {
/// ```
#[inline]
#[must_use]
pub fn drain<R>(&mut self, range: R) -> Drain<'_, T, [MaybeUninit<T>; N]>
pub fn drain<R>(&mut self, range: R) -> Drain<'_, N, T>
where R: RangeBounds<usize>
{
self.backend.drain(range)
Drain(self.backend.drain(range))
}

pub(crate) fn into_backend(self) -> Backend<T, [MaybeUninit<T>; N]> {
self.backend
}

impl_buffer!();
Expand Down Expand Up @@ -1305,11 +1354,11 @@ impl<'a, const N: usize, T> Extend<&'a T> for CircularBuffer<N, T>
unstable_const_impl! {
impl<{const N: usize, T}> const IntoIterator for CircularBuffer<N, T> {
type Item = T;
type IntoIter = IntoIter<T, [MaybeUninit<T>; N]>;
type IntoIter = IntoIter<N, T>;

#[inline]
fn into_iter(self) -> Self::IntoIter {
IntoIter::new(self.backend)
IntoIter(self.backend.into_iter())
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions tests/covariance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use circular_buffer::CircularBuffer;
use circular_buffer::Iter;
use circular_buffer::Drain;
use circular_buffer::heap::HeapCircularBuffer;
use circular_buffer::heap::{HeapCircularBuffer, HeapDrain};

/// Verify that `CircularBuffer<N, T>` is covariant over `T`
#[test]
Expand Down Expand Up @@ -55,14 +55,14 @@ fn heap_iter<'a>() {
#[test]
fn drain<'a>() {
let mut buf = CircularBuffer::<1, &'static str>::new();
let drain: Drain<'_, &'static str, _> = buf.drain(..);
let _: Drain<'_, &'a str, _> = drain;
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: Drain<'_, &'static str, _> = buf.drain(..);
let _: Drain<'_, &'a str, _> = drain;
let drain: HeapDrain<'_, &'static str> = buf.drain(..);
let _: HeapDrain<'_, &'a str> = drain;
}

0 comments on commit 80e573f

Please sign in to comment.