// SPDX-License-Identifier: CC0-1.0 //! A simplified `Copy` version of `arrayvec::ArrayVec`. use core::fmt; pub use safety_boundary::ArrayVec; /// Limits the scope of `unsafe` auditing. // New trait impls and fns that don't need to access internals should go below the module, not // inside it! mod safety_boundary { use core::mem::MaybeUninit; use crate::const_tools::cond_const; /// A growable contiguous collection backed by array. #[derive(Copy)] pub struct ArrayVec { len: usize, data: [MaybeUninit; CAP], } impl ArrayVec { // The bounds are const-unstable until 1.61 cond_const! { /// Creates an empty `ArrayVec`. pub const(in rust_v_1_61 = "1.61") fn new() -> Self { Self { len: 0, data: [MaybeUninit::uninit(); CAP], } } /// Creates an `ArrayVec` initialized with the contets of `slice`. /// /// # Panics /// /// If the slice is longer than `CAP`. pub const(in rust_v_1_61 = "1.61") fn from_slice(slice: &[T]) -> Self { assert!(slice.len() <= CAP); let mut data = [MaybeUninit::uninit(); CAP]; let mut i = 0; // can't use mutable references and operators in const while i < slice.len() { data[i] = MaybeUninit::new(slice[i]); i += 1; } Self { len: slice.len(), data, } } } // from_raw_parts is const-unstable until 1.64 cond_const! { /// Returns a reference to the underlying data. pub const(in rust_v_1_64 = "1.64") fn as_slice(&self) -> &[T] { let ptr = &self.data as *const _ as *const T; unsafe { core::slice::from_raw_parts(ptr, self.len) } } } /// Returns a mutable reference to the underlying data. pub fn as_mut_slice(&mut self) -> &mut [T] { unsafe { &mut *(&mut self.data[..self.len] as *mut _ as *mut [T]) } } /// Adds an element into `self`. /// /// # Panics /// /// If the length would increase past CAP. pub fn push(&mut self, element: T) { assert!(self.len < CAP); self.data[self.len] = MaybeUninit::new(element); self.len += 1; } /// Copies and appends all elements from `slice` into `self`. /// /// # Panics /// /// If the length would increase past CAP. pub fn extend_from_slice(&mut self, slice: &[T]) { let new_len = self.len.checked_add(slice.len()).expect("integer/buffer overflow"); assert!(new_len <= CAP, "buffer overflow"); // SAFETY: MaybeUninit has the same layout as T let slice = unsafe { &*(slice as *const _ as *const [MaybeUninit]) }; self.data[self.len..].copy_from_slice(slice); self.len = new_len; } } } /// Clones the value *faster* than using `Copy`. /// /// Because we avoid copying the uninitialized part of the array this copies the value faster than /// memcpy. #[allow(clippy::non_canonical_clone_impl)] impl Clone for ArrayVec { fn clone(&self) -> Self { Self::from_slice(self) } } impl core::ops::Deref for ArrayVec { type Target = [T]; fn deref(&self) -> &Self::Target { self.as_slice() } } impl core::ops::DerefMut for ArrayVec { fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut_slice() } } impl Eq for ArrayVec {} impl PartialEq> for ArrayVec { fn eq(&self, other: &ArrayVec) -> bool { **self == **other } } impl PartialEq<[T]> for ArrayVec { fn eq(&self, other: &[T]) -> bool { **self == *other } } impl PartialEq> for [T] { fn eq(&self, other: &ArrayVec) -> bool { *self == **other } } impl PartialEq<[T; LEN]> for ArrayVec { fn eq(&self, other: &[T; LEN]) -> bool { **self == *other } } impl PartialEq> for [T; LEN] { fn eq(&self, other: &ArrayVec) -> bool { *self == **other } } impl Ord for ArrayVec { fn cmp(&self, other: &ArrayVec) -> core::cmp::Ordering { (**self).cmp(&**other) } } impl PartialOrd> for ArrayVec { fn partial_cmp(&self, other: &ArrayVec) -> Option { (**self).partial_cmp(&**other) } } impl fmt::Debug for ArrayVec { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } impl core::hash::Hash for ArrayVec { fn hash(&self, state: &mut H) { core::hash::Hash::hash(&**self, state) } } #[cfg(test)] mod tests { use super::ArrayVec; #[test] fn arrayvec_ops() { let mut av = ArrayVec::<_, 1>::new(); assert!(av.is_empty()); av.push(42); assert_eq!(av.len(), 1); assert_eq!(av, [42]); } #[test] #[should_panic] fn overflow_push() { let mut av = ArrayVec::<_, 0>::new(); av.push(42); } #[test] #[should_panic] fn overflow_extend() { let mut av = ArrayVec::<_, 0>::new(); av.extend_from_slice(&[42]); } }