Skip to content

Commit

Permalink
Create HeapRb directly from Vec and Box<[]>
Browse files Browse the repository at this point in the history
  • Loading branch information
agerasev committed Jan 22, 2024
1 parent 2345b39 commit 568b20b
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 8 deletions.
23 changes: 17 additions & 6 deletions src/rb/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,23 @@ macro_rules! rb_impl_init {
pub fn try_new(capacity: usize) -> Result<Self, alloc::collections::TryReserveError> {
let mut vec = alloc::vec::Vec::new();
vec.try_reserve_exact(capacity)?;
let ptr = vec.as_mut_ptr();
core::mem::forget(vec);
let data = unsafe { Box::from_raw(core::ptr::slice_from_raw_parts_mut(ptr, capacity)) };
assert_eq!(data.len(), capacity);
assert_eq!(ptr as *const _, data.as_ptr());
Ok(unsafe { Self::from_raw_parts(data.into(), usize::default(), usize::default()) })
Ok(unsafe { Self::from_raw_parts(vec.into(), usize::default(), usize::default()) })
}
}

#[cfg(feature = "alloc")]
impl<T> From<alloc::vec::Vec<T>> for $type<crate::storage::Heap<T>> {
fn from(value: alloc::vec::Vec<T>) -> Self {
let (read, write) = (0, value.len());
unsafe { Self::from_raw_parts(crate::utils::vec_to_uninit(value).into(), read, write) }
}
}

#[cfg(feature = "alloc")]
impl<T> From<alloc::boxed::Box<[T]>> for $type<crate::storage::Heap<T>> {
fn from(value: alloc::boxed::Box<[T]>) -> Self {
let (read, write) = (0, value.len());
unsafe { Self::from_raw_parts(crate::utils::boxed_slice_to_uninit(value).into(), read, write) }
}
}
};
Expand Down
13 changes: 11 additions & 2 deletions src/storage.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#[cfg(feature = "alloc")]
use alloc::{boxed::Box, vec::Vec};
#[cfg(feature = "alloc")]
use core::ptr;
use core::{cell::UnsafeCell, marker::PhantomData, mem::MaybeUninit, ops::Range, ptr::NonNull, slice};
#[cfg(feature = "alloc")]
use core::{mem::forget, ptr};

/// Abstract storage for the ring buffer.
///
Expand Down Expand Up @@ -161,6 +161,15 @@ impl<T> Heap<T> {
}
}
#[cfg(feature = "alloc")]
impl<T> From<Vec<MaybeUninit<T>>> for Heap<T> {
fn from(mut value: Vec<MaybeUninit<T>>) -> Self {
let len = value.capacity();
let ptr = value.as_mut_ptr();
forget(value);
Self { ptr, len }
}
}
#[cfg(feature = "alloc")]
impl<T> From<Box<[MaybeUninit<T>]>> for Heap<T> {
fn from(value: Box<[MaybeUninit<T>]>) -> Self {
Self {
Expand Down
54 changes: 54 additions & 0 deletions src/tests/init.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use super::Rb;
use crate::{storage::Heap, traits::*};
use alloc::{boxed::Box, vec::Vec};

#[test]
fn new() {
const CAP: usize = 2;
let rb = Rb::<Heap<i32>>::new(CAP);
let (mut prod, mut cons) = rb.split();

assert_eq!(prod.capacity().get(), CAP);

assert_eq!(prod.try_push(0), Ok(()));
assert_eq!(prod.try_push(1), Ok(()));
assert_eq!(prod.try_push(2), Err(2));

assert_eq!(cons.try_pop(), Some(0));
assert_eq!(cons.try_pop(), Some(1));
assert_eq!(cons.try_pop(), None);
}

#[test]
fn from_vec() {
let mut vec = Vec::with_capacity(2);
vec.push(123);
let rb = Rb::<Heap<i32>>::from(vec);
let (mut prod, mut cons) = rb.split();

assert_eq!(prod.capacity().get(), 2);
assert_eq!(cons.occupied_len(), 1);

assert_eq!(prod.try_push(321), Ok(()));
assert_eq!(prod.try_push(444), Err(444));

assert_eq!(cons.try_pop(), Some(123));
assert_eq!(cons.try_pop(), Some(321));
assert_eq!(cons.try_pop(), None);
}

#[test]
fn from_boxed_slice() {
let boxed_slice = Box::new([123, 321]) as Box<[i32]>;
let rb = Rb::<Heap<i32>>::from(boxed_slice);
let (mut prod, mut cons) = rb.split();

assert_eq!(prod.capacity().get(), 2);
assert_eq!(cons.occupied_len(), 2);

assert_eq!(prod.try_push(444), Err(444));

assert_eq!(cons.try_pop(), Some(123));
assert_eq!(cons.try_pop(), Some(321));
assert_eq!(cons.try_pop(), None);
}
2 changes: 2 additions & 0 deletions src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ mod drop;
mod fmt_write;
mod frozen;
mod hold;
#[cfg(feature = "alloc")]
mod init;
mod iter;
mod overwrite;
#[cfg(feature = "std")]
Expand Down
16 changes: 16 additions & 0 deletions src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#[cfg(feature = "alloc")]
use alloc::{boxed::Box, vec::Vec};
use core::mem::{self, MaybeUninit};

// TODO: Remove on `maybe_uninit_uninit_array` stabilization.
Expand Down Expand Up @@ -26,3 +28,17 @@ pub unsafe fn write_uninit_slice<'a, T: Copy>(dst: &'a mut [T], src: &[MaybeUnin
dst.copy_from_slice(slice_assume_init_ref(src));
dst
}

#[cfg(feature = "alloc")]
pub fn vec_to_uninit<T>(value: Vec<T>) -> Vec<MaybeUninit<T>> {
let value = mem::ManuallyDrop::new(value);
let ptr = &value as *const _ as *const Vec<MaybeUninit<T>>;
unsafe { ptr.read() }
}

#[cfg(feature = "alloc")]
pub fn boxed_slice_to_uninit<T>(value: Box<[T]>) -> Box<[MaybeUninit<T>]> {
let value = mem::ManuallyDrop::new(value);
let ptr = &value as *const _ as *const Box<[MaybeUninit<T>]>;
unsafe { ptr.read() }
}

0 comments on commit 568b20b

Please sign in to comment.