Skip to content

Commit

Permalink
internally use MaybeUninit
Browse files Browse the repository at this point in the history
which has been proposed in rust-lang/rfcs#1892
  • Loading branch information
japaric authored and XOSplicer committed Aug 22, 2018
1 parent d695f3c commit b3e30ea
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 69 deletions.
69 changes: 37 additions & 32 deletions src/__core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>() -> T {
#[allow(unions_with_drop_fields)]
union U<T> {
none: (),
some: T,
}
pub union MaybeUninit<T> {
uninit: (),
value: ManuallyDrop<T>,
}

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<T> {
value: ManuallyDrop<T>
}
}

#[cfg(feature = "const-fn")] // Remove this if there are more tests
#[cfg(test)]
mod test {
use __core;
use __core::mem::ManuallyDrop;
use core;
impl<T> MaybeUninit<T> {
#[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<i32> = 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
}
}
}
18 changes: 9 additions & 9 deletions src/ring_buffer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -230,7 +230,7 @@ where
// this is where we enqueue new items
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>
Expand Down Expand Up @@ -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),
}
Expand All @@ -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))) };
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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 {
Expand Down
12 changes: 5 additions & 7 deletions src/ring_buffer/spsc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -47,8 +47,7 @@ where
Sum<N, U1>: ArrayLength<T>,
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
Expand All @@ -69,8 +68,7 @@ where
Sum<N, U1>: ArrayLength<T>,
T: Send,
U: Uxx,
{
}
{}

macro_rules! impl_ {
($uxx:ident) => {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
36 changes: 15 additions & 21 deletions src/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -39,7 +39,7 @@ pub struct Vec<T, N>
where
N: ArrayLength<T>,
{
buffer: ManuallyDrop<GenericArray<T, N>>,
buffer: MaybeUninit<GenericArray<T, N>>,
len: usize,
}

Expand All @@ -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,
}
}
Expand Down Expand Up @@ -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));
Expand All @@ -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
Expand Down Expand Up @@ -314,7 +314,6 @@ where
}
}


impl<T, N> FromIterator<T> for Vec<T, N>
where
N: ArrayLength<T>,
Expand Down Expand Up @@ -345,15 +344,15 @@ where
next: usize,
}

impl <T, N> Iterator for IntoIter<T, N>
impl<T, N> Iterator for IntoIter<T, N>
where
N: ArrayLength<T>,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
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 {
Expand All @@ -362,7 +361,7 @@ where
}
}

impl <T, N> Drop for IntoIter<T, N>
impl<T, N> Drop for IntoIter<T, N>
where
N: ArrayLength<T>,
{
Expand All @@ -376,18 +375,15 @@ where
}
}

impl <T, N> IntoIterator for Vec<T, N>
impl<T, N> IntoIterator for Vec<T, N>
where
N: ArrayLength<T>,
{
type Item = T;
type IntoIter = IntoIter<T, N>;

fn into_iter(self) -> Self::IntoIter {
IntoIter {
vec: self,
next: 0,
}
IntoIter { vec: self, next: 0 }
}
}

Expand Down Expand Up @@ -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) }
Expand All @@ -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]
Expand Down Expand Up @@ -521,7 +517,7 @@ mod tests {
}

macro_rules! droppable {
() => (
() => {
struct Droppable;
impl Droppable {
fn new() -> Self {
Expand All @@ -540,12 +536,11 @@ mod tests {
}

static mut COUNT: i32 = 0;
)
};
}

#[test]
fn drop() {

droppable!();

{
Expand Down Expand Up @@ -660,7 +655,6 @@ mod tests {

#[test]
fn iter_move_drop() {

droppable!();

{
Expand Down

0 comments on commit b3e30ea

Please sign in to comment.