[stack;vec]
A rust crate to use stack-allocated vectors (to improve performance and/or when there is no std)
unsafe
is used ⚠️⚠️However, it should be noted that special attention has been paid to array indices arithmetic (overflow/underflow), since they are, after all, pointers, and to memory management (no memory leaks or double frees).
The only remaining issue is Exception safety; as of v0.1.0
, a non fatal panic while drop
ping (very rare), should "only" cause memory leaks (preferable to dangling pointers).
It may thus be ill-suited for production. Use at your own risk.
Rust stack/inline arrays don't implement 2 very useful iterator-related interfaces:
IntoIterator<Item = T> for [T; n]
.into_iter()
instead of .iter().cloned()
(which, by the way, can only be used when T: Clone
, and requires cloning, which may be expensive)```rust extern crate stackvec; use ::stackvec::prelude::*;
struct NoClone { /* ... */ }
fn main () { let array: [NoClone; _] = [ /* ... */ ];
// Recollect the array into another collection: .into_iter().collect()
let set: ::std::collections::HashSet =
array()
.into_iter() // Would error if not for line 1
.collect()
;
}
```
FromIterator for [T; n]
.collect()
TryFromIterator
] trait (providing [try_collect
]).```rust extern crate stackvec; use ::stackvec::prelude::*;
fn main () { const N: usize = 7; // Attempt to collect into the array. This can fail // since there needs to be at least N elements. let array: [; N] = (3 .. 10) .trycollect() // Would error if not for line 1 .expect("Missing elements to collect") ; assert_eq!( array, [3, 4, 5, 6, 7, 8, 9], ); } ```
The reason for that is that both interfaces need a structure being able to hold
the partially iterated state: i.e., incomplete arrays. Those have (statically-allocated) memory that might not be initialized: so they are, in a way, like [Vec
]tors (except for the fact that their (initial) capacity is fixed and cannot be changed)
That's why having those nice iterator interfaces require writing down a cell-accurate memory ownership management logic very similar to [Vec
]'s : hence the [StackVec
].
By exposing the underlying [StackVec
] needed by the aformentioned interfaces, we get full access to a stack-allocated [Vec
], which can also be useful on its own, since it avoids heap allocation:
the heap is a mutable global state and in multi-threaded environments locks are involved,
it may require (slow) system allocation
[heap allocation is not always available][no_std
]
The performance gain (from using [StackVec
] instead of [Vec
]) is not always guaranteed, since:
[Vec
] is the cornerstone of Rust's std library collection and has extremely efficient code written so that LLVM can easily optimize its usage
Rust's allocator is also incredibly well optimised so the performance penalties from bins management and system allocations (and the locks in a multi-threaded environment) are quite well amortized on average.
Vec
] vs [StackVec
] basic benchmark```sh $ cargo +nightly bench --features nightly
test vecextend ... bench: 64,129 ns/iter (+/- 3,069) test vecfromiter ... bench: 65,569 ns/iter (+/- 3,761) test arrayfromiter ... bench: 358,993 ns/iter (+/- 6,916) test stackvecextend ... bench: 360,105 ns/iter (+/- 17,489) test stackvecfromiter ... bench: 369,585 ns/iter (+/- 40,894) test stackvecextendbyref ... bench: 374,226 ns/iter (+/- 11,686) test vecextendbyref ... bench: 863,362 ns/iter (+/- 32,483) ```
Add this line to your Cargo.toml
(under [dependencies]
):
toml
stackvec = "0.1.0"
stackvec
improves all the arrays with less than 1000 elements. This leads to longer compilation times. If this is an issue, and you don't really plan or using arbitrary-length arrays but at fixed multiples of 100 or powers of 2, you can depend on a "lighter" stackvec
using the following line instead:
toml
stackvec = { version="0.1.0", default-features = false }
Add this to your .rs
code:
```rust
extern crate stackvec;
use ::stackvec::prelude::*; ```
See the source files for the examples
You can run each example (example_name.rs
) with:
sh
$ cargo run --example example_name
[Documentation]
[no_std
] support
More [Vec
]-like methods