Skip to content

Commit

Permalink
Don't keep a live mut ref to the RingBuffer in IterMut.
Browse files Browse the repository at this point in the history
Change the mutable reference to the buffer into a mutable pointer, to
avoid aliasing issues.

Fixes #8.
  • Loading branch information
bodil committed Mar 19, 2020
1 parent ff87cd0 commit 421287f
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 22 deletions.
60 changes: 52 additions & 8 deletions src/ring_buffer/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::iter::FusedIterator;
use std::marker::PhantomData;

use crate::types::ChunkLength;

Expand Down Expand Up @@ -64,15 +65,45 @@ pub struct IterMut<'a, A, N>
where
N: ChunkLength<A>,
{
pub(crate) buffer: &'a mut RingBuffer<A, N>,
pub(crate) left_index: RawIndex<N>,
pub(crate) right_index: RawIndex<N>,
pub(crate) remaining: usize,
data: *mut A,
left_index: RawIndex<N>,
right_index: RawIndex<N>,
remaining: usize,
phantom: PhantomData<&'a ()>,
}

impl<'a, A, N> IterMut<'a, A, N>
where
N: ChunkLength<A>,
A: 'a,
{
pub(crate) fn new(buffer: &mut RingBuffer<A, N>) -> Self {
Self::new_slice(buffer, buffer.origin, buffer.len())
}

pub(crate) fn new_slice(
buffer: &mut RingBuffer<A, N>,
origin: RawIndex<N>,
len: usize,
) -> Self {
Self {
left_index: origin,
right_index: origin + len,
remaining: len,
phantom: PhantomData,
data: buffer.data.as_mut_ptr().cast(),
}
}

unsafe fn mut_ptr(&mut self, index: RawIndex<N>) -> *mut A {
self.data.add(index.to_usize())
}
}

impl<'a, A, N> Iterator for IterMut<'a, A, N>
where
N: ChunkLength<A>,
A: 'a,
{
type Item = &'a mut A;

Expand All @@ -81,7 +112,8 @@ where
None
} else {
self.remaining -= 1;
Some(unsafe { &mut *self.buffer.mut_ptr(self.left_index.inc()) })
let index = self.left_index.inc();
Some(unsafe { &mut *self.mut_ptr(index) })
}
}

Expand All @@ -95,20 +127,32 @@ where
impl<'a, A, N> DoubleEndedIterator for IterMut<'a, A, N>
where
N: ChunkLength<A>,
A: 'a,
{
fn next_back(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
None
} else {
self.remaining -= 1;
Some(unsafe { &mut *self.buffer.mut_ptr(self.right_index.dec()) })
let index = self.right_index.dec();
Some(unsafe { &mut *self.mut_ptr(index) })
}
}
}

impl<'a, A, N> ExactSizeIterator for IterMut<'a, A, N> where N: ChunkLength<A> {}
impl<'a, A, N> ExactSizeIterator for IterMut<'a, A, N>
where
N: ChunkLength<A>,
A: 'a,
{
}

impl<'a, A, N> FusedIterator for IterMut<'a, A, N> where N: ChunkLength<A> {}
impl<'a, A, N> FusedIterator for IterMut<'a, A, N>
where
N: ChunkLength<A>,
A: 'a,
{
}

/// A draining iterator over a `RingBuffer`.
pub struct Drain<'a, A, N: ChunkLength<A>> {
Expand Down
7 changes: 1 addition & 6 deletions src/ring_buffer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,12 +320,7 @@ where
#[inline]
#[must_use]
pub fn iter_mut(&mut self) -> IterMut<'_, A, N> {
IterMut {
left_index: self.origin,
right_index: self.origin + self.len(),
remaining: self.len(),
buffer: self,
}
IterMut::new(self)
}

#[must_use]
Expand Down
13 changes: 5 additions & 8 deletions src/ring_buffer/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,14 +451,11 @@ impl<'a, A: 'a, N: ChunkLength<A> + 'a> SliceMut<'a, A, N> {
#[inline]
#[must_use]
pub fn iter_mut(&mut self) -> IterMut<'_, A, N> {
let origin = self.buffer.origin;
let len = self.len();
IterMut {
buffer: self.buffer,
left_index: origin + self.range.start,
right_index: origin + self.range.start + len,
remaining: len,
}
IterMut::new_slice(
self.buffer,
self.buffer.origin + self.range.start,
self.len(),
)
}

/// Create a subslice of this slice.
Expand Down

0 comments on commit 421287f

Please sign in to comment.