Compare commits

...

3 Commits

5 changed files with 131 additions and 24 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
/target /target
Cargo.lock

5
Cargo.lock generated
View File

@ -1,5 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "nslice"
version = "0.1.0"

View File

@ -1,10 +1,11 @@
[package] [package]
name = "nslice" name = "nslice"
version = "0.1.0" version = "0.2.0"
authors = ["Leonora Tindall <nora@nora.codes>"] authors = ["Leonora Tindall <nora@nora.codes>"]
edition = "2018" edition = "2021"
description = "Structures for interpreting slices of variable length as arrays" description = "Structures for interpreting slices of variable length as arrays"
license = "MIT" license = "MIT"
keywords = ["memory", "slice", "array"] keywords = ["memory", "slice", "array"]
categories = ["data-structures"] categories = ["data-structures"]
repository = "https://git.nora.codes/nora/nslice" repository = "https://git.nora.codes/nora/nslice"
readme = "README.md"

25
README.md Normal file
View File

@ -0,0 +1,25 @@
# nslice
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.
This is useful when dealing with a slice whose length you expect to be exactly
or at least some particular length;
rather than making runtime checks on each access,
you can check the length once and access values freely with no copying.
```rust
# 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);
```
## License
This project is licensed MIT.

View File

@ -1,15 +1,4 @@
//! Structures for interpreting slices of variable length as arrays. #![doc=include_str!("../README.md")]
//!
//! `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; use std::slice;
/// A reference to a region of memory which is known to contain `N` or more elements /// A reference to a region of memory which is known to contain `N` or more elements
@ -19,6 +8,16 @@ use std::slice;
/// `MinSlice` is merely a way of reinterpreting an existing slice /// `MinSlice` is merely a way of reinterpreting an existing slice
/// (`&[T]` or `&mut [T]`), and it is exactly the same size as a slice: /// (`&[T]` or `&mut [T]`), and it is exactly the same size as a slice:
/// one pointer and one `usize`. /// one pointer and one `usize`.
///
/// # 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' ')
/// ```
pub struct MinSlice<T, const N: usize> { pub struct MinSlice<T, const N: usize> {
/// The bounded region of memory. Exactly `N` `T`s. /// The bounded region of memory. Exactly `N` `T`s.
pub head: [T; N], pub head: [T; N],
@ -57,6 +56,56 @@ impl<T, const N: usize> MinSlice<T, N> {
None None
} }
} }
}
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)
}
}
/// Produce a `&MinSlice` from a slice of `T`s without checking its length. /// Produce a `&MinSlice` from a slice of `T`s without checking its length.
/// ///
@ -112,14 +161,26 @@ impl<T, const N: usize> ExactSlice<T, N> {
} }
} }
/// 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. /// Produce a `&MinSlice` from this `&ExactSlice`. Its `tail` will be empty.
pub fn as_min_slice(&self) -> Option<&MinSlice<T, N>> { pub fn as_min_slice(&self) -> &MinSlice<T, N> {
MinSlice::from_slice(&self.head[..]) unsafe { MinSlice::from_slice_unchecked(&self.head[..]) }
} }
/// Produce a `&mut MinSlice` from this `&min ExactSlice`. Its `tail` will be empty. /// 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>> { pub fn as_mut_min_slice(&mut self) -> &mut MinSlice<T, N> {
MinSlice::from_mut(&mut self.head[..]) unsafe { MinSlice::from_mut_unchecked(&mut self.head[..]) }
} }
/// Produce an `&ExactSlice` from a slice of `T`s without checking its length. /// Produce an `&ExactSlice` from a slice of `T`s without checking its length.
@ -143,6 +204,30 @@ impl<T, const N: usize> ExactSlice<T, N> {
} }
} }
impl<'a, T, const N: usize> Into<&'a MinSlice<T, N>> for &'a ExactSlice<T, N> {
fn into(self) -> &'a MinSlice<T, N> {
self.as_min_slice()
}
}
impl<'a, T, const N: usize> Into<&'a mut MinSlice<T, N>> for &'a mut ExactSlice<T, N> {
fn into(self) -> &'a mut MinSlice<T, N> {
self.as_mut_min_slice()
}
}
impl<'a, T, const N: usize> Into<&'a ExactSlice<T, N>> for &'a MinSlice<T, N> {
fn into(self) -> &'a ExactSlice<T, N> {
unsafe { ExactSlice::from_slice_unchecked(&self.head[..]) }
}
}
impl<'a, T, const N: usize> Into<&'a mut ExactSlice<T, N>> for &'a mut MinSlice<T, N> {
fn into(self) -> &'a mut ExactSlice<T, N> {
unsafe { ExactSlice::from_mut_unchecked(&mut self.head[..]) }
}
}
#[test] #[test]
fn basic_min_success() { fn basic_min_success() {
let slice = &[1, 2, 3, 4, 5, 6]; let slice = &[1, 2, 3, 4, 5, 6];