├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md ├── benches └── vec_vs_stackvec.rs ├── codecov.yml ├── examples ├── into_iter.rs ├── try_collect.rs └── try_collect_panic.rs ├── src ├── array.rs ├── error.rs ├── lib.rs ├── stackvec │ ├── mod.rs │ └── traits │ │ ├── array_into_iter.rs │ │ ├── from_iter.rs │ │ ├── into_iter.rs │ │ ├── mod.rs │ │ ├── try_from_iter.rs │ │ └── try_into.rs └── tests.rs └── tests └── basic.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | 3 | sudo: required 4 | 5 | rust: 6 | - stable 7 | - beta 8 | - nightly 9 | 10 | matrix: 11 | allow_failures: 12 | - rust: nightly 13 | 14 | addons: 15 | apt: 16 | packages: 17 | - libcurl4-openssl-dev 18 | - libelf-dev 19 | - libdw-dev 20 | - cmake 21 | - gcc 22 | - binutils-dev 23 | - libiberty-dev 24 | 25 | after_success: | 26 | wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz && 27 | tar xzf master.tar.gz && 28 | cd kcov-master && 29 | mkdir build && 30 | cd build && 31 | cmake .. && 32 | make && 33 | make install DESTDIR=../../kcov-build && 34 | cd ../.. && 35 | rm -rf kcov-master && 36 | for file in target/debug/examplerust-*[^\.d]; do mkdir -p "target/cov/$(basename $file)"; ./kcov-build/usr/local/bin/kcov --exclude-pattern=/.cargo,/usr/lib --verify "target/cov/$(basename $file)" "$file"; done && 37 | bash <(curl -s https://codecov.io/bash) && 38 | echo "Uploaded code coverage" 39 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stackvec" 3 | version = "0.2.1" 4 | authors = ["Daniel Henry-Mantilla "] 5 | 6 | description = "A crate to use stack-allocated Vectors (performance and/or no-std)" 7 | 8 | documentation = "https://docs.rs/stackvec/" 9 | homepage = "https://github.com/danielhenrymantilla/stackvec-rs" 10 | repository = "https://github.com/danielhenrymantilla/stackvec-rs" 11 | 12 | readme = "README.md" 13 | 14 | keywords = ["stack", "vec", "inline", "no-std", "performance"] 15 | 16 | categories = ["no-std", "memory-management", "rust-patterns"] 17 | 18 | license = "MIT" 19 | 20 | [dependencies] 21 | 22 | [profile.dev] 23 | debug = true 24 | opt-level = 0 25 | codegen-units = 4 26 | debug-assertions = true 27 | 28 | [profile.release] 29 | debug = false 30 | opt-level = 3 31 | lto = true 32 | debug-assertions = false 33 | overflow-checks = false 34 | 35 | [profile.bench] 36 | debug = true 37 | opt-level = 3 38 | lto = true 39 | debug-assertions = false 40 | overflow-checks = false 41 | 42 | [features] 43 | default = ["a_thousand_array_impls"] 44 | nightly = [] 45 | a_thousand_array_impls = [] 46 | 47 | [package.metadata.docs.rs] 48 | no-default-features = true 49 | features = [ "nightly", "a_thousand_array_impls" ] 50 | 51 | [badges] 52 | travis-ci = {repository = "danielhenrymantilla/stackvec-rs", branch = "master"} 53 | codecov = {repository = "danielhenrymantilla/stackvec-rs", branch = "master", service = "github"} 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Daniel Henry-Mantilla 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `[stack;vec]` 2 | 3 | **A rust crate to use stack-allocated vectors (to improve performance and/or when there is no std)** 4 | 5 | [![Repository](https://img.shields.io/badge/repository-GitHub-brightgreen.svg)][Repository] [![Latest version](https://img.shields.io/crates/v/stackvec.svg)][crates.io] [![Documentation](https://docs.rs/stackvec/badge.svg)][Documentation] 6 | 7 | [![Travis-CI Status](https://travis-ci.org/danielhenrymantilla/stackvec-rs.svg?branch=master)](https://travis-ci.org/danielhenrymantilla/stackvec-rs) 8 | [![Test code coverage](https://codecov.io/gh/danielhenrymantilla/stackvec-rs/branch/master/graph/badge.svg)](https://codecov.io/gh/danielhenrymantilla/stackvec-rs) 9 | [![License](https://img.shields.io/crates/l/stackvec.svg)](https://github.com/danielhenrymantilla/stackvec-rs#license) 10 | 11 | ## Motivation 12 | Rust [stack/inline arrays](https://doc.rust-lang.org/std/primitive.array.html) don't implement 2 very useful [iterator-related](https://doc.rust-lang.org/std/iter) [interfaces](https://doc.rust-lang.org/stable/std/iter/#traits): 13 | 14 | 1. `IntoIterator for [T; n]` 15 | 16 | * Allows using `.into_iter()` instead of `.iter().cloned()` (which, by the way, can only be used when `T: Clone`, and requires cloning, which may be expensive) 17 | * ```rust 18 | extern crate stackvec; use ::stackvec::prelude::*; 19 | 20 | fn main () 21 | { 22 | // An array of vectors (potentially expensive to clone) 23 | let vecs_array = [ 24 | vec![1, 2, 3, 4], 25 | vec![], 26 | vec![5, 6], 27 | ]; 28 | 29 | // Collect / chain all the vectors together 30 | let flattened: Vec = vecs_array 31 | .into_iter() // Needs stackvec (line 1) 32 | .flatten() 33 | .collect() 34 | ; 35 | assert_eq!(flattened, vec![1, 2, 3, 4, 5, 6]); 36 | } 37 | ``` 38 | 39 | 1. `FromIterator for [T; n]` 40 | * Allows [`collect`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect)ing into an [`array`]( 41 | https://doc.rust-lang.org/std/primitive.array.html) 42 | * Since it is unsound to have an incomplete array, the collecting fails when the iterator does not have enough elements to fill the array. Hence the new [`TryFromIterator`] trait (providing [`try_collect`]). 43 | * ```rust 44 | extern crate stackvec; use ::stackvec::prelude::*; 45 | 46 | fn main () 47 | { 48 | let array: [_; 3] = [1, 2, 3]; 49 | 50 | let doubled: [_; 3] = array 51 | .iter() 52 | .map(|&x| 2 * x) 53 | .try_collect() // Needs stackvec (line 1) 54 | .expect("Missing elements to collect") 55 | ; 56 | assert_eq!(doubled, [2, 4, 6]); 57 | } 58 | ``` 59 | 60 | The reason for that is that both interfaces need a structure being able to hold 61 | 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) 62 | 63 | That's why having those nice [iterator](https://doc.rust-lang.org/std/iter) [interfaces](https://doc.rust-lang.org/stable/std/iter/#traits) requires writing down a slot-accurate memory ownership management logic very similar to [`Vec`]'s : hence the [`StackVec`]. 64 | 65 | ### Bonus 66 | 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: 67 | 68 | * the heap is a mutable global state and in multi-threaded environments locks are involved, 69 | 70 | * it may require (slow) system allocation 71 | 72 | * [heap allocation is not always available][`no_std`] 73 | 74 | ### Disclaimer 75 | The performance gain (from using [`StackVec`] instead of [`Vec`]) is not always guaranteed, since: 76 | 77 | 1. [`Vec`] is the cornerstone of Rust's std library collection and has extremely efficient code written so that LLVM can easily optimize its usage 78 | 79 | 1. Rust's [allocator](http://smallcultfollowing.com/babysteps/blog/2014/11/14/allocators-in-rust/) 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. 80 | 81 | #### [`Vec`] vs [`StackVec`] basic benchmark 82 | ```sh 83 | $ cargo +nightly bench --features nightly 84 | 85 | test vec_extend ... bench: 64,129 ns/iter (+/- 3,069) 86 | test vec_from_iter ... bench: 65,569 ns/iter (+/- 3,761) 87 | test array_from_iter ... bench: 358,993 ns/iter (+/- 6,916) 88 | test stackvec_extend ... bench: 360,105 ns/iter (+/- 17,489) 89 | test stackvec_from_iter ... bench: 369,585 ns/iter (+/- 40,894) 90 | test stackvec_extend_by_ref ... bench: 374,226 ns/iter (+/- 11,686) 91 | test vec_extend_by_ref ... bench: 863,362 ns/iter (+/- 32,483) 92 | ``` 93 | 94 | ## Usage 95 | 96 | - Add this line to your `Cargo.toml` (under `[dependencies]`): 97 | ```toml 98 | stackvec = "0.2.1" 99 | ``` 100 | - Note: By default `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 on 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: 101 | ```toml 102 | stackvec = { version = "0.2.1", default-features = false } 103 | ``` 104 | 105 | - Add this to your `.rs` code: 106 | ```rust 107 | extern crate stackvec; 108 | 109 | use ::stackvec::prelude::*; 110 | ``` 111 | 112 | ### Examples 113 | 114 | See the [source files for the examples](https://github.com/danielhenrymantilla/stackvec-rs/tree/master/) 115 | 116 | You can run each example (`example_name.rs`) with: 117 | ```sh 118 | $ cargo run --example example_name 119 | ``` 120 | 121 | # WIP 122 | 123 | 1. [`no_std`] support 124 | 125 | 1. More [`Vec`]-like [methods](https://docs.rs/stackvec/0.2.1/stackvec/struct.StackVec.html#methods) 126 | 127 | [comment]: # (==== LINKS ====) 128 | 129 | [Repository]: https://github.com/danielhenrymantilla/stackvec-rs 130 | [Documentation]: https://docs.rs/stackvec/0.2.1/ 131 | [crates.io]: https://crates.io/crates/stackvec 132 | 133 | [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html 134 | 135 | [`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html 136 | [`into_iter`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html#tymethod.into_iter 137 | 138 | [`FromIterator`]: https://doc.rust-lang.org/std/iter/trait.FromIterator.html 139 | [`from_iter`]: https://doc.rust-lang.org/std/iter/trait.FromIterator.html#tymethod.from_iter 140 | 141 | [`StackVec`]: https://docs.rs/stackvec/0.2.1/stackvec/struct.StackVec.html 142 | 143 | [`TryFromIterator`]: https://docs.rs/stackvec/0.2.1/stackvec/trait.TryFromIterator.html 144 | [`try_collect`]: https://docs.rs/stackvec/0.2.1/stackvec/trait.TryCollect.html#method.try_collect 145 | 146 | [`no_std`]: https://doc.rust-lang.org/1.7.0/book/no-stdlib.html 147 | -------------------------------------------------------------------------------- /benches/vec_vs_stackvec.rs: -------------------------------------------------------------------------------- 1 | // $ cargo +nightly bench --features nightly 2 | #![cfg(all(test, feature = "nightly"))] 3 | #![feature(test)] 4 | 5 | extern crate stackvec; 6 | use ::stackvec::prelude::*; 7 | 8 | extern crate test; 9 | use ::test::{ 10 | Bencher, 11 | }; 12 | 13 | #[bench] 14 | fn stackvec_extend_by_ref (benchmark: &mut Bencher) 15 | { 16 | benchmark.iter(|| { 17 | for n in 0 .. (0x400 - 8) { 18 | let mut vec = StackVec::<[_; 0x400]>::new(); 19 | vec.extend( 20 | Iterator::chain( 21 | (0 .. n).map(|x| x * x), 22 | b"StackVec".iter().map(|&b| b as u16), 23 | ) 24 | .by_ref() 25 | ); 26 | } 27 | }); 28 | } 29 | 30 | #[bench] 31 | fn vec_extend_by_ref (benchmark: &mut Bencher) 32 | { 33 | benchmark.iter(|| { 34 | for n in 0 .. (0x400 - 8) { 35 | let mut vec = Vec::with_capacity(0x400); 36 | vec.extend( 37 | Iterator::chain( 38 | (0 .. n).map(|x| x * x), 39 | b"StackVec".iter().map(|&b| b as u16), 40 | ) 41 | .by_ref() 42 | ); 43 | } 44 | }); 45 | } 46 | 47 | #[bench] 48 | fn stackvec_extend (benchmark: &mut Bencher) 49 | { 50 | benchmark.iter(|| { 51 | for n in 0 .. (0x400 - 8) { 52 | let mut vec = StackVec::<[_; 0x400]>::new(); 53 | vec.extend( 54 | Iterator::chain( 55 | (0 .. n).map(|x| x * x), 56 | b"StackVec".iter().map(|&b| b as u16), 57 | ) 58 | ); 59 | } 60 | }); 61 | } 62 | 63 | #[bench] 64 | fn vec_extend (benchmark: &mut Bencher) 65 | { 66 | benchmark.iter(|| { 67 | for n in 0 .. (0x400 - 8) { 68 | let mut vec = Vec::with_capacity(0x400); 69 | vec.extend( 70 | Iterator::chain( 71 | (0 .. n).map(|x| x * x), 72 | b"StackVec".iter().map(|&b| b as u16), 73 | ) 74 | ); 75 | } 76 | }); 77 | } 78 | 79 | #[bench] 80 | fn stackvec_from_iter (benchmark: &mut Bencher) 81 | { 82 | benchmark.iter(|| { 83 | for n in 0 .. (0x400 - 8) { 84 | let _vec = StackVec::<[_; 0x400]>::from_iter( 85 | Iterator::chain( 86 | (0 .. n).map(|x| x * x), 87 | b"StackVec".iter().map(|&b| b as u16), 88 | ) 89 | ); 90 | } 91 | }); 92 | } 93 | 94 | #[bench] 95 | fn vec_from_iter (benchmark: &mut Bencher) 96 | { 97 | benchmark.iter(|| { 98 | for n in 0 .. (0x400 - 8) { 99 | let _vec = Vec::from_iter( 100 | Iterator::chain( 101 | (0 .. n).map(|x| x * x), 102 | b"StackVec".iter().map(|&b| b as u16), 103 | ) 104 | ); 105 | } 106 | }); 107 | } 108 | 109 | #[bench] 110 | fn array_from_iter (benchmark: &mut Bencher) 111 | { 112 | benchmark.iter(|| { 113 | for n in 0 .. (0x400 - 8) { 114 | let _array = <[_; 0x400]>::try_from_iter( 115 | Iterator::chain( 116 | (0 .. n).map(|x| x * x), 117 | b"StackVec".iter().map(|&b| b as u16), 118 | ) 119 | ); 120 | } 121 | }); 122 | } 123 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | # Team Yaml 2 | coverage: 3 | round: down 4 | precision: 5 5 | 6 | # Repository Yaml 7 | coverage: 8 | round: up 9 | range: 0..10 10 | 11 | # Used in Codecov after updating 12 | coverage: 13 | round: up 14 | range: 0..10 15 | precision: 5 -------------------------------------------------------------------------------- /examples/into_iter.rs: -------------------------------------------------------------------------------- 1 | // $ cargo run --example into_iter 2 | 3 | #![allow(unused_variables)] 4 | 5 | extern crate stackvec; use ::stackvec::prelude::*; 6 | 7 | fn main () 8 | { 9 | // An array of vectors (potentially expensive to clone) 10 | let vecs_array = [ 11 | vec![1, 2, 3, 4], 12 | vec![], 13 | vec![5, 6], 14 | ]; 15 | 16 | // Collect / chain all the vectors together 17 | let flattened: Vec = vecs_array 18 | .into_iter() 19 | .flatten() 20 | .collect() 21 | ; 22 | assert_eq!(flattened, vec![1, 2, 3, 4, 5, 6]); 23 | } -------------------------------------------------------------------------------- /examples/try_collect.rs: -------------------------------------------------------------------------------- 1 | // $ cargo run --example try_collect 2 | 3 | #![allow(unused_variables)] 4 | 5 | extern crate stackvec; use ::stackvec::prelude::*; 6 | 7 | fn main () 8 | { 9 | let array: [_; 3] = [1, 2, 3]; 10 | 11 | let doubled: [_; 3] = array 12 | .iter() 13 | .map(|&x| 2 * x) 14 | .try_collect() 15 | .expect("Missing elements to collect") 16 | ; 17 | assert_eq!(doubled, [2, 4, 6]); 18 | } 19 | -------------------------------------------------------------------------------- /examples/try_collect_panic.rs: -------------------------------------------------------------------------------- 1 | //! Example to see how "human-readable" the collection error message is. 2 | // $ cargo run --example try_collect_panic 3 | 4 | #![allow(unused_variables)] 5 | 6 | extern crate stackvec; use ::stackvec::prelude::*; 7 | 8 | fn main () 9 | { 10 | let array: [_; 3] = [1, 2, 3]; 11 | 12 | let doubled: [_; 5] = array 13 | .iter() 14 | .map(|&x| 2 * x) 15 | .try_collect() 16 | .expect("Missing elements to collect") 17 | ; 18 | } 19 | -------------------------------------------------------------------------------- /src/array.rs: -------------------------------------------------------------------------------- 1 | pub trait Sealed {} 2 | 3 | /// Trait to abstract over fixed-size (thus inline-able) [`array`]s. 4 | /// 5 | /// Suprisingly, neither [rust's core]( 6 | /// https://doc.rust-lang.org/core) nor its [standard library]( 7 | /// https://doc.rust-lang.org/std) provide a unified abstraction over 8 | /// fixed-size [`array`]s. Hence [this trait]. 9 | /// 10 | /// The trait is both `Sealed` and `unsafe`, to avoid it being implemented 11 | /// on non-array elements, and to remind of the implicit assumptions about 12 | /// the object's memory layout and interactions. 13 | /// 14 | /// Sadly, this means that downstream crates cannot implement [this trait], not 15 | /// even for an actual but very specific [`array`] that has not been already 16 | /// given an implementation in this crate. 17 | /// 18 | /// That's why, by [default]( 19 | /// https://doc.rust-lang.org/cargo/reference/manifest.html#rules), 20 | /// the feature `a_thousand_array_impls` is enabled: it provides 21 | /// implementations of [this trait] for **all arrays of 22 | /// [`LEN`][`Array::LEN`] `<= 1000`**. 23 | /// The reason for this is that 24 | /// [`StackVec`]s conversions to/from [`array`]s (used by 25 | /// [`array.into_iter()`][`::stackvec::traits::ArrayIntoIter`] 26 | /// and [`.try_collect()`][`::stackvec::traits::TryFromIterator`]) 27 | /// [involve / require a full `StackVec`][`::stackvec::traits::TryInto`], which 28 | /// in turn requires very fine-grained control over the [`Array::LEN`] for the 29 | /// operations to be efficient (avoid dealing with extra stuff / garbage). 30 | /// 31 | /// However, all these `impl`s come at a very steep cost at compile time and 32 | /// size, and may not be needed for those whishing to manipulate [`StackVec`]s 33 | /// without converting to/from [`array`]s. In that case, the classic 34 | /// exponentially-grown [`Array::LEN`]s for the backing [`StackVec::CAPACITY`] 35 | /// should suffice: 36 | /// 37 | /// - you may opt out of the `a_thousand_array_impls` [feature]( 38 | /// https://doc.rust-lang.org/cargo/reference/manifest.html#rules) replacing the 39 | /// `stackvec = ...` line in the `Cargo.toml` file of your project by: 40 | /// ```toml 41 | /// stackvec = { version = ... , default-features = false } 42 | /// ``` 43 | /// 44 | /// [`array`]: https://doc.rust-lang.org/std/primitive.array.html 45 | /// [this trait]: `::stackvec::Array` 46 | /// [`StackVec`]: `::stackvec::StackVec` 47 | /// [`StackVec::CAPACITY`]: `::stackvec::StackVec::CAPACITY` 48 | pub unsafe trait Array: Sealed + Sized { 49 | /// `[Item; LEN]` 50 | type Item: Sized; 51 | 52 | /// `[Item; LEN]` 53 | const LEN: usize; 54 | 55 | /// Read-only pointer to the first (`0`-th) element of the array. 56 | /// 57 | /// Used to get a pointer to the `n`-th element using [`.offset(n)`]. 58 | /// 59 | /// [`.offset(n)`]: 60 | /// https://doc.rust-lang.org/std/primitive.pointer.html#method.offset 61 | fn as_ptr ( 62 | self: &Self, 63 | ) -> *const Self::Item; 64 | 65 | /// Read-write pointer to the first (`0`-th) element of the array. 66 | /// 67 | /// Used to get a pointer to the `n`-th element using [`.offset(n)`]. 68 | /// 69 | /// [`.offset(n)`]: 70 | /// https://doc.rust-lang.org/std/primitive.pointer.html#method.offset-1 71 | fn as_mut_ptr ( 72 | self: &mut Self, 73 | ) -> *mut Self::Item; 74 | } 75 | 76 | macro_rules! impl_array { 77 | ($N:expr) => ( 78 | impl Sealed for [T; $N] {} 79 | unsafe impl Array for [T; $N] { 80 | type Item = T; 81 | 82 | const LEN: usize = $N; 83 | 84 | #[inline(always)] 85 | fn as_ptr ( 86 | self: &Self, 87 | ) -> *const Self::Item 88 | { 89 | <[Self::Item]>::as_ptr(self) 90 | } 91 | 92 | #[inline(always)] 93 | fn as_mut_ptr ( 94 | self: &mut Self, 95 | ) -> *mut Self::Item 96 | { 97 | <[Self::Item]>::as_mut_ptr(self) 98 | } 99 | } 100 | ) 101 | } 102 | 103 | macro_rules! impl_arrays { 104 | ( 105 | $($N:expr,)* 106 | ) => ( 107 | $( impl_array!($N); )* 108 | ) 109 | } 110 | 111 | // Top 100 112 | impl_arrays! { 113 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 114 | 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 115 | 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 116 | 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 117 | 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 118 | 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 119 | 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 120 | 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 121 | 96, 97, 98, 99, 100, 122 | } 123 | 124 | // 100 < ... <= 1000 (sparse) 125 | #[cfg(not(feature = "a_thousand_array_impls"))] 126 | impl_arrays! { 127 | 200, 256, 300, 400, 500, 512, 600, 700, 800, 900, 1000, 128 | } 129 | 130 | // 1024 and onwards 131 | impl_arrays! { 132 | 0x400, 0x800, 0x1000, 0x2000, 0x4000, 133 | 0x600, 0xc00, 0x1800, 0x3000, 134 | } 135 | 136 | // 100 < ... <= 1000 (full) 137 | #[cfg(feature = "a_thousand_array_impls")] 138 | impl_arrays! { 139 | 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 140 | 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 141 | 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 142 | 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 143 | 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 144 | 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 145 | 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 146 | 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 147 | 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 148 | 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 149 | 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 150 | 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 151 | 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 152 | 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 153 | 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 154 | 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 155 | 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 156 | 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 157 | 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 158 | 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 159 | 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 160 | 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 161 | 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 162 | 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 163 | 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 164 | 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 165 | 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 166 | 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 167 | 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 168 | 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 169 | 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 170 | 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 171 | 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 172 | 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 173 | 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 174 | 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 175 | 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 176 | 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 177 | 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 178 | 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 179 | 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 180 | 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 181 | 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 182 | 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 183 | 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 184 | 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 185 | 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 186 | 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 187 | 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 188 | 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 189 | 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 190 | 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 191 | 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 192 | 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 193 | 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 194 | 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 195 | 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 196 | 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 197 | 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 198 | 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 199 | 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 200 | 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 201 | 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 202 | 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 203 | 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 204 | 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 205 | 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 206 | 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 207 | 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 208 | 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 209 | 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 210 | 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 211 | 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 212 | 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 213 | 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 214 | } 215 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | //! The crate's [errors][`::std::error::Error`]. 2 | 3 | use super::*; 4 | 5 | use ::std::error::Error; 6 | 7 | /// Error returned by [`StackVec::try_push`][`::stackvec::StackVec::try_push] 8 | /// method. 9 | #[derive(Clone, Copy, Debug)] 10 | pub struct OutOfCapacityError(pub T); 11 | 12 | impl fmt::Display for OutOfCapacityError { 13 | fn fmt ( 14 | self: &Self, 15 | stream: &mut fmt::Formatter, 16 | ) -> fmt::Result 17 | { 18 | fmt::Display::fmt( 19 | "Attempted to add an element to a full StackVec", 20 | stream 21 | ) 22 | } 23 | } 24 | 25 | impl ::std::error::Error for OutOfCapacityError { 26 | fn description ( 27 | self: &Self, 28 | ) -> &str 29 | { 30 | "Attempted to add an element to a full StackVec" 31 | } 32 | } 33 | 34 | 35 | /// Error returned by 36 | /// [`StackVec::try_into`][`::stackvec::traits::TryInto::try_into] 37 | /// method. 38 | #[derive(Clone, Copy, Debug)] 39 | pub struct IncompleteArrayError; 40 | 41 | impl fmt::Display for IncompleteArrayError { 42 | fn fmt ( 43 | self: &Self, 44 | stream: &mut fmt::Formatter, 45 | ) -> fmt::Result 46 | { 47 | fmt::Display::fmt(self.description(), stream) 48 | } 49 | } 50 | 51 | impl ::std::error::Error for IncompleteArrayError { 52 | fn description ( 53 | self: &Self, 54 | ) -> &str 55 | { 56 | concat!( 57 | "Cannot build an incomplete array.", 58 | ) 59 | } 60 | } 61 | 62 | /// Error used generic-wise to extend fake fallible operations from unfallible 63 | /// ones. 64 | #[derive(Debug)] 65 | pub enum UnreachableError {} 66 | 67 | impl UnreachableError { 68 | /// This error is unconstructible and can thus safely be seen as anything. 69 | pub fn unreachable (&self) -> ! { match *self {} } 70 | } 71 | 72 | impl fmt::Display for UnreachableError { 73 | fn fmt (&self, _: &mut fmt::Formatter) -> fmt::Result { 74 | self.unreachable() 75 | } 76 | } 77 | 78 | impl ::std::error::Error for UnreachableError { 79 | fn description (&self) -> &str { 80 | self.unreachable() 81 | } 82 | } -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc(test(attr(deny(warnings))))] 2 | #![doc(test(attr(allow(unused_variables))))] 3 | #![warn(missing_docs)] 4 | #![doc(html_root_url = "https://docs.rs/stackvec/0.1.1")] 5 | 6 | #![cfg_attr(feature = "nightly", 7 | feature(trusted_len, exact_size_is_empty) 8 | )] 9 | 10 | // #![cfg_attr(feature = "nightly", 11 | // feature(try_from) 12 | // )] 13 | 14 | #![cfg_attr(feature = "nightly", 15 | feature(external_doc) 16 | )] 17 | #![cfg_attr(feature = "nightly", 18 | doc(include = "../README.md") 19 | )] 20 | #![cfg_attr(not(feature = "nightly"), 21 | doc = "See [crates.io](https://crates.io/crates/stackvec)" 22 | )] 23 | #![cfg_attr(not(feature = "nightly"), 24 | doc = "for more info about this crate." 25 | )] 26 | 27 | use ::std::*; 28 | 29 | /// Module to bring the most important items into scope 30 | /// ```rust 31 | /// # #![allow(unused_imports)] 32 | /// extern crate stackvec; use ::stackvec::prelude::*; 33 | /// ``` 34 | pub mod prelude { 35 | pub use super::{ 36 | StackVec, 37 | ArrayIntoIter, 38 | TryInto, 39 | TryFromIterator, 40 | TryCollect, 41 | }; 42 | 43 | pub use ::std::iter::FromIterator; 44 | } 45 | 46 | pub use self::array::Array; 47 | mod array; 48 | 49 | pub mod error; 50 | use self::error::*; 51 | 52 | mod stackvec; 53 | pub use self::stackvec::*; 54 | pub use self::into_iter::Iter as IntoIter; 55 | 56 | #[cfg(test)] 57 | mod tests; 58 | -------------------------------------------------------------------------------- /src/stackvec/mod.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | pub use self::traits::*; 4 | mod traits; 5 | 6 | /// Like a [`Vec`], but inlined / "stored in the stack" 7 | /// 8 | /// It is backed by a partially uninitialised [`array`], that keeps track of 9 | /// its initialised / uninitialised slots by using a `len: usize` field. 10 | /// 11 | /// **Its capacity is the length of the backing [`array`]**, and is thus 12 | /// (statically) fixed within its type: see [the `Array` trait]. 13 | /// Only an [`array`] that implements [the `Array` trait] can be used as a 14 | /// backing array. 15 | /// 16 | /// It can be constructed: 17 | /// 18 | /// - either by hand with [its constructor][`StackVec::new`]: 19 | /// ```rust 20 | /// # use ::stackvec::prelude::*; 21 | /// let empty_vec: StackVec<[i32; 16]> 22 | /// = Default::default(); 23 | /// assert_eq!( 24 | /// empty_vec.as_slice(), 25 | /// &[], 26 | /// ); 27 | /// ``` 28 | /// 29 | /// - or by [collecting][`Iterator::collect`] 30 | /// an [iterable][`iter::IntoIterator`]: 31 | /// ```rust 32 | /// # use ::stackvec::prelude::*; 33 | /// let vec: StackVec<[i32; 16]> 34 | /// = (0 .. 5) 35 | /// .filter(|&x| x % 2 == 0) 36 | /// .map(|x| x * x) 37 | /// .collect(); 38 | /// assert_eq!( 39 | /// vec.as_slice(), 40 | /// &[0, 4, 16], 41 | /// ); 42 | /// ``` 43 | /// 44 | /// [`array`]: https://doc.rust-lang.org/std/primitive.array.html 45 | /// [the `Array` trait]: `stackvec::Array` 46 | pub struct StackVec { 47 | array: mem::ManuallyDrop, 48 | len: usize, 49 | } 50 | 51 | impl Default for StackVec { 52 | /// Default constructor: new empty [`StackVec`] 53 | #[inline(always)] 54 | fn default () -> Self 55 | { 56 | debug_assert!(Self::CAPACITY <= isize::MAX as usize); 57 | StackVec { 58 | len: 0, 59 | array: mem::ManuallyDrop::new(unsafe { mem::uninitialized() }), 60 | } 61 | } 62 | } 63 | 64 | impl StackVec { 65 | /// The (statically) fixed capacity of the [`StackVec`] 66 | pub const CAPACITY: usize = A::LEN; 67 | 68 | /// The (statically) fixed capacity of the [`StackVec`] 69 | #[inline] 70 | pub fn capacity (&self) -> usize { Self::CAPACITY } 71 | 72 | /// Constructor: alias for [`Stackvec::default`]( 73 | /// struct.StackVec.html#impl-Default) 74 | #[inline(always)] 75 | pub fn new () -> Self 76 | { 77 | Self::default() 78 | } 79 | 80 | /// Attempts to push a `value` into the [`StackVec`]. 81 | /// 82 | /// If it is full, it fails returning the given `value` wrapped in 83 | /// a `Err(OutOfCapacityError(value))` 84 | #[inline] 85 | pub fn try_push ( 86 | self: &mut Self, 87 | value: A::Item, 88 | ) -> Result<(), OutOfCapacityError> 89 | { 90 | debug_assert!(self.len <= Self::CAPACITY); 91 | if self.len == Self::CAPACITY { 92 | Err(OutOfCapacityError(value)) 93 | } else { 94 | unsafe { 95 | self.push_unchecked(value) 96 | }; 97 | Ok(()) 98 | } 99 | } 100 | 101 | /// Pushes the given `value` into the [`StackVec`] if there is room for it, 102 | /// else it does nothing. 103 | /// 104 | /// This has the same semantics as 105 | /// `let _ = stackvec.try_push(value);` 106 | /// but may be more efficient. 107 | #[inline] 108 | pub fn push_or_ignore ( 109 | self: &mut Self, 110 | value: A::Item, 111 | ) 112 | { 113 | debug_assert!(self.len <= Self::CAPACITY); 114 | if self.len < Self::CAPACITY { 115 | unsafe { self.push_unchecked(value) } 116 | }; 117 | } 118 | 119 | /// Pushes the given `value` 120 | /// into the [`StackVec`], without any kind of bound-checking whatsoever. 121 | /// 122 | /// This is generally not recommended, use with caution! 123 | /// 124 | /// For a safe alternative use 125 | /// [`self.try_push().expect("stackvec cannot be full")`] 126 | /// [`StackVec::try_push`] 127 | /// 128 | /// # Safety 129 | /// 130 | /// The assertion that `stackvec.len() < stackvec.capacity()` must hold 131 | /// for the operation to be safe. 132 | #[inline] 133 | pub unsafe fn push_unchecked ( 134 | self: &mut Self, 135 | value: A::Item, 136 | ) 137 | { 138 | debug_assert!(self.len < Self::CAPACITY); // implicit assertion 139 | ptr::write( 140 | self.array.as_mut_ptr() 141 | .offset(self.len as isize), 142 | value, 143 | ); 144 | self.len += 1; 145 | } 146 | 147 | /// Removes `value` and returns `Some(value)`, where `value` is the last 148 | /// element of the non-empty [`StackVec`], else it just returns `None`. 149 | #[inline] 150 | pub fn pop ( 151 | self: &mut Self, 152 | ) -> Option 153 | { 154 | debug_assert!(self.len <= Self::CAPACITY); 155 | if self.len > 0 { 156 | self.len -= 1; 157 | Some( 158 | unsafe { 159 | ptr::read( 160 | self.array.as_ptr() 161 | .offset(self.len as isize), 162 | ) 163 | } 164 | ) 165 | } else { 166 | None 167 | } 168 | } 169 | 170 | /// Shortens the [`StackVec`], keeping the first `new_len` elements and 171 | /// dropping the rest. 172 | /// 173 | /// If `new_len` is greater than the current length, this has no effect. 174 | /// 175 | /// This has the same semantics as 176 | /// `(new_len .. stackvec.len()).for_each(|_| { stackvec.pop(); })` 177 | /// but may be more efficient. 178 | #[inline] 179 | pub fn truncate ( 180 | self: &mut Self, 181 | new_len: usize, 182 | ) 183 | { 184 | for new_len in Iterator::rev(new_len .. self.len) { 185 | self.len = new_len; 186 | unsafe { 187 | ptr::drop_in_place( 188 | self.array.as_mut_ptr() 189 | .offset(new_len as isize) 190 | ); 191 | }; 192 | }; 193 | } 194 | 195 | /// Clears the [`StackVec`], removing all the values. 196 | /// 197 | /// This is exactly the same as `stackvec.truncate(0)`. 198 | #[inline] 199 | pub fn clear ( 200 | self: &mut Self, 201 | ) 202 | { 203 | self.truncate(0) 204 | } 205 | 206 | /// Extracts a slice containing the entire [`StackVec`]. 207 | /// 208 | /// Equivalent to `&stackvec[..]`. 209 | #[inline] 210 | pub fn as_slice ( 211 | self: &Self, 212 | ) -> &[A::Item] 213 | { 214 | &* self 215 | } 216 | 217 | /// Extracts a mutable slice of the entire [`StackVec`]. 218 | /// 219 | /// Equivalent to `&mut stackvec[..]`. 220 | #[inline] 221 | pub fn as_mut_slice ( 222 | self: &mut Self, 223 | ) -> &mut [A::Item] 224 | { 225 | &mut* self 226 | } 227 | 228 | /// Returns `true` iff the [`StackVec`] is empty 229 | /// (`self.len() == 0`) 230 | #[inline] 231 | pub fn is_empty ( 232 | self: &Self, 233 | ) -> bool 234 | { 235 | self.len() == 0 236 | } 237 | 238 | /// Returns `true` iff the [`StackVec`] is full 239 | /// (`self.len() == self.capacity()`) 240 | #[inline] 241 | pub fn is_full ( 242 | self: &Self, 243 | ) -> bool 244 | { 245 | debug_assert!(self.len <= Self::CAPACITY); 246 | self.len() == Self::CAPACITY 247 | } 248 | 249 | /// Fills the [`StackVec`] with the different values created by the 250 | /// given `factory`. 251 | /// 252 | /// # Examples 253 | /// 254 | /// ```rust 255 | /// # use ::stackvec::prelude::*; 256 | /// let vec = StackVec::<[Option; 64]>:: 257 | /// default() 258 | /// .fill_using(|| None); 259 | /// ``` 260 | /// 261 | /// ```rust 262 | /// # use ::stackvec::prelude::*; 263 | /// let vec = StackVec::<[String; 64]>:: 264 | /// default() 265 | /// .fill_using(Default::default); 266 | /// ``` 267 | /// 268 | /// ```rust 269 | /// # use ::stackvec::prelude::*; 270 | /// let s = String::from("!"); 271 | /// let vec = StackVec::<[String; 64]>:: 272 | /// from_iter( 273 | /// ["Hello", "world"] 274 | /// .into_iter() 275 | /// .map(String::from) 276 | /// ).fill_using(|| s.clone()); 277 | /// ``` 278 | /// 279 | /// See [`StackVec::try_into::`][`stackvec::traits::TryInto`] 280 | /// for more detailed examples. 281 | #[inline] 282 | pub fn fill_using ( 283 | self: &mut Self, 284 | factory: impl FnMut() -> A::Item, 285 | ) 286 | { 287 | self.extend( 288 | iter::repeat_with(factory) 289 | ) 290 | } 291 | } 292 | 293 | impl StackVec 294 | where 295 | A::Item: Copy, 296 | { 297 | /// Fills the [`StackVec`] with [copies][`Copy`] of the given `value`. 298 | /// 299 | /// # Example 300 | /// ```rust 301 | /// # use ::stackvec::prelude::*; 302 | /// let vec = StackVec::<[&'static str; 64]>:: 303 | /// from_iter( 304 | /// ["Hello", "world"] 305 | /// .into_iter() 306 | /// ).fill_with("!"); 307 | /// ``` 308 | #[inline] 309 | pub fn fill_with ( 310 | self: &mut Self, 311 | value: A::Item, 312 | ) 313 | { 314 | self.extend( 315 | iter::repeat(value) 316 | ) 317 | } 318 | } 319 | 320 | impl Drop for StackVec { 321 | #[inline] 322 | fn drop ( 323 | self: &mut Self, 324 | ) 325 | { 326 | self.clear() 327 | } 328 | } 329 | 330 | impl ops::Deref for StackVec { 331 | type Target = [A::Item]; 332 | 333 | #[inline] 334 | fn deref ( 335 | self: &Self, 336 | ) -> &Self::Target 337 | { 338 | unsafe { 339 | slice::from_raw_parts( 340 | self.array.as_ptr(), 341 | self.len, 342 | ) 343 | } 344 | } 345 | } 346 | 347 | impl ops::DerefMut for StackVec { 348 | #[inline] 349 | fn deref_mut ( 350 | self: &mut Self, 351 | ) -> &mut Self::Target 352 | { 353 | unsafe { 354 | slice::from_raw_parts_mut( 355 | self.array.as_mut_ptr(), 356 | self.len, 357 | ) 358 | } 359 | } 360 | } 361 | 362 | impl fmt::Debug for StackVec 363 | where 364 | A::Item: fmt::Debug, 365 | { 366 | fn fmt ( 367 | self: &Self, 368 | stream: &mut fmt::Formatter, 369 | ) -> fmt::Result 370 | { 371 | try!(fmt::Display::fmt("[", stream)); 372 | let mut iterator = self.iter(); 373 | if let Some(first) = iterator.next() { 374 | try!(fmt::Debug::fmt(first, stream)); 375 | for x in iterator { 376 | try!(write!(stream, ", {:?}", x)); 377 | }; 378 | }; 379 | fmt::Display::fmt("]", stream) 380 | } 381 | } 382 | -------------------------------------------------------------------------------- /src/stackvec/traits/array_into_iter.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl From for StackVec 4 | { 5 | #[inline(always)] 6 | fn from ( 7 | array: A, 8 | ) -> StackVec 9 | { 10 | StackVec { 11 | array: mem::ManuallyDrop::new(array), 12 | len: A::LEN, 13 | } 14 | } 15 | } 16 | 17 | /// Grants [`Array`]s an [`.into_iter()`][`ArrayIntoIter::into_iter`] 18 | /// method to almost seamlessly use [`array`]s 19 | /// as [by-owned-value iterators][`IntoIterator`]. 20 | /// 21 | /// # Example 22 | /// ```rust 23 | /// # use ::stackvec::prelude::*; 24 | /// let array: [_; 2] = [ 25 | /// vec![1, 2, 3, 4], 26 | /// vec![5, 6], 27 | /// ]; 28 | /// let flattened: Vec = array 29 | /// .into_iter() 30 | /// .flatten() 31 | /// .collect(); 32 | /// assert_eq!(flattened, &[1, 2, 3, 4, 5, 6]); 33 | /// ``` 34 | /// 35 | /// [`array`]: https://doc.rust-lang.org/std/primitive.array.html 36 | pub trait ArrayIntoIter: Array { 37 | /// Consumes the given [`Array`] and its contents and returns a 38 | /// [by-owned-value iterator][`IntoIterator`]. 39 | #[inline(always)] 40 | fn into_iter ( 41 | self: Self, 42 | ) -> crate::IntoIter 43 | { 44 | StackVec::from(self).into_iter() 45 | } 46 | } 47 | impl ArrayIntoIter for A {} 48 | 49 | #[cfg(test)] 50 | mod tests { 51 | use crate::prelude::*; 52 | 53 | #[derive(PartialEq, Eq, Hash)] 54 | struct NoClone; 55 | 56 | #[test] 57 | fn array_into_iter () 58 | { 59 | let array = [NoClone, NoClone, NoClone, NoClone]; 60 | let set = ::std::collections::HashSet::::from_iter( 61 | array.into_iter() 62 | ); 63 | assert!(!set.is_empty()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/stackvec/traits/from_iter.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl iter::Extend for StackVec { 4 | #[inline] 5 | fn extend> ( 6 | self: &mut Self, 7 | iterable: Iterable, 8 | ) 9 | { 10 | // This is currently the most optimized `extend` implementation, 11 | // branching-prediction-wise 12 | let mut len = self.len; 13 | debug_assert!(len <= Self::CAPACITY); 14 | if len == Self::CAPACITY { 15 | return 16 | }; 17 | unsafe { 18 | for value in iterable { 19 | debug_assert!(len < Self::CAPACITY); 20 | ptr::write( 21 | self.array.as_mut_ptr() 22 | .offset(len as isize), 23 | value, 24 | ); 25 | len += 1; 26 | self.len = len; 27 | if len == Self::CAPACITY { break }; 28 | }; 29 | }; 30 | 31 | // // This version was less optimized: 32 | // let mut iterator = iterable.into_iter(); 33 | // let mut len = self.len; 34 | // while len < Self::CAPACITY { 35 | // if let Some(value) = iterator.next() { 36 | // unsafe { 37 | // ptr::write( 38 | // self.array.as_mut_ptr() 39 | // .offset(len as isize), 40 | // value, 41 | // ); 42 | // len += 1; 43 | // } 44 | // } else { 45 | // break 46 | // }; 47 | // }; 48 | // self.len = len; 49 | 50 | // // And this one even worse o_O 51 | // iterable.into_iter() 52 | // .take(Self::CAPACITY - self.len) 53 | // .for_each(|value| unsafe { 54 | // self.push_unchecked(value) 55 | // }) 56 | } 57 | } 58 | 59 | impl iter::FromIterator for StackVec { 60 | #[inline(always)] 61 | fn from_iter> ( 62 | iterable: Iterable, 63 | ) -> Self 64 | { 65 | let mut slf = Self::new(); 66 | slf.extend(iterable); 67 | slf 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/stackvec/traits/into_iter.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | /// An iterator that moves out of a [`StackVec`]. 4 | /// 5 | /// This `struct` is created by the `into_iter` method (provided 6 | /// by the [`IntoIterator`] trait). 7 | pub struct Iter { 8 | stackvec: StackVec, 9 | start: usize, 10 | } 11 | 12 | impl Drop for Iter { 13 | fn drop ( 14 | self: &mut Self, 15 | ) 16 | { 17 | let len = self.stackvec.len; 18 | self.stackvec.len = 0; 19 | for i in self.start .. len { 20 | unsafe { 21 | ptr::drop_in_place( 22 | self.stackvec 23 | .array.as_mut_ptr() 24 | .offset(i as isize) 25 | ); 26 | }; 27 | }; 28 | } 29 | } 30 | 31 | impl Iterator for Iter { 32 | type Item = A::Item; 33 | 34 | #[inline] 35 | fn next ( 36 | self: &mut Self, 37 | ) -> Option 38 | { 39 | let start = self.start; 40 | if start < self.stackvec.len { 41 | self.start = start + 1; 42 | Some(unsafe { 43 | ptr::read( 44 | self.stackvec 45 | .array.as_ptr() 46 | .offset(start as isize), 47 | ) 48 | }) 49 | } else { 50 | None 51 | } 52 | } 53 | 54 | #[inline] 55 | fn size_hint ( 56 | self: &Self, 57 | ) -> (usize, Option) 58 | { 59 | let size = self.stackvec.len - self.start; 60 | (size, Some(size)) 61 | } 62 | } 63 | 64 | impl iter::FusedIterator for Iter {} 65 | 66 | #[cfg(feature = "nightly")] 67 | unsafe impl iter::TrustedLen for Iter {} 68 | 69 | impl ExactSizeIterator for Iter { 70 | #[inline] 71 | fn len ( 72 | self: &Self, 73 | ) -> usize 74 | { 75 | self.stackvec.len - self.start 76 | } 77 | 78 | #[cfg(feature = "nightly")] 79 | #[inline] 80 | fn is_empty ( 81 | self: &Self, 82 | ) -> bool 83 | { 84 | self.stackvec.len == self.start 85 | } 86 | } 87 | 88 | impl DoubleEndedIterator for Iter { 89 | #[inline] 90 | fn next_back ( 91 | self: &mut Self, 92 | ) -> Option 93 | { 94 | let last = self.stackvec.len.saturating_sub(1); 95 | if self.start <= last { 96 | self.stackvec.len = last; 97 | Some(unsafe { 98 | ptr::read( 99 | self.stackvec 100 | .array.as_ptr() 101 | .offset(last as isize), 102 | ) 103 | }) 104 | } else { 105 | None 106 | } 107 | 108 | } 109 | } 110 | 111 | impl IntoIterator for StackVec { 112 | type Item = A::Item; 113 | 114 | type IntoIter = Iter; 115 | 116 | #[inline(always)] 117 | fn into_iter ( 118 | self: Self, 119 | ) -> Self::IntoIter 120 | { 121 | Iter { 122 | stackvec: self, 123 | start: 0, 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/stackvec/traits/mod.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl Eq for StackVec 4 | where 5 | A::Item : Eq, 6 | {} 7 | 8 | impl PartialEq for StackVec 9 | where 10 | A::Item : PartialEq, 11 | { 12 | #[inline(always)] 13 | fn eq ( 14 | self: &Self, 15 | other: &Self, 16 | ) -> bool 17 | { 18 | self.as_slice().eq(other.as_slice()) 19 | } 20 | } 21 | 22 | impl hash::Hash for StackVec 23 | where 24 | A::Item : hash::Hash, 25 | { 26 | fn hash ( 27 | self: &Self, 28 | state: &mut H, 29 | ) 30 | { 31 | self.as_slice().hash(state) 32 | } 33 | } 34 | 35 | impl Clone for StackVec 36 | where 37 | A::Item : Clone, 38 | { 39 | fn clone ( 40 | self: &Self, 41 | ) -> Self 42 | { 43 | self.iter().cloned().collect() 44 | } 45 | } 46 | 47 | mod from_iter; 48 | 49 | pub(in crate) 50 | mod into_iter; 51 | 52 | pub use self::array_into_iter::*; 53 | mod array_into_iter; 54 | 55 | pub use self::try_into::*; 56 | mod try_into; 57 | 58 | pub use self::try_from_iter::*; 59 | mod try_from_iter; 60 | -------------------------------------------------------------------------------- /src/stackvec/traits/try_from_iter.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | use self::iter::FromIterator; 4 | 5 | use self::try_into::TryInto; 6 | 7 | /// Fallible conversion from an [`Iterable`][`IntoIterator`]. 8 | /// 9 | /// By implementing [`TryFromIterator`] for a type, you define how it will be 10 | /// created from an [`Iterable`][`IntoIterator`]. 11 | /// This is common for types which describe a collection of some kind. 12 | /// 13 | /// [`TryFromIterator`]'s 14 | /// [`try_from_iter`][`::stackvec::traits::TryFromIterator::try_from_iter`] 15 | /// is rarely called explicitly, and is instead 16 | /// used through [`Iterator`]'s [`try_collect`] method. 17 | /// 18 | /// See also: [`IntoIterator`]. 19 | /// 20 | /// [`try_collect`]: `::stackvec::traits::TryCollect::try_collect` 21 | pub trait TryFromIterator: Sized { 22 | /// The type returned in the event of a conversion error. 23 | type Error: ::std::error::Error; 24 | 25 | /// Attempts to perform the conversion. 26 | fn try_from_iter> ( 27 | iterable: Iterable 28 | ) -> Result; 29 | } 30 | 31 | /// [`Iterator`][`Iterator`] [extension trait]( 32 | /// https://users.rust-lang.org/t/supertraits-vs-generic-implementations/21266) 33 | /// to extend [`Iterator`]s with a 34 | /// [`.try_collect()`][::stackvec::traits::TryCollect::try_collect] method. 35 | /// 36 | /// # Example 37 | /// 38 | /// ```rust 39 | /// extern crate stackvec; 40 | /// 41 | /// use ::stackvec::prelude::*; // Needed to bring `.try_collect()` into scope. 42 | /// 43 | /// fn main () 44 | /// { 45 | /// let array: [_; 3] = [1, 2, 3]; 46 | /// 47 | /// let doubled: [_; 3] = array 48 | /// .iter() 49 | /// .map(|&x| 2 * x) 50 | /// .try_collect() 51 | /// .expect("Missing elements to collect") 52 | /// ; 53 | /// assert_eq!(doubled, [2, 4, 6]); 54 | /// } 55 | /// ``` 56 | pub trait TryCollect: Iterator + Sized { 57 | /// Fallible version of [`collect`][`Iterator::collect`] 58 | #[inline(always)] 59 | fn try_collect ( 60 | self: Self, 61 | ) -> Result 62 | where 63 | Collection: TryFromIterator, 64 | { 65 | Collection::try_from_iter(self) 66 | } 67 | } 68 | impl TryCollect for T {} 69 | 70 | // pub enum Unreachable {} 71 | 72 | // impl fmt::Display for Unreachable { 73 | // fn fmt (&self, _: &mut fmt::Formatter) -> fmt::Result { 74 | // unreachable!() 75 | // } 76 | // } 77 | // impl fmt::Debug for Unreachable { 78 | // fn fmt (&self, _: &mut fmt::Formatter) -> fmt::Result { 79 | // unreachable!() 80 | // } 81 | // } 82 | // impl ::std::error::Error for Unreachable {} 83 | 84 | // impl> TryFromIterator for T { 85 | // type Error = Unreachable; 86 | 87 | // #[inline(always)] 88 | // fn try_from_iter> ( 89 | // iterable: Iterable, 90 | // ) -> Result 91 | // { 92 | // Ok(Self::from_iter(iterable)) 93 | // } 94 | // } 95 | 96 | impl TryFromIterator for A { 97 | type Error = as super::try_into::TryInto>::Error; 98 | 99 | #[inline(always)] 100 | fn try_from_iter> ( 101 | iterable: Iterable, 102 | ) -> Result 103 | { 104 | let stackvec = StackVec::from_iter(iterable); 105 | stackvec.try_into() 106 | } 107 | } 108 | 109 | #[cfg(test)] 110 | mod tests { 111 | use crate::prelude::*; 112 | 113 | #[test] 114 | fn it_works_with_enough_elements () 115 | { 116 | let array: [_; 15] = 117 | (0 .. 15) 118 | .try_collect() 119 | .expect("Missing elements to collect"); 120 | assert_eq!( 121 | array, 122 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], 123 | ) 124 | } 125 | 126 | #[test] 127 | #[should_panic] 128 | fn it_fails_with_missing_elements () 129 | { 130 | let _: [_; 15] = 131 | (0 .. 10) 132 | .try_collect() 133 | .expect("Missing elements to collect"); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/stackvec/traits/try_into.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | // #[cfg(feature = "nightly")] 4 | // pub use std::convert::TryInto; 5 | // #[cfg(not(feature = "nightly"))] 6 | 7 | /// An attempted conversion that consumes `self`, 8 | /// which may or may not be expensive. 9 | pub trait TryInto { 10 | /// The type returned in the event of a conversion error. 11 | type Error: ::std::error::Error; 12 | 13 | /// Attempts to perform the conversion. 14 | fn try_into ( 15 | self: Self 16 | ) -> Result; 17 | } 18 | 19 | /// Try to promote a [`StackVec`] to a full [`array`] 20 | /// 21 | /// # Example 22 | /// ``` 23 | /// # use ::stackvec::prelude::*; 24 | /// /// Objective: build an array of `Option` 25 | /// /// [Some("Hello"), Some("world!"), None, None, ... , None] 26 | /// type Array = [Option; 64]; 27 | /// 28 | /// // Since `String` is not `Copy`, `None: Option` isn't either. 29 | /// // Thus, sadly, we cannot do: 30 | /// // let mut array: Array = [None; 64]; 31 | /// // array[0] = Some(String::from("Hello")); 32 | /// // array[1] = Some(String::from("world!")); 33 | /// 34 | /// let mut vec: StackVec 35 | /// = ["Hello", "world!"] // First 2 values 36 | /// .iter() 37 | /// .map(|&x| Some(String::from(x))) 38 | /// .collect(); 39 | /// 40 | /// assert_eq!(vec[0].as_ref().unwrap(), "Hello"); 41 | /// assert_eq!(vec[1].as_ref().unwrap(), "world!"); 42 | /// 43 | /// assert!(vec.len() < vec.capacity()); // not full 44 | /// // Thus it can't be converted to an array yet 45 | /// // let array: Array = vec.try_into().unwrap(); // conversion would fail 46 | /// 47 | /// vec.fill_using(|| None); // Fill with `None`s 48 | /// assert_eq!(vec.len(), vec.capacity()); // now it is full 49 | /// let array: Array = vec.try_into().unwrap(); // conversion can now be successful 50 | /// ``` 51 | /// 52 | /// ``` 53 | /// # use ::stackvec::prelude::*; 54 | /// /// Objective: build an array of `String` 55 | /// /// ["Hello", "world!", "", "", ... , ""] 56 | /// type Array = [String; 64]; 57 | /// 58 | /// let mut vec: StackVec 59 | /// = ["Hello", "world!"] // First 2 values 60 | /// .into_iter() 61 | /// .map(String::from) 62 | /// .collect(); 63 | /// 64 | /// assert_eq!(vec[0], "Hello"); 65 | /// assert_eq!(vec[1], "world!"); 66 | /// 67 | /// assert!(vec.len() < vec.capacity()); // not full 68 | /// // Thus it can't be converted to an array yet 69 | /// // let array: Array = vec.try_into().unwrap(); // conversion would fail 70 | /// 71 | /// let end = String::from(""); 72 | /// vec.fill_using(|| end.clone()); // Fill with clones 73 | /// // or 74 | /// // vec.fill_using(Default::default); // Fill with default value 75 | /// 76 | /// assert_eq!(vec.len(), vec.capacity()); // now it is full 77 | /// let array: Array = vec.try_into().unwrap(); // conversion can now be successful 78 | /// ``` 79 | /// 80 | /// [`array`]: https://doc.rust-lang.org/std/primitive.array.html 81 | impl TryInto for StackVec 82 | { 83 | type Error = IncompleteArrayError; 84 | 85 | #[inline(always)] 86 | fn try_into ( 87 | self: StackVec, 88 | ) -> Result 89 | { 90 | if self.len == Self::CAPACITY { 91 | let array_ptr: *const mem::ManuallyDrop = &self.array; 92 | mem::forget(self); 93 | Ok(mem::ManuallyDrop::into_inner( 94 | unsafe { ptr::read(array_ptr) } 95 | )) 96 | } else { 97 | Err(IncompleteArrayError) 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | use self::prelude::*; 4 | 5 | #[test] 6 | fn build_stackvec () 7 | { 8 | let array = StackVec::<[_; 10]>::from_iter( 9 | [3, 4, 6, 8].iter().cloned() 10 | ); 11 | println!("{:?}", array); 12 | } 13 | 14 | #[test] 15 | fn build_array () 16 | { 17 | let array: [_; 4] = 18 | [3, 4, 6, 8] 19 | .iter().cloned() 20 | .try_collect() 21 | .expect("Missing elements to collect"); 22 | println!("{:?}", array); 23 | } 24 | 25 | #[test] 26 | #[should_panic] 27 | fn build_array_but_incomplete () 28 | { 29 | let _array: [_; 10] = 30 | [3, 4, 6, 8] 31 | .iter().cloned() 32 | .try_collect() 33 | .expect("Missing elements to collect"); 34 | } 35 | 36 | #[test] 37 | fn array_into_iter () 38 | { 39 | assert_eq!( 40 | [3, 4, 6, 8].into_iter().collect::>(), 41 | vec![3, 4, 6, 8], 42 | ); 43 | } 44 | 45 | #[test] 46 | fn array_into_iter_dropped () 47 | { 48 | let _ = [3, 4, 6, 8].into_iter(); 49 | } 50 | 51 | #[test] 52 | fn array_map () 53 | { 54 | let array: [_; 4] = 55 | [3, 4, 6, 8] 56 | .into_iter() 57 | .map(|x| 2 * x) 58 | .try_collect() 59 | .expect("Missing elements to collect"); 60 | let mut array_map_in_place = [3, 4, 6, 8]; 61 | array_map_in_place.iter_mut().for_each(|x| *x *= 2); 62 | assert_eq!( 63 | array, 64 | array_map_in_place, 65 | ); 66 | } 67 | 68 | #[test] 69 | #[should_panic] 70 | fn try_push_to_full_stackvec () 71 | { 72 | let mut stackvec: StackVec<[_; 1]> = Default::default(); 73 | stackvec.try_push(0).unwrap(); 74 | stackvec.try_push(0).unwrap(); 75 | } 76 | -------------------------------------------------------------------------------- /tests/basic.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | extern crate stackvec; 4 | use stackvec::prelude::*; 5 | 6 | use ::std::iter::{ 7 | self, 8 | Iterator, 9 | }; 10 | 11 | static NUMBERS: [u8; 9] = [ 12 | 5, 8, 9, 10, 6, 7, 4, 6, 7 13 | ]; 14 | 15 | mod counted_instances { 16 | use ::std::cell::Cell; 17 | 18 | thread_local! { 19 | static INSTANCES_COUNT: Cell = Cell::new(0); 20 | } 21 | 22 | #[derive(Debug)] 23 | pub struct Instance(()); 24 | 25 | impl Default for Instance { 26 | fn default() -> Self 27 | { 28 | INSTANCES_COUNT.with(|slf| slf.set(slf.get() + 1)); 29 | Instance(()) 30 | } 31 | } 32 | 33 | 34 | impl Instance { 35 | #[allow(non_upper_case_globals)] 36 | pub const new 37 | : fn() -> Self 38 | = Self::default; 39 | 40 | pub fn clone (&self) -> Self { Self::new() } 41 | 42 | pub fn total_count () -> isize 43 | { 44 | INSTANCES_COUNT.with(Cell::get) 45 | } 46 | 47 | pub fn count_assert_balanced () 48 | { 49 | use ::std::cmp::Ordering::*; 50 | let instance_count = Self::total_count(); 51 | match instance_count.cmp(&0) { 52 | Less => panic!( 53 | concat!( 54 | "Error, instance count {} < 0 ", 55 | r"=> /!\ double free /!\", 56 | ), 57 | instance_count, 58 | ), 59 | Greater => panic!( 60 | concat!( 61 | "Error, instance count {} > 0 ", 62 | r"=> /!\ memory leak /!\", 63 | ), 64 | instance_count, 65 | ), 66 | Equal =>(), 67 | } 68 | } 69 | } 70 | 71 | impl Drop for Instance { 72 | fn drop (&mut self) 73 | { 74 | INSTANCES_COUNT.with(|slf| slf.set(slf.get() - 1)) 75 | } 76 | } 77 | } 78 | 79 | #[test] 80 | fn build () 81 | { 82 | let array = StackVec::<[u8; 10]>::from_iter( 83 | NUMBERS.iter().cloned() 84 | ); 85 | println!("{:?}", array); 86 | } 87 | 88 | #[test] 89 | fn build_with_drop_full () 90 | { 91 | use counted_instances::*; 92 | { 93 | let array = StackVec::<[Instance; 3]>::from_iter( 94 | iter::repeat_with(Instance::new) 95 | ); 96 | println!("{:?}", array); 97 | } 98 | Instance::count_assert_balanced(); 99 | } 100 | 101 | #[test] 102 | fn build_with_drop_partial () 103 | { 104 | use counted_instances::*; 105 | { 106 | let mut array = StackVec::<[Instance; 3]>::default(); 107 | array.try_push( 108 | Instance::new() 109 | ).unwrap(); 110 | println!("{:?}", array); 111 | } 112 | Instance::count_assert_balanced(); 113 | } 114 | 115 | #[test] 116 | fn extend () 117 | { 118 | let mut array = StackVec::<[u8; 0x40]>:: 119 | default(); 120 | array.extend(Iterator::chain( 121 | (0 .. 56).map(|_| 0), 122 | b"Stackvec".iter().cloned(), 123 | )); 124 | println!("{:?}", array); 125 | } 126 | 127 | 128 | #[test] 129 | fn iter () 130 | { 131 | let array = StackVec::<[u8; 10]>::from_iter( 132 | NUMBERS.iter().cloned() 133 | ); 134 | for (value, expected_value) in Iterator::zip(array.iter(), &NUMBERS) 135 | { 136 | assert_eq!(value, expected_value); 137 | }; 138 | } 139 | 140 | #[test] 141 | fn iter_mut () 142 | { 143 | let mut array = StackVec::from([0_u8; 10]); 144 | for (array_i, &value) in Iterator::zip(array.iter_mut(), &NUMBERS) 145 | { 146 | *array_i = value; 147 | }; 148 | for (value, expected_value) in Iterator::zip(array.iter(), &NUMBERS) 149 | { 150 | assert_eq!(value, expected_value); 151 | }; 152 | } 153 | 154 | #[test] 155 | fn into_iter () 156 | { 157 | let array = StackVec::<[u8; 10]>::from_iter( 158 | NUMBERS.iter().cloned() 159 | ); 160 | assert_eq!( 161 | Vec::from_iter(array), 162 | Vec::from_iter(NUMBERS.iter().cloned()), 163 | ); 164 | } 165 | 166 | #[test] 167 | fn array_into_iter () 168 | { 169 | assert_eq!( 170 | Vec::from_iter(NUMBERS.into_iter()), 171 | Vec::from_iter(NUMBERS.iter().cloned()), 172 | ); 173 | } 174 | 175 | #[test] 176 | fn into_iter_with_drop_full () 177 | { 178 | use counted_instances::*; 179 | { 180 | let array = StackVec::<[_; 3]>::from_iter( 181 | iter::repeat_with(Instance::new) 182 | ); 183 | println!("{:?}", array); 184 | for _ in array {} 185 | } 186 | Instance::count_assert_balanced(); 187 | } 188 | 189 | #[test] 190 | fn into_iter_with_drop_partial_left () 191 | { 192 | use counted_instances::*; 193 | { 194 | let array = StackVec::<[_; 3]>::from_iter( 195 | iter::repeat_with(Instance::new) 196 | ); 197 | println!("{:?}", array); 198 | let mut iterator = array.into_iter(); 199 | let _ = iterator.next(); 200 | } 201 | Instance::count_assert_balanced(); 202 | } 203 | 204 | 205 | 206 | #[test] 207 | fn into_iter_with_drop_partial_right () 208 | { 209 | use counted_instances::*; 210 | { 211 | let array = StackVec::<[_; 3]>::from_iter( 212 | iter::repeat_with(Instance::new) 213 | ); 214 | println!("{:?}", array); 215 | let mut iterator = array.into_iter(); 216 | let _ = iterator.next_back(); 217 | } 218 | Instance::count_assert_balanced(); 219 | } 220 | 221 | --------------------------------------------------------------------------------