// 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 { /// Constructs an empty `ArrayVec`. pub const fn new() -> Self { Self { len: 0, data: [MaybeUninit::uninit(); CAP] } } /// Constructs a new `ArrayVec` initialized with the contents of `slice`. /// /// # Panics /// /// If the slice is longer than `CAP`. pub const 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 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..new_len].copy_from_slice(slice); self.len = new_len; } } } impl Default for ArrayVec { fn default() -> Self { Self::new() } } /// 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]); } #[test] fn extend_from_slice() { let mut av = ArrayVec::::new(); av.extend_from_slice(b"abc"); } } #[cfg(kani)] mod verification { use super::*; #[kani::unwind(16)] // One greater than 15 (max number of elements). #[kani::proof] fn no_out_of_bounds_less_than_cap() { const CAP: usize = 32; let n = kani::any::(); let elements = (n & 0x0F) as usize; // Just use 4 bits. let val = kani::any::(); let mut v = ArrayVec::::new(); for _ in 0..elements { v.push(val); } for i in 0..elements { assert_eq!(v[i], val); } } #[kani::unwind(16)] // One grater than 15. #[kani::proof] fn no_out_of_bounds_upto_cap() { const CAP: usize = 15; let elements = CAP; let val = kani::any::(); let mut v = ArrayVec::::new(); for _ in 0..elements { v.push(val); } for i in 0..elements { assert_eq!(v[i], val); } } }