mirror of
https://github.com/rust-embedded/heapless.git
synced 2025-09-28 04:50:34 +00:00
Merge #55
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:
commit
9037d97263
@ -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>,
|
||||
}
|
||||
|
||||
// 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(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);
|
||||
#[cfg(not(feature = "const-fn"))]
|
||||
pub unsafe fn uninitialized() -> Self {
|
||||
mem::uninitialized()
|
||||
}
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<U>,
|
||||
|
||||
buffer: ManuallyDrop<GenericArray<T, Sum<N, U1>>>,
|
||||
buffer: MaybeUninit<GenericArray<T, Sum<N, U1>>>,
|
||||
}
|
||||
|
||||
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`
|
||||
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 {
|
||||
|
@ -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<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
|
||||
@ -69,8 +68,7 @@ where
|
||||
Sum<N, U1>: ArrayLength<T>,
|
||||
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
|
||||
|
36
src/vec.rs
36
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<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
buffer: ManuallyDrop<GenericArray<T, N>>,
|
||||
buffer: MaybeUninit<GenericArray<T, N>>,
|
||||
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<T, N> FromIterator<T> for Vec<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
@ -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 {
|
||||
@ -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>,
|
||||
{
|
||||
@ -376,7 +375,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl <T, N> IntoIterator for Vec<T, N>
|
||||
impl<T, N> IntoIterator for Vec<T, N>
|
||||
where
|
||||
N: ArrayLength<T>,
|
||||
{
|
||||
@ -384,10 +383,7 @@ where
|
||||
type IntoIter = IntoIter<T, N>;
|
||||
|
||||
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!();
|
||||
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user