//! # Ad-hoc stack vectors //! This crate defines the macro `stack![]`, which can be used to create ad-hoc `Vec` like structs of a specific compile-time size on the stack. //! These structs never allocate on the heap, and expose an API similar to `Vec`. //! ## Usage //! The macro can be used like `vec!`, with optional type inference. //! //! ``` //! # use stack_vec::stack; //! let mut sv = stack![100]; // Implicitly typed. //! sv.push(10usize); //! let sv = stack![usize; 100]; // Explicitly typed, circumvents that error. //! ``` //! //! To see documentation of the types themselves, see one of the pre-defined `StackVec` types in the crate's root. //! # Pre-defined types //! `StackVec` types of powers of 2 up until 4096 are defined in this crate too. //! //! You can use the macro to create your own named non-opaque `StackVec` types as well. //! ``` //! # use stack_vec::stack; //! stack!(pub type S10Elements S10IntoIter 10); // A `StackVec` type with a capacity of 10. //! ``` /// Create an ad-hoc sized `Vec`-like array on the stack. /// /// # Usage /// ``` /// # use stack_vec::stack; /// let sv = stack![usize; 100]; /// assert_eq!(sv.cap(), 100); /// ``` /// /// Can be used mostly just like `Vec`, except the size must be a literal. /// ``` /// # use stack_vec::stack; /// let mut sv = stack![12]; /// for x in 0..12 { /// sv.push(vec![x,x]); /// } /// assert_eq!(sv.into_iter().map(|x| x.into_iter().product::()).sum::(), (0..12).map(|x| x*x).sum::()); /// ``` /// # Defining `StackVec` types /// You can also use this macro to define your own transparent `StackVec` types /// ``` /// # use stack_vec::stack; /// stack!(pub type StackVec10 StackVec10IntoIter 10); /// /// let sv: StackVec10<_> = [1i32; 10].iter().copied().collect(); /// let sv: StackVec10IntoIter<_> = sv.into_iter(); /// assert_eq!(sv.sum::(), 10); /// ``` /// /// See one of the `StackVec` structs defined here for more information. #[macro_export] macro_rules! stack { ($($q:tt)? type $name:ident $into_iter_name:ident $n:literal) => { #[allow(unused_doc_comments)] #[doc="A sized stack vector"] $($q)? struct $name([::std::mem::MaybeUninit; $n], usize); impl $name { #![allow(dead_code)] /// The max capacity of this `StackVec` type pub const CAPACITY: usize = $n; /// The max capacity of this `StackVec` /// /// # Note /// Identical to `Self::CAPACITY`, however more convenient for ad-hoc types created through `stack![n]`. #[inline] pub const fn cap(&self) -> usize { Self::CAPACITY } /// Create a new empty `StackVec`. #[inline] pub fn new() -> Self { use std::mem::MaybeUninit; unsafe { Self(MaybeUninit::uninit().assume_init(), 0) // for now we can't make this `const fn` :( } } /// Extend from a slice where `T: Copy`. /// /// Returns the number of elements copied. If the copy would overflow the capacity the rest is ignored. #[inline] pub fn extend_from_slice_copy>(&mut self, slice: U) -> usize where T: Copy { let rest = unsafe {self.rest_mut()}; let slice = slice.as_ref(); let len = std::cmp::min(rest.len(),slice.len()); unsafe { std::ptr::copy(slice.as_ptr(), rest.as_mut_ptr() as *mut std::mem::MaybeUninit as *mut T, len); } self.1+=len; len } /// Extend from a slice where `T: Clone` /// /// Returns the number of elements copied. If the copy would overflow the capacity the rest is ignored. pub fn extend_from_slice>(&mut self, slice: U) -> usize where T: ::std::clone::Clone { let rest = &mut self.0[self.1..]; let slice = slice.as_ref(); let mut wrote=0; for (d,s) in rest.iter_mut().zip(slice.iter()) { *d = std::mem::MaybeUninit::new(s.clone()); self.1+=1; wrote+=1; } wrote } /// Try to push an element on to the end of the `StackVec`. /// /// If it is full, return the value as `Err(T)` instead. #[inline(always)] pub fn try_push(&mut self, value: T) -> Result<(), T> { if self.1 < Self::CAPACITY { self.0[self.1] = std::mem::MaybeUninit::new(value); self.1+=1; Ok(()) } else { Err(value) } } /// Push an element on the the end of the `StackVec`. /// /// # Panics /// If the `StackVec` is full. #[inline] pub fn push(&mut self, value: T) { #[cold] fn off_end() -> ! { panic!(concat!("Tried to push off the end of `StackVec", stringify!($n), "`")); } if self.1 < Self::CAPACITY { self.0[self.1] = std::mem::MaybeUninit::new(value); self.1+=1; } else { off_end() } } /// The number of elements currently in the `StackVec`. #[inline] pub fn len(&self) -> usize { self.1 } /// A slice of the elements in the `StackVec`. #[inline(always)] pub fn as_slice(&self) -> &[T] { unsafe { &*(&self.0[..self.1] as *const [std::mem::MaybeUninit] as *const [T]) } } /// A mutable slice of the elements in the `StackVec`. #[inline(always)] pub fn as_mut_slice(&mut self) -> &mut [T] { unsafe { &mut *(&mut self.0[..self.1] as *mut [std::mem::MaybeUninit] as *mut [T]) } } /// A mutable slice of the initialised part of the buffer. /// /// All elements of the returned slice are initialised. #[inline(always)] pub fn init_buffer_mut(&mut self) -> &mut [std::mem::MaybeUninit] { &mut self.0[..self.1] } /// The initialised part of the buffer. /// /// All elements of the returned slice are initialised. #[inline(always)] pub fn init_buffer(&self) -> &[std::mem::MaybeUninit] { &self.0[..self.1] } /// A mutable reference to the uninitialised part of the instance. /// /// No elements of the returned slice are initialised. /// # Note /// If you initialise some, you must remember to update the length with `set_len()`. #[inline(always)] pub unsafe fn rest_mut(&mut self) -> &mut [std::mem::MaybeUninit] { &mut self.0[self.1..] } /// The uninitialised part of the instance. /// /// No elements of the returned slice are initialised. #[inline(always)] pub fn rest(&self) -> &[std::mem::MaybeUninit] { &self.0[self.1..] } /// A mutable reference to the whole capacity buffer. /// /// `..self.len()` will be initialised, `self.len()..` will be uninitialised. /// /// # Note /// If you initialise or uninitialise some element(s), you must remember to update the length with `set_len()`. #[inline] pub unsafe fn buffer_mut(&mut self) -> &mut [std::mem::MaybeUninit; $n] { &mut self.0 } /// A reference to the whole capacity buffer. /// /// `..self.len()` will be initialised, `self.len()..` will be uninitialised. #[inline] pub fn buffer(&self) -> &[std::mem::MaybeUninit; $n] { &self.0 } /// Set the internal fill pointer of the `StackVec`. /// /// This changes how much of the buffer is assumed to be initialised. /// Only use this if you have manually initialised some of the uninitialised buffer, as it does no initialising itself. #[inline] pub unsafe fn set_len(&mut self, len: usize) { self.1 = len; } } impl ::std::ops::Drop for $name { fn drop(&mut self) { if std::mem::needs_drop::() { for init in &mut self.0[..self.1] { unsafe { drop(std::mem::replace(init, std::mem::MaybeUninit::uninit()).assume_init()); } } } } } impl ::std::ops::DerefMut for $name { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut_slice() } } impl ::std::ops::Deref for $name { type Target = [T]; #[inline] fn deref(&self) -> &Self::Target { self.as_slice() } } impl ::std::convert::AsRef<[T]> for $name { #[inline] fn as_ref(&self) -> &[T] { self.as_slice() } } impl ::std::convert::AsMut<[T]> for $name { #[inline] fn as_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } impl ::std::borrow::Borrow<[T]> for $name { #[inline] fn borrow(&self) -> &[T] { self.as_slice() } } impl ::std::borrow::BorrowMut<[T]> for $name { #[inline] fn borrow_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } impl ::std::fmt::Debug for $name where T: ::std::fmt::Debug { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { write!(f, "{:?}", self.as_slice()) } } impl ::std::cmp::Eq for $name where T: ::std::cmp::Eq{} impl ::std::cmp::PartialEq for $name where T: ::std::cmp::PartialEq, U: AsRef<[T]> { #[inline] fn eq(&self, other: &U) -> bool { self.as_slice() == other.as_ref() } } impl ::std::cmp::Ord for $name where T: ::std::cmp::Ord { #[inline] fn cmp(&self, other: &Self) -> std::cmp::Ordering { std::cmp::Ord::cmp(self.as_slice(), other.as_slice()) } } impl ::std::cmp::PartialOrd for $name where T: ::std::cmp::PartialOrd, U: AsRef<[T]> { #[inline] fn partial_cmp(&self, other: &U) -> Option { std::cmp::PartialOrd::partial_cmp(self.as_slice(), other.as_ref()) } } impl> std::ops::Index for $name { type Output = I::Output; #[inline] fn index(&self, index: I) -> &Self::Output { std::ops::Index::index(self.as_slice(), index) } } impl> std::ops::IndexMut for $name { #[inline] fn index_mut(&mut self, index: I) -> &mut Self::Output { std::ops::IndexMut::index_mut(self.as_mut_slice(), index) } } impl ::std::clone::Clone for $name where T: ::std::clone::Clone { fn clone(&self) -> Self { let mut emp = Self::new(); for (d,s) in emp.0.iter_mut().zip(self.iter()) { *d = std::mem::MaybeUninit::new(s.clone()); emp.1+=1;//increment in case of `clone` panic } emp } } impl ::std::convert::From<$name> for ::std::vec::Vec { #[inline] fn from(from: $name) -> Self { from.into_iter().collect() } } impl std::default::Default for $name { #[inline] fn default() -> Self { Self::new() } } impl ::std::iter::IntoIterator for $name { type Item= T; type IntoIter = $into_iter_name; fn into_iter(self) -> Self::IntoIter { $into_iter_name(self, 0) } } impl ::std::io::Write for $name { fn write(&mut self, buf: &[u8]) -> ::std::io::Result { Ok(self.extend_from_slice_copy(buf)) } #[inline] fn write_vectored(&mut self, bufs: &[::std::io::IoSlice<'_>]) -> ::std::io::Result { let mut w = 0; for buf in bufs { w += self.extend_from_slice_copy(&buf[..]); } Ok(w) } #[inline] fn write_all(&mut self, buf: &[u8]) -> ::std::io::Result<()> { let w = self.extend_from_slice_copy(buf); if w!=buf.len() { Err(::std::io::Error::new(::std::io::ErrorKind::Other, "No more space")) } else { Ok(()) } } #[inline] fn flush(&mut self) -> ::std::io::Result<()> { Ok(()) } } impl ::std::convert::From<[T; $n]> for $name { #[inline] fn from(from: [T; $n]) -> Self { let mut this = Self::new(); unsafe { std::ptr::copy(&from[0] as *const T, &mut this.0[0] as *mut std::mem::MaybeUninit as *mut T, $n); } this.1=$n; std::mem::forget(from); this } } impl ::std::iter::FromIterator for $name { fn from_iter>(iter: I) -> Self { let mut output = Self::new(); for item in iter { output.push(item); } output } } /// Consuming iterator type for a `StackVec` pub struct $into_iter_name($name, usize); impl $into_iter_name { #![allow(dead_code)] /// The rest of the initialised buffer that has not been consumed yet. #[inline] pub fn rest(&self) -> &[T] { &self.0.as_slice()[self.1..] } #[inline(always)] fn m_rest(&self) -> &[std::mem::MaybeUninit] { &self.0.init_buffer()[self.1..] } /// A mutable reference to the rest of the initialised buffer that has not been consumed yet. #[inline] pub fn rest_mut(&mut self) -> &mut [T] { &mut self.0.as_mut_slice()[self.1..] } #[inline(always)] fn m_rest_mut(&mut self) -> &mut [std::mem::MaybeUninit] { &mut self.0.init_buffer_mut()[self.1..] } } impl std::iter::Iterator for $into_iter_name { type Item = T; fn next(&mut self) -> Option { let buf = self.0.init_buffer_mut(); if self.1 < buf.len() { (unsafe { Some(std::mem::replace(&mut buf[self.1], std::mem::MaybeUninit::uninit()).assume_init()) },self.1+=1).0 } else { None } } fn size_hint(&self) -> (usize, Option) { (self.0.len(), Some(self.0.len())) } } impl std::iter::ExactSizeIterator for $into_iter_name{} impl std::iter::FusedIterator for $into_iter_name{} impl std::ops::Drop for $into_iter_name { fn drop(&mut self) { if std::mem::needs_drop::() { unsafe { for init in self.m_rest_mut() { drop(std::mem::replace(init, std::mem::MaybeUninit::uninit()).assume_init()); } } self.0.1=0; //prevent StackVec$n from trying to drop anything } } } }; ($t:ty; $n:literal) => { { $crate::stack!({} type StackVecN StackVecNIntoIter $n); StackVecN::<$t>::new() } }; ($n:literal) => { { $crate::stack!({} type StackVecN StackVecNIntoIter $n); StackVecN::new() } }; } stack!(pub type StackVec1 StackVec1IntoIter 1); stack!(pub type StackVec2 StackVec2IntoIter 2); stack!(pub type StackVec4 StackVec4IntoIter 4); stack!(pub type StackVec8 StackVec8IntoIter 8); stack!(pub type StackVec16 StackVec16IntoIter 16); stack!(pub type StackVec32 StackVec32IntoIter 32); stack!(pub type StackVec64 StackVec64IntoIter 64); stack!(pub type StackVec128 StackVec128IntoIter 128); stack!(pub type StackVec256 StackVec256IntoIter 256); stack!(pub type StackVec512 StackVec512IntoIter 512); stack!(pub type StackVec1024 StackVec1024IntoIter 1024); stack!(pub type StackVec2048 StackVec2048IntoIter 2048); stack!(pub type StackVec4096 StackVec4096IntoIter 4096); fn _assert_comp() { let _svec: StackVec256 = StackVec256::new(); } #[cfg(test)] mod tests { use super::*; #[test] fn push_and_drop() { let mut sv = StackVec256::new(); sv.push(String::from("Hello")); sv.push(String::from(" ")); sv.push(String::from("world.")); sv.push(String::from("!!!")); sv.push(String::from("owo")); assert_eq!(sv.len(), 5); assert_eq!("Hello world.", sv.into_iter().take(3).collect::().as_str()); } #[test] fn conversions() { let mut sv = StackVec256::new(); assert_eq!(sv.extend_from_slice(&[vec![1usize,2],vec![3,4], vec![5,6]]), 3); assert_eq!(sv[1].iter().sum::(), 7); assert_eq!(sv.iter().flat_map(|x| x.iter()).sum::(), 1+2+3+4+5+6); let v = Vec::from(sv.clone()); assert_eq!(&v[..], &sv[..]); drop(sv); assert_eq!(v.iter().flat_map(|x| x.iter()).sum::(), 1+2+3+4+5+6); } #[test] fn write() { use std::io::Write; let mut sv = StackVec256::new(); let buf1 = [0u8; 128]; let buf2 = [1u8; 128]; sv.write_all(&buf1[..]).expect("Failed to write buf1"); sv.write_all(&buf2[..]).expect("Failed to write buf2"); assert!(sv.write_all(&buf1[..]).is_err()); assert_eq!(&sv[..buf1.len()], &buf1[..]); assert_eq!(&sv[buf1.len()..], &buf2[..]); assert_eq!(buf1.iter().chain(buf2.iter()).copied().collect::>(), sv.into_iter().collect::>()); } #[test] fn from_iterator() { let sv: StackVec256<_> = vec![1,2,3,4,5,6].into_iter().collect(); assert_eq!(sv.into_iter().sum::(), 6+5+4+3+2+1i32); let nt: StackVec256<_> = vec![ vec![1,2,3], vec![4,5,6], vec![7,8,9], ].into_iter().collect(); assert_eq!(nt.iter().flat_map(|x| x.iter()).copied().sum::(), 9+8+7+6+5+4+3+2+1); } #[test] #[should_panic] fn from_too_big() { let _sv: StackVec256<_> = vec![vec![String::from("hi")]; 257].into_iter().collect(); } #[test] fn ad_hoc() { let mut sv = stack![23]; assert_eq!(sv.cap(), 23); for x in 0..23 { sv.push(vec![x,x]); } assert_eq!(sv.len(), 23); assert_eq!(sv.into_iter().flat_map(|x| x.into_iter()).sum::(), (0..23).map(|x| x*2).sum::()); } }