Skip to content

Commit

Permalink
Add more methods
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesmunns committed Nov 28, 2023
1 parent b7d63e3 commit 18ee87d
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 5 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "grounded"
version = "0.1.0"
version = "0.1.1"
authors = ["James Munns <[email protected]>"]
edition = "2021"
readme = "README.md"
Expand Down
164 changes: 160 additions & 4 deletions src/uninit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,64 @@ impl<T, const N: usize> GroundedArrayCell<T, N> {
}
}

/// Initialize each element from the provided value, if `T: Copy`.
///
/// ## Safety
///
/// The caller must ensure that no other access is made to the data contained within this
/// cell for the duration of this function
#[inline]
pub unsafe fn initialize_all_copied(&'static self, val: T)
where
T: Copy,
{
let (mut ptr, len) = self.get_ptr_len();
let end = ptr.add(len);
while ptr != end {
ptr.write(val);
ptr = ptr.add(1);
}
}

/// Initialize each item, using a provided closure on a per-element basis
///
/// ## Safety
///
/// The caller must ensure that no other access is made to the data contained within this
/// cell for the duration of this function
#[inline]
pub unsafe fn initialize_all_with<F: FnMut() -> T>(&'static self, mut f: F)
{
let (mut ptr, len) = self.get_ptr_len();
let end = ptr.add(len);
while ptr != end {
ptr.write(f());
ptr = ptr.add(1);
}
}

/// Obtain a mutable starting pointer to the contained [T; N].
///
/// No claims are made on the validity of the [T; N] (they may be partially or wholly
/// invalid or uninitialized), and the caller is required to guarantee synchronization of
/// access, e.g. guaranteeing that access is shared XOR mutable for the duration of any
/// references (including slices) created from this pointer.
///
/// ```rust
/// use grounded::uninit::GroundedArrayCell;
/// static EXAMPLE: GroundedArrayCell<u8, 128> = GroundedArrayCell::uninit();
///
/// let ptr: *mut u8 = EXAMPLE.as_mut_ptr();
/// assert_ne!(core::ptr::null_mut(), ptr);
/// ```
#[inline]
pub fn as_mut_ptr(&'static self) -> *mut T {
let mu_ptr: *mut MaybeUninit<[T; N]> = self.inner.get();
let arr_ptr: *mut [T; N] = mu_ptr.cast::<[T; N]>();
let t_ptr: *mut T = arr_ptr.cast::<T>();
t_ptr
}

/// Obtain a mutable starting pointer and length to the contained [T; N].
///
/// No claims are made on the validity of the [T; N] (they may be partially or wholly
Expand All @@ -115,10 +173,108 @@ impl<T, const N: usize> GroundedArrayCell<T, N> {
/// assert_ne!(core::ptr::null_mut(), ptr);
/// assert_eq!(len, 128);
/// ```
///
/// ## NOTE
///
/// This method is suggested to only be used for actions such as initializing the entire
/// range. If you are building a data structure that provides partial access safely, such
/// as a channel, bip-buffer, or similar, consider using one of the following methods, which
/// can help avoid cases where strict provenance is invalidated by creation of an aliasing
/// slice:
///
/// * For getting a single element:
/// * [Self::get_element_unchecked()]
/// * [Self::get_element_mut_unchecked()]
/// * For getting a subslice:
/// * [Self::get_subslice_unchecked()]
/// * [Self::get_subslice_mut_unchecked()]
#[inline]
pub fn get_ptr_len(&'static self) -> (*mut T, usize) {
let mu_ptr: *mut MaybeUninit<[T; N]> = self.inner.get();
let arr_ptr: *mut [T; N] = mu_ptr.cast::<[T; N]>();
let t_ptr: *mut T = arr_ptr.cast::<T>();
(t_ptr, N)
(self.as_mut_ptr(), N)
}

/// Obtain a reference to a single element, which can be thought of as `&data[offset]`.
///
/// The reference is created **without** creating the entire slice this cell represents.
/// This is important, if a mutable reference of a disjoint region is currently live.
///
/// ## Safety
///
/// The caller **must** ensure all of the following:
///
/// * The selected element has been initialized with a valid value prior to calling
/// this function
/// * No `&mut` slices or references may overlap the produced reference for the duration the reference is live
/// * No modifications (even via pointers) are made to to the element pointed to
/// while the reference is live
/// * `offset` is < N
#[inline]
pub unsafe fn get_element_unchecked(&'static self, offset: usize) -> &'static T {
&*self.as_mut_ptr().add(offset)
}

/// Obtain a mutable reference to a single element, which can be thought of as `&mut data[offset]`.
///
/// The reference is created **without** creating the entire slice this cell represents.
/// This is important, if a mutable reference of a disjoint region is currently live.
///
/// ## Safety
///
/// The caller **must** ensure all of the following:
///
/// * The selected element has been initialized with a valid value prior to calling
/// this function
/// * No slices or references of any kind may overlap the produced reference for the duration
/// the reference is live
/// * No modifications (even via pointers) are made to to the element pointed to
/// while the reference is live
/// * `offset` is < N
#[allow(clippy::mut_from_ref)]
#[inline]
pub unsafe fn get_element_mut_unchecked(&'static self, offset: usize) -> &'static mut T {
&mut *self.as_mut_ptr().add(offset)
}

/// Obtain a subslice starting at `offset`, of length `len`, which
/// can be thought of as `&data[offset..][..len]`.
///
/// The subslice is created **without** creating the entire slice this cell represents.
/// This is important, if a mutable reference of a disjoint region is currently live.
///
/// ## Safety
///
/// The caller **must** ensure all of the following:
///
/// * All elements in this region have been initialized with a valid value prior to calling
/// this function
/// * No `&mut` slices may overlap the produced slice for the duration the slice is live
/// * No modifications (even via pointers) are made to data within the range of this slice
/// while the slice is live
/// * `offset` and `offset + len` are <= N
#[inline]
pub unsafe fn get_subslice_unchecked(&'static self, offset: usize, len: usize) -> &'static [T] {
core::slice::from_raw_parts(self.as_mut_ptr().add(offset), len)
}

/// Obtain a mutable subslice starting at `offset`, of length `len`, which
/// can be thought of as `&mut data[offset..][..len]`.
///
/// The subslice is created **without** creating the entire slice this cell represents.
/// This is important, if ANY reference of a disjoint region is currently live.
///
/// ## Safety
///
/// The caller **must** ensure all of the following:
///
/// * All elements in this region have been initialized with a valid value prior to calling
/// this function
/// * No ``&` or &mut` slices may overlap the produced slice for the duration the slice is live
/// * No modifications (even via pointers) are made to data within the range of this slice
/// while the slice is live
/// * `offset` and `offset + len` are <= N
#[allow(clippy::mut_from_ref)]
#[inline]
pub unsafe fn get_subslice_mut_unchecked(&'static self, offset: usize, len: usize) -> &'static mut [T] {
core::slice::from_raw_parts_mut(self.as_mut_ptr().add(offset), len)
}
}

0 comments on commit 18ee87d

Please sign in to comment.