Skip to content

Commit cad4e22

Browse files
committed
add iterator wrappter types
1 parent fecc76f commit cad4e22

File tree

5 files changed

+155
-18
lines changed

5 files changed

+155
-18
lines changed

src/drain.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::iter::translate_range_bounds;
2020
///
2121
/// [`CircularBuffer::drain()`]: crate::CircularBuffer::drain
2222
/// [`HeapCircularBuffer::drain()`]: crate::heap::HeapCircularBuffer::drain
23-
pub struct Drain<'a, T, B>
23+
pub(crate) struct Drain<'a, T, B>
2424
where B: AsSlice<Item = MaybeUninit<T>>
2525
{
2626
/// This is a pointer and not a reference (`&'a mut CircularBuffer`) because using a reference
@@ -382,3 +382,27 @@ impl<'a, T> Clone for CircularSlicePtr<'a, T> {
382382
*self
383383
}
384384
}
385+
386+
387+
/// A draining [iterator](std::iter::Iterator) that removes and returns elements
388+
/// from a `CircularBuffer`
389+
///
390+
/// This struct is created by [`CircularBuffer::drain()`]. See its documentation
391+
/// for more details.
392+
///
393+
/// [`CircularBuffer::drain()`]: crate::CircularBuffer::drain
394+
#[repr(transparent)]
395+
pub struct StaticDrain<'a, const N: usize, T>(pub(crate) Drain<'a, T, [MaybeUninit<T>; N]>);
396+
super::impl_iter_traits!(<{const N: usize, T}> - StaticDrain<'_, N, T>);
397+
398+
399+
/// A draining [iterator](std::iter::Iterator) that removes and returns elements
400+
/// from a `HeapCircularBuffer`.
401+
///
402+
/// This struct is created by [`HeapCircularBuffer::drain()`]. See its
403+
/// documentation for more details.
404+
///
405+
/// [`HeapCircularBuffer::drain()`]: crate::heap::HeapCircularBuffer::drain
406+
#[repr(transparent)]
407+
pub struct HeapDrain<'a, T>(pub(crate) Drain<'a, T, Box<[MaybeUninit<T>]>>);
408+
super::impl_iter_traits!(<{T}> - HeapDrain<'_, T>);

src/heap.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ use core::{ptr, fmt};
22
use core::cmp::Ordering;
33
use core::mem::{MaybeUninit, self};
44
use core::ops::RangeBounds;
5-
use crate::{backend::Backend, Iter, IntoIter, IterMut, Drain};
5+
use crate::{backend::Backend, Iter, IterMut};
66
use crate::unstable_const_impl;
77

8+
pub use crate::drain::HeapDrain;
9+
pub use crate::iter::HeapIntoIter;
10+
811

912
/// A fixed-size circular buffer allocated on the heap.
1013
///
@@ -109,10 +112,14 @@ impl <T> HeapCircularBuffer<T> {
109112
/// ```
110113
#[inline]
111114
#[must_use]
112-
pub fn drain<R>(&mut self, range: R) -> Drain<'_, T, Box<[MaybeUninit<T>]>>
115+
pub fn drain<R>(&mut self, range: R) -> HeapDrain<'_, T>
113116
where R: RangeBounds<usize>
114117
{
115-
self.backend.drain(range)
118+
HeapDrain(self.backend.drain(range))
119+
}
120+
121+
pub(crate) fn into_backend(self) -> Backend<T, Box<[MaybeUninit<T>]>> {
122+
self.backend
116123
}
117124

118125
super::impl_buffer!();
@@ -185,11 +192,11 @@ impl<'a, T> Extend<&'a T> for HeapCircularBuffer<T>
185192
unstable_const_impl! {
186193
impl<{T}> const IntoIterator for HeapCircularBuffer<T> {
187194
type Item = T;
188-
type IntoIter = IntoIter<T, Box<[MaybeUninit<T>]>>;
195+
type IntoIter = HeapIntoIter<T>;
189196

190197
#[inline]
191198
fn into_iter(self) -> Self::IntoIter {
192-
IntoIter::new(self.backend)
199+
HeapIntoIter(self.backend.into_iter())
193200
}
194201
}
195202
}

src/iter.rs

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,43 @@ use crate::backend::Backend;
1515
///
1616
/// [`CircularBuffer`]: crate::CircularBuffer
1717
/// [`HeapCircularBuffer`]: crate::heap::HeapCircularBuffer
18-
pub struct IntoIter<T, B>
18+
pub(crate) struct IntoIter<T, B>
1919
where B: AsSlice<Item = MaybeUninit<T>>
2020
{
2121
inner: Backend<T, B>,
2222
}
2323

24+
impl<const N: usize, T> Clone for IntoIter<T, [MaybeUninit<T>; N]>
25+
where T: Clone,
26+
{
27+
fn clone(&self) -> Self {
28+
use crate::CircularBuffer;
29+
let buf = CircularBuffer::from_iter(self.inner.iter().cloned());
30+
Self { inner: buf.into_backend() }
31+
}
32+
33+
fn clone_from(&mut self, other: &Self) {
34+
self.inner.clear();
35+
self.inner.extend(other.inner.iter().cloned());
36+
}
37+
}
38+
39+
impl<T> Clone for IntoIter<T, Box<[MaybeUninit<T>]>>
40+
where T: Clone,
41+
{
42+
fn clone(&self) -> Self {
43+
use crate::heap::HeapCircularBuffer;
44+
let mut buf = HeapCircularBuffer::with_capacity(self.inner.capacity());
45+
buf.extend(self.inner.iter().cloned());
46+
Self { inner: buf.into_backend() }
47+
}
48+
49+
fn clone_from(&mut self, other: &Self) {
50+
self.inner.clear();
51+
self.inner.extend(other.inner.iter().cloned());
52+
}
53+
}
54+
2455
impl<T, B> IntoIter<T, B>
2556
where B: AsSlice<Item = MaybeUninit<T>>
2657
{
@@ -77,6 +108,32 @@ impl<T, B> fmt::Debug for IntoIter<T, B>
77108
}
78109
}
79110

111+
/// An owning [iterator](std::iter::Iterator) over the elements of a
112+
/// [`CircularBuffer`]
113+
///
114+
/// This yields the elements of a `CircularBuffer` from fron to back.
115+
///
116+
/// This struct is created when iterating over a `CircularBuffer`. See the
117+
/// documentation for [`IntoIterator`] for more details.
118+
///
119+
/// [`CircularBuffer`]: crate::CircularBuffer
120+
#[derive(Clone)]
121+
pub struct StaticIntoIter<const N: usize, T>(pub(crate) IntoIter<T, [MaybeUninit<T>; N]>);
122+
super::impl_iter_traits!(<{const N: usize, T}> - StaticIntoIter<N, T>);
123+
124+
/// An owning [iterator](std::iter::Iterator) over the elements of a
125+
/// [`HeapCircularBuffer`].
126+
///
127+
/// This yields the elements of a `CircularBuffer` from fron to back.
128+
///
129+
/// This struct is created when iterating over a `CircularBuffer`. See the
130+
/// documentation for [`IntoIterator`] for more details.
131+
///
132+
/// [`HeapCircularBuffer`]: crate::heap::HeapCircularBuffer
133+
#[derive(Clone)]
134+
pub struct HeapIntoIter<T>(pub(crate) IntoIter<T, Box<[MaybeUninit<T>]>>);
135+
super::impl_iter_traits!(<{T}> - HeapIntoIter<T>);
136+
80137
pub(crate) fn translate_range_bounds<T, B, R>(buf: &Backend<T, B>, range: R) -> (usize, usize)
81138
where
82139
R: RangeBounds<usize>,

src/lib.rs

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,8 @@ use core::ptr;
185185
use backend::Backend;
186186

187187

188-
pub use crate::drain::Drain;
189-
pub use crate::iter::IntoIter;
188+
pub use crate::drain::StaticDrain as Drain;
189+
pub use crate::iter::StaticIntoIter as IntoIter;
190190
pub use crate::iter::Iter;
191191
pub use crate::iter::IterMut;
192192

@@ -213,6 +213,51 @@ macro_rules! unstable_const_impl {
213213
}
214214
pub(crate) use unstable_const_impl;
215215

216+
macro_rules! impl_iter_traits {
217+
($( <{ $( $generics:tt )* }> )? - $type:ty) => {
218+
impl $(<$($generics)*>)? Iterator for $type {
219+
type Item = T;
220+
221+
#[inline]
222+
fn next(&mut self) -> Option<Self::Item> {
223+
self.0.next()
224+
}
225+
226+
#[inline]
227+
fn size_hint(&self) -> (usize, Option<usize>) {
228+
self.0.size_hint()
229+
}
230+
}
231+
232+
impl $(<$($generics)*>)? ExactSizeIterator for $type {
233+
#[inline]
234+
fn len(&self) -> usize {
235+
self.0.len()
236+
}
237+
}
238+
239+
impl $(<$($generics)*>)? FusedIterator for $type {}
240+
241+
impl $(<$($generics)*>)? DoubleEndedIterator for $type {
242+
#[inline]
243+
fn next_back(&mut self) -> Option<Self::Item> {
244+
self.0.next_back()
245+
}
246+
}
247+
248+
249+
impl $(<$($generics)*>)? fmt::Debug for $type
250+
where T: fmt::Debug
251+
{
252+
#[inline]
253+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254+
self.0.fmt(f)
255+
}
256+
}
257+
};
258+
}
259+
pub(crate) use impl_iter_traits;
260+
216261
/// Returns `(x + y) % m` without risk of overflows if `x + y` cannot fit in `usize`.
217262
///
218263
/// `x` and `y` are expected to be less than, or equal to `m`.
@@ -410,10 +455,14 @@ impl<const N: usize, T> CircularBuffer<N, T> {
410455
/// ```
411456
#[inline]
412457
#[must_use]
413-
pub fn drain<R>(&mut self, range: R) -> Drain<'_, T, [MaybeUninit<T>; N]>
458+
pub fn drain<R>(&mut self, range: R) -> Drain<'_, N, T>
414459
where R: RangeBounds<usize>
415460
{
416-
self.backend.drain(range)
461+
Drain(self.backend.drain(range))
462+
}
463+
464+
pub(crate) fn into_backend(self) -> Backend<T, [MaybeUninit<T>; N]> {
465+
self.backend
417466
}
418467

419468
impl_buffer!();
@@ -1305,11 +1354,11 @@ impl<'a, const N: usize, T> Extend<&'a T> for CircularBuffer<N, T>
13051354
unstable_const_impl! {
13061355
impl<{const N: usize, T}> const IntoIterator for CircularBuffer<N, T> {
13071356
type Item = T;
1308-
type IntoIter = IntoIter<T, [MaybeUninit<T>; N]>;
1357+
type IntoIter = IntoIter<N, T>;
13091358

13101359
#[inline]
13111360
fn into_iter(self) -> Self::IntoIter {
1312-
IntoIter::new(self.backend)
1361+
IntoIter(self.backend.into_iter())
13131362
}
13141363
}
13151364
}

tests/covariance.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use circular_buffer::CircularBuffer;
88
use circular_buffer::Iter;
99
use circular_buffer::Drain;
10-
use circular_buffer::heap::HeapCircularBuffer;
10+
use circular_buffer::heap::{HeapCircularBuffer, HeapDrain};
1111

1212
/// Verify that `CircularBuffer<N, T>` is covariant over `T`
1313
#[test]
@@ -55,14 +55,14 @@ fn heap_iter<'a>() {
5555
#[test]
5656
fn drain<'a>() {
5757
let mut buf = CircularBuffer::<1, &'static str>::new();
58-
let drain: Drain<'_, &'static str, _> = buf.drain(..);
59-
let _: Drain<'_, &'a str, _> = drain;
58+
let drain: Drain<'_, 1, &'static str> = buf.drain(..);
59+
let _: Drain<'_, 1, &'a str> = drain;
6060
}
6161

6262
/// Verify that `Drain<'_, N, T>` is covariant over `T`
6363
#[test]
6464
fn heap_drain<'a>() {
6565
let mut buf = HeapCircularBuffer::<&'static str>::with_capacity(1);
66-
let drain: Drain<'_, &'static str, _> = buf.drain(..);
67-
let _: Drain<'_, &'a str, _> = drain;
66+
let drain: HeapDrain<'_, &'static str> = buf.drain(..);
67+
let _: HeapDrain<'_, &'a str> = drain;
6868
}

0 commit comments

Comments
 (0)