Skip to content

Commit

Permalink
Add push_persisted and push_raw_persisted to `ContiguousMemorySto…
Browse files Browse the repository at this point in the history
…rage`.

Signed-off-by: Tin Svagelj <tin.svagelj@live.com>
  • Loading branch information
Caellian committed Sep 17, 2023
1 parent ed1fceb commit ec08513
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 4 deletions.
40 changes: 40 additions & 0 deletions src/details.rs
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,12 @@ pub trait StoreDataDetails: StorageDetails {
layout: Layout,
) -> Self::PushResult<T>;

unsafe fn push_raw_persisted<T: StoreRequirements>(
state: &mut Self::StorageState,
data: *const T,
layout: Layout,
) -> Self::PushResult<T>;

fn assume_stored<T: StoreRequirements>(
state: &Self::StorageState,
position: usize,
Expand Down Expand Up @@ -612,6 +618,21 @@ impl StoreDataDetails for ImplConcurrent {
Ok(ImplConcurrent::build_ref(state, addr as *mut T, range))
}

unsafe fn push_raw_persisted<T: StoreRequirements>(
state: &mut Self::StorageState,
data: *const T,
layout: Layout,
) -> Self::PushResult<T> {
match Self::push_raw(state, data, layout) {
Ok(it) => {
let result = it.clone();
core::mem::forget(it.inner);
Ok(result)
}
err => err,
}
}

fn assume_stored<T: StoreRequirements>(
state: &Self::StorageState,
position: usize,
Expand Down Expand Up @@ -670,6 +691,17 @@ impl StoreDataDetails for ImplDefault {
ImplDefault::build_ref(state, addr as *mut T, range)
}

unsafe fn push_raw_persisted<T: StoreRequirements>(
state: &mut Self::StorageState,
data: *const T,
layout: Layout,
) -> Self::PushResult<T> {
let value = Self::push_raw(state, data, layout);
let result = value.clone();
core::mem::forget(value.inner);
result
}

fn assume_stored<T: StoreRequirements>(
state: &Self::StorageState,
position: usize,
Expand Down Expand Up @@ -705,6 +737,14 @@ impl StoreDataDetails for ImplUnsafe {
Ok(ImplUnsafe::build_ref(state, addr as *mut T, range))
}

unsafe fn push_raw_persisted<T: StoreRequirements>(
state: &mut Self::StorageState,
data: *const T,
layout: Layout,
) -> Self::PushResult<T> {
Self::push_raw(state, data, layout)
}

fn assume_stored<T: StoreRequirements>(state: &Self::StorageState, position: usize) -> *mut T {
let addr =
unsafe { ImplUnsafe::get_base(&ImplUnsafe::deref_state(state).base).add(position) };
Expand Down
39 changes: 35 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ mod types;
use details::*;
pub use details::{ImplConcurrent, ImplDefault, ImplUnsafe};
use range::ByteRange;
use refs::sealed::EntryRef;
pub use refs::{CERef, ContiguousEntryRef, SCERef, SyncContiguousEntryRef};
use types::*;

Expand Down Expand Up @@ -176,7 +177,23 @@ impl<Impl: ImplDetails> ContiguousMemoryStorage<Impl> {
unsafe { self.push_raw(pos, layout) }
}

/// Works same as [`store`](ContiguousMemory::push) but takes a pointer and
/// Stores a `value` of type `T` in the contiguous memory block and returns
/// a reference to it which doesn't mark the memory segment as free when
/// dropped.
///
/// See [`ContiguousMemoryStorage::push`] for details.
pub fn push_persisted<T: StoreRequirements>(&mut self, value: T) -> Impl::PushResult<T>
where
Impl::ReferenceType<T>: EntryRef,
{
let mut data = ManuallyDrop::new(value);
let layout = Layout::for_value(&data);
let pos = &mut *data as *mut T;

unsafe { self.push_raw_persisted(pos, layout) }
}

/// Works same as [`push`](ContiguousMemory::push) but takes a pointer and
/// layout.
///
/// Pointer type is used to deduce the destruction behavior for
Expand Down Expand Up @@ -213,6 +230,20 @@ impl<Impl: ImplDetails> ContiguousMemoryStorage<Impl> {
Impl::push_raw(&mut self.inner, data, layout)
}

/// Variant of [`push_raw`](ContiguousMemory::push_raw) which returns a
/// reference that doesn't mark the used memory segment as free when
/// dropped.
pub unsafe fn push_raw_persisted<T: StoreRequirements>(
&mut self,
data: *const T,
layout: Layout,
) -> Impl::PushResult<T>
where
Impl::ReferenceType<T>: EntryRef,
{
Impl::push_raw_persisted(&mut self.inner, data, layout)
}

/// Assumes value is stored at the provided _relative_ `position` in
/// managed memory and returns a pointer or a reference to it.
///
Expand Down Expand Up @@ -762,10 +793,10 @@ mod test {

memory.resize(4).expect("can't shrink empty storage");
{
let _a = memory.push(1u16);
let _b = memory.push(2u16);
memory.push_persisted(1u16);
memory.push_persisted(2u16);
assert_eq!(memory.can_push::<u64>(), false);
let _c = memory.push(3u64);
memory.push_persisted(3u64);
// expecting 12, but due to alignment we're skipping two u16 slots
// and then double the size as remaining (aligned) 4 bytes aren't
// enough for u64
Expand Down
6 changes: 6 additions & 0 deletions src/refs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,8 @@ impl<T: ?Sized> SyncContiguousEntryRef<T> {
}
}

impl<T: ?Sized> EntryRef for SyncContiguousEntryRef<T> {}

impl<T: ?Sized> Clone for SyncContiguousEntryRef<T> {
fn clone(&self) -> Self {
SyncContiguousEntryRef {
Expand Down Expand Up @@ -495,6 +497,8 @@ impl<T: ?Sized> ContiguousEntryRef<T> {
}
}

impl<T: ?Sized> EntryRef for ContiguousEntryRef<T> {}

impl<T: ?Sized> Clone for ContiguousEntryRef<T> {
fn clone(&self) -> Self {
ContiguousEntryRef {
Expand All @@ -519,6 +523,8 @@ impl<T: ?Sized> core::fmt::Debug for ContiguousEntryRef<T> {
pub(crate) mod sealed {
use super::*;

pub trait EntryRef {}

/// Internal state of [`ContiguousEntryRef`] and [`SyncContiguousEntryRef`].
pub struct ReferenceState<T: ?Sized, Impl: ImplDetails> {
pub state: Impl::StorageState,
Expand Down

0 comments on commit ec08513

Please sign in to comment.