2021-06-14 19:34:49 +00:00
|
|
|
//! Structures for interpreting slices of variable length as arrays.
|
|
|
|
//!
|
|
|
|
//! `nslice` provides `MinSlice` and `ExactSlice` for representing slices known to have
|
|
|
|
//! either exactly or at least some compile-time-known number of values.
|
|
|
|
//! ```
|
|
|
|
//! use nslice::MinSlice;
|
|
|
|
//! let slice = &[1, 2, 3, 4, 5, 6];
|
|
|
|
//! let minslice: &MinSlice<_, 3> = MinSlice::from_slice(slice).unwrap();
|
|
|
|
//! assert_eq!(minslice.tail.len(), 3);
|
|
|
|
//! assert_eq!(minslice.head[0], 1);
|
|
|
|
//! assert_eq!(minslice.tail[2], 6);
|
|
|
|
//! ```
|
|
|
|
use std::slice;
|
|
|
|
|
|
|
|
/// A reference to a region of memory which is known to contain `N` or more elements
|
|
|
|
/// of type `T`.
|
|
|
|
///
|
|
|
|
/// Much like `[T]` itself, it is not possible to construct an owned `MinSlice`.
|
|
|
|
/// `MinSlice` is merely a way of reinterpreting an existing slice
|
|
|
|
/// (`&[T]` or `&mut [T]`), and it is exactly the same size as a slice:
|
|
|
|
/// one pointer and one `usize`.
|
2021-11-07 18:53:43 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use nslice::MinSlice;
|
|
|
|
/// let slice: &[u8] = b"Hello, world";
|
|
|
|
/// let minslice = MinSlice::<u8, 12>::from_slice(slice).unwrap();
|
|
|
|
/// let value: u8 = minslice.head[6];
|
|
|
|
/// assert_eq!(value, b' ')
|
|
|
|
/// ```
|
2021-06-14 19:34:49 +00:00
|
|
|
pub struct MinSlice<T, const N: usize> {
|
|
|
|
/// The bounded region of memory. Exactly `N` `T`s.
|
|
|
|
pub head: [T; N],
|
|
|
|
/// Zero or more remaining `T`s after the `N` in the bounded region.
|
|
|
|
pub tail: [T],
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A reference to a region of memory which contains exactly `N` elements of type `T`.
|
|
|
|
///
|
|
|
|
/// `ExactSlice` is merely a way of reinterpreting an existing slice
|
|
|
|
/// (`&[T]` or `&mut [T]`), but because there is no need to store a length
|
|
|
|
/// for retrieval at runtime, its representation consists of just one pointer.
|
|
|
|
|
|
|
|
pub struct ExactSlice<T, const N: usize> {
|
|
|
|
/// The bounded region of memory. Exactly `N` `T`s.
|
|
|
|
head: [T; N]
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T, const N: usize> MinSlice<T, N> {
|
|
|
|
/// Produce a `&MinSlice` from a slice of `T`s.
|
|
|
|
/// Returns `None` if there are not enough elements in `slice`.
|
|
|
|
pub fn from_slice(slice: &[T]) -> Option<&MinSlice<T, N>> {
|
|
|
|
if slice.len() >= N {
|
|
|
|
Some(unsafe { Self::from_slice_unchecked(slice) })
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
2021-11-07 18:53:43 +00:00
|
|
|
|
2021-06-14 19:34:49 +00:00
|
|
|
/// Produce a `&mut MinSlice` from a mutable slice of `T`s.
|
|
|
|
/// Returns `None` if there are not enough elements in `slice`.
|
|
|
|
pub fn from_mut(slice: &mut [T]) -> Option<&mut MinSlice<T, N>> {
|
|
|
|
if slice.len() >= N {
|
|
|
|
Some(unsafe { Self::from_mut_unchecked(slice) })
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
2021-11-07 18:53:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<T, const N: usize> MinSlice<T, N> {
|
|
|
|
/// Returns a slice over the memory referred to by the `MinSlice`.
|
|
|
|
/// Its length is guaranteed to be no less than `N`.
|
|
|
|
pub fn as_slice(&self) -> &[T] {
|
|
|
|
unsafe { slice::from_raw_parts(self.head.as_ptr(), N + self.tail.len()) }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a mutable slice over the memory referred to by the `MinSlice`.
|
|
|
|
/// Its length is guaranteed to be no less than `N`.
|
|
|
|
pub fn as_mut_slice(&mut self) -> &mut [T] {
|
|
|
|
unsafe { slice::from_raw_parts_mut(self.head.as_mut_ptr(), N + self.tail.len()) }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Resize the `MinSlice`, returning a new `Some(&MinSlice<T, M>)`
|
|
|
|
/// if there are at least `M` `T`s in `self`.
|
|
|
|
pub fn resize<const M: usize>(&self) -> Option<&MinSlice<T, M>> {
|
|
|
|
MinSlice::<T, M>::from_slice(self.as_slice())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Resize the `MinSlice`, returning a new `Some(&mut MinSlice<T, M>)`
|
|
|
|
/// if there are at least `M` `T`s in `self`.
|
|
|
|
pub fn resize_mut<const M: usize>(&mut self) -> Option<&mut MinSlice<T, M>> {
|
|
|
|
MinSlice::<T, M>::from_mut(self.as_mut_slice())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get a reference to a value from the `MinSlice` by index.
|
|
|
|
///
|
|
|
|
/// Return `Some(&T)` for the `T` at index `i` if `i < (N + self.tail.len)`,
|
|
|
|
/// or `None` otherwise.
|
|
|
|
pub fn get(&self, i: usize) -> Option<&T> {
|
|
|
|
if i < N {
|
|
|
|
Some(&self.head[i])
|
|
|
|
} else {
|
|
|
|
self.tail.get(i)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get a mutable reference to a value from the `MinSlice` by index.
|
|
|
|
///
|
|
|
|
/// Return `Some(&mut T)` for the `T` at index `i` if `i < (N + self.tail.len)`,
|
|
|
|
/// or `None` otherwise.
|
|
|
|
pub fn get_mut(&mut self, i: usize) -> Option<&mut T> {
|
|
|
|
if i < N {
|
|
|
|
Some(&mut self.head[i])
|
|
|
|
} else {
|
|
|
|
self.tail.get_mut(i)
|
|
|
|
}
|
|
|
|
}
|
2021-06-14 19:34:49 +00:00
|
|
|
|
|
|
|
/// Produce a `&MinSlice` from a slice of `T`s without checking its length.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// The caller is responsible for upholding the length invariant
|
|
|
|
/// `slice.len() >= N`, in addition to all normal slice invariants.
|
|
|
|
pub unsafe fn from_slice_unchecked(slice: &[T]) -> &MinSlice<T, N> {
|
|
|
|
let resized = slice::from_raw_parts(slice.as_ptr(), slice.len() - N);
|
|
|
|
&*(resized as *const [T] as *const MinSlice<T, N>)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Produce a `&mut MinSlice` from a slice of `T`s without checking its length.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// The caller is responsible for upholding the length invariant
|
|
|
|
/// `slice.len() >= N`, in addition to all normal slice invariants.
|
|
|
|
pub unsafe fn from_mut_unchecked(slice: &mut [T]) -> &mut MinSlice<T, N> {
|
|
|
|
let resized = slice::from_raw_parts_mut(slice.as_mut_ptr(), slice.len() - N);
|
|
|
|
&mut *(resized as *mut [T] as *mut MinSlice<T, N>)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T, const N: usize> ExactSlice<T, N> {
|
2021-09-10 20:39:21 +00:00
|
|
|
/// Produce a `&ExactSlice` from an array of `N` `T`s.
|
|
|
|
pub fn from_array(array: &[T; N]) -> &ExactSlice<T, N> {
|
|
|
|
unsafe { Self::from_slice_unchecked(&array[..]) }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Produce a `&mut ExactSlice` from an array of `N` `T`s.
|
|
|
|
pub fn from_mut_array(array: &mut [T; N]) -> &mut ExactSlice<T, N> {
|
|
|
|
unsafe { Self::from_mut_unchecked(&mut array[..]) }
|
|
|
|
}
|
|
|
|
|
2021-06-14 19:34:49 +00:00
|
|
|
/// Produce an `&ExactSlice` from a slice of `T`s.
|
|
|
|
/// Returns `None` if there are not the correct number of elements in `slice`.
|
|
|
|
pub fn from_slice(slice: &[T]) -> Option<&ExactSlice<T, N>> {
|
|
|
|
if slice.len() == N {
|
|
|
|
Some(unsafe { Self::from_slice_unchecked(slice) })
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Produce an `&mut ExactSlice` from a mutable slice of `T`s.
|
|
|
|
/// Returns `None` if there are not the correct number of elements in `slice`.
|
|
|
|
pub fn from_mut(slice: &mut [T]) -> Option<&mut ExactSlice<T, N>> {
|
|
|
|
if slice.len() == N {
|
|
|
|
Some(unsafe { Self::from_mut_unchecked(slice) })
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-07 18:53:43 +00:00
|
|
|
/// Returns a slice over the memory referred to by the `ExactSlice`.
|
|
|
|
/// Its length is guaranteed to be exactly `N`.
|
|
|
|
pub fn as_slice(&self) -> &[T] {
|
|
|
|
unsafe { slice::from_raw_parts(self.head.as_ptr(), N) }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a mutable slice over the memory referred to by the `ExactSlice`.
|
|
|
|
/// Its length is guaranteed to be exactly `N`.
|
|
|
|
pub fn as_mut_slice(&mut self) -> &mut [T] {
|
|
|
|
unsafe { slice::from_raw_parts_mut(self.head.as_mut_ptr(), N) }
|
|
|
|
}
|
|
|
|
|
2021-06-14 19:34:49 +00:00
|
|
|
/// Produce a `&MinSlice` from this `&ExactSlice`. Its `tail` will be empty.
|
2021-11-07 18:53:43 +00:00
|
|
|
pub fn as_min_slice(&self) -> &MinSlice<T, N> {
|
|
|
|
unsafe { MinSlice::from_slice_unchecked(&self.head[..]) }
|
2021-06-14 19:34:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Produce a `&mut MinSlice` from this `&min ExactSlice`. Its `tail` will be empty.
|
2021-11-07 18:53:43 +00:00
|
|
|
pub fn as_mut_min_slice(&mut self) -> &mut MinSlice<T, N> {
|
|
|
|
unsafe { MinSlice::from_mut_unchecked(&mut self.head[..]) }
|
2021-06-14 19:34:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Produce an `&ExactSlice` from a slice of `T`s without checking its length.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// The caller is responsible for upholding the length invariant
|
|
|
|
/// `slice.len() == N`, in addition to all normal slice invariants.
|
|
|
|
pub unsafe fn from_slice_unchecked(slice: &[T]) -> &ExactSlice<T, N> {
|
|
|
|
&*(slice.as_ptr() as *const ExactSlice<T, N>)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Produce an `&mut ExactSlice` from a slice of `T`s without checking its length.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// The caller is responsible for upholding the length invariant
|
|
|
|
/// `slice.len() == N`, in addition to all normal slice invariants.
|
|
|
|
pub unsafe fn from_mut_unchecked(slice: &mut [T]) -> &mut ExactSlice<T, N> {
|
|
|
|
&mut *(slice.as_mut_ptr() as *mut ExactSlice<T, N>)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn basic_min_success() {
|
|
|
|
let slice = &[1, 2, 3, 4, 5, 6];
|
|
|
|
let minslice: &MinSlice<_, 3> = MinSlice::from_slice(slice).unwrap();
|
|
|
|
assert_eq!(minslice.tail.len(), 3);
|
|
|
|
assert_eq!(minslice.head[0], 1);
|
|
|
|
assert_eq!(minslice.tail[2], 6);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn basic_min_failure() {
|
|
|
|
let slice = &[1, 2, 3, 4, 5, 6];
|
|
|
|
let minslice: Option<&MinSlice<_, 7>> = MinSlice::from_slice(slice);
|
|
|
|
assert!(minslice.is_none());
|
|
|
|
}
|
|
|
|
|
2021-09-10 20:39:21 +00:00
|
|
|
#[test]
|
|
|
|
fn basic_exact_success() {
|
|
|
|
let slice = &[1, 2, 3, 4, 5, 6];
|
|
|
|
let exactslice: &ExactSlice<_, 6> = ExactSlice::from_slice(slice).unwrap();
|
|
|
|
assert_eq!(exactslice.head[0], 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn basic_exact_failure() {
|
|
|
|
let slice = &[1, 2, 3, 4, 5, 6];
|
|
|
|
let exactslice: Option<&ExactSlice<_, 3>> = ExactSlice::from_slice(slice);
|
|
|
|
assert!(exactslice.is_none());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn array_exact_success() {
|
|
|
|
let array = [1, 2, 3, 4, 5, 6];
|
|
|
|
let exactslice: &ExactSlice<_, 6> = ExactSlice::from_array(&array);
|
|
|
|
assert_eq!(exactslice.head[0], 1);
|
|
|
|
assert_eq!(exactslice.head[5], 6);
|
|
|
|
}
|
|
|
|
|