commit
620f926fdd
3 changed files with 163 additions and 0 deletions
@ -0,0 +1 @@ |
|||
/target |
@ -0,0 +1,10 @@ |
|||
[package] |
|||
name = "nslice" |
|||
version = "0.1.0" |
|||
authors = ["Leonora Tindall <nora@nora.codes>"] |
|||
edition = "2018" |
|||
description = "Structures for interpreting slices of variable length as arrays" |
|||
license = "MIT" |
|||
keywords = ["memory", "slice", "array"] |
|||
categories = ["data-structures"] |
|||
repository = "https://git.nora.codes/nora/nslice" |
@ -0,0 +1,152 @@ |
|||
//! 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`.
|
|||
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 |
|||
} |
|||
} |
|||
|
|||
/// 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 |
|||
} |
|||
} |
|||
|
|||
/// 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> { |
|||
/// 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 |
|||
} |
|||
} |
|||
|
|||
/// Produce a `&MinSlice` from this `&ExactSlice`. Its `tail` will be empty.
|
|||
pub fn as_min_slice(&self) -> Option<&MinSlice<T, N>> { |
|||
MinSlice::from_slice(&self.head[..]) |
|||
} |
|||
|
|||
/// Produce a `&mut MinSlice` from this `&min ExactSlice`. Its `tail` will be empty.
|
|||
pub fn as_mut_min_slice(&mut self) -> Option<&mut MinSlice<T, N>> { |
|||
MinSlice::from_mut(&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<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()); |
|||
} |
|||
|
Loading…
Reference in new issue