535 lines
14 KiB
Rust
535 lines
14 KiB
Rust
#![forbid(unused_must_use)]
|
|
#![feature(array_into_iter_constructors)]
|
|
#![feature(const_intrinsic_copy)]
|
|
#![feature(const_maybe_uninit_assume_init)]
|
|
#![feature(const_maybe_uninit_uninit_array)]
|
|
#![feature(const_mut_refs)]
|
|
#![feature(const_option)]
|
|
#![feature(const_refs_to_cell)]
|
|
#![feature(const_slice_from_raw_parts_mut)]
|
|
#![feature(const_slice_split_at_mut)]
|
|
#![feature(const_trait_impl)]
|
|
#![feature(effects)]
|
|
#![feature(generic_const_exprs)]
|
|
#![feature(iter_repeat_n)]
|
|
#![feature(maybe_uninit_array_assume_init)]
|
|
#![feature(maybe_uninit_slice)]
|
|
#![feature(maybe_uninit_uninit_array)]
|
|
#![feature(maybe_uninit_uninit_array_transpose)]
|
|
#![feature(new_uninit)]
|
|
#![feature(slice_index_methods)]
|
|
#![feature(split_array)]
|
|
|
|
use std::fmt::{Debug, Display};
|
|
use std::hash::Hash;
|
|
use std::mem::MaybeUninit;
|
|
use std::ops::{Deref, DerefMut};
|
|
|
|
#[derive(Copy)]
|
|
pub struct ArrayVec<T, const N: usize> {
|
|
data: [MaybeUninit<T>; N],
|
|
/// Do not ever modify this field directly. Use [`Self::set_len`] instead.
|
|
len: usize,
|
|
}
|
|
|
|
// impl<T> ArrayVec<T, 0> {
|
|
// pub const EMPTY: ArrayVec<T, 0> = Self::new();
|
|
// }
|
|
|
|
#[inline(always)]
|
|
const unsafe fn slice_unchecked<T>(slice: &[T], offset: usize, len: Option<usize>) -> &[T] {
|
|
std::slice::from_raw_parts(
|
|
slice.as_ptr().add(offset),
|
|
match len {
|
|
Some(t) => t,
|
|
None => slice.len() - offset,
|
|
},
|
|
)
|
|
}
|
|
|
|
#[inline(always)]
|
|
const unsafe fn slice_unchecked_mut<T>(
|
|
slice: &mut [T],
|
|
offset: usize,
|
|
len: Option<usize>,
|
|
) -> &mut [T] {
|
|
std::slice::from_raw_parts_mut(
|
|
slice.as_mut_ptr().add(offset),
|
|
match len {
|
|
Some(t) => t,
|
|
None => slice.len() - offset,
|
|
},
|
|
)
|
|
}
|
|
|
|
impl<T, const N: usize> ArrayVec<T, N> {
|
|
#[inline]
|
|
pub const fn new() -> Self {
|
|
Self {
|
|
data: MaybeUninit::uninit_array(),
|
|
len: 0,
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub const fn as_slice(&self) -> &[T] {
|
|
unsafe {
|
|
MaybeUninit::slice_assume_init_ref(slice_unchecked(&self.data, 0, Some(self.len)))
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub const fn as_slice_mut(&mut self) -> &mut [T] {
|
|
unsafe {
|
|
MaybeUninit::slice_assume_init_mut(slice_unchecked_mut(
|
|
&mut self.data,
|
|
0,
|
|
Some(self.len),
|
|
))
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub const fn as_ptr(&self) -> *const T {
|
|
MaybeUninit::slice_as_ptr(&self.data)
|
|
}
|
|
|
|
#[inline]
|
|
pub const fn as_mut_ptr(&mut self) -> *mut T {
|
|
MaybeUninit::slice_as_mut_ptr(&mut self.data)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn iter(&self) -> std::slice::Iter<T> {
|
|
(**self).iter()
|
|
}
|
|
|
|
#[inline]
|
|
pub fn iter_mut(&mut self) -> std::slice::IterMut<T> {
|
|
(**self).iter_mut()
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub const fn len(&self) -> usize {
|
|
self.len
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub const fn unused(&self) -> &[MaybeUninit<T>] {
|
|
unsafe { slice_unchecked(&self.data, self.len, None) }
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub const fn unused_mut(&mut self) -> &mut [MaybeUninit<T>] {
|
|
unsafe { slice_unchecked_mut(&mut self.data, self.len, None) }
|
|
}
|
|
|
|
/// # Safety
|
|
///
|
|
/// - `new_len` must be less than or equal to `N`.
|
|
/// - The elements at `0..new_len` must be initialized. In practice, this can be reduced to `old_len..new_len`.
|
|
#[inline(always)]
|
|
pub const unsafe fn set_len(&mut self, len: usize) {
|
|
debug_assert!(len <= N);
|
|
self.len = len;
|
|
}
|
|
|
|
/// # Panics
|
|
///
|
|
/// This function will panic if there is not sufficient spare capacity for the entire `slice`.
|
|
#[inline]
|
|
pub const fn push_slice(&mut self, slice: &[T])
|
|
where
|
|
T: Copy,
|
|
{
|
|
assert!(slice.len() <= self.unused().len());
|
|
let old_len = self.len();
|
|
let (_, unused) = self.data.split_at_mut(old_len);
|
|
unsafe {
|
|
MaybeUninit::slice_as_mut_ptr(unused)
|
|
.copy_from_nonoverlapping(slice.as_ptr(), slice.len());
|
|
self.set_len(old_len + slice.len());
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub const fn from(value: [T; N]) -> Self {
|
|
Self {
|
|
len: value.len(),
|
|
data: MaybeUninit::transpose(MaybeUninit::new(value)),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: Clone, const N: usize> Clone for ArrayVec<T, N> {
|
|
#[inline]
|
|
fn clone(&self) -> Self {
|
|
let mut new = Self::new();
|
|
self.as_slice()
|
|
.iter()
|
|
.zip(&mut new.data[0..self.len])
|
|
.for_each(|(src, dst)| *dst = MaybeUninit::new(src.clone()));
|
|
unsafe { new.set_len(self.len) };
|
|
new
|
|
}
|
|
|
|
#[inline]
|
|
fn clone_from(&mut self, source: &Self) {
|
|
source
|
|
.as_slice()
|
|
.iter()
|
|
.zip(&mut self.data[0..self.len])
|
|
.for_each(|(src, dst)| *dst = MaybeUninit::new(src.clone()));
|
|
unsafe { self.set_len(source.len) };
|
|
}
|
|
}
|
|
|
|
impl<T: PartialEq, const N: usize> PartialEq for ArrayVec<T, N> {
|
|
#[inline]
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.as_slice() == other.as_slice()
|
|
}
|
|
}
|
|
|
|
impl<T: Eq, const N: usize> Eq for ArrayVec<T, N> {}
|
|
|
|
impl<T: PartialOrd, const N: usize> PartialOrd for ArrayVec<T, N> {
|
|
#[inline]
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
self.as_slice().partial_cmp(other.as_slice())
|
|
}
|
|
}
|
|
|
|
impl<T: Ord, const N: usize> Ord for ArrayVec<T, N> {
|
|
#[inline]
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
self.as_slice().cmp(other.as_slice())
|
|
}
|
|
}
|
|
|
|
impl<T: Hash, const N: usize> Hash for ArrayVec<T, N> {
|
|
#[inline]
|
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
self.as_slice().hash(state)
|
|
}
|
|
}
|
|
|
|
impl<T, const N: usize> IntoIterator for ArrayVec<T, N> {
|
|
type Item = T;
|
|
|
|
type IntoIter = std::array::IntoIter<T, N>;
|
|
|
|
#[inline]
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
unsafe { std::array::IntoIter::new_unchecked(self.data, 0..self.len) }
|
|
}
|
|
}
|
|
|
|
impl<T: Debug, const N: usize> Debug for ArrayVec<T, N> {
|
|
#[inline]
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.debug_list().entries(self.iter()).finish()
|
|
}
|
|
}
|
|
|
|
impl<T, const N: usize> Deref for ArrayVec<T, N> {
|
|
type Target = [T];
|
|
|
|
#[inline]
|
|
fn deref(&self) -> &Self::Target {
|
|
self.as_slice()
|
|
}
|
|
}
|
|
|
|
impl<T, const N: usize> DerefMut for ArrayVec<T, N> {
|
|
#[inline]
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
self.as_slice_mut()
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
#[repr(transparent)]
|
|
pub struct ArrayStr<const N: usize>(ArrayVec<u8, N>);
|
|
|
|
// impl ArrayStr<0> {
|
|
// pub const EMPTY: ArrayStr<0> = Self::new();
|
|
// }
|
|
|
|
impl<const N: usize> ArrayStr<N> {
|
|
#[inline]
|
|
pub const fn new() -> Self {
|
|
Self(ArrayVec::new())
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub const fn from_utf8(bytes: ArrayVec<u8, N>) -> Result<Self, std::str::Utf8Error> {
|
|
if let Err(e) = std::str::from_utf8(bytes.as_slice()) {
|
|
return Err(e);
|
|
}
|
|
Ok(Self(bytes))
|
|
}
|
|
|
|
#[inline]
|
|
pub const unsafe fn from_utf8_unchecked(bytes: ArrayVec<u8, N>) -> Self {
|
|
if cfg!(debug_assertions) {
|
|
match Self::from_utf8(bytes) {
|
|
Ok(t) => t,
|
|
Err(_) => panic!(),
|
|
}
|
|
} else {
|
|
Self(bytes)
|
|
}
|
|
}
|
|
|
|
pub const fn data(&self) -> &ArrayVec<u8, N> {
|
|
&self.0
|
|
}
|
|
|
|
pub const fn data_mut(&mut self) -> &mut ArrayVec<u8, N> {
|
|
&mut self.0
|
|
}
|
|
|
|
pub const fn into_data(self) -> ArrayVec<u8, N> {
|
|
self.0
|
|
}
|
|
|
|
#[inline]
|
|
pub const fn as_str(&self) -> &str {
|
|
unsafe { std::str::from_utf8_unchecked(&self.0) }
|
|
}
|
|
|
|
#[inline]
|
|
pub fn as_mut_str(&mut self) -> &mut str {
|
|
unsafe { std::str::from_utf8_unchecked_mut(&mut self.0) }
|
|
}
|
|
|
|
#[inline]
|
|
pub const fn as_ptr(&self) -> *const u8 {
|
|
self.0.as_ptr()
|
|
}
|
|
|
|
#[inline]
|
|
pub const fn as_mut_ptr(&mut self) -> *mut u8 {
|
|
self.0.as_mut_ptr()
|
|
}
|
|
|
|
/// # Panics
|
|
///
|
|
/// This function will panic if there is not sufficient spare capacity for the entire `string`.
|
|
#[inline]
|
|
pub const fn push_str(&mut self, string: &str) {
|
|
self.0.push_slice(string.as_bytes())
|
|
}
|
|
|
|
#[inline]
|
|
pub fn push(&mut self, character: char) -> Result<(), PushCharError> {
|
|
let len = character.len_utf8();
|
|
let unused = self.0.unused_mut();
|
|
if len <= unused.len() {
|
|
let unused = &mut unused[0..len];
|
|
unused.fill(MaybeUninit::new(0));
|
|
// SAFETY: the first `len` bytes have been initialized.
|
|
let unused = unsafe { MaybeUninit::slice_assume_init_mut(unused) };
|
|
character.encode_utf8(unused);
|
|
unsafe { self.0.set_len(len) };
|
|
Ok(())
|
|
} else {
|
|
Err(PushCharError {
|
|
unused_len: unused.len(),
|
|
character,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<const N: usize> Deref for ArrayStr<N> {
|
|
type Target = str;
|
|
|
|
#[inline]
|
|
fn deref(&self) -> &Self::Target {
|
|
self.as_str()
|
|
}
|
|
}
|
|
|
|
impl<const N: usize> DerefMut for ArrayStr<N> {
|
|
#[inline]
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
self.as_mut_str()
|
|
}
|
|
}
|
|
|
|
impl<const N: usize> AsRef<str> for ArrayStr<N> {
|
|
#[inline]
|
|
fn as_ref(&self) -> &str {
|
|
self
|
|
}
|
|
}
|
|
|
|
impl<const N: usize> AsMut<str> for ArrayStr<N> {
|
|
#[inline]
|
|
fn as_mut(&mut self) -> &mut str {
|
|
self
|
|
}
|
|
}
|
|
|
|
impl<const N: usize> Debug for ArrayStr<N> {
|
|
#[inline]
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
Debug::fmt(&**self, f)
|
|
}
|
|
}
|
|
|
|
impl<const N: usize> Display for ArrayStr<N> {
|
|
#[inline]
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
Display::fmt(&**self, f)
|
|
}
|
|
}
|
|
|
|
impl<T, const N: usize> From<[T; N]> for ArrayVec<T, N> {
|
|
#[inline]
|
|
fn from(value: [T; N]) -> Self {
|
|
Self::from(value)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub struct TryFromSliceError {
|
|
max_len: usize,
|
|
slice_len: usize,
|
|
}
|
|
|
|
impl Display for TryFromSliceError {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.write_str("The slice, with length ")?;
|
|
write!(f, "{}", self.slice_len)?;
|
|
f.write_str(", is too long for the type, with maximum length ")?;
|
|
write!(f, "{}", self.max_len)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl std::error::Error for TryFromSliceError {}
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub struct PushCharError {
|
|
unused_len: usize,
|
|
character: char,
|
|
}
|
|
|
|
impl Display for PushCharError {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
use std::fmt::Write;
|
|
f.write_str("The code point ")?;
|
|
for c in self.character.escape_debug() {
|
|
f.write_char(c)?;
|
|
}
|
|
f.write_str(", with UTF-8 length ")?;
|
|
write!(f, "{}", self.character.len_utf8())?;
|
|
f.write_str(", is too long for the type, with maximum length ")?;
|
|
write!(f, "{}", self.unused_len)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl std::error::Error for PushCharError {}
|
|
|
|
impl<'a, T: Copy, const N: usize> ArrayVec<T, N> {
|
|
#[inline(always)]
|
|
pub const fn try_from(value: &'a [T]) -> Result<Self, TryFromSliceError> {
|
|
if value.len() > N {
|
|
return Err(TryFromSliceError {
|
|
slice_len: value.len(),
|
|
max_len: N,
|
|
});
|
|
}
|
|
let mut vec = Self::new();
|
|
unsafe {
|
|
MaybeUninit::slice_as_mut_ptr(&mut vec.data)
|
|
.copy_from_nonoverlapping(value.as_ptr(), value.len());
|
|
vec.set_len(value.len());
|
|
}
|
|
Ok(vec)
|
|
}
|
|
}
|
|
|
|
impl<'a, T: Copy, const N: usize> TryFrom<&'a [T]> for ArrayVec<T, N> {
|
|
type Error = TryFromSliceError;
|
|
|
|
#[inline(always)]
|
|
fn try_from(value: &'a [T]) -> Result<Self, Self::Error> {
|
|
Self::try_from(value)
|
|
}
|
|
}
|
|
|
|
impl<'a, const N: usize> ArrayStr<N> {
|
|
#[inline(always)]
|
|
pub const fn try_from(value: &'a str) -> Result<Self, TryFromSliceError> {
|
|
match ArrayVec::try_from(value.as_bytes()) {
|
|
Ok(t) => Ok(Self(t)),
|
|
Err(e) => Err(e),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, const N: usize> TryFrom<&'a str> for ArrayStr<N> {
|
|
type Error = TryFromSliceError;
|
|
|
|
#[inline(always)]
|
|
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
|
|
Self::try_from(value)
|
|
}
|
|
}
|
|
|
|
impl<'a, const N: usize> TryFrom<char> for ArrayStr<N> {
|
|
type Error = PushCharError;
|
|
|
|
#[inline]
|
|
fn try_from(value: char) -> Result<Self, Self::Error> {
|
|
let mut arr = Self::new();
|
|
arr.push(value)?;
|
|
Ok(arr)
|
|
}
|
|
}
|
|
|
|
// impl<T, const N: usize> ArrayVec<T, N> {
|
|
// pub const fn concat<const M: usize>(self, rhs: ArrayVec<T, M>) -> ArrayVec<T, { N + M }>
|
|
// where
|
|
// [(); N + M]:,
|
|
// {
|
|
// let mut new = ArrayVec::<T, { N + M }>::new();
|
|
// let mut i = 0;
|
|
// while i < self.len {
|
|
// new.data[i] = unsafe { MaybeUninit::new(self.data[i].assume_init_read()) };
|
|
// i += 1;
|
|
// }
|
|
// let mut j = 0;
|
|
// while j < rhs.len {
|
|
// new.data[i] = unsafe { MaybeUninit::new(rhs.data[j].assume_init_read()) };
|
|
// i += 1;
|
|
// j += 1;
|
|
// }
|
|
// unsafe { new.set_len(self.len + rhs.len) };
|
|
// new
|
|
// }
|
|
// }
|
|
|
|
// impl<const N: usize> ArrayStr<N> {
|
|
// pub const fn concat<const M: usize>(self, rhs: ArrayStr<M>) -> ArrayStr<{ N + M }>
|
|
// where
|
|
// [(); N + M]:,
|
|
// {
|
|
// ArrayStr(self.0.concat(rhs.0))
|
|
// }
|
|
// }
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::ArrayVec;
|
|
|
|
const _FOO: ArrayVec<(), 4> = ArrayVec::from([(), (), (), ()]);
|
|
const _FOO_LEN: usize = _FOO.as_slice().len();
|
|
const _FOO_UNUSED: usize = _FOO.unused().len();
|
|
}
|