mirror of
https://github.com/rust-embedded/heapless.git
synced 2025-10-01 14:30:33 +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 {
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
36
src/vec.rs
36
src/vec.rs
@ -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!();
|
||||||
|
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user