55: internally use MaybeUninit r=japaric a=japaric

which has been proposed in rust-lang/rfcs#1892

Co-authored-by: Jorge Aparicio <jorge@japaric.io>
This commit is contained in:
bors[bot] 2018-08-19 09:22:56 +00:00
commit 9037d97263
4 changed files with 69 additions and 72 deletions

View File

@ -2,46 +2,51 @@
pub mod mem { pub mod mem {
#[cfg(not(feature = "const-fn"))] #[cfg(not(feature = "const-fn"))]
pub use core::mem::uninitialized; pub use core::mem;
pub use core::mem::{replace, zeroed, ManuallyDrop}; pub use core::mem::{replace, zeroed, ManuallyDrop};
// See RFC 1892
#[cfg(feature = "const-fn")] #[cfg(feature = "const-fn")]
pub const unsafe fn uninitialized<T>() -> T { pub union MaybeUninit<T> {
#[allow(unions_with_drop_fields)] uninit: (),
union U<T> { value: ManuallyDrop<T>,
none: (), }
some: T,
// workaround to get this to compile on stable ("unions with non-`Copy` fields are unstable")
#[cfg(not(feature = "const-fn"))]
pub struct MaybeUninit<T> {
value: ManuallyDrop<T>
}
impl<T> MaybeUninit<T> {
#[cfg(feature = "const-fn")]
pub const unsafe fn uninitialized() -> Self {
MaybeUninit { uninit: () }
} }
U { none: () }.some #[cfg(not(feature = "const-fn"))]
} pub unsafe fn uninitialized() -> Self {
} mem::uninitialized()
#[cfg(feature = "const-fn")] // Remove this if there are more tests
#[cfg(test)]
mod test {
use __core;
use __core::mem::ManuallyDrop;
use core;
#[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(feature = "const-fn")]
#[test]
fn static_new_manually_drop() {
static mut M: ManuallyDrop<i32> = ManuallyDrop::new(42);
unsafe {
assert_eq!(*M, 42);
} }
// Drop before deinitialization
unsafe { core::ptr::drop_in_place(&mut M as &mut i32 as *mut i32) };
}
/// 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
}
/// 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
}
}
} }

View File

@ -8,11 +8,11 @@ use core::ptr;
#[cfg(not(feature = "smaller-atomics"))] #[cfg(not(feature = "smaller-atomics"))]
use core::sync::atomic::{AtomicUsize, Ordering}; 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}; use generic_array::{ArrayLength, GenericArray};
pub use self::spsc::{Consumer, Producer}; pub use self::spsc::{Consumer, Producer};
use __core::mem::{self, ManuallyDrop}; use __core::mem::MaybeUninit;
mod spsc; mod spsc;
@ -230,7 +230,7 @@ where
// this is where we enqueue new items // this is where we enqueue new items
tail: Atomic<U>, tail: Atomic<U>,
buffer: ManuallyDrop<GenericArray<T, Sum<N, U1>>>, buffer: MaybeUninit<GenericArray<T, Sum<N, U1>>>,
} }
impl<T, N, U> RingBuffer<T, N, U> impl<T, N, U> RingBuffer<T, N, U>
@ -334,7 +334,7 @@ macro_rules! impl_ {
/// Creates an empty ring buffer with a fixed capacity of `N` /// Creates an empty ring buffer with a fixed capacity of `N`
pub const fn $uxx() -> Self { pub const fn $uxx() -> Self {
RingBuffer { RingBuffer {
buffer: ManuallyDrop::new(unsafe { mem::uninitialized() }), buffer: unsafe { MaybeUninit::uninitialized() },
head: Atomic::new(0), head: Atomic::new(0),
tail: Atomic::new(0), tail: Atomic::new(0),
} }
@ -348,7 +348,7 @@ macro_rules! impl_ {
let head = self.head.get_mut(); let head = self.head.get_mut();
let tail = self.tail.get_mut(); let tail = self.tail.get_mut();
let buffer = self.buffer.as_slice(); let buffer = unsafe { self.buffer.get_ref() };
if *head != *tail { if *head != *tail {
let item = unsafe { ptr::read(buffer.get_unchecked(usize::from(*head))) }; 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 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; let next_tail = (*tail + 1) % n;
// NOTE(ptr::write) the memory slot that we are about to write to is // 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 head = self.rb.head.load_relaxed().into();
let capacity = self.rb.capacity().into() + 1; 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 ptr: $ptr = buffer.$asptr();
let i = (head + self.index) % capacity; let i = (head + self.index) % capacity;
self.index += 1; 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 Iter -> &'a T, *const T, get_ref, as_ptr, make_ref);
iterator!(struct IterMut -> &'a mut T, *mut T, as_mut_slice, as_mut_ptr, make_ref_mut); iterator!(struct IterMut -> &'a mut T, *mut T, get_mut, as_mut_ptr, make_ref_mut);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -2,7 +2,7 @@ use core::marker::PhantomData;
use core::ops::Add; use core::ops::Add;
use core::ptr::{self, NonNull}; use core::ptr::{self, NonNull};
use generic_array::typenum::{Sum, U1, Unsigned}; use generic_array::typenum::{Sum, Unsigned, U1};
use generic_array::ArrayLength; use generic_array::ArrayLength;
use ring_buffer::{RingBuffer, Uxx}; use ring_buffer::{RingBuffer, Uxx};
@ -47,8 +47,7 @@ where
Sum<N, U1>: ArrayLength<T>, Sum<N, U1>: ArrayLength<T>,
T: Send, T: Send,
U: Uxx, U: Uxx,
{ {}
}
/// A ring buffer "producer"; it can enqueue items into the ring buffer /// A ring buffer "producer"; it can enqueue items into the ring buffer
// NOTE the producer semantically owns the `tail` pointer of the ring buffer // NOTE the producer semantically owns the `tail` pointer of the ring buffer
@ -69,8 +68,7 @@ where
Sum<N, U1>: ArrayLength<T>, Sum<N, U1>: ArrayLength<T>,
T: Send, T: Send,
U: Uxx, U: Uxx,
{ {}
}
macro_rules! impl_ { macro_rules! impl_ {
($uxx:ident) => { ($uxx:ident) => {
@ -114,7 +112,7 @@ macro_rules! impl_ {
let rb = self.rb.as_ref(); let rb = self.rb.as_ref();
let n = rb.capacity() + 1; 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))); let item = ptr::read(buffer.get_unchecked(usize::from(head)));
rb.head.store_release((head + 1) % n); rb.head.store_release((head + 1) % n);
@ -183,7 +181,7 @@ macro_rules! impl_ {
let rb = self.rb.as_mut(); let rb = self.rb.as_mut();
let n = rb.capacity() + 1; 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; let next_tail = (tail + 1) % n;
// NOTE(ptr::write) the memory slot that we are about to write to is // NOTE(ptr::write) the memory slot that we are about to write to is

View File

@ -2,7 +2,7 @@ use core::{fmt, ops, ptr, slice};
use generic_array::{ArrayLength, GenericArray}; use generic_array::{ArrayLength, GenericArray};
use __core::mem::{self, ManuallyDrop}; use __core::mem::MaybeUninit;
use core::iter::FromIterator; use core::iter::FromIterator;
@ -39,7 +39,7 @@ pub struct Vec<T, N>
where where
N: ArrayLength<T>, N: ArrayLength<T>,
{ {
buffer: ManuallyDrop<GenericArray<T, N>>, buffer: MaybeUninit<GenericArray<T, N>>,
len: usize, len: usize,
} }
@ -52,7 +52,7 @@ where
/// Constructs a new, empty vector with a fixed capacity of `N` /// Constructs a new, empty vector with a fixed capacity of `N`
pub const fn new() -> Self { pub const fn new() -> Self {
Vec { Vec {
buffer: ManuallyDrop::new(unsafe { mem::uninitialized() }), buffer: unsafe { MaybeUninit::uninitialized() },
len: 0, len: 0,
} }
} }
@ -112,7 +112,7 @@ where
pub(crate) unsafe fn pop_unchecked(&mut self) -> T { pub(crate) unsafe fn pop_unchecked(&mut self) -> T {
debug_assert!(!self.is_empty()); debug_assert!(!self.is_empty());
let buffer = self.buffer.as_slice(); let buffer = self.buffer.get_ref();
self.len -= 1; self.len -= 1;
let item = ptr::read(buffer.get_unchecked(self.len)); let item = ptr::read(buffer.get_unchecked(self.len));
@ -132,7 +132,7 @@ where
} }
pub(crate) unsafe fn push_unchecked(&mut self, item: T) { 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 // 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 // use `ptr::write` to avoid running `T`'s destructor on the uninitialized memory
@ -314,7 +314,6 @@ where
} }
} }
impl<T, N> FromIterator<T> for Vec<T, N> impl<T, N> FromIterator<T> for Vec<T, N>
where where
N: ArrayLength<T>, N: ArrayLength<T>,
@ -345,15 +344,15 @@ where
next: usize, next: usize,
} }
impl <T, N> Iterator for IntoIter<T, N> impl<T, N> Iterator for IntoIter<T, N>
where where
N: ArrayLength<T>, N: ArrayLength<T>,
{ {
type Item = T; type Item = T;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.next < self.vec.len() { if self.next < self.vec.len() {
let buffer = self.vec.buffer.as_slice(); let buffer = unsafe { self.vec.buffer.get_ref() };
let item = unsafe {ptr::read(buffer.get_unchecked(self.next))}; let item = unsafe { ptr::read(buffer.get_unchecked(self.next)) };
self.next += 1; self.next += 1;
Some(item) Some(item)
} else { } else {
@ -362,7 +361,7 @@ where
} }
} }
impl <T, N> Drop for IntoIter<T, N> impl<T, N> Drop for IntoIter<T, N>
where where
N: ArrayLength<T>, N: ArrayLength<T>,
{ {
@ -376,7 +375,7 @@ where
} }
} }
impl <T, N> IntoIterator for Vec<T, N> impl<T, N> IntoIterator for Vec<T, N>
where where
N: ArrayLength<T>, N: ArrayLength<T>,
{ {
@ -384,10 +383,7 @@ where
type IntoIter = IntoIter<T, N>; type IntoIter = IntoIter<T, N>;
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
IntoIter { IntoIter { vec: self, next: 0 }
vec: self,
next: 0,
}
} }
} }
@ -448,7 +444,7 @@ where
type Target = [T]; type Target = [T];
fn deref(&self) -> &[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 // NOTE(unsafe) avoid bound checks in the slicing operation
// &buffer[..self.len] // &buffer[..self.len]
unsafe { slice::from_raw_parts(buffer.as_ptr(), self.len) } unsafe { slice::from_raw_parts(buffer.as_ptr(), self.len) }
@ -461,7 +457,7 @@ where
{ {
fn deref_mut(&mut self) -> &mut [T] { fn deref_mut(&mut self) -> &mut [T] {
let len = self.len(); 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 // NOTE(unsafe) avoid bound checks in the slicing operation
// &mut buffer[..len] // &mut buffer[..len]
@ -521,7 +517,7 @@ mod tests {
} }
macro_rules! droppable { macro_rules! droppable {
() => ( () => {
struct Droppable; struct Droppable;
impl Droppable { impl Droppable {
fn new() -> Self { fn new() -> Self {
@ -540,12 +536,11 @@ mod tests {
} }
static mut COUNT: i32 = 0; static mut COUNT: i32 = 0;
) };
} }
#[test] #[test]
fn drop() { fn drop() {
droppable!(); droppable!();
{ {
@ -660,7 +655,6 @@ mod tests {
#[test] #[test]
fn iter_move_drop() { fn iter_move_drop() {
droppable!(); droppable!();
{ {