//! 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`. /// /// # Example /// /// ``` /// # use nslice::MinSlice; /// let slice: &[u8] = b"Hello, world"; /// let minslice = MinSlice::::from_slice(slice).unwrap(); /// let value: u8 = minslice.head[6]; /// assert_eq!(value, b' ') /// ``` pub struct MinSlice { /// 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 { /// The bounded region of memory. Exactly `N` `T`s. head: [T; N] } impl MinSlice { /// 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> { if slice.len() >= N { Some(unsafe { Self::from_slice_unchecked(slice) }) } else { None } } /// 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> { if slice.len() >= N { Some(unsafe { Self::from_mut_unchecked(slice) }) } else { None } } } impl MinSlice { /// 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)` /// if there are at least `M` `T`s in `self`. pub fn resize(&self) -> Option<&MinSlice> { MinSlice::::from_slice(self.as_slice()) } /// Resize the `MinSlice`, returning a new `Some(&mut MinSlice)` /// if there are at least `M` `T`s in `self`. pub fn resize_mut(&mut self) -> Option<&mut MinSlice> { MinSlice::::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) } } /// 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 { let resized = slice::from_raw_parts(slice.as_ptr(), slice.len() - N); &*(resized as *const [T] as *const MinSlice) } /// 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 { let resized = slice::from_raw_parts_mut(slice.as_mut_ptr(), slice.len() - N); &mut *(resized as *mut [T] as *mut MinSlice) } } impl ExactSlice { /// Produce a `&ExactSlice` from an array of `N` `T`s. pub fn from_array(array: &[T; N]) -> &ExactSlice { 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 { unsafe { Self::from_mut_unchecked(&mut array[..]) } } /// 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> { 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> { if slice.len() == N { Some(unsafe { Self::from_mut_unchecked(slice) }) } else { None } } /// 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) } } /// Produce a `&MinSlice` from this `&ExactSlice`. Its `tail` will be empty. pub fn as_min_slice(&self) -> &MinSlice { unsafe { MinSlice::from_slice_unchecked(&self.head[..]) } } /// Produce a `&mut MinSlice` from this `&min ExactSlice`. Its `tail` will be empty. pub fn as_mut_min_slice(&mut self) -> &mut MinSlice { unsafe { MinSlice::from_mut_unchecked(&mut self.head[..]) } } /// 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 { &*(slice.as_ptr() as *const ExactSlice) } /// 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 { &mut *(slice.as_mut_ptr() as *mut ExactSlice) } } #[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()); } #[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); }