commit
f043a949c5
@ -0,0 +1,3 @@
|
||||
/target
|
||||
Cargo.lock
|
||||
*~
|
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "stack-vec"
|
||||
version = "0.1.0"
|
||||
authors = ["Avril <flanchan@cumallover.me>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
@ -0,0 +1,606 @@
|
||||
|
||||
/// 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<T>`, 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::<i32>()).sum::<i32>(), (0..12).map(|x| x*x).sum::<i32>());
|
||||
/// ```
|
||||
/// # 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::<i32>(), 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<T>([::std::mem::MaybeUninit<T>; $n], usize);
|
||||
|
||||
impl<T> $name<T>
|
||||
{
|
||||
#![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<U: AsRef<[T]>>(&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<T> 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<U: AsRef<[T]>>(&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<T>] 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<T>] 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<T>]
|
||||
{
|
||||
&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<T>]
|
||||
{
|
||||
&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<T>]
|
||||
{
|
||||
&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<T>]
|
||||
{
|
||||
&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<T>; $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<T>; $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<T> ::std::ops::Drop for $name<T>
|
||||
{
|
||||
fn drop(&mut self)
|
||||
{
|
||||
if std::mem::needs_drop::<T>() {
|
||||
for init in &mut self.0[..self.1]
|
||||
{
|
||||
unsafe {
|
||||
drop(std::mem::replace(init, std::mem::MaybeUninit::uninit()).assume_init());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T> ::std::ops::DerefMut for $name<T>
|
||||
{
|
||||
#[inline] fn deref_mut(&mut self) -> &mut Self::Target
|
||||
{
|
||||
self.as_mut_slice()
|
||||
}
|
||||
}
|
||||
impl<T> ::std::ops::Deref for $name<T>
|
||||
{
|
||||
type Target = [T];
|
||||
|
||||
#[inline] fn deref(&self) -> &Self::Target
|
||||
{
|
||||
self.as_slice()
|
||||
}
|
||||
}
|
||||
impl<T> ::std::convert::AsRef<[T]> for $name<T>
|
||||
{
|
||||
#[inline] fn as_ref(&self) -> &[T]
|
||||
{
|
||||
self.as_slice()
|
||||
}
|
||||
}
|
||||
impl<T> ::std::convert::AsMut<[T]> for $name<T>
|
||||
{
|
||||
#[inline] fn as_mut(&mut self) -> &mut [T]
|
||||
{
|
||||
self.as_mut_slice()
|
||||
}
|
||||
}
|
||||
impl<T> ::std::borrow::Borrow<[T]> for $name<T>
|
||||
{
|
||||
#[inline] fn borrow(&self) -> &[T]
|
||||
{
|
||||
self.as_slice()
|
||||
}
|
||||
}
|
||||
impl<T> ::std::borrow::BorrowMut<[T]> for $name<T>
|
||||
{
|
||||
#[inline] fn borrow_mut(&mut self) -> &mut [T]
|
||||
{
|
||||
self.as_mut_slice()
|
||||
}
|
||||
}
|
||||
impl<T> ::std::fmt::Debug for $name<T>
|
||||
where T: ::std::fmt::Debug
|
||||
{
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result
|
||||
{
|
||||
write!(f, "{:?}", self.as_slice())
|
||||
}
|
||||
}
|
||||
impl<T> ::std::cmp::Eq for $name<T>
|
||||
where T: ::std::cmp::Eq{}
|
||||
impl<T,U> ::std::cmp::PartialEq<U> for $name<T>
|
||||
where T: ::std::cmp::PartialEq,
|
||||
U: AsRef<[T]>
|
||||
{
|
||||
#[inline]
|
||||
fn eq(&self, other: &U) -> bool
|
||||
{
|
||||
self.as_slice() == other.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ::std::cmp::Ord for $name<T>
|
||||
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<T, U> ::std::cmp::PartialOrd<U> for $name<T>
|
||||
where T: ::std::cmp::PartialOrd,
|
||||
U: AsRef<[T]>
|
||||
{
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &U) -> Option<std::cmp::Ordering> {
|
||||
std::cmp::PartialOrd::partial_cmp(self.as_slice(), other.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T,I: ::std::slice::SliceIndex<[T]>> std::ops::Index<I> for $name<T>
|
||||
{
|
||||
type Output = I::Output;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: I) -> &Self::Output {
|
||||
std::ops::Index::index(self.as_slice(), index)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T,I: ::std::slice::SliceIndex<[T]>> std::ops::IndexMut<I> for $name<T>
|
||||
{
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: I) -> &mut Self::Output {
|
||||
std::ops::IndexMut::index_mut(self.as_mut_slice(), index)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T> ::std::clone::Clone for $name<T>
|
||||
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<T> ::std::convert::From<$name<T>> for ::std::vec::Vec<T>
|
||||
{
|
||||
#[inline] fn from(from: $name<T>) -> Self
|
||||
{
|
||||
from.into_iter().collect()
|
||||
}
|
||||
}
|
||||
impl<T> std::default::Default for $name<T>
|
||||
{
|
||||
#[inline]
|
||||
fn default() -> Self
|
||||
{
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl<T> ::std::iter::IntoIterator for $name<T>
|
||||
{
|
||||
type Item= T;
|
||||
type IntoIter = $into_iter_name<T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter
|
||||
{
|
||||
$into_iter_name(self, 0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::io::Write for $name<u8>
|
||||
{
|
||||
fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize>
|
||||
{
|
||||
Ok(self.extend_from_slice_copy(buf))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_vectored(&mut self, bufs: &[::std::io::IoSlice<'_>]) -> ::std::io::Result<usize> {
|
||||
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<T> ::std::convert::From<[T; $n]> for $name<T>
|
||||
{
|
||||
#[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<T> as *mut T, $n);
|
||||
}
|
||||
this.1=$n;
|
||||
std::mem::forget(from);
|
||||
this
|
||||
}
|
||||
}
|
||||
impl<T> ::std::iter::FromIterator<T> for $name<T>
|
||||
{
|
||||
fn from_iter<I: IntoIterator<Item=T>>(iter: I) -> Self
|
||||
{
|
||||
let mut output = Self::new();
|
||||
for item in iter
|
||||
{
|
||||
output.push(item);
|
||||
}
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct $into_iter_name<T>($name<T>, usize);
|
||||
|
||||
impl<T> $into_iter_name<T>
|
||||
{
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub fn rest(&self) -> &[std::mem::MaybeUninit<T>]
|
||||
{
|
||||
&self.0.init_buffer()[self.1..]
|
||||
}
|
||||
pub fn rest_mut(&mut self) -> &mut [std::mem::MaybeUninit<T>]
|
||||
{
|
||||
&mut self.0.init_buffer_mut()[self.1..]
|
||||
}
|
||||
}
|
||||
impl<T> std::iter::Iterator for $into_iter_name<T>
|
||||
{
|
||||
type Item = T;
|
||||
fn next(&mut self) -> Option<Self::Item>
|
||||
{
|
||||
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<usize>)
|
||||
{
|
||||
(self.0.len(), Some(self.0.len()))
|
||||
}
|
||||
}
|
||||
impl<T> std::iter::ExactSizeIterator for $into_iter_name<T>{}
|
||||
impl<T> std::iter::FusedIterator for $into_iter_name<T>{}
|
||||
impl<T> std::ops::Drop for $into_iter_name<T>
|
||||
{
|
||||
fn drop(&mut self)
|
||||
{
|
||||
if std::mem::needs_drop::<T>() {
|
||||
unsafe {
|
||||
for init in self.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<i32> = 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::<String>().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::<usize>(), 7);
|
||||
assert_eq!(sv.iter().flat_map(|x| x.iter()).sum::<usize>(), 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::<usize>(), 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::<Vec<_>>(), sv.into_iter().collect::<Vec<_>>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_iterator()
|
||||
{
|
||||
let sv: StackVec256<_> = vec![1,2,3,4,5,6].into_iter().collect();
|
||||
assert_eq!(sv.into_iter().sum::<i32>(), 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::<i32>(), 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::<i32>(), (0..23).map(|x| x*2).sum::<i32>());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in new issue