Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

internally use MaybeUninit #55

Merged
merged 1 commit into from
Aug 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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