Initial commit

This commit is contained in:
Michael Pfaff 2024-03-15 17:57:12 -04:00
commit 01b794e81a
3 changed files with 498 additions and 0 deletions

2
.gitignore vendored Normal file
View File

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

6
Cargo.toml Normal file
View File

@ -0,0 +1,6 @@
[package]
name = "array-vec"
version = "0.1.0"
edition = "2021"
[dependencies]

490
src/lib.rs Normal file
View File

@ -0,0 +1,490 @@
#![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_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};
use std::slice::SliceIndex;
#[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();
// }
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(&*(0..self.len).get_unchecked(self.data.as_slice()))
}
}
#[inline]
pub const fn as_slice_mut(&mut self) -> &mut [T] {
let slice: &mut [MaybeUninit<T>] = &mut self.data;
unsafe { MaybeUninit::slice_assume_init_mut(&mut *(0..self.len).get_unchecked_mut(slice)) }
}
#[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 { &*(self.len..).get_unchecked(self.data.as_slice()) }
}
#[inline(always)]
pub const fn unused_mut(&mut self) -> &mut [MaybeUninit<T>] {
let slice: &mut [MaybeUninit<T>] = &mut self.data;
unsafe { &mut *(self.len..).get_unchecked_mut(slice) }
}
/// # 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());
}
}
}
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 {
len: value.len(),
data: MaybeUninit::transpose(MaybeUninit::new(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))
// }
// }