commit 01b794e81a8dbd06537aea34b5386f94937ba682 Author: Michael Pfaff Date: Fri Mar 15 17:57:12 2024 -0400 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..db60873 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "array-vec" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..8bf16d5 --- /dev/null +++ b/src/lib.rs @@ -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 { + data: [MaybeUninit; N], + /// Do not ever modify this field directly. Use [`Self::set_len`] instead. + len: usize, +} + +// impl ArrayVec { +// pub const EMPTY: ArrayVec = Self::new(); +// } + +impl ArrayVec { + #[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] = &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 { + (**self).iter() + } + + #[inline] + pub fn iter_mut(&mut self) -> std::slice::IterMut { + (**self).iter_mut() + } + + #[inline(always)] + pub const fn len(&self) -> usize { + self.len + } + + #[inline(always)] + pub const fn unused(&self) -> &[MaybeUninit] { + unsafe { &*(self.len..).get_unchecked(self.data.as_slice()) } + } + + #[inline(always)] + pub const fn unused_mut(&mut self) -> &mut [MaybeUninit] { + let slice: &mut [MaybeUninit] = &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 Clone for ArrayVec { + #[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 PartialEq for ArrayVec { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.as_slice() == other.as_slice() + } +} + +impl Eq for ArrayVec {} + +impl PartialOrd for ArrayVec { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + self.as_slice().partial_cmp(other.as_slice()) + } +} + +impl Ord for ArrayVec { + #[inline] + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.as_slice().cmp(other.as_slice()) + } +} + +impl Hash for ArrayVec { + #[inline] + fn hash(&self, state: &mut H) { + self.as_slice().hash(state) + } +} + +impl IntoIterator for ArrayVec { + type Item = T; + + type IntoIter = std::array::IntoIter; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + unsafe { std::array::IntoIter::new_unchecked(self.data, 0..self.len) } + } +} + +impl Debug for ArrayVec { + #[inline] + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +impl Deref for ArrayVec { + type Target = [T]; + + #[inline] + fn deref(&self) -> &Self::Target { + self.as_slice() + } +} + +impl DerefMut for ArrayVec { + #[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(ArrayVec); + +// impl ArrayStr<0> { +// pub const EMPTY: ArrayStr<0> = Self::new(); +// } + +impl ArrayStr { + #[inline] + pub const fn new() -> Self { + Self(ArrayVec::new()) + } + + #[inline(always)] + pub const fn from_utf8(bytes: ArrayVec) -> Result { + 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) -> Self { + if cfg!(debug_assertions) { + match Self::from_utf8(bytes) { + Ok(t) => t, + Err(_) => panic!(), + } + } else { + Self(bytes) + } + } + + pub const fn data(&self) -> &ArrayVec { + &self.0 + } + + pub const fn data_mut(&mut self) -> &mut ArrayVec { + &mut self.0 + } + + pub const fn into_data(self) -> ArrayVec { + 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 Deref for ArrayStr { + type Target = str; + + #[inline] + fn deref(&self) -> &Self::Target { + self.as_str() + } +} + +impl DerefMut for ArrayStr { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + self.as_mut_str() + } +} + +impl AsRef for ArrayStr { + #[inline] + fn as_ref(&self) -> &str { + self + } +} + +impl AsMut for ArrayStr { + #[inline] + fn as_mut(&mut self) -> &mut str { + self + } +} + +impl Debug for ArrayStr { + #[inline] + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Debug::fmt(&**self, f) + } +} + +impl Display for ArrayStr { + #[inline] + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Display::fmt(&**self, f) + } +} + +impl From<[T; N]> for ArrayVec { + #[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 { + #[inline(always)] + pub const fn try_from(value: &'a [T]) -> Result { + 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 { + type Error = TryFromSliceError; + + #[inline(always)] + fn try_from(value: &'a [T]) -> Result { + Self::try_from(value) + } +} + +impl<'a, const N: usize> ArrayStr { + #[inline(always)] + pub const fn try_from(value: &'a str) -> Result { + 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 { + type Error = TryFromSliceError; + + #[inline(always)] + fn try_from(value: &'a str) -> Result { + Self::try_from(value) + } +} + +impl<'a, const N: usize> TryFrom for ArrayStr { + type Error = PushCharError; + + #[inline] + fn try_from(value: char) -> Result { + let mut arr = Self::new(); + arr.push(value)?; + Ok(arr) + } +} + +// impl ArrayVec { +// pub const fn concat(self, rhs: ArrayVec) -> ArrayVec +// where +// [(); N + M]:, +// { +// let mut new = ArrayVec::::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 ArrayStr { +// pub const fn concat(self, rhs: ArrayStr) -> ArrayStr<{ N + M }> +// where +// [(); N + M]:, +// { +// ArrayStr(self.0.concat(rhs.0)) +// } +// }