From 234ac98e16d1c05322a22e5ad1b293cbb04d864d Mon Sep 17 00:00:00 2001 From: Brian Cully Date: Wed, 14 Aug 2019 16:41:59 -0400 Subject: Remove `Copy` requirement for most methods. The ring buffer will now take and pass ownership as required, so the `Copy` trait constraint is no longer required. The one exception is `Writer::unshift_from`, where we're taking data we don't know how to replace from an arbitrary slice, so that needs to be `Copy`-able. --- src/lib.rs | 77 +++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a77193f..be2ed31 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,6 +11,7 @@ use core::{ cmp, marker::PhantomData, mem::{self, MaybeUninit}, + ptr, sync::atomic::{AtomicUsize, Ordering}, }; @@ -41,10 +42,7 @@ pub struct RingBuffer { buf: UnsafeCell>, } -impl RingBuffer -where - T: Copy, -{ +impl RingBuffer { /// Create a new RingBuffer. pub const fn new() -> Self { Self { @@ -93,10 +91,7 @@ pub struct Writer<'a, T> { unsafe impl Send for Writer<'_, T> where T: Send {} unsafe impl Sync for Writer<'_, T> {} -impl Reader<'_, T> -where - T: Copy, -{ +impl Reader<'_, T> { /// The number of elements currently available for reading. /// /// NB: Because the `Writer` half of the ring buffer may be adding @@ -165,24 +160,18 @@ where #[inline(always)] unsafe fn load_val_at(i: usize, buf: &MaybeUninit<[T; CAPACITY]>) -> T { let b: &[T; CAPACITY] = &*buf.as_ptr(); - *b.get_unchecked(i) + ptr::read(b.get_unchecked(i)) } } -impl Iterator for Reader<'_, T> -where - T: Copy, -{ +impl Iterator for Reader<'_, T> { type Item = T; fn next(&mut self) -> Option { self.shift() } } -impl Writer<'_, T> -where - T: Copy, -{ +impl Writer<'_, T> { /// Put `v` at the end of the buffer. /// /// Returns `BufferFull` if appending `v` would overlap with the @@ -212,6 +201,20 @@ where } } + #[inline(always)] + unsafe fn store_val_at(i: usize, buf: &mut MaybeUninit<[T; CAPACITY]>, val: T) { + let b: &mut [T; CAPACITY] = &mut *buf.as_mut_ptr(); + ptr::write(b.get_unchecked_mut(i), val); + } +} + +// TODO: this needs to be `Copy` because we're pulling data from a +// slice, and we can't just take stuff out of an index without +// replacing it, and there's no good value for that. +impl Writer<'_, T> +where + T: Copy, +{ /// Copy as much of `buf` into the ring buffer. /// /// Returns the number of items copied. @@ -236,12 +239,6 @@ where rb.tail.store(t, Ordering::SeqCst); len } - - #[inline(always)] - unsafe fn store_val_at(i: usize, buf: &mut MaybeUninit<[T; CAPACITY]>, val: T) { - let b: &mut [T; CAPACITY] = &mut *buf.as_mut_ptr(); - *b.get_unchecked_mut(i) = val - } } #[cfg(test)] @@ -390,4 +387,38 @@ mod test { } assert!(rbr.shift().is_none()); } + + #[test] + fn ownership_passes_through() { + static mut DROPPED: bool = false; + struct DropTest {}; + impl DropTest { + fn i_own_it_now(self) {} + } + impl Drop for DropTest { + fn drop(&mut self) { + unsafe { DROPPED = true }; + } + } + + let rb = RingBuffer::::new(); + let (mut rbr, mut rbw) = rb.split(); + + // Create a closure to take ownership of a `DropTest` so we + // can make sure it's not dropped when the closure is over. + let mut cl = |dt| { + rbw.unshift(dt).expect("couldn't store item"); + }; + cl(DropTest {}); + assert_eq!(unsafe { DROPPED }, false); + + // Still, nothing should be dropped, since we now own the + // value. + let dt = rbr.shift().expect("buffer was empty"); + assert_eq!(unsafe { DROPPED }, false); + + // And, finally, by giving ownership away, it'll get dropped. + dt.i_own_it_now(); + assert_eq!(unsafe { DROPPED }, true); + } } -- cgit v1.2.3