pub struct ContiguousMemoryStorage<Impl: ImplDetails = ImplDefault> { /* private fields */ }
Expand description

A memory container for efficient allocation and storage of contiguous data.

This collection manages a contiguous block of memory, allowing for storage of arbitrary data types while ensuring that stored items are placed adjacently and ensuring they’re properly alligned.

Type argument Impl specifies implementation details for the behavior of this struct. This struct also implements StoreData for all of the details which specifies underlying logic for storing items.

Note that this structure is a smart abstraction over underlying data, copying it creates a copy which represents the same internal state.

Implementations§

source§

impl<Impl: ImplDetails> ContiguousMemoryStorage<Impl>

source

pub fn new(capacity: usize) -> Self

Creates a new ContiguousMemory instance with the specified capacity, aligned as platform dependant alignment of usize.

Examples found in repository?
examples/default_impl.rs (line 10)
8
9
10
11
12
13
14
15
16
17
18
19
20
fn main() {
    // Create a ContiguousMemory instance with a capacity of 1024 bytes and 1-byte alignment
    let mut memory = ContiguousMemory::new(1024);

    // Store data in the memory container
    let data = Data { value: 42 };
    let stored_number: ContiguousMemoryRef<u64> = memory.store(22u64);
    let stored_data: ContiguousMemoryRef<Data> = memory.store(data);

    // Retrieve and use the stored data
    assert_eq!(*stored_data.get(), data);
    assert_eq!(*stored_number.get(), 22);
}
More examples
Hide additional examples
examples/unsafe_impl.rs (line 10)
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
fn main() {
    // Create a ContiguousMemory instance with a capacity of 1024 bytes and 1-byte alignment
    let mut memory = UnsafeContiguousMemory::new(1024);

    // Store data in the memory container
    let data = Data { value: 42 };

    let stored_number: *mut u64 = memory
        .store(22u64)
        .expect("there should be enough space to store a number");
    let stored_data: *mut Data = memory
        .store(data)
        .expect("there should be enough space to store Data");

    // Retrieve and use the stored data
    unsafe {
        assert_eq!(*stored_data, data);
        assert_eq!(*stored_number, 22);
    }
}
examples/sync_impl.rs (line 9)
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
fn main() {
    let storage = SyncContiguousMemory::new(4096);

    let mut sent_storage = storage.clone();
    let writer_one =
        std::thread::spawn(move || sent_storage.store(22u64).expect("unable to store number"));

    let data = Data { value: 42 };

    let mut sent_storage = storage.clone();
    let writer_two = std::thread::spawn(move || {
        sent_storage
            .store(Data { value: 42 })
            .expect("unable to store Data")
    });

    let stored_number: SyncContiguousMemoryRef<u64> =
        writer_one.join().expect("unable to join number thread");
    let mut stored_number_clone = stored_number.clone();
    let stored_data: SyncContiguousMemoryRef<Data> =
        writer_two.join().expect("unable to join Data thread");

    let number_ref = stored_number
        .get()
        .expect("number ref poisoned on first use");
    let stored_data = stored_data.get().expect("Data ref poisoned on first use");

    // note that number is still locked here
    assert!(
        stored_number_clone.try_get_mut().is_err(),
        "number reference should not be writable as the number is currently borrowed"
    );

    assert_eq!(*number_ref, 22);
    assert_eq!(*stored_data, data);
}
source

pub fn new_aligned( capacity: usize, alignment: usize ) -> Result<Self, LayoutError>

Creates a new ContiguousMemory instance with the specified capacity and alignment.

source

pub fn get_base(&self) -> Impl::LockResult<*mut u8>

Returns the base address (*mut u8) of the allocated memory.

Errors

For concurrent implementation this function can return LockingError::Poisoned if the mutex holding the base address has been poisoned.

source

pub fn get_capacity(&self) -> usize

Returns the current capacity of the memory container.

The capacity represents the size of the memory block that has been allocated for storing data. It may be larger than the amount of data currently stored within the container.

source

pub fn get_layout(&self) -> Layout

Returns the layout of the memory region containing stored data.

source

pub fn resize( &mut self, new_capacity: usize ) -> Result<Option<*mut u8>, ContiguousMemoryError>

Resizes the memory container to the specified new_capacity, optionally returning the new base address of the stored items.

Shrinking the container is generally performed in place by freeing tailing memory space, but growing it can move the data in memory to find a location that can fit it.

Unsafe implementation should match on the returned value and update any existing pointers accordingly.

Errors

This function can return the following errors:

source

pub fn shrink_to_fit(&mut self) -> Result<(), ContiguousMemoryError>

Shrinks the allocated memory to fit the currently stored data.

source

pub fn store<T: StoreRequirements>( &mut self, value: T ) -> <Impl as StorageDetails>::StoreResult<T>where Self: StoreData<Impl>,

Stores a value of type T in the contiguous memory block.

Value type is used to deduce type size and returned reference dropping behavior.

Returned value is implementation specific:

Examples found in repository?
examples/default_impl.rs (line 14)
8
9
10
11
12
13
14
15
16
17
18
19
20
fn main() {
    // Create a ContiguousMemory instance with a capacity of 1024 bytes and 1-byte alignment
    let mut memory = ContiguousMemory::new(1024);

    // Store data in the memory container
    let data = Data { value: 42 };
    let stored_number: ContiguousMemoryRef<u64> = memory.store(22u64);
    let stored_data: ContiguousMemoryRef<Data> = memory.store(data);

    // Retrieve and use the stored data
    assert_eq!(*stored_data.get(), data);
    assert_eq!(*stored_number.get(), 22);
}
More examples
Hide additional examples
examples/unsafe_impl.rs (line 16)
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
fn main() {
    // Create a ContiguousMemory instance with a capacity of 1024 bytes and 1-byte alignment
    let mut memory = UnsafeContiguousMemory::new(1024);

    // Store data in the memory container
    let data = Data { value: 42 };

    let stored_number: *mut u64 = memory
        .store(22u64)
        .expect("there should be enough space to store a number");
    let stored_data: *mut Data = memory
        .store(data)
        .expect("there should be enough space to store Data");

    // Retrieve and use the stored data
    unsafe {
        assert_eq!(*stored_data, data);
        assert_eq!(*stored_number, 22);
    }
}
examples/sync_impl.rs (line 13)
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
fn main() {
    let storage = SyncContiguousMemory::new(4096);

    let mut sent_storage = storage.clone();
    let writer_one =
        std::thread::spawn(move || sent_storage.store(22u64).expect("unable to store number"));

    let data = Data { value: 42 };

    let mut sent_storage = storage.clone();
    let writer_two = std::thread::spawn(move || {
        sent_storage
            .store(Data { value: 42 })
            .expect("unable to store Data")
    });

    let stored_number: SyncContiguousMemoryRef<u64> =
        writer_one.join().expect("unable to join number thread");
    let mut stored_number_clone = stored_number.clone();
    let stored_data: SyncContiguousMemoryRef<Data> =
        writer_two.join().expect("unable to join Data thread");

    let number_ref = stored_number
        .get()
        .expect("number ref poisoned on first use");
    let stored_data = stored_data.get().expect("Data ref poisoned on first use");

    // note that number is still locked here
    assert!(
        stored_number_clone.try_get_mut().is_err(),
        "number reference should not be writable as the number is currently borrowed"
    );

    assert_eq!(*number_ref, 22);
    assert_eq!(*stored_data, data);
}
source

pub fn can_store<T: StoreRequirements>( &self, value: &T ) -> Result<bool, ContiguousMemoryError>

Returns true if the provided value can be stored.

If the AllocationTracker can’t be immutably accesed, a ContiguousMemoryError::TrackerInUse error is returned.

For concurrent implementation a ContiguousMemoryError::Lock is returned under same conditions.

Unsafe implementation never fails.

source§

impl ContiguousMemoryStorage<ImplUnsafe>

source

pub unsafe fn free_typed<T>(&mut self, position: *mut T)

Allows freeing a memory range stored at provided position.

Type of the position pointer T determines the size of the freed chunk.

source

pub unsafe fn free<T>(&mut self, position: *mut T, size: usize)

Allows freeing a memory range stored at provided position with the specified size.

Trait Implementations§

source§

impl<Impl: ImplDetails> Clone for ContiguousMemoryStorage<Impl>

source§

fn clone(&self) -> Self

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<Impl: ImplDetails> Deref for ContiguousMemoryStorage<Impl>

§

type Target = ContiguousMemoryState<Impl>

The resulting type after dereferencing.
source§

fn deref(&self) -> &Self::Target

Dereferences the value.
source§

impl StoreData<ImplConcurrent> for ContiguousMemoryStorage<ImplConcurrent>

source§

unsafe fn store_data<T: StoreRequirements>( &mut self, data: *mut T, layout: Layout ) -> Result<SyncContiguousMemoryRef<T>, LockingError>

Returns a SyncContiguousMemoryRef pointing to the stored value, or a LockingError::Poisoned error when the AllocationTracker associated with the memory container is poisoned.

source§

impl StoreData<ImplDefault> for ContiguousMemoryStorage<ImplDefault>

source§

unsafe fn store_data<T: StoreRequirements>( &mut self, data: *mut T, layout: Layout ) -> ContiguousMemoryRef<T>

Returns a ContiguousMemoryRef pointing to the stored value.

source§

impl StoreData<ImplUnsafe> for ContiguousMemoryStorage<ImplUnsafe>

source§

unsafe fn store_data<T: StoreRequirements>( &mut self, data: *mut T, layout: Layout ) -> Result<*mut T, ContiguousMemoryError>

Returns a raw pointer (*mut T) to the stored value or a ContiguousMemoryError::NoStorageLeft indicating that the container couldn’t store the provided data with current size.

Memory block can still be grown by calling ContiguousMemory::resize, but it can’t be done automatically as that would invalidate all the existing pointers without any indication.

Auto Trait Implementations§

§

impl<Impl> RefUnwindSafe for ContiguousMemoryStorage<Impl>where <Impl as ImplBase>::StorageState: RefUnwindSafe,

§

impl<Impl> Send for ContiguousMemoryStorage<Impl>where <Impl as ImplBase>::StorageState: Send,

§

impl<Impl> Sync for ContiguousMemoryStorage<Impl>where <Impl as ImplBase>::StorageState: Sync,

§

impl<Impl> Unpin for ContiguousMemoryStorage<Impl>where <Impl as ImplBase>::StorageState: Unpin,

§

impl<Impl> UnwindSafe for ContiguousMemoryStorage<Impl>where <Impl as ImplBase>::StorageState: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToOwned for Twhere T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.