diff --git a/Cargo.toml b/Cargo.toml index 2c35825..51a66ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grounded" -version = "0.1.0" +version = "0.1.1" authors = ["James Munns "] edition = "2021" readme = "README.md" diff --git a/src/uninit.rs b/src/uninit.rs index 5381ba7..9482b13 100644 --- a/src/uninit.rs +++ b/src/uninit.rs @@ -100,6 +100,64 @@ impl GroundedArrayCell { } } + /// 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 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 = 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_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 @@ -115,10 +173,108 @@ impl GroundedArrayCell { /// 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_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) } }