Skip to content

Commit 6caf6b9

Browse files
committed
Separate IntoIter and PopIter, optimize PopIter
1 parent 1c966f7 commit 6caf6b9

File tree

2 files changed

+68
-20
lines changed

2 files changed

+68
-20
lines changed

src/storage.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ use core::{mem::forget, ptr};
88
///
99
/// Storage items must be stored as a contiguous array.
1010
///
11-
/// Storage is converted to internal representation before use (see [`Self::Internal`]).
12-
///
1311
/// # Safety
1412
///
1513
/// Must not alias with its contents

src/traits/consumer.rs

Lines changed: 68 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use super::{
33
utils::modulus,
44
};
55
use crate::utils::{move_uninit_slice, slice_as_uninit_mut, slice_assume_init_mut, slice_assume_init_ref};
6-
use core::{iter::Chain, marker::PhantomData, mem::MaybeUninit, ptr, slice};
6+
use core::{iter::Chain, mem::MaybeUninit, ptr, slice};
77
#[cfg(feature = "std")]
88
use std::io::{self, Write};
99

@@ -156,10 +156,7 @@ pub trait Consumer: Observer {
156156
}
157157

158158
/// Returns an iterator that removes items one by one from the ring buffer.
159-
fn pop_iter(&mut self) -> PopIter<&mut Self, Self>
160-
where
161-
Self: AsMut<Self> + AsRef<Self>,
162-
{
159+
fn pop_iter(&mut self) -> PopIter<Self> {
163160
PopIter::new(self)
164161
}
165162

@@ -256,37 +253,90 @@ pub trait Consumer: Observer {
256253
}
257254
}
258255

256+
/// Owning ring buffer iterator.
257+
pub struct IntoIter<C: Consumer + ?Sized> {
258+
inner: C,
259+
}
260+
261+
impl<C: Consumer> IntoIter<C> {
262+
pub fn new(inner: C) -> Self {
263+
Self { inner }
264+
}
265+
pub fn into_inner(self) -> C {
266+
self.inner
267+
}
268+
}
269+
270+
impl<C: Consumer> Iterator for IntoIter<C> {
271+
type Item = C::Item;
272+
273+
#[inline]
274+
fn next(&mut self) -> Option<Self::Item> {
275+
self.inner.try_pop()
276+
}
277+
#[inline]
278+
fn size_hint(&self) -> (usize, Option<usize>) {
279+
(self.inner.occupied_len(), None)
280+
}
281+
}
282+
259283
/// An iterator that removes items from the ring buffer.
260-
pub struct PopIter<U: AsMut<C> + AsRef<C>, C: Consumer + ?Sized> {
261-
inner: U,
262-
_ghost: PhantomData<C>,
284+
///
285+
/// Producer will see removed items only when iterator is dropped or [`PopIter::commit`] is called.
286+
pub struct PopIter<'a, C: Consumer + ?Sized> {
287+
inner: &'a C,
288+
iter: Chain<slice::Iter<'a, MaybeUninit<C::Item>>, slice::Iter<'a, MaybeUninit<C::Item>>>,
289+
count: usize,
290+
len: usize,
263291
}
264292

265-
impl<U: AsMut<C> + AsRef<C>, C: Consumer + ?Sized> PopIter<U, C> {
266-
pub fn new(inner: U) -> Self {
293+
impl<'a, C: Consumer + ?Sized> Drop for PopIter<'a, C> {
294+
fn drop(&mut self) {
295+
self.commit();
296+
}
297+
}
298+
299+
impl<'a, C: Consumer + ?Sized> PopIter<'a, C> {
300+
/// Create an iterator.
301+
pub fn new(inner: &'a mut C) -> Self {
302+
let (len, iter) = {
303+
let (left, right) = inner.occupied_slices();
304+
(left.len() + right.len(), left.iter().chain(right))
305+
};
267306
Self {
268307
inner,
269-
_ghost: PhantomData,
308+
iter,
309+
count: 0,
310+
len,
270311
}
271312
}
272-
pub fn into_inner(self) -> U {
273-
self.inner
313+
314+
/// Send information about removed items to the ring buffer.
315+
pub fn commit(&mut self) {
316+
unsafe { self.inner.advance_read_index(self.count) };
317+
self.count = 0;
274318
}
275319
}
276320

277-
impl<U: AsMut<C> + AsRef<C>, C: Consumer> Iterator for PopIter<U, C> {
321+
impl<'a, C: Consumer> Iterator for PopIter<'a, C> {
278322
type Item = C::Item;
279323

280324
#[inline]
281325
fn next(&mut self) -> Option<Self::Item> {
282-
self.inner.as_mut().try_pop()
326+
self.iter.next().map(|item| {
327+
self.count += 1;
328+
unsafe { item.assume_init_read() }
329+
})
283330
}
284331
#[inline]
285332
fn size_hint(&self) -> (usize, Option<usize>) {
286-
(self.inner.as_ref().occupied_len(), None)
333+
let remain = self.len - self.count;
334+
(remain, Some(remain))
287335
}
288336
}
289337

338+
impl<'a, C: Consumer> ExactSizeIterator for PopIter<'a, C> {}
339+
290340
/// Iterator over ring buffer contents.
291341
///
292342
/// *Please do not rely on actual type, it may change in future.*
@@ -376,9 +426,9 @@ macro_rules! impl_consumer_traits {
376426
($type:ident $(< $( $param:tt $( : $first_bound:tt $(+ $next_bound:tt )* )? ),+ >)?) => {
377427
impl $(< $( $param $( : $first_bound $(+ $next_bound )* )? ),+ >)? core::iter::IntoIterator for $type $(< $( $param ),+ >)? where Self: Sized {
378428
type Item = <Self as $crate::traits::Observer>::Item;
379-
type IntoIter = $crate::traits::consumer::PopIter<Self, Self>;
429+
type IntoIter = $crate::traits::consumer::IntoIter<Self>;
380430
fn into_iter(self) -> Self::IntoIter {
381-
$crate::traits::consumer::PopIter::new(self)
431+
$crate::traits::consumer::IntoIter::new(self)
382432
}
383433
}
384434

0 commit comments

Comments
 (0)