From 8baf6ec65ef6ced53134b13e48e2215c8554047a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 19 Aug 2018 11:22:06 +0200 Subject: [PATCH] internally use MaybeUninit which has been proposed in rust-lang/rfcs#1892 --- src/__core.rs | 69 ++++++++++++++++++++++------------------- src/ring_buffer/mod.rs | 18 +++++------ src/ring_buffer/spsc.rs | 12 +++---- src/vec.rs | 36 +++++++++------------ 4 files changed, 66 insertions(+), 69 deletions(-) diff --git a/src/__core.rs b/src/__core.rs index 001a802479..3d856fbde5 100644 --- a/src/__core.rs +++ b/src/__core.rs @@ -2,46 +2,51 @@ pub mod mem { #[cfg(not(feature = "const-fn"))] - pub use core::mem::uninitialized; + pub use core::mem; pub use core::mem::{replace, zeroed, ManuallyDrop}; + // See RFC 1892 #[cfg(feature = "const-fn")] - pub const unsafe fn uninitialized() -> T { - #[allow(unions_with_drop_fields)] - union U { - none: (), - some: T, - } + pub union MaybeUninit { + uninit: (), + value: ManuallyDrop, + } - U { none: () }.some + // workaround to get this to compile on stable ("unions with non-`Copy` fields are unstable") + #[cfg(not(feature = "const-fn"))] + pub struct MaybeUninit { + value: ManuallyDrop } -} -#[cfg(feature = "const-fn")] // Remove this if there are more tests -#[cfg(test)] -mod test { - use __core; - use __core::mem::ManuallyDrop; - use core; + impl MaybeUninit { + #[cfg(feature = "const-fn")] + pub const unsafe fn uninitialized() -> Self { + MaybeUninit { uninit: () } + } - #[cfg(feature = "const-fn")] - #[test] - fn static_uninitzialized() { - static mut I: i32 = unsafe { __core::mem::uninitialized() }; - // Initialize before drop - unsafe { core::ptr::write(&mut I as *mut i32, 42) }; - unsafe { assert_eq!(I, 42) }; - } + #[cfg(not(feature = "const-fn"))] + pub unsafe fn uninitialized() -> Self { + mem::uninitialized() + } - #[cfg(feature = "const-fn")] - #[test] - fn static_new_manually_drop() { - static mut M: ManuallyDrop = ManuallyDrop::new(42); - unsafe { - assert_eq!(*M, 42); + /// Get a reference to the contained value. + /// + /// # Unsafety + /// + /// It is up to the caller to guarantee that the the `MaybeUninit` really is in an + /// initialized state, otherwise this will immediately cause undefined behavior. + pub unsafe fn get_ref(&self) -> &T { + &*self.value } - // Drop before deinitialization - unsafe { core::ptr::drop_in_place(&mut M as &mut i32 as *mut i32) }; - } + /// Get a mutable reference to the contained value. + /// + /// # Unsafety + /// + /// It is up to the caller to guarantee that the the `MaybeUninit` really is in an + /// initialized state, otherwise this will immediately cause undefined behavior. + pub unsafe fn get_mut(&mut self) -> &mut T { + &mut *self.value + } + } } diff --git a/src/ring_buffer/mod.rs b/src/ring_buffer/mod.rs index 911ce0a4cc..7cd132a10e 100644 --- a/src/ring_buffer/mod.rs +++ b/src/ring_buffer/mod.rs @@ -8,11 +8,11 @@ use core::ptr; #[cfg(not(feature = "smaller-atomics"))] use core::sync::atomic::{AtomicUsize, Ordering}; -use generic_array::typenum::{Sum, U1, Unsigned}; +use generic_array::typenum::{Sum, Unsigned, U1}; use generic_array::{ArrayLength, GenericArray}; pub use self::spsc::{Consumer, Producer}; -use __core::mem::{self, ManuallyDrop}; +use __core::mem::MaybeUninit; mod spsc; @@ -230,7 +230,7 @@ where // this is where we enqueue new items tail: Atomic, - buffer: ManuallyDrop>>, + buffer: MaybeUninit>>, } impl RingBuffer @@ -334,7 +334,7 @@ macro_rules! impl_ { /// Creates an empty ring buffer with a fixed capacity of `N` pub const fn $uxx() -> Self { RingBuffer { - buffer: ManuallyDrop::new(unsafe { mem::uninitialized() }), + buffer: unsafe { MaybeUninit::uninitialized() }, head: Atomic::new(0), tail: Atomic::new(0), } @@ -348,7 +348,7 @@ macro_rules! impl_ { let head = self.head.get_mut(); let tail = self.tail.get_mut(); - let buffer = self.buffer.as_slice(); + let buffer = unsafe { self.buffer.get_ref() }; if *head != *tail { let item = unsafe { ptr::read(buffer.get_unchecked(usize::from(*head))) }; @@ -387,7 +387,7 @@ macro_rules! impl_ { let tail = self.tail.get_mut(); - let buffer = self.buffer.as_mut_slice(); + let buffer = unsafe { self.buffer.get_mut() }; let next_tail = (*tail + 1) % n; // NOTE(ptr::write) the memory slot that we are about to write to is @@ -473,7 +473,7 @@ macro_rules! iterator { let head = self.rb.head.load_relaxed().into(); let capacity = self.rb.capacity().into() + 1; - let buffer = self.rb.buffer.$asref(); + let buffer = unsafe { self.rb.buffer.$asref() }; let ptr: $ptr = buffer.$asptr(); let i = (head + self.index) % capacity; self.index += 1; @@ -498,8 +498,8 @@ macro_rules! make_ref_mut { }; } -iterator!(struct Iter -> &'a T, *const T, as_slice, as_ptr, make_ref); -iterator!(struct IterMut -> &'a mut T, *mut T, as_mut_slice, as_mut_ptr, make_ref_mut); +iterator!(struct Iter -> &'a T, *const T, get_ref, as_ptr, make_ref); +iterator!(struct IterMut -> &'a mut T, *mut T, get_mut, as_mut_ptr, make_ref_mut); #[cfg(test)] mod tests { diff --git a/src/ring_buffer/spsc.rs b/src/ring_buffer/spsc.rs index e3c299db9d..8f5236e568 100644 --- a/src/ring_buffer/spsc.rs +++ b/src/ring_buffer/spsc.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use core::ops::Add; use core::ptr::{self, NonNull}; -use generic_array::typenum::{Sum, U1, Unsigned}; +use generic_array::typenum::{Sum, Unsigned, U1}; use generic_array::ArrayLength; use ring_buffer::{RingBuffer, Uxx}; @@ -47,8 +47,7 @@ where Sum: ArrayLength, T: Send, U: Uxx, -{ -} +{} /// A ring buffer "producer"; it can enqueue items into the ring buffer // NOTE the producer semantically owns the `tail` pointer of the ring buffer @@ -69,8 +68,7 @@ where Sum: ArrayLength, T: Send, U: Uxx, -{ -} +{} macro_rules! impl_ { ($uxx:ident) => { @@ -114,7 +112,7 @@ macro_rules! impl_ { let rb = self.rb.as_ref(); let n = rb.capacity() + 1; - let buffer: &[T] = rb.buffer.as_ref(); + let buffer = rb.buffer.get_ref(); let item = ptr::read(buffer.get_unchecked(usize::from(head))); rb.head.store_release((head + 1) % n); @@ -183,7 +181,7 @@ macro_rules! impl_ { let rb = self.rb.as_mut(); let n = rb.capacity() + 1; - let buffer: &mut [T] = rb.buffer.as_mut(); + let buffer = rb.buffer.get_mut(); let next_tail = (tail + 1) % n; // NOTE(ptr::write) the memory slot that we are about to write to is diff --git a/src/vec.rs b/src/vec.rs index e7db938dd6..b067aeafe5 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -2,7 +2,7 @@ use core::{fmt, ops, ptr, slice}; use generic_array::{ArrayLength, GenericArray}; -use __core::mem::{self, ManuallyDrop}; +use __core::mem::MaybeUninit; use core::iter::FromIterator; @@ -39,7 +39,7 @@ pub struct Vec where N: ArrayLength, { - buffer: ManuallyDrop>, + buffer: MaybeUninit>, len: usize, } @@ -52,7 +52,7 @@ where /// Constructs a new, empty vector with a fixed capacity of `N` pub const fn new() -> Self { Vec { - buffer: ManuallyDrop::new(unsafe { mem::uninitialized() }), + buffer: unsafe { MaybeUninit::uninitialized() }, len: 0, } } @@ -112,7 +112,7 @@ where pub(crate) unsafe fn pop_unchecked(&mut self) -> T { debug_assert!(!self.is_empty()); - let buffer = self.buffer.as_slice(); + let buffer = self.buffer.get_ref(); self.len -= 1; let item = ptr::read(buffer.get_unchecked(self.len)); @@ -132,7 +132,7 @@ where } pub(crate) unsafe fn push_unchecked(&mut self, item: T) { - let buffer = self.buffer.as_mut_slice(); + let buffer = self.buffer.get_mut(); // NOTE(ptr::write) the memory slot that we are about to write to is uninitialized. We // use `ptr::write` to avoid running `T`'s destructor on the uninitialized memory @@ -314,7 +314,6 @@ where } } - impl FromIterator for Vec where N: ArrayLength, @@ -345,15 +344,15 @@ where next: usize, } -impl Iterator for IntoIter +impl Iterator for IntoIter where N: ArrayLength, { type Item = T; fn next(&mut self) -> Option { if self.next < self.vec.len() { - let buffer = self.vec.buffer.as_slice(); - let item = unsafe {ptr::read(buffer.get_unchecked(self.next))}; + let buffer = unsafe { self.vec.buffer.get_ref() }; + let item = unsafe { ptr::read(buffer.get_unchecked(self.next)) }; self.next += 1; Some(item) } else { @@ -362,7 +361,7 @@ where } } -impl Drop for IntoIter +impl Drop for IntoIter where N: ArrayLength, { @@ -376,7 +375,7 @@ where } } -impl IntoIterator for Vec +impl IntoIterator for Vec where N: ArrayLength, { @@ -384,10 +383,7 @@ where type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { - IntoIter { - vec: self, - next: 0, - } + IntoIter { vec: self, next: 0 } } } @@ -448,7 +444,7 @@ where type Target = [T]; fn deref(&self) -> &[T] { - let buffer = self.buffer.as_slice(); + let buffer = unsafe { self.buffer.get_ref() }; // NOTE(unsafe) avoid bound checks in the slicing operation // &buffer[..self.len] unsafe { slice::from_raw_parts(buffer.as_ptr(), self.len) } @@ -461,7 +457,7 @@ where { fn deref_mut(&mut self) -> &mut [T] { let len = self.len(); - let buffer = self.buffer.as_mut_slice(); + let buffer = unsafe { self.buffer.get_mut() }; // NOTE(unsafe) avoid bound checks in the slicing operation // &mut buffer[..len] @@ -521,7 +517,7 @@ mod tests { } macro_rules! droppable { - () => ( + () => { struct Droppable; impl Droppable { fn new() -> Self { @@ -540,12 +536,11 @@ mod tests { } static mut COUNT: i32 = 0; - ) + }; } #[test] fn drop() { - droppable!(); { @@ -660,7 +655,6 @@ mod tests { #[test] fn iter_move_drop() { - droppable!(); {