Initial commit
This commit is contained in:
commit
01b794e81a
|
@ -0,0 +1,2 @@
|
|||
/target
|
||||
Cargo.lock
|
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "array-vec"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
|
@ -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))
|
||||
// }
|
||||
// }
|
Loading…
Reference in New Issue