├── .github └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── RELEASES.md └── src └── lib.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | miri: 14 | name: "Miri" 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Install Miri 19 | run: | 20 | rustup toolchain install nightly --component miri 21 | rustup override set nightly 22 | cargo miri setup 23 | - name: Test (default) with Miri 24 | run: MIRIFLAGS=-Zmiri-strict-provenance cargo miri test 25 | - name: Test (gecko-ffi) with Miri 26 | run: MIRIFLAGS=-Zmiri-strict-provenance cargo miri test --features=gecko-ffi 27 | 28 | build: 29 | runs-on: ubuntu-latest 30 | steps: 31 | - uses: actions/checkout@v2 32 | - name: Build 33 | run: cargo build --verbose 34 | - name: Build (malloc_size_of) 35 | run: cargo build --features=malloc_size_of --verbose 36 | - name: Run tests 37 | run: cargo test --verbose 38 | - name: Run tests 39 | run: cargo test --verbose 40 | - name: Run tests (serde) 41 | run: cargo test --features=serde --verbose 42 | - name: Run tests (gecko-ffi) 43 | run: cargo test --tests --features=gecko-ffi --verbose 44 | - name: Run tests (no_std) 45 | run: cargo test --tests --no-default-features --verbose 46 | 47 | fmt: 48 | runs-on: ubuntu-latest 49 | steps: 50 | - uses: actions/checkout@v2 51 | - uses: actions-rs/toolchain@v1 52 | with: 53 | toolchain: stable 54 | profile: minimal 55 | components: rustfmt 56 | override: true 57 | - uses: actions-rs/cargo@v1 58 | with: 59 | command: fmt 60 | args: --all -- --check 61 | 62 | 63 | clippy: 64 | runs-on: ubuntu-latest 65 | steps: 66 | - uses: actions/checkout@v2 67 | - uses: actions-rs/toolchain@v1 68 | with: 69 | toolchain: stable 70 | profile: minimal 71 | components: clippy 72 | override: true 73 | - uses: actions-rs/clippy-check@v1 74 | env: 75 | PWD: ${{ env.GITHUB_WORKSPACE }} 76 | with: 77 | token: ${{ secrets.GITHUB_TOKEN }} 78 | args: --workspace --tests --examples 79 | 80 | 81 | docs: 82 | runs-on: ubuntu-latest 83 | env: 84 | RUSTDOCFLAGS: -Dwarnings 85 | steps: 86 | - uses: actions/checkout@v2 87 | - uses: actions-rs/toolchain@v1 88 | with: 89 | toolchain: stable 90 | profile: minimal 91 | components: rust-docs 92 | override: true 93 | - uses: swatinem/rust-cache@v1 94 | - uses: actions-rs/cargo@v1 95 | with: 96 | command: doc 97 | args: --workspace --no-deps 98 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2018" 3 | name = "thin-vec" 4 | version = "0.2.14" 5 | authors = ["Aria Beingessner "] 6 | description = "A vec that takes up less space on the stack" 7 | license = "MIT/Apache-2.0" 8 | repository = "https://github.com/gankra/thin-vec" 9 | homepage = "https://github.com/gankra/thin-vec" 10 | readme = "README.md" 11 | 12 | [features] 13 | unstable = [] 14 | default = ["std"] 15 | std = [] 16 | 17 | # Gecko specific features. These features cause thin-vec to have the same layout 18 | # and behaviour as nsTArray, allowing it to be used in C++ FFI. Requires 19 | # the empty header to be statically linked in with the symbol name "sEmptyTArrayHeader" 20 | gecko-ffi = [] 21 | 22 | [dependencies] 23 | serde = { version = "1.0", optional = true } 24 | malloc_size_of = { version = "0.1", default-features = false, optional = true } 25 | 26 | [dev-dependencies] 27 | serde_test = "1.0" 28 | 29 | [lints.rust] 30 | unexpected_cfgs = { level = "warn", check-cfg = ['cfg(no_global_oom_handling)'] } 31 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Rust CI](https://github.com/Gankra/thin-vec/workflows/Rust/badge.svg?branch=master) [![crates.io](https://img.shields.io/crates/v/thin-vec.svg)](https://crates.io/crates/thin-vec) [![](https://docs.rs/thin-vec/badge.svg)](https://docs.rs/thin-vec) 2 | 3 | # thin-vec 4 | 5 | ThinVec is a Vec that stores its length and capacity inline, making it take up 6 | less space. 7 | 8 | Currently this crate mostly exists to facilitate Gecko (Firefox) FFI, but it 9 | works perfectly fine as a native rust library as well. 10 | -------------------------------------------------------------------------------- /RELEASES.md: -------------------------------------------------------------------------------- 1 | # Version 0.2.14 (2025-02-19) 2 | * Add "malloc_size_of" feature for heap size measurement support 3 | 4 | # Version 0.2.13 (2023-12-02) 5 | 6 | * add default-on "std" feature for no_std support 7 | * added has_capacity method for checking if something is the empty singleton 8 | * marked more things as `#[inline]` 9 | * added license files 10 | * appeased clippy 11 | 12 | # Previous Versions 13 | 14 | *shrug* -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(missing_docs)] 2 | 3 | //! `ThinVec` is exactly the same as `Vec`, except that it stores its `len` and `capacity` in the buffer 4 | //! it allocates. 5 | //! 6 | //! This makes the memory footprint of ThinVecs lower; notably in cases where space is reserved for 7 | //! a non-existence `ThinVec`. So `Vec>` and `Option>::None` will waste less 8 | //! space. Being pointer-sized also means it can be passed/stored in registers. 9 | //! 10 | //! Of course, any actually constructed `ThinVec` will theoretically have a bigger allocation, but 11 | //! the fuzzy nature of allocators means that might not actually be the case. 12 | //! 13 | //! Properties of `Vec` that are preserved: 14 | //! * `ThinVec::new()` doesn't allocate (it points to a statically allocated singleton) 15 | //! * reallocation can be done in place 16 | //! * `size_of::>()` == `size_of::>>()` 17 | //! 18 | //! Properties of `Vec` that aren't preserved: 19 | //! * `ThinVec` can't ever be zero-cost roundtripped to a `Box<[T]>`, `String`, or `*mut T` 20 | //! * `from_raw_parts` doesn't exist 21 | //! * `ThinVec` currently doesn't bother to not-allocate for Zero Sized Types (e.g. `ThinVec<()>`), 22 | //! but it could be done if someone cared enough to implement it. 23 | //! 24 | //! 25 | //! 26 | //! # Gecko FFI 27 | //! 28 | //! If you enable the gecko-ffi feature, `ThinVec` will verbatim bridge with the nsTArray type in 29 | //! Gecko (Firefox). That is, `ThinVec` and nsTArray have identical layouts *but not ABIs*, 30 | //! so nsTArrays/ThinVecs an be natively manipulated by C++ and Rust, and ownership can be 31 | //! transferred across the FFI boundary (**IF YOU ARE CAREFUL, SEE BELOW!!**). 32 | //! 33 | //! While this feature is handy, it is also inherently dangerous to use because Rust and C++ do not 34 | //! know about each other. Specifically, this can be an issue with non-POD types (types which 35 | //! have destructors, move constructors, or are `!Copy`). 36 | //! 37 | //! ## Do Not Pass By Value 38 | //! 39 | //! The biggest thing to keep in mind is that **FFI functions cannot pass ThinVec/nsTArray 40 | //! by-value**. That is, these are busted APIs: 41 | //! 42 | //! ```rust,ignore 43 | //! // BAD WRONG 44 | //! extern fn process_data(data: ThinVec) { ... } 45 | //! // BAD WRONG 46 | //! extern fn get_data() -> ThinVec { ... } 47 | //! ``` 48 | //! 49 | //! You must instead pass by-reference: 50 | //! 51 | //! ```rust 52 | //! # use thin_vec::*; 53 | //! # use std::mem; 54 | //! 55 | //! // Read-only access, ok! 56 | //! extern fn process_data(data: &ThinVec) { 57 | //! for val in data { 58 | //! println!("{}", val); 59 | //! } 60 | //! } 61 | //! 62 | //! // Replace with empty instance to take ownership, ok! 63 | //! extern fn consume_data(data: &mut ThinVec) { 64 | //! let owned = mem::replace(data, ThinVec::new()); 65 | //! mem::drop(owned); 66 | //! } 67 | //! 68 | //! // Mutate input, ok! 69 | //! extern fn add_data(dataset: &mut ThinVec) { 70 | //! dataset.push(37); 71 | //! dataset.push(12); 72 | //! } 73 | //! 74 | //! // Return via out-param, usually ok! 75 | //! // 76 | //! // WARNING: output must be initialized! (Empty nsTArrays are free, so just do it!) 77 | //! extern fn get_data(output: &mut ThinVec) { 78 | //! *output = thin_vec![1, 2, 3, 4, 5]; 79 | //! } 80 | //! ``` 81 | //! 82 | //! Ignorable Explanation For Those Who Really Want To Know Why: 83 | //! 84 | //! > The fundamental issue is that Rust and C++ can't currently communicate about destructors, and 85 | //! > the semantics of C++ require destructors of function arguments to be run when the function 86 | //! > returns. Whether the callee or caller is responsible for this is also platform-specific, so 87 | //! > trying to hack around it manually would be messy. 88 | //! > 89 | //! > Also a type having a destructor changes its C++ ABI, because that type must actually exist 90 | //! > in memory (unlike a trivial struct, which is often passed in registers). We don't currently 91 | //! > have a way to communicate to Rust that this is happening, so even if we worked out the 92 | //! > destructor issue with say, MaybeUninit, it would still be a non-starter without some RFCs 93 | //! > to add explicit rustc support. 94 | //! > 95 | //! > Realistically, the best answer here is to have a "heavier" bindgen that can secretly 96 | //! > generate FFI glue so we can pass things "by value" and have it generate by-reference code 97 | //! > behind our back (like the cxx crate does). This would muddy up debugging/searchfox though. 98 | //! 99 | //! ## Types Should Be Trivially Relocatable 100 | //! 101 | //! Types in Rust are always trivially relocatable (unless suitably borrowed/[pinned][]/hidden). 102 | //! This means all Rust types are legal to relocate with a bitwise copy, you cannot provide 103 | //! copy or move constructors to execute when this happens, and the old location won't have its 104 | //! destructor run. This will cause problems for types which have a significant location 105 | //! (types that intrusively point into themselves or have their location registered with a service). 106 | //! 107 | //! While relocations are generally predictable if you're very careful, **you should avoid using 108 | //! types with significant locations with Rust FFI**. 109 | //! 110 | //! Specifically, `ThinVec` will trivially relocate its contents whenever it needs to reallocate its 111 | //! buffer to change its capacity. This is the default reallocation strategy for nsTArray, and is 112 | //! suitable for the vast majority of types. Just be aware of this limitation! 113 | //! 114 | //! ## Auto Arrays Are Dangerous 115 | //! 116 | //! `ThinVec` has *some* support for handling auto arrays which store their buffer on the stack, 117 | //! but this isn't well tested. 118 | //! 119 | //! Regardless of how much support we provide, Rust won't be aware of the buffer's limited lifetime, 120 | //! so standard auto array safety caveats apply about returning/storing them! `ThinVec` won't ever 121 | //! produce an auto array on its own, so this is only an issue for transferring an nsTArray into 122 | //! Rust. 123 | //! 124 | //! ## Other Issues 125 | //! 126 | //! Standard FFI caveats also apply: 127 | //! 128 | //! * Rust is more strict about POD types being initialized (use MaybeUninit if you must) 129 | //! * `ThinVec` has no idea if the C++ version of `T` has move/copy/assign/delete overloads 130 | //! * `nsTArray` has no idea if the Rust version of `T` has a Drop/Clone impl 131 | //! * C++ can do all sorts of unsound things that Rust can't catch 132 | //! * C++ and Rust don't agree on how zero-sized/empty types should be handled 133 | //! 134 | //! The gecko-ffi feature will not work if you aren't linking with code that has nsTArray 135 | //! defined. Specifically, we must share the symbol for nsTArray's empty singleton. You will get 136 | //! linking errors if that isn't defined. 137 | //! 138 | //! The gecko-ffi feature also limits `ThinVec` to the legacy behaviors of nsTArray. Most notably, 139 | //! nsTArray has a maximum capacity of i32::MAX (~2.1 billion items). Probably not an issue. 140 | //! Probably. 141 | //! 142 | //! [pinned]: https://doc.rust-lang.org/std/pin/index.html 143 | 144 | #![cfg_attr(not(feature = "std"), no_std)] 145 | #![allow(clippy::comparison_chain, clippy::missing_safety_doc)] 146 | 147 | extern crate alloc; 148 | 149 | use alloc::alloc::*; 150 | use alloc::{boxed::Box, vec::Vec}; 151 | use core::borrow::*; 152 | use core::cmp::*; 153 | use core::convert::TryFrom; 154 | use core::convert::TryInto; 155 | use core::hash::*; 156 | use core::iter::FromIterator; 157 | use core::marker::PhantomData; 158 | use core::ops::Bound; 159 | use core::ops::{Deref, DerefMut, RangeBounds}; 160 | use core::ptr::NonNull; 161 | use core::slice::IterMut; 162 | use core::{fmt, mem, ptr, slice}; 163 | 164 | use impl_details::*; 165 | 166 | #[cfg(feature = "malloc_size_of")] 167 | use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps}; 168 | 169 | // modules: a simple way to cfg a whole bunch of impl details at once 170 | 171 | #[cfg(not(feature = "gecko-ffi"))] 172 | mod impl_details { 173 | pub type SizeType = usize; 174 | pub const MAX_CAP: usize = !0; 175 | 176 | #[inline(always)] 177 | pub fn assert_size(x: usize) -> SizeType { 178 | x 179 | } 180 | } 181 | 182 | #[cfg(feature = "gecko-ffi")] 183 | mod impl_details { 184 | // Support for briding a gecko nsTArray verbatim into a ThinVec. 185 | // 186 | // `ThinVec` can't see copy/move/delete implementations 187 | // from C++ 188 | // 189 | // The actual layout of an nsTArray is: 190 | // 191 | // ```cpp 192 | // struct { 193 | // uint32_t mLength; 194 | // uint32_t mCapacity: 31; 195 | // uint32_t mIsAutoArray: 1; 196 | // } 197 | // ``` 198 | // 199 | // Rust doesn't natively support bit-fields, so we manually mask 200 | // and shift the bit. When the "auto" bit is set, the header and buffer 201 | // are actually on the stack, meaning the `ThinVec` pointer-to-header 202 | // is essentially an "owned borrow", and therefore dangerous to handle. 203 | // There are no safety guards for this situation. 204 | // 205 | // On little-endian platforms, the auto bit will be the high-bit of 206 | // our capacity u32. On big-endian platforms, it will be the low bit. 207 | // Hence we need some platform-specific CFGs for the necessary masking/shifting. 208 | // 209 | // `ThinVec` won't ever construct an auto array. They only happen when 210 | // bridging from C++. This means we don't need to ever set/preserve the bit. 211 | // We just need to be able to read and handle it if it happens to be there. 212 | // 213 | // Handling the auto bit mostly just means not freeing/reallocating the buffer. 214 | 215 | pub type SizeType = u32; 216 | 217 | pub const MAX_CAP: usize = i32::max_value() as usize; 218 | 219 | // Little endian: the auto bit is the high bit, and the capacity is 220 | // verbatim. So we just need to mask off the high bit. Note that 221 | // this masking is unnecessary when packing, because assert_size 222 | // guards against the high bit being set. 223 | #[cfg(target_endian = "little")] 224 | pub fn pack_capacity(cap: SizeType) -> SizeType { 225 | cap as SizeType 226 | } 227 | #[cfg(target_endian = "little")] 228 | pub fn unpack_capacity(cap: SizeType) -> usize { 229 | (cap as usize) & !(1 << 31) 230 | } 231 | #[cfg(target_endian = "little")] 232 | pub fn is_auto(cap: SizeType) -> bool { 233 | (cap & (1 << 31)) != 0 234 | } 235 | 236 | // Big endian: the auto bit is the low bit, and the capacity is 237 | // shifted up one bit. Masking out the auto bit is unnecessary, 238 | // as rust shifts always shift in 0's for unsigned integers. 239 | #[cfg(target_endian = "big")] 240 | pub fn pack_capacity(cap: SizeType) -> SizeType { 241 | (cap as SizeType) << 1 242 | } 243 | #[cfg(target_endian = "big")] 244 | pub fn unpack_capacity(cap: SizeType) -> usize { 245 | (cap >> 1) as usize 246 | } 247 | #[cfg(target_endian = "big")] 248 | pub fn is_auto(cap: SizeType) -> bool { 249 | (cap & 1) != 0 250 | } 251 | 252 | #[inline] 253 | pub fn assert_size(x: usize) -> SizeType { 254 | if x > MAX_CAP as usize { 255 | panic!("nsTArray size may not exceed the capacity of a 32-bit sized int"); 256 | } 257 | x as SizeType 258 | } 259 | } 260 | 261 | // The header of a ThinVec. 262 | // 263 | // The _cap can be a bitfield, so use accessors to avoid trouble. 264 | // 265 | // In "real" gecko-ffi mode, the empty singleton will be aligned 266 | // to 8 by gecko. But in tests we have to provide the singleton 267 | // ourselves, and Rust makes it hard to "just" align a static. 268 | // To avoid messing around with a wrapper type around the 269 | // singleton *just* for tests, we just force all headers to be 270 | // aligned to 8 in this weird "zombie" gecko mode. 271 | // 272 | // This shouldn't affect runtime layout (padding), but it will 273 | // result in us asking the allocator to needlessly overalign 274 | // non-empty ThinVecs containing align < 8 types in 275 | // zombie-mode, but not in "real" geck-ffi mode. Minor. 276 | #[cfg_attr(all(feature = "gecko-ffi", any(test, miri)), repr(align(8)))] 277 | #[repr(C)] 278 | struct Header { 279 | _len: SizeType, 280 | _cap: SizeType, 281 | } 282 | 283 | impl Header { 284 | #[inline] 285 | #[allow(clippy::unnecessary_cast)] 286 | fn len(&self) -> usize { 287 | self._len as usize 288 | } 289 | 290 | #[inline] 291 | fn set_len(&mut self, len: usize) { 292 | self._len = assert_size(len); 293 | } 294 | } 295 | 296 | #[cfg(feature = "gecko-ffi")] 297 | impl Header { 298 | fn cap(&self) -> usize { 299 | unpack_capacity(self._cap) 300 | } 301 | 302 | fn set_cap(&mut self, cap: usize) { 303 | // debug check that our packing is working 304 | debug_assert_eq!(unpack_capacity(pack_capacity(cap as SizeType)), cap); 305 | // FIXME: this assert is busted because it reads uninit memory 306 | // debug_assert!(!self.uses_stack_allocated_buffer()); 307 | 308 | // NOTE: this always stores a cleared auto bit, because set_cap 309 | // is only invoked by Rust, and Rust doesn't create auto arrays. 310 | self._cap = pack_capacity(assert_size(cap)); 311 | } 312 | 313 | fn uses_stack_allocated_buffer(&self) -> bool { 314 | is_auto(self._cap) 315 | } 316 | } 317 | 318 | #[cfg(not(feature = "gecko-ffi"))] 319 | impl Header { 320 | #[inline] 321 | #[allow(clippy::unnecessary_cast)] 322 | fn cap(&self) -> usize { 323 | self._cap as usize 324 | } 325 | 326 | #[inline] 327 | fn set_cap(&mut self, cap: usize) { 328 | self._cap = assert_size(cap); 329 | } 330 | } 331 | 332 | /// Singleton that all empty collections share. 333 | /// Note: can't store non-zero ZSTs, we allocate in that case. We could 334 | /// optimize everything to not do that (basically, make ptr == len and branch 335 | /// on size == 0 in every method), but it's a bunch of work for something that 336 | /// doesn't matter much. 337 | #[cfg(any(not(feature = "gecko-ffi"), test, miri))] 338 | static EMPTY_HEADER: Header = Header { _len: 0, _cap: 0 }; 339 | 340 | #[cfg(all(feature = "gecko-ffi", not(test), not(miri)))] 341 | extern "C" { 342 | #[link_name = "sEmptyTArrayHeader"] 343 | static EMPTY_HEADER: Header; 344 | } 345 | 346 | // Utils for computing layouts of allocations 347 | 348 | /// Gets the size necessary to allocate a `ThinVec` with the give capacity. 349 | /// 350 | /// # Panics 351 | /// 352 | /// This will panic if isize::MAX is overflowed at any point. 353 | fn alloc_size(cap: usize) -> usize { 354 | // Compute "real" header size with pointer math 355 | // 356 | // We turn everything into isizes here so that we can catch isize::MAX overflow, 357 | // we never want to allow allocations larger than that! 358 | let header_size = mem::size_of::
() as isize; 359 | let padding = padding::() as isize; 360 | 361 | let data_size = if mem::size_of::() == 0 { 362 | // If we're allocating an array for ZSTs we need a header/padding but no actual 363 | // space for items, so we don't care about the capacity that was requested! 364 | 0 365 | } else { 366 | let cap: isize = cap.try_into().expect("capacity overflow"); 367 | let elem_size = mem::size_of::() as isize; 368 | elem_size.checked_mul(cap).expect("capacity overflow") 369 | }; 370 | 371 | let final_size = data_size 372 | .checked_add(header_size + padding) 373 | .expect("capacity overflow"); 374 | 375 | // Ok now we can turn it back into a usize (don't need to worry about negatives) 376 | final_size as usize 377 | } 378 | 379 | /// Gets the padding necessary for the array of a `ThinVec` 380 | fn padding() -> usize { 381 | let alloc_align = alloc_align::(); 382 | let header_size = mem::size_of::
(); 383 | 384 | if alloc_align > header_size { 385 | if cfg!(feature = "gecko-ffi") { 386 | panic!( 387 | "nsTArray does not handle alignment above > {} correctly", 388 | header_size 389 | ); 390 | } 391 | alloc_align - header_size 392 | } else { 393 | 0 394 | } 395 | } 396 | 397 | /// Gets the align necessary to allocate a `ThinVec` 398 | fn alloc_align() -> usize { 399 | max(mem::align_of::(), mem::align_of::
()) 400 | } 401 | 402 | /// Gets the layout necessary to allocate a `ThinVec` 403 | /// 404 | /// # Panics 405 | /// 406 | /// Panics if the required size overflows `isize::MAX`. 407 | fn layout(cap: usize) -> Layout { 408 | unsafe { Layout::from_size_align_unchecked(alloc_size::(cap), alloc_align::()) } 409 | } 410 | 411 | /// Allocates a header (and array) for a `ThinVec` with the given capacity. 412 | /// 413 | /// # Panics 414 | /// 415 | /// Panics if the required size overflows `isize::MAX`. 416 | fn header_with_capacity(cap: usize) -> NonNull
{ 417 | debug_assert!(cap > 0); 418 | unsafe { 419 | let layout = layout::(cap); 420 | let header = alloc(layout) as *mut Header; 421 | 422 | if header.is_null() { 423 | handle_alloc_error(layout) 424 | } 425 | 426 | // "Infinite" capacity for zero-sized types: 427 | (*header).set_cap(if mem::size_of::() == 0 { 428 | MAX_CAP 429 | } else { 430 | cap 431 | }); 432 | (*header).set_len(0); 433 | 434 | NonNull::new_unchecked(header) 435 | } 436 | } 437 | 438 | /// See the crate's top level documentation for a description of this type. 439 | #[repr(C)] 440 | pub struct ThinVec { 441 | ptr: NonNull
, 442 | boo: PhantomData, 443 | } 444 | 445 | unsafe impl Sync for ThinVec {} 446 | unsafe impl Send for ThinVec {} 447 | 448 | /// Creates a `ThinVec` containing the arguments. 449 | /// 450 | // A hack to avoid linking problems with `cargo test --features=gecko-ffi`. 451 | #[cfg_attr(not(feature = "gecko-ffi"), doc = "```")] 452 | #[cfg_attr(feature = "gecko-ffi", doc = "```ignore")] 453 | /// #[macro_use] extern crate thin_vec; 454 | /// 455 | /// fn main() { 456 | /// let v = thin_vec![1, 2, 3]; 457 | /// assert_eq!(v.len(), 3); 458 | /// assert_eq!(v[0], 1); 459 | /// assert_eq!(v[1], 2); 460 | /// assert_eq!(v[2], 3); 461 | /// 462 | /// let v = thin_vec![1; 3]; 463 | /// assert_eq!(v, [1, 1, 1]); 464 | /// } 465 | /// ``` 466 | #[macro_export] 467 | macro_rules! thin_vec { 468 | (@UNIT $($t:tt)*) => (()); 469 | 470 | ($elem:expr; $n:expr) => ({ 471 | let mut vec = $crate::ThinVec::new(); 472 | vec.resize($n, $elem); 473 | vec 474 | }); 475 | () => {$crate::ThinVec::new()}; 476 | ($($x:expr),*) => ({ 477 | let len = [$(thin_vec!(@UNIT $x)),*].len(); 478 | let mut vec = $crate::ThinVec::with_capacity(len); 479 | $(vec.push($x);)* 480 | vec 481 | }); 482 | ($($x:expr,)*) => (thin_vec![$($x),*]); 483 | } 484 | 485 | impl ThinVec { 486 | /// Creates a new empty ThinVec. 487 | /// 488 | /// This will not allocate. 489 | pub fn new() -> ThinVec { 490 | ThinVec::with_capacity(0) 491 | } 492 | 493 | /// Constructs a new, empty `ThinVec` with at least the specified capacity. 494 | /// 495 | /// The vector will be able to hold at least `capacity` elements without 496 | /// reallocating. This method is allowed to allocate for more elements than 497 | /// `capacity`. If `capacity` is 0, the vector will not allocate. 498 | /// 499 | /// It is important to note that although the returned vector has the 500 | /// minimum *capacity* specified, the vector will have a zero *length*. 501 | /// 502 | /// If it is important to know the exact allocated capacity of a `ThinVec`, 503 | /// always use the [`capacity`] method after construction. 504 | /// 505 | /// **NOTE**: unlike `Vec`, `ThinVec` **MUST** allocate once to keep track of non-zero 506 | /// lengths. As such, we cannot provide the same guarantees about ThinVecs 507 | /// of ZSTs not allocating. However the allocation never needs to be resized 508 | /// to add more ZSTs, since the underlying array is still length 0. 509 | /// 510 | /// [Capacity and reallocation]: #capacity-and-reallocation 511 | /// [`capacity`]: Vec::capacity 512 | /// 513 | /// # Panics 514 | /// 515 | /// Panics if the new capacity exceeds `isize::MAX` bytes. 516 | /// 517 | /// # Examples 518 | /// 519 | /// ``` 520 | /// use thin_vec::ThinVec; 521 | /// 522 | /// let mut vec = ThinVec::with_capacity(10); 523 | /// 524 | /// // The vector contains no items, even though it has capacity for more 525 | /// assert_eq!(vec.len(), 0); 526 | /// assert!(vec.capacity() >= 10); 527 | /// 528 | /// // These are all done without reallocating... 529 | /// for i in 0..10 { 530 | /// vec.push(i); 531 | /// } 532 | /// assert_eq!(vec.len(), 10); 533 | /// assert!(vec.capacity() >= 10); 534 | /// 535 | /// // ...but this may make the vector reallocate 536 | /// vec.push(11); 537 | /// assert_eq!(vec.len(), 11); 538 | /// assert!(vec.capacity() >= 11); 539 | /// 540 | /// // A vector of a zero-sized type will always over-allocate, since no 541 | /// // space is needed to store the actual elements. 542 | /// let vec_units = ThinVec::<()>::with_capacity(10); 543 | /// 544 | /// // Only true **without** the gecko-ffi feature! 545 | /// // assert_eq!(vec_units.capacity(), usize::MAX); 546 | /// ``` 547 | pub fn with_capacity(cap: usize) -> ThinVec { 548 | // `padding` contains ~static assertions against types that are 549 | // incompatible with the current feature flags. We also call it to 550 | // invoke these assertions when getting a pointer to the `ThinVec` 551 | // contents, but since we also get a pointer to the contents in the 552 | // `Drop` impl, trippng an assertion along that code path causes a 553 | // double panic. We duplicate the assertion here so that it is 554 | // testable, 555 | let _ = padding::(); 556 | 557 | if cap == 0 { 558 | unsafe { 559 | ThinVec { 560 | ptr: NonNull::new_unchecked(&EMPTY_HEADER as *const Header as *mut Header), 561 | boo: PhantomData, 562 | } 563 | } 564 | } else { 565 | ThinVec { 566 | ptr: header_with_capacity::(cap), 567 | boo: PhantomData, 568 | } 569 | } 570 | } 571 | 572 | // Accessor conveniences 573 | 574 | fn ptr(&self) -> *mut Header { 575 | self.ptr.as_ptr() 576 | } 577 | fn header(&self) -> &Header { 578 | unsafe { self.ptr.as_ref() } 579 | } 580 | fn data_raw(&self) -> *mut T { 581 | // `padding` contains ~static assertions against types that are 582 | // incompatible with the current feature flags. Even if we don't 583 | // care about its result, we should always call it before getting 584 | // a data pointer to guard against invalid types! 585 | let padding = padding::(); 586 | 587 | // Although we ensure the data array is aligned when we allocate, 588 | // we can't do that with the empty singleton. So when it might not 589 | // be properly aligned, we substitute in the NonNull::dangling 590 | // which *is* aligned. 591 | // 592 | // To minimize dynamic branches on `cap` for all accesses 593 | // to the data, we include this guard which should only involve 594 | // compile-time constants. Ideally this should result in the branch 595 | // only be included for types with excessive alignment. 596 | let empty_header_is_aligned = if cfg!(feature = "gecko-ffi") { 597 | // in gecko-ffi mode `padding` will ensure this under 598 | // the assumption that the header has size 8 and the 599 | // static empty singleton is aligned to 8. 600 | true 601 | } else { 602 | // In non-gecko-ffi mode, the empty singleton is just 603 | // naturally aligned to the Header. If the Header is at 604 | // least as aligned as T *and* the padding would have 605 | // been 0, then one-past-the-end of the empty singleton 606 | // *is* a valid data pointer and we can remove the 607 | // `dangling` special case. 608 | mem::align_of::
() >= mem::align_of::() && padding == 0 609 | }; 610 | 611 | unsafe { 612 | if !empty_header_is_aligned && self.header().cap() == 0 { 613 | NonNull::dangling().as_ptr() 614 | } else { 615 | // This could technically result in overflow, but padding 616 | // would have to be absurdly large for this to occur. 617 | let header_size = mem::size_of::
(); 618 | let ptr = self.ptr.as_ptr() as *mut u8; 619 | ptr.add(header_size + padding) as *mut T 620 | } 621 | } 622 | } 623 | 624 | // This is unsafe when the header is EMPTY_HEADER. 625 | unsafe fn header_mut(&mut self) -> &mut Header { 626 | &mut *self.ptr() 627 | } 628 | 629 | /// Returns the number of elements in the vector, also referred to 630 | /// as its 'length'. 631 | /// 632 | /// # Examples 633 | /// 634 | /// ``` 635 | /// use thin_vec::thin_vec; 636 | /// 637 | /// let a = thin_vec![1, 2, 3]; 638 | /// assert_eq!(a.len(), 3); 639 | /// ``` 640 | pub fn len(&self) -> usize { 641 | self.header().len() 642 | } 643 | 644 | /// Returns `true` if the vector contains no elements. 645 | /// 646 | /// # Examples 647 | /// 648 | /// ``` 649 | /// use thin_vec::ThinVec; 650 | /// 651 | /// let mut v = ThinVec::new(); 652 | /// assert!(v.is_empty()); 653 | /// 654 | /// v.push(1); 655 | /// assert!(!v.is_empty()); 656 | /// ``` 657 | pub fn is_empty(&self) -> bool { 658 | self.len() == 0 659 | } 660 | 661 | /// Returns the number of elements the vector can hold without 662 | /// reallocating. 663 | /// 664 | /// # Examples 665 | /// 666 | /// ``` 667 | /// use thin_vec::ThinVec; 668 | /// 669 | /// let vec: ThinVec = ThinVec::with_capacity(10); 670 | /// assert_eq!(vec.capacity(), 10); 671 | /// ``` 672 | pub fn capacity(&self) -> usize { 673 | self.header().cap() 674 | } 675 | 676 | /// Returns `true` if the vector has the capacity to hold any element. 677 | pub fn has_capacity(&self) -> bool { 678 | !self.is_singleton() 679 | } 680 | 681 | /// Forces the length of the vector to `new_len`. 682 | /// 683 | /// This is a low-level operation that maintains none of the normal 684 | /// invariants of the type. Normally changing the length of a vector 685 | /// is done using one of the safe operations instead, such as 686 | /// [`truncate`], [`resize`], [`extend`], or [`clear`]. 687 | /// 688 | /// [`truncate`]: ThinVec::truncate 689 | /// [`resize`]: ThinVec::resize 690 | /// [`extend`]: ThinVec::extend 691 | /// [`clear`]: ThinVec::clear 692 | /// 693 | /// # Safety 694 | /// 695 | /// - `new_len` must be less than or equal to [`capacity()`]. 696 | /// - The elements at `old_len..new_len` must be initialized. 697 | /// 698 | /// [`capacity()`]: ThinVec::capacity 699 | /// 700 | /// # Examples 701 | /// 702 | /// This method can be useful for situations in which the vector 703 | /// is serving as a buffer for other code, particularly over FFI: 704 | /// 705 | /// ```no_run 706 | /// use thin_vec::ThinVec; 707 | /// 708 | /// # // This is just a minimal skeleton for the doc example; 709 | /// # // don't use this as a starting point for a real library. 710 | /// # pub struct StreamWrapper { strm: *mut std::ffi::c_void } 711 | /// # const Z_OK: i32 = 0; 712 | /// # extern "C" { 713 | /// # fn deflateGetDictionary( 714 | /// # strm: *mut std::ffi::c_void, 715 | /// # dictionary: *mut u8, 716 | /// # dictLength: *mut usize, 717 | /// # ) -> i32; 718 | /// # } 719 | /// # impl StreamWrapper { 720 | /// pub fn get_dictionary(&self) -> Option> { 721 | /// // Per the FFI method's docs, "32768 bytes is always enough". 722 | /// let mut dict = ThinVec::with_capacity(32_768); 723 | /// let mut dict_length = 0; 724 | /// // SAFETY: When `deflateGetDictionary` returns `Z_OK`, it holds that: 725 | /// // 1. `dict_length` elements were initialized. 726 | /// // 2. `dict_length` <= the capacity (32_768) 727 | /// // which makes `set_len` safe to call. 728 | /// unsafe { 729 | /// // Make the FFI call... 730 | /// let r = deflateGetDictionary(self.strm, dict.as_mut_ptr(), &mut dict_length); 731 | /// if r == Z_OK { 732 | /// // ...and update the length to what was initialized. 733 | /// dict.set_len(dict_length); 734 | /// Some(dict) 735 | /// } else { 736 | /// None 737 | /// } 738 | /// } 739 | /// } 740 | /// # } 741 | /// ``` 742 | /// 743 | /// While the following example is sound, there is a memory leak since 744 | /// the inner vectors were not freed prior to the `set_len` call: 745 | /// 746 | /// ```no_run 747 | /// use thin_vec::thin_vec; 748 | /// 749 | /// let mut vec = thin_vec![thin_vec![1, 0, 0], 750 | /// thin_vec![0, 1, 0], 751 | /// thin_vec![0, 0, 1]]; 752 | /// // SAFETY: 753 | /// // 1. `old_len..0` is empty so no elements need to be initialized. 754 | /// // 2. `0 <= capacity` always holds whatever `capacity` is. 755 | /// unsafe { 756 | /// vec.set_len(0); 757 | /// } 758 | /// ``` 759 | /// 760 | /// Normally, here, one would use [`clear`] instead to correctly drop 761 | /// the contents and thus not leak memory. 762 | pub unsafe fn set_len(&mut self, len: usize) { 763 | if self.is_singleton() { 764 | // A prerequisite of `Vec::set_len` is that `new_len` must be 765 | // less than or equal to capacity(). The same applies here. 766 | debug_assert!(len == 0, "invalid set_len({}) on empty ThinVec", len); 767 | } else { 768 | self.header_mut().set_len(len) 769 | } 770 | } 771 | 772 | // For internal use only, when setting the length and it's known to be the non-singleton. 773 | unsafe fn set_len_non_singleton(&mut self, len: usize) { 774 | self.header_mut().set_len(len) 775 | } 776 | 777 | /// Appends an element to the back of a collection. 778 | /// 779 | /// # Panics 780 | /// 781 | /// Panics if the new capacity exceeds `isize::MAX` bytes. 782 | /// 783 | /// # Examples 784 | /// 785 | /// ``` 786 | /// use thin_vec::thin_vec; 787 | /// 788 | /// let mut vec = thin_vec![1, 2]; 789 | /// vec.push(3); 790 | /// assert_eq!(vec, [1, 2, 3]); 791 | /// ``` 792 | pub fn push(&mut self, val: T) { 793 | let old_len = self.len(); 794 | if old_len == self.capacity() { 795 | self.reserve(1); 796 | } 797 | unsafe { 798 | ptr::write(self.data_raw().add(old_len), val); 799 | self.set_len_non_singleton(old_len + 1); 800 | } 801 | } 802 | 803 | /// Removes the last element from a vector and returns it, or [`None`] if it 804 | /// is empty. 805 | /// 806 | /// # Examples 807 | /// 808 | /// ``` 809 | /// use thin_vec::thin_vec; 810 | /// 811 | /// let mut vec = thin_vec![1, 2, 3]; 812 | /// assert_eq!(vec.pop(), Some(3)); 813 | /// assert_eq!(vec, [1, 2]); 814 | /// ``` 815 | pub fn pop(&mut self) -> Option { 816 | let old_len = self.len(); 817 | if old_len == 0 { 818 | return None; 819 | } 820 | 821 | unsafe { 822 | self.set_len_non_singleton(old_len - 1); 823 | Some(ptr::read(self.data_raw().add(old_len - 1))) 824 | } 825 | } 826 | 827 | /// Inserts an element at position `index` within the vector, shifting all 828 | /// elements after it to the right. 829 | /// 830 | /// # Panics 831 | /// 832 | /// Panics if `index > len`. 833 | /// 834 | /// # Examples 835 | /// 836 | /// ``` 837 | /// use thin_vec::thin_vec; 838 | /// 839 | /// let mut vec = thin_vec![1, 2, 3]; 840 | /// vec.insert(1, 4); 841 | /// assert_eq!(vec, [1, 4, 2, 3]); 842 | /// vec.insert(4, 5); 843 | /// assert_eq!(vec, [1, 4, 2, 3, 5]); 844 | /// ``` 845 | pub fn insert(&mut self, idx: usize, elem: T) { 846 | let old_len = self.len(); 847 | 848 | assert!(idx <= old_len, "Index out of bounds"); 849 | if old_len == self.capacity() { 850 | self.reserve(1); 851 | } 852 | unsafe { 853 | let ptr = self.data_raw(); 854 | ptr::copy(ptr.add(idx), ptr.add(idx + 1), old_len - idx); 855 | ptr::write(ptr.add(idx), elem); 856 | self.set_len_non_singleton(old_len + 1); 857 | } 858 | } 859 | 860 | /// Removes and returns the element at position `index` within the vector, 861 | /// shifting all elements after it to the left. 862 | /// 863 | /// Note: Because this shifts over the remaining elements, it has a 864 | /// worst-case performance of *O*(*n*). If you don't need the order of elements 865 | /// to be preserved, use [`swap_remove`] instead. If you'd like to remove 866 | /// elements from the beginning of the `ThinVec`, consider using `std::collections::VecDeque`. 867 | /// 868 | /// [`swap_remove`]: ThinVec::swap_remove 869 | /// 870 | /// # Panics 871 | /// 872 | /// Panics if `index` is out of bounds. 873 | /// 874 | /// # Examples 875 | /// 876 | /// ``` 877 | /// use thin_vec::thin_vec; 878 | /// 879 | /// let mut v = thin_vec![1, 2, 3]; 880 | /// assert_eq!(v.remove(1), 2); 881 | /// assert_eq!(v, [1, 3]); 882 | /// ``` 883 | pub fn remove(&mut self, idx: usize) -> T { 884 | let old_len = self.len(); 885 | 886 | assert!(idx < old_len, "Index out of bounds"); 887 | 888 | unsafe { 889 | self.set_len_non_singleton(old_len - 1); 890 | let ptr = self.data_raw(); 891 | let val = ptr::read(self.data_raw().add(idx)); 892 | ptr::copy(ptr.add(idx + 1), ptr.add(idx), old_len - idx - 1); 893 | val 894 | } 895 | } 896 | 897 | /// Removes an element from the vector and returns it. 898 | /// 899 | /// The removed element is replaced by the last element of the vector. 900 | /// 901 | /// This does not preserve ordering, but is *O*(1). 902 | /// If you need to preserve the element order, use [`remove`] instead. 903 | /// 904 | /// [`remove`]: ThinVec::remove 905 | /// 906 | /// # Panics 907 | /// 908 | /// Panics if `index` is out of bounds. 909 | /// 910 | /// # Examples 911 | /// 912 | /// ``` 913 | /// use thin_vec::thin_vec; 914 | /// 915 | /// let mut v = thin_vec!["foo", "bar", "baz", "qux"]; 916 | /// 917 | /// assert_eq!(v.swap_remove(1), "bar"); 918 | /// assert_eq!(v, ["foo", "qux", "baz"]); 919 | /// 920 | /// assert_eq!(v.swap_remove(0), "foo"); 921 | /// assert_eq!(v, ["baz", "qux"]); 922 | /// ``` 923 | pub fn swap_remove(&mut self, idx: usize) -> T { 924 | let old_len = self.len(); 925 | 926 | assert!(idx < old_len, "Index out of bounds"); 927 | 928 | unsafe { 929 | let ptr = self.data_raw(); 930 | ptr::swap(ptr.add(idx), ptr.add(old_len - 1)); 931 | self.set_len_non_singleton(old_len - 1); 932 | ptr::read(ptr.add(old_len - 1)) 933 | } 934 | } 935 | 936 | /// Shortens the vector, keeping the first `len` elements and dropping 937 | /// the rest. 938 | /// 939 | /// If `len` is greater than the vector's current length, this has no 940 | /// effect. 941 | /// 942 | /// The [`drain`] method can emulate `truncate`, but causes the excess 943 | /// elements to be returned instead of dropped. 944 | /// 945 | /// Note that this method has no effect on the allocated capacity 946 | /// of the vector. 947 | /// 948 | /// # Examples 949 | /// 950 | /// Truncating a five element vector to two elements: 951 | /// 952 | /// ``` 953 | /// use thin_vec::thin_vec; 954 | /// 955 | /// let mut vec = thin_vec![1, 2, 3, 4, 5]; 956 | /// vec.truncate(2); 957 | /// assert_eq!(vec, [1, 2]); 958 | /// ``` 959 | /// 960 | /// No truncation occurs when `len` is greater than the vector's current 961 | /// length: 962 | /// 963 | /// ``` 964 | /// use thin_vec::thin_vec; 965 | /// 966 | /// let mut vec = thin_vec![1, 2, 3]; 967 | /// vec.truncate(8); 968 | /// assert_eq!(vec, [1, 2, 3]); 969 | /// ``` 970 | /// 971 | /// Truncating when `len == 0` is equivalent to calling the [`clear`] 972 | /// method. 973 | /// 974 | /// ``` 975 | /// use thin_vec::thin_vec; 976 | /// 977 | /// let mut vec = thin_vec![1, 2, 3]; 978 | /// vec.truncate(0); 979 | /// assert_eq!(vec, []); 980 | /// ``` 981 | /// 982 | /// [`clear`]: ThinVec::clear 983 | /// [`drain`]: ThinVec::drain 984 | pub fn truncate(&mut self, len: usize) { 985 | unsafe { 986 | // drop any extra elements 987 | while len < self.len() { 988 | // decrement len before the drop_in_place(), so a panic on Drop 989 | // doesn't re-drop the just-failed value. 990 | let new_len = self.len() - 1; 991 | self.set_len_non_singleton(new_len); 992 | ptr::drop_in_place(self.data_raw().add(new_len)); 993 | } 994 | } 995 | } 996 | 997 | /// Clears the vector, removing all values. 998 | /// 999 | /// Note that this method has no effect on the allocated capacity 1000 | /// of the vector. 1001 | /// 1002 | /// # Examples 1003 | /// 1004 | /// ``` 1005 | /// use thin_vec::thin_vec; 1006 | /// 1007 | /// let mut v = thin_vec![1, 2, 3]; 1008 | /// v.clear(); 1009 | /// assert!(v.is_empty()); 1010 | /// ``` 1011 | pub fn clear(&mut self) { 1012 | unsafe { 1013 | ptr::drop_in_place(&mut self[..]); 1014 | self.set_len(0); // could be the singleton 1015 | } 1016 | } 1017 | 1018 | /// Extracts a slice containing the entire vector. 1019 | /// 1020 | /// Equivalent to `&s[..]`. 1021 | /// 1022 | /// # Examples 1023 | /// 1024 | /// ``` 1025 | /// use thin_vec::thin_vec; 1026 | /// use std::io::{self, Write}; 1027 | /// let buffer = thin_vec![1, 2, 3, 5, 8]; 1028 | /// io::sink().write(buffer.as_slice()).unwrap(); 1029 | /// ``` 1030 | pub fn as_slice(&self) -> &[T] { 1031 | unsafe { slice::from_raw_parts(self.data_raw(), self.len()) } 1032 | } 1033 | 1034 | /// Extracts a mutable slice of the entire vector. 1035 | /// 1036 | /// Equivalent to `&mut s[..]`. 1037 | /// 1038 | /// # Examples 1039 | /// 1040 | /// ``` 1041 | /// use thin_vec::thin_vec; 1042 | /// use std::io::{self, Read}; 1043 | /// let mut buffer = vec![0; 3]; 1044 | /// io::repeat(0b101).read_exact(buffer.as_mut_slice()).unwrap(); 1045 | /// ``` 1046 | pub fn as_mut_slice(&mut self) -> &mut [T] { 1047 | unsafe { slice::from_raw_parts_mut(self.data_raw(), self.len()) } 1048 | } 1049 | 1050 | /// Reserve capacity for at least `additional` more elements to be inserted. 1051 | /// 1052 | /// May reserve more space than requested, to avoid frequent reallocations. 1053 | /// 1054 | /// Panics if the new capacity overflows `usize`. 1055 | /// 1056 | /// Re-allocates only if `self.capacity() < self.len() + additional`. 1057 | #[cfg(not(feature = "gecko-ffi"))] 1058 | pub fn reserve(&mut self, additional: usize) { 1059 | let len = self.len(); 1060 | let old_cap = self.capacity(); 1061 | let min_cap = len.checked_add(additional).expect("capacity overflow"); 1062 | if min_cap <= old_cap { 1063 | return; 1064 | } 1065 | // Ensure the new capacity is at least double, to guarantee exponential growth. 1066 | let double_cap = if old_cap == 0 { 1067 | // skip to 4 because tiny ThinVecs are dumb; but not if that would cause overflow 1068 | if mem::size_of::() > (!0) / 8 { 1069 | 1 1070 | } else { 1071 | 4 1072 | } 1073 | } else { 1074 | old_cap.saturating_mul(2) 1075 | }; 1076 | let new_cap = max(min_cap, double_cap); 1077 | unsafe { 1078 | self.reallocate(new_cap); 1079 | } 1080 | } 1081 | 1082 | /// Reserve capacity for at least `additional` more elements to be inserted. 1083 | /// 1084 | /// This method mimics the growth algorithm used by the C++ implementation 1085 | /// of nsTArray. 1086 | #[cfg(feature = "gecko-ffi")] 1087 | pub fn reserve(&mut self, additional: usize) { 1088 | let elem_size = mem::size_of::(); 1089 | 1090 | let len = self.len(); 1091 | let old_cap = self.capacity(); 1092 | let min_cap = len.checked_add(additional).expect("capacity overflow"); 1093 | if min_cap <= old_cap { 1094 | return; 1095 | } 1096 | 1097 | // The growth logic can't handle zero-sized types, so we have to exit 1098 | // early here. 1099 | if elem_size == 0 { 1100 | unsafe { 1101 | self.reallocate(min_cap); 1102 | } 1103 | return; 1104 | } 1105 | 1106 | let min_cap_bytes = assert_size(min_cap) 1107 | .checked_mul(assert_size(elem_size)) 1108 | .and_then(|x| x.checked_add(assert_size(mem::size_of::
()))) 1109 | .unwrap(); 1110 | 1111 | // Perform some checked arithmetic to ensure all of the numbers we 1112 | // compute will end up in range. 1113 | let will_fit = min_cap_bytes.checked_mul(2).is_some(); 1114 | if !will_fit { 1115 | panic!("Exceeded maximum nsTArray size"); 1116 | } 1117 | 1118 | const SLOW_GROWTH_THRESHOLD: usize = 8 * 1024 * 1024; 1119 | 1120 | let bytes = if min_cap > SLOW_GROWTH_THRESHOLD { 1121 | // Grow by a minimum of 1.125x 1122 | let old_cap_bytes = old_cap * elem_size + mem::size_of::
(); 1123 | let min_growth = old_cap_bytes + (old_cap_bytes >> 3); 1124 | let growth = max(min_growth, min_cap_bytes as usize); 1125 | 1126 | // Round up to the next megabyte. 1127 | const MB: usize = 1 << 20; 1128 | MB * ((growth + MB - 1) / MB) 1129 | } else { 1130 | // Try to allocate backing buffers in powers of two. 1131 | min_cap_bytes.next_power_of_two() as usize 1132 | }; 1133 | 1134 | let cap = (bytes - core::mem::size_of::
()) / elem_size; 1135 | unsafe { 1136 | self.reallocate(cap); 1137 | } 1138 | } 1139 | 1140 | /// Reserves the minimum capacity for `additional` more elements to be inserted. 1141 | /// 1142 | /// Panics if the new capacity overflows `usize`. 1143 | /// 1144 | /// Re-allocates only if `self.capacity() < self.len() + additional`. 1145 | pub fn reserve_exact(&mut self, additional: usize) { 1146 | let new_cap = self 1147 | .len() 1148 | .checked_add(additional) 1149 | .expect("capacity overflow"); 1150 | let old_cap = self.capacity(); 1151 | if new_cap > old_cap { 1152 | unsafe { 1153 | self.reallocate(new_cap); 1154 | } 1155 | } 1156 | } 1157 | 1158 | /// Shrinks the capacity of the vector as much as possible. 1159 | /// 1160 | /// It will drop down as close as possible to the length but the allocator 1161 | /// may still inform the vector that there is space for a few more elements. 1162 | /// 1163 | /// # Examples 1164 | /// 1165 | /// ``` 1166 | /// use thin_vec::ThinVec; 1167 | /// 1168 | /// let mut vec = ThinVec::with_capacity(10); 1169 | /// vec.extend([1, 2, 3]); 1170 | /// assert_eq!(vec.capacity(), 10); 1171 | /// vec.shrink_to_fit(); 1172 | /// assert!(vec.capacity() >= 3); 1173 | /// ``` 1174 | pub fn shrink_to_fit(&mut self) { 1175 | let old_cap = self.capacity(); 1176 | let new_cap = self.len(); 1177 | if new_cap < old_cap { 1178 | if new_cap == 0 { 1179 | *self = ThinVec::new(); 1180 | } else { 1181 | unsafe { 1182 | self.reallocate(new_cap); 1183 | } 1184 | } 1185 | } 1186 | } 1187 | 1188 | /// Retains only the elements specified by the predicate. 1189 | /// 1190 | /// In other words, remove all elements `e` such that `f(&e)` returns `false`. 1191 | /// This method operates in place and preserves the order of the retained 1192 | /// elements. 1193 | /// 1194 | /// # Examples 1195 | /// 1196 | // A hack to avoid linking problems with `cargo test --features=gecko-ffi`. 1197 | #[cfg_attr(not(feature = "gecko-ffi"), doc = "```")] 1198 | #[cfg_attr(feature = "gecko-ffi", doc = "```ignore")] 1199 | /// # #[macro_use] extern crate thin_vec; 1200 | /// # fn main() { 1201 | /// let mut vec = thin_vec![1, 2, 3, 4]; 1202 | /// vec.retain(|&x| x%2 == 0); 1203 | /// assert_eq!(vec, [2, 4]); 1204 | /// # } 1205 | /// ``` 1206 | pub fn retain(&mut self, mut f: F) 1207 | where 1208 | F: FnMut(&T) -> bool, 1209 | { 1210 | self.retain_mut(|x| f(&*x)); 1211 | } 1212 | 1213 | /// Retains only the elements specified by the predicate, passing a mutable reference to it. 1214 | /// 1215 | /// In other words, remove all elements `e` such that `f(&mut e)` returns `false`. 1216 | /// This method operates in place and preserves the order of the retained 1217 | /// elements. 1218 | /// 1219 | /// # Examples 1220 | /// 1221 | // A hack to avoid linking problems with `cargo test --features=gecko-ffi`. 1222 | #[cfg_attr(not(feature = "gecko-ffi"), doc = "```")] 1223 | #[cfg_attr(feature = "gecko-ffi", doc = "```ignore")] 1224 | /// # #[macro_use] extern crate thin_vec; 1225 | /// # fn main() { 1226 | /// let mut vec = thin_vec![1, 2, 3, 4, 5]; 1227 | /// vec.retain_mut(|x| { 1228 | /// *x += 1; 1229 | /// (*x)%2 == 0 1230 | /// }); 1231 | /// assert_eq!(vec, [2, 4, 6]); 1232 | /// # } 1233 | /// ``` 1234 | pub fn retain_mut(&mut self, mut f: F) 1235 | where 1236 | F: FnMut(&mut T) -> bool, 1237 | { 1238 | let len = self.len(); 1239 | let mut del = 0; 1240 | { 1241 | let v = &mut self[..]; 1242 | 1243 | for i in 0..len { 1244 | if !f(&mut v[i]) { 1245 | del += 1; 1246 | } else if del > 0 { 1247 | v.swap(i - del, i); 1248 | } 1249 | } 1250 | } 1251 | if del > 0 { 1252 | self.truncate(len - del); 1253 | } 1254 | } 1255 | 1256 | /// Removes consecutive elements in the vector that resolve to the same key. 1257 | /// 1258 | /// If the vector is sorted, this removes all duplicates. 1259 | /// 1260 | /// # Examples 1261 | /// 1262 | // A hack to avoid linking problems with `cargo test --features=gecko-ffi`. 1263 | #[cfg_attr(not(feature = "gecko-ffi"), doc = "```")] 1264 | #[cfg_attr(feature = "gecko-ffi", doc = "```ignore")] 1265 | /// # #[macro_use] extern crate thin_vec; 1266 | /// # fn main() { 1267 | /// let mut vec = thin_vec![10, 20, 21, 30, 20]; 1268 | /// 1269 | /// vec.dedup_by_key(|i| *i / 10); 1270 | /// 1271 | /// assert_eq!(vec, [10, 20, 30, 20]); 1272 | /// # } 1273 | /// ``` 1274 | pub fn dedup_by_key(&mut self, mut key: F) 1275 | where 1276 | F: FnMut(&mut T) -> K, 1277 | K: PartialEq, 1278 | { 1279 | self.dedup_by(|a, b| key(a) == key(b)) 1280 | } 1281 | 1282 | /// Removes consecutive elements in the vector according to a predicate. 1283 | /// 1284 | /// The `same_bucket` function is passed references to two elements from the vector, and 1285 | /// returns `true` if the elements compare equal, or `false` if they do not. Only the first 1286 | /// of adjacent equal items is kept. 1287 | /// 1288 | /// If the vector is sorted, this removes all duplicates. 1289 | /// 1290 | /// # Examples 1291 | /// 1292 | // A hack to avoid linking problems with `cargo test --features=gecko-ffi`. 1293 | #[cfg_attr(not(feature = "gecko-ffi"), doc = "```")] 1294 | #[cfg_attr(feature = "gecko-ffi", doc = "```ignore")] 1295 | /// # #[macro_use] extern crate thin_vec; 1296 | /// # fn main() { 1297 | /// let mut vec = thin_vec!["foo", "bar", "Bar", "baz", "bar"]; 1298 | /// 1299 | /// vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b)); 1300 | /// 1301 | /// assert_eq!(vec, ["foo", "bar", "baz", "bar"]); 1302 | /// # } 1303 | /// ``` 1304 | #[allow(clippy::swap_ptr_to_ref)] 1305 | pub fn dedup_by(&mut self, mut same_bucket: F) 1306 | where 1307 | F: FnMut(&mut T, &mut T) -> bool, 1308 | { 1309 | // See the comments in `Vec::dedup` for a detailed explanation of this code. 1310 | unsafe { 1311 | let ln = self.len(); 1312 | if ln <= 1 { 1313 | return; 1314 | } 1315 | 1316 | // Avoid bounds checks by using raw pointers. 1317 | let p = self.as_mut_ptr(); 1318 | let mut r: usize = 1; 1319 | let mut w: usize = 1; 1320 | 1321 | while r < ln { 1322 | let p_r = p.add(r); 1323 | let p_wm1 = p.add(w - 1); 1324 | if !same_bucket(&mut *p_r, &mut *p_wm1) { 1325 | if r != w { 1326 | let p_w = p_wm1.add(1); 1327 | mem::swap(&mut *p_r, &mut *p_w); 1328 | } 1329 | w += 1; 1330 | } 1331 | r += 1; 1332 | } 1333 | 1334 | self.truncate(w); 1335 | } 1336 | } 1337 | 1338 | /// Splits the collection into two at the given index. 1339 | /// 1340 | /// Returns a newly allocated vector containing the elements in the range 1341 | /// `[at, len)`. After the call, the original vector will be left containing 1342 | /// the elements `[0, at)` with its previous capacity unchanged. 1343 | /// 1344 | /// # Panics 1345 | /// 1346 | /// Panics if `at > len`. 1347 | /// 1348 | /// # Examples 1349 | /// 1350 | /// ``` 1351 | /// use thin_vec::thin_vec; 1352 | /// 1353 | /// let mut vec = thin_vec![1, 2, 3]; 1354 | /// let vec2 = vec.split_off(1); 1355 | /// assert_eq!(vec, [1]); 1356 | /// assert_eq!(vec2, [2, 3]); 1357 | /// ``` 1358 | pub fn split_off(&mut self, at: usize) -> ThinVec { 1359 | let old_len = self.len(); 1360 | let new_vec_len = old_len - at; 1361 | 1362 | assert!(at <= old_len, "Index out of bounds"); 1363 | 1364 | unsafe { 1365 | let mut new_vec = ThinVec::with_capacity(new_vec_len); 1366 | 1367 | ptr::copy_nonoverlapping(self.data_raw().add(at), new_vec.data_raw(), new_vec_len); 1368 | 1369 | new_vec.set_len(new_vec_len); // could be the singleton 1370 | self.set_len(at); // could be the singleton 1371 | 1372 | new_vec 1373 | } 1374 | } 1375 | 1376 | /// Moves all the elements of `other` into `self`, leaving `other` empty. 1377 | /// 1378 | /// # Panics 1379 | /// 1380 | /// Panics if the new capacity exceeds `isize::MAX` bytes. 1381 | /// 1382 | /// # Examples 1383 | /// 1384 | /// ``` 1385 | /// use thin_vec::thin_vec; 1386 | /// 1387 | /// let mut vec = thin_vec![1, 2, 3]; 1388 | /// let mut vec2 = thin_vec![4, 5, 6]; 1389 | /// vec.append(&mut vec2); 1390 | /// assert_eq!(vec, [1, 2, 3, 4, 5, 6]); 1391 | /// assert_eq!(vec2, []); 1392 | /// ``` 1393 | pub fn append(&mut self, other: &mut ThinVec) { 1394 | self.extend(other.drain(..)) 1395 | } 1396 | 1397 | /// Removes the specified range from the vector in bulk, returning all 1398 | /// removed elements as an iterator. If the iterator is dropped before 1399 | /// being fully consumed, it drops the remaining removed elements. 1400 | /// 1401 | /// The returned iterator keeps a mutable borrow on the vector to optimize 1402 | /// its implementation. 1403 | /// 1404 | /// # Panics 1405 | /// 1406 | /// Panics if the starting point is greater than the end point or if 1407 | /// the end point is greater than the length of the vector. 1408 | /// 1409 | /// # Leaking 1410 | /// 1411 | /// If the returned iterator goes out of scope without being dropped (due to 1412 | /// [`mem::forget`], for example), the vector may have lost and leaked 1413 | /// elements arbitrarily, including elements outside the range. 1414 | /// 1415 | /// # Examples 1416 | /// 1417 | /// ``` 1418 | /// use thin_vec::{ThinVec, thin_vec}; 1419 | /// 1420 | /// let mut v = thin_vec![1, 2, 3]; 1421 | /// let u: ThinVec<_> = v.drain(1..).collect(); 1422 | /// assert_eq!(v, &[1]); 1423 | /// assert_eq!(u, &[2, 3]); 1424 | /// 1425 | /// // A full range clears the vector, like `clear()` does 1426 | /// v.drain(..); 1427 | /// assert_eq!(v, &[]); 1428 | /// ``` 1429 | pub fn drain(&mut self, range: R) -> Drain<'_, T> 1430 | where 1431 | R: RangeBounds, 1432 | { 1433 | // See comments in the Drain struct itself for details on this 1434 | let len = self.len(); 1435 | let start = match range.start_bound() { 1436 | Bound::Included(&n) => n, 1437 | Bound::Excluded(&n) => n + 1, 1438 | Bound::Unbounded => 0, 1439 | }; 1440 | let end = match range.end_bound() { 1441 | Bound::Included(&n) => n + 1, 1442 | Bound::Excluded(&n) => n, 1443 | Bound::Unbounded => len, 1444 | }; 1445 | assert!(start <= end); 1446 | assert!(end <= len); 1447 | 1448 | unsafe { 1449 | // Set our length to the start bound 1450 | self.set_len(start); // could be the singleton 1451 | 1452 | let iter = 1453 | slice::from_raw_parts_mut(self.data_raw().add(start), end - start).iter_mut(); 1454 | 1455 | Drain { 1456 | iter, 1457 | vec: self, 1458 | end, 1459 | tail: len - end, 1460 | } 1461 | } 1462 | } 1463 | 1464 | /// Creates a splicing iterator that replaces the specified range in the vector 1465 | /// with the given `replace_with` iterator and yields the removed items. 1466 | /// `replace_with` does not need to be the same length as `range`. 1467 | /// 1468 | /// `range` is removed even if the iterator is not consumed until the end. 1469 | /// 1470 | /// It is unspecified how many elements are removed from the vector 1471 | /// if the `Splice` value is leaked. 1472 | /// 1473 | /// The input iterator `replace_with` is only consumed when the `Splice` value is dropped. 1474 | /// 1475 | /// This is optimal if: 1476 | /// 1477 | /// * The tail (elements in the vector after `range`) is empty, 1478 | /// * or `replace_with` yields fewer or equal elements than `range`’s length 1479 | /// * or the lower bound of its `size_hint()` is exact. 1480 | /// 1481 | /// Otherwise, a temporary vector is allocated and the tail is moved twice. 1482 | /// 1483 | /// # Panics 1484 | /// 1485 | /// Panics if the starting point is greater than the end point or if 1486 | /// the end point is greater than the length of the vector. 1487 | /// 1488 | /// # Examples 1489 | /// 1490 | /// ``` 1491 | /// use thin_vec::{ThinVec, thin_vec}; 1492 | /// 1493 | /// let mut v = thin_vec![1, 2, 3, 4]; 1494 | /// let new = [7, 8, 9]; 1495 | /// let u: ThinVec<_> = v.splice(1..3, new).collect(); 1496 | /// assert_eq!(v, &[1, 7, 8, 9, 4]); 1497 | /// assert_eq!(u, &[2, 3]); 1498 | /// ``` 1499 | #[inline] 1500 | pub fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter> 1501 | where 1502 | R: RangeBounds, 1503 | I: IntoIterator, 1504 | { 1505 | Splice { 1506 | drain: self.drain(range), 1507 | replace_with: replace_with.into_iter(), 1508 | } 1509 | } 1510 | 1511 | /// Resize the buffer and update its capacity, without changing the length. 1512 | /// Unsafe because it can cause length to be greater than capacity. 1513 | unsafe fn reallocate(&mut self, new_cap: usize) { 1514 | debug_assert!(new_cap > 0); 1515 | if self.has_allocation() { 1516 | let old_cap = self.capacity(); 1517 | let ptr = realloc( 1518 | self.ptr() as *mut u8, 1519 | layout::(old_cap), 1520 | alloc_size::(new_cap), 1521 | ) as *mut Header; 1522 | 1523 | if ptr.is_null() { 1524 | handle_alloc_error(layout::(new_cap)) 1525 | } 1526 | (*ptr).set_cap(new_cap); 1527 | self.ptr = NonNull::new_unchecked(ptr); 1528 | } else { 1529 | let new_header = header_with_capacity::(new_cap); 1530 | 1531 | // If we get here and have a non-zero len, then we must be handling 1532 | // a gecko auto array, and we have items in a stack buffer. We shouldn't 1533 | // free it, but we should memcopy the contents out of it and mark it as empty. 1534 | // 1535 | // T is assumed to be trivially relocatable, as this is ~required 1536 | // for Rust compatibility anyway. Furthermore, we assume C++ won't try 1537 | // to unconditionally destroy the contents of the stack allocated buffer 1538 | // (i.e. it's obfuscated behind a union). 1539 | // 1540 | // In effect, we are partially reimplementing the auto array move constructor 1541 | // by leaving behind a valid empty instance. 1542 | let len = self.len(); 1543 | if cfg!(feature = "gecko-ffi") && len > 0 { 1544 | new_header 1545 | .as_ptr() 1546 | .add(1) 1547 | .cast::() 1548 | .copy_from_nonoverlapping(self.data_raw(), len); 1549 | self.set_len_non_singleton(0); 1550 | } 1551 | 1552 | self.ptr = new_header; 1553 | } 1554 | } 1555 | 1556 | #[cfg(feature = "gecko-ffi")] 1557 | #[inline] 1558 | #[allow(unused_unsafe)] 1559 | fn is_singleton(&self) -> bool { 1560 | // NOTE: the tests will complain that this "unsafe" isn't needed, but it *IS*! 1561 | // In production this refers to an *extern static* which *is* unsafe to reference. 1562 | // In tests this refers to a local static because we don't have Firefox's codebase 1563 | // providing the symbol! 1564 | unsafe { self.ptr.as_ptr() as *const Header == &EMPTY_HEADER } 1565 | } 1566 | 1567 | #[cfg(not(feature = "gecko-ffi"))] 1568 | #[inline] 1569 | fn is_singleton(&self) -> bool { 1570 | self.ptr.as_ptr() as *const Header == &EMPTY_HEADER 1571 | } 1572 | 1573 | #[cfg(feature = "gecko-ffi")] 1574 | #[inline] 1575 | fn has_allocation(&self) -> bool { 1576 | unsafe { !self.is_singleton() && !self.ptr.as_ref().uses_stack_allocated_buffer() } 1577 | } 1578 | 1579 | #[cfg(not(feature = "gecko-ffi"))] 1580 | #[inline] 1581 | fn has_allocation(&self) -> bool { 1582 | !self.is_singleton() 1583 | } 1584 | } 1585 | 1586 | impl ThinVec { 1587 | /// Resizes the `Vec` in-place so that `len()` is equal to `new_len`. 1588 | /// 1589 | /// If `new_len` is greater than `len()`, the `Vec` is extended by the 1590 | /// difference, with each additional slot filled with `value`. 1591 | /// If `new_len` is less than `len()`, the `Vec` is simply truncated. 1592 | /// 1593 | /// # Examples 1594 | /// 1595 | // A hack to avoid linking problems with `cargo test --features=gecko-ffi`. 1596 | #[cfg_attr(not(feature = "gecko-ffi"), doc = "```")] 1597 | #[cfg_attr(feature = "gecko-ffi", doc = "```ignore")] 1598 | /// # #[macro_use] extern crate thin_vec; 1599 | /// # fn main() { 1600 | /// let mut vec = thin_vec!["hello"]; 1601 | /// vec.resize(3, "world"); 1602 | /// assert_eq!(vec, ["hello", "world", "world"]); 1603 | /// 1604 | /// let mut vec = thin_vec![1, 2, 3, 4]; 1605 | /// vec.resize(2, 0); 1606 | /// assert_eq!(vec, [1, 2]); 1607 | /// # } 1608 | /// ``` 1609 | pub fn resize(&mut self, new_len: usize, value: T) { 1610 | let old_len = self.len(); 1611 | 1612 | if new_len > old_len { 1613 | let additional = new_len - old_len; 1614 | self.reserve(additional); 1615 | for _ in 1..additional { 1616 | self.push(value.clone()); 1617 | } 1618 | // We can write the last element directly without cloning needlessly 1619 | if additional > 0 { 1620 | self.push(value); 1621 | } 1622 | } else if new_len < old_len { 1623 | self.truncate(new_len); 1624 | } 1625 | } 1626 | 1627 | /// Clones and appends all elements in a slice to the `ThinVec`. 1628 | /// 1629 | /// Iterates over the slice `other`, clones each element, and then appends 1630 | /// it to this `ThinVec`. The `other` slice is traversed in-order. 1631 | /// 1632 | /// Note that this function is same as [`extend`] except that it is 1633 | /// specialized to work with slices instead. If and when Rust gets 1634 | /// specialization this function will likely be deprecated (but still 1635 | /// available). 1636 | /// 1637 | /// # Examples 1638 | /// 1639 | /// ``` 1640 | /// use thin_vec::thin_vec; 1641 | /// 1642 | /// let mut vec = thin_vec![1]; 1643 | /// vec.extend_from_slice(&[2, 3, 4]); 1644 | /// assert_eq!(vec, [1, 2, 3, 4]); 1645 | /// ``` 1646 | /// 1647 | /// [`extend`]: ThinVec::extend 1648 | pub fn extend_from_slice(&mut self, other: &[T]) { 1649 | self.extend(other.iter().cloned()) 1650 | } 1651 | } 1652 | 1653 | impl ThinVec { 1654 | /// Removes consecutive repeated elements in the vector. 1655 | /// 1656 | /// If the vector is sorted, this removes all duplicates. 1657 | /// 1658 | /// # Examples 1659 | /// 1660 | // A hack to avoid linking problems with `cargo test --features=gecko-ffi`. 1661 | #[cfg_attr(not(feature = "gecko-ffi"), doc = "```")] 1662 | #[cfg_attr(feature = "gecko-ffi", doc = "```ignore")] 1663 | /// # #[macro_use] extern crate thin_vec; 1664 | /// # fn main() { 1665 | /// let mut vec = thin_vec![1, 2, 2, 3, 2]; 1666 | /// 1667 | /// vec.dedup(); 1668 | /// 1669 | /// assert_eq!(vec, [1, 2, 3, 2]); 1670 | /// # } 1671 | /// ``` 1672 | pub fn dedup(&mut self) { 1673 | self.dedup_by(|a, b| a == b) 1674 | } 1675 | } 1676 | 1677 | impl Drop for ThinVec { 1678 | #[inline] 1679 | fn drop(&mut self) { 1680 | #[cold] 1681 | #[inline(never)] 1682 | fn drop_non_singleton(this: &mut ThinVec) { 1683 | unsafe { 1684 | ptr::drop_in_place(&mut this[..]); 1685 | 1686 | #[cfg(feature = "gecko-ffi")] 1687 | if this.ptr.as_ref().uses_stack_allocated_buffer() { 1688 | return; 1689 | } 1690 | 1691 | dealloc(this.ptr() as *mut u8, layout::(this.capacity())) 1692 | } 1693 | } 1694 | 1695 | if !self.is_singleton() { 1696 | drop_non_singleton(self); 1697 | } 1698 | } 1699 | } 1700 | 1701 | impl Deref for ThinVec { 1702 | type Target = [T]; 1703 | 1704 | fn deref(&self) -> &[T] { 1705 | self.as_slice() 1706 | } 1707 | } 1708 | 1709 | impl DerefMut for ThinVec { 1710 | fn deref_mut(&mut self) -> &mut [T] { 1711 | self.as_mut_slice() 1712 | } 1713 | } 1714 | 1715 | impl Borrow<[T]> for ThinVec { 1716 | fn borrow(&self) -> &[T] { 1717 | self.as_slice() 1718 | } 1719 | } 1720 | 1721 | impl BorrowMut<[T]> for ThinVec { 1722 | fn borrow_mut(&mut self) -> &mut [T] { 1723 | self.as_mut_slice() 1724 | } 1725 | } 1726 | 1727 | impl AsRef<[T]> for ThinVec { 1728 | fn as_ref(&self) -> &[T] { 1729 | self.as_slice() 1730 | } 1731 | } 1732 | 1733 | impl Extend for ThinVec { 1734 | #[inline] 1735 | fn extend(&mut self, iter: I) 1736 | where 1737 | I: IntoIterator, 1738 | { 1739 | let iter = iter.into_iter(); 1740 | let hint = iter.size_hint().0; 1741 | if hint > 0 { 1742 | self.reserve(hint); 1743 | } 1744 | for x in iter { 1745 | self.push(x); 1746 | } 1747 | } 1748 | } 1749 | 1750 | impl fmt::Debug for ThinVec { 1751 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1752 | fmt::Debug::fmt(&**self, f) 1753 | } 1754 | } 1755 | 1756 | impl Hash for ThinVec 1757 | where 1758 | T: Hash, 1759 | { 1760 | fn hash(&self, state: &mut H) 1761 | where 1762 | H: Hasher, 1763 | { 1764 | self[..].hash(state); 1765 | } 1766 | } 1767 | 1768 | impl PartialOrd for ThinVec 1769 | where 1770 | T: PartialOrd, 1771 | { 1772 | #[inline] 1773 | fn partial_cmp(&self, other: &ThinVec) -> Option { 1774 | self[..].partial_cmp(&other[..]) 1775 | } 1776 | } 1777 | 1778 | impl Ord for ThinVec 1779 | where 1780 | T: Ord, 1781 | { 1782 | #[inline] 1783 | fn cmp(&self, other: &ThinVec) -> Ordering { 1784 | self[..].cmp(&other[..]) 1785 | } 1786 | } 1787 | 1788 | impl PartialEq> for ThinVec 1789 | where 1790 | A: PartialEq, 1791 | { 1792 | #[inline] 1793 | fn eq(&self, other: &ThinVec) -> bool { 1794 | self[..] == other[..] 1795 | } 1796 | } 1797 | 1798 | impl PartialEq> for ThinVec 1799 | where 1800 | A: PartialEq, 1801 | { 1802 | #[inline] 1803 | fn eq(&self, other: &Vec) -> bool { 1804 | self[..] == other[..] 1805 | } 1806 | } 1807 | 1808 | impl PartialEq<[B]> for ThinVec 1809 | where 1810 | A: PartialEq, 1811 | { 1812 | #[inline] 1813 | fn eq(&self, other: &[B]) -> bool { 1814 | self[..] == other[..] 1815 | } 1816 | } 1817 | 1818 | impl<'a, A, B> PartialEq<&'a [B]> for ThinVec 1819 | where 1820 | A: PartialEq, 1821 | { 1822 | #[inline] 1823 | fn eq(&self, other: &&'a [B]) -> bool { 1824 | self[..] == other[..] 1825 | } 1826 | } 1827 | 1828 | // Serde impls based on 1829 | // https://github.com/bluss/arrayvec/blob/67ec907a98c0f40c4b76066fed3c1af59d35cf6a/src/arrayvec.rs#L1222-L1267 1830 | #[cfg(feature = "serde")] 1831 | impl serde::Serialize for ThinVec { 1832 | fn serialize(&self, serializer: S) -> Result 1833 | where 1834 | S: serde::Serializer, 1835 | { 1836 | serializer.collect_seq(self.as_slice()) 1837 | } 1838 | } 1839 | 1840 | #[cfg(feature = "serde")] 1841 | impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for ThinVec { 1842 | fn deserialize(deserializer: D) -> Result 1843 | where 1844 | D: serde::Deserializer<'de>, 1845 | { 1846 | use serde::de::{SeqAccess, Visitor}; 1847 | use serde::Deserialize; 1848 | 1849 | struct ThinVecVisitor(PhantomData); 1850 | 1851 | impl<'de, T: Deserialize<'de>> Visitor<'de> for ThinVecVisitor { 1852 | type Value = ThinVec; 1853 | 1854 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 1855 | write!(formatter, "a sequence") 1856 | } 1857 | 1858 | fn visit_seq(self, mut seq: SA) -> Result 1859 | where 1860 | SA: SeqAccess<'de>, 1861 | { 1862 | // Same policy as 1863 | // https://github.com/serde-rs/serde/blob/ce0844b9ecc32377b5e4545d759d385a8c46bc6a/serde/src/private/size_hint.rs#L13 1864 | let initial_capacity = seq.size_hint().unwrap_or_default().min(4096); 1865 | let mut values = ThinVec::::with_capacity(initial_capacity); 1866 | 1867 | while let Some(value) = seq.next_element()? { 1868 | values.push(value); 1869 | } 1870 | 1871 | Ok(values) 1872 | } 1873 | } 1874 | 1875 | deserializer.deserialize_seq(ThinVecVisitor::(PhantomData)) 1876 | } 1877 | } 1878 | 1879 | #[cfg(feature = "malloc_size_of")] 1880 | impl MallocShallowSizeOf for ThinVec { 1881 | fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { 1882 | if self.capacity() == 0 { 1883 | // If it's the singleton we might not be a heap pointer. 1884 | return 0; 1885 | } 1886 | 1887 | assert_eq!( 1888 | std::mem::size_of::(), 1889 | std::mem::size_of::<*const ()>() 1890 | ); 1891 | unsafe { ops.malloc_size_of(*(self as *const Self as *const *const ())) } 1892 | } 1893 | } 1894 | 1895 | #[cfg(feature = "malloc_size_of")] 1896 | impl MallocSizeOf for ThinVec { 1897 | fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { 1898 | let mut n = self.shallow_size_of(ops); 1899 | for elem in self.iter() { 1900 | n += elem.size_of(ops); 1901 | } 1902 | n 1903 | } 1904 | } 1905 | 1906 | macro_rules! array_impls { 1907 | ($($N:expr)*) => {$( 1908 | impl PartialEq<[B; $N]> for ThinVec where A: PartialEq { 1909 | #[inline] 1910 | fn eq(&self, other: &[B; $N]) -> bool { self[..] == other[..] } 1911 | } 1912 | 1913 | impl<'a, A, B> PartialEq<&'a [B; $N]> for ThinVec where A: PartialEq { 1914 | #[inline] 1915 | fn eq(&self, other: &&'a [B; $N]) -> bool { self[..] == other[..] } 1916 | } 1917 | )*} 1918 | } 1919 | 1920 | array_impls! { 1921 | 0 1 2 3 4 5 6 7 8 9 1922 | 10 11 12 13 14 15 16 17 18 19 1923 | 20 21 22 23 24 25 26 27 28 29 1924 | 30 31 32 1925 | } 1926 | 1927 | impl Eq for ThinVec where T: Eq {} 1928 | 1929 | impl IntoIterator for ThinVec { 1930 | type Item = T; 1931 | type IntoIter = IntoIter; 1932 | 1933 | fn into_iter(self) -> IntoIter { 1934 | IntoIter { 1935 | vec: self, 1936 | start: 0, 1937 | } 1938 | } 1939 | } 1940 | 1941 | impl<'a, T> IntoIterator for &'a ThinVec { 1942 | type Item = &'a T; 1943 | type IntoIter = slice::Iter<'a, T>; 1944 | 1945 | fn into_iter(self) -> slice::Iter<'a, T> { 1946 | self.iter() 1947 | } 1948 | } 1949 | 1950 | impl<'a, T> IntoIterator for &'a mut ThinVec { 1951 | type Item = &'a mut T; 1952 | type IntoIter = slice::IterMut<'a, T>; 1953 | 1954 | fn into_iter(self) -> slice::IterMut<'a, T> { 1955 | self.iter_mut() 1956 | } 1957 | } 1958 | 1959 | impl Clone for ThinVec 1960 | where 1961 | T: Clone, 1962 | { 1963 | #[inline] 1964 | fn clone(&self) -> ThinVec { 1965 | #[cold] 1966 | #[inline(never)] 1967 | fn clone_non_singleton(this: &ThinVec) -> ThinVec { 1968 | let len = this.len(); 1969 | let mut new_vec = ThinVec::::with_capacity(len); 1970 | let mut data_raw = new_vec.data_raw(); 1971 | for x in this.iter() { 1972 | unsafe { 1973 | ptr::write(data_raw, x.clone()); 1974 | data_raw = data_raw.add(1); 1975 | } 1976 | } 1977 | unsafe { 1978 | // `this` is not the singleton, but `new_vec` will be if 1979 | // `this` is empty. 1980 | new_vec.set_len(len); // could be the singleton 1981 | } 1982 | new_vec 1983 | } 1984 | 1985 | if self.is_singleton() { 1986 | ThinVec::new() 1987 | } else { 1988 | clone_non_singleton(self) 1989 | } 1990 | } 1991 | } 1992 | 1993 | impl Default for ThinVec { 1994 | fn default() -> ThinVec { 1995 | ThinVec::new() 1996 | } 1997 | } 1998 | 1999 | impl FromIterator for ThinVec { 2000 | #[inline] 2001 | fn from_iter>(iter: I) -> ThinVec { 2002 | let mut vec = ThinVec::new(); 2003 | vec.extend(iter); 2004 | vec 2005 | } 2006 | } 2007 | 2008 | impl From<&[T]> for ThinVec { 2009 | /// Allocate a `ThinVec` and fill it by cloning `s`'s items. 2010 | /// 2011 | /// # Examples 2012 | /// 2013 | /// ``` 2014 | /// use thin_vec::{ThinVec, thin_vec}; 2015 | /// 2016 | /// assert_eq!(ThinVec::from(&[1, 2, 3][..]), thin_vec![1, 2, 3]); 2017 | /// ``` 2018 | fn from(s: &[T]) -> ThinVec { 2019 | s.iter().cloned().collect() 2020 | } 2021 | } 2022 | 2023 | #[cfg(not(no_global_oom_handling))] 2024 | impl From<&mut [T]> for ThinVec { 2025 | /// Allocate a `ThinVec` and fill it by cloning `s`'s items. 2026 | /// 2027 | /// # Examples 2028 | /// 2029 | /// ``` 2030 | /// use thin_vec::{ThinVec, thin_vec}; 2031 | /// 2032 | /// assert_eq!(ThinVec::from(&mut [1, 2, 3][..]), thin_vec![1, 2, 3]); 2033 | /// ``` 2034 | fn from(s: &mut [T]) -> ThinVec { 2035 | s.iter().cloned().collect() 2036 | } 2037 | } 2038 | 2039 | impl From<[T; N]> for ThinVec { 2040 | /// Allocate a `ThinVec` and move `s`'s items into it. 2041 | /// 2042 | /// # Examples 2043 | /// 2044 | /// ``` 2045 | /// use thin_vec::{ThinVec, thin_vec}; 2046 | /// 2047 | /// assert_eq!(ThinVec::from([1, 2, 3]), thin_vec![1, 2, 3]); 2048 | /// ``` 2049 | fn from(s: [T; N]) -> ThinVec { 2050 | core::iter::IntoIterator::into_iter(s).collect() 2051 | } 2052 | } 2053 | 2054 | impl From> for ThinVec { 2055 | /// Convert a boxed slice into a vector by transferring ownership of 2056 | /// the existing heap allocation. 2057 | /// 2058 | /// **NOTE:** unlike `std`, this must reallocate to change the layout! 2059 | /// 2060 | /// # Examples 2061 | /// 2062 | /// ``` 2063 | /// use thin_vec::{ThinVec, thin_vec}; 2064 | /// 2065 | /// let b: Box<[i32]> = thin_vec![1, 2, 3].into_iter().collect(); 2066 | /// assert_eq!(ThinVec::from(b), thin_vec![1, 2, 3]); 2067 | /// ``` 2068 | fn from(s: Box<[T]>) -> Self { 2069 | // Can just lean on the fact that `Box<[T]>` -> `Vec` is Free. 2070 | Vec::from(s).into_iter().collect() 2071 | } 2072 | } 2073 | 2074 | impl From> for ThinVec { 2075 | /// Convert a `std::Vec` into a `ThinVec`. 2076 | /// 2077 | /// **NOTE:** this must reallocate to change the layout! 2078 | /// 2079 | /// # Examples 2080 | /// 2081 | /// ``` 2082 | /// use thin_vec::{ThinVec, thin_vec}; 2083 | /// 2084 | /// let b: Vec = vec![1, 2, 3]; 2085 | /// assert_eq!(ThinVec::from(b), thin_vec![1, 2, 3]); 2086 | /// ``` 2087 | fn from(s: Vec) -> Self { 2088 | s.into_iter().collect() 2089 | } 2090 | } 2091 | 2092 | impl From> for Vec { 2093 | /// Convert a `ThinVec` into a `std::Vec`. 2094 | /// 2095 | /// **NOTE:** this must reallocate to change the layout! 2096 | /// 2097 | /// # Examples 2098 | /// 2099 | /// ``` 2100 | /// use thin_vec::{ThinVec, thin_vec}; 2101 | /// 2102 | /// let b: ThinVec = thin_vec![1, 2, 3]; 2103 | /// assert_eq!(Vec::from(b), vec![1, 2, 3]); 2104 | /// ``` 2105 | fn from(s: ThinVec) -> Self { 2106 | s.into_iter().collect() 2107 | } 2108 | } 2109 | 2110 | impl From> for Box<[T]> { 2111 | /// Convert a vector into a boxed slice. 2112 | /// 2113 | /// If `v` has excess capacity, its items will be moved into a 2114 | /// newly-allocated buffer with exactly the right capacity. 2115 | /// 2116 | /// **NOTE:** unlike `std`, this must reallocate to change the layout! 2117 | /// 2118 | /// # Examples 2119 | /// 2120 | /// ``` 2121 | /// use thin_vec::{ThinVec, thin_vec}; 2122 | /// assert_eq!(Box::from(thin_vec![1, 2, 3]), thin_vec![1, 2, 3].into_iter().collect()); 2123 | /// ``` 2124 | fn from(v: ThinVec) -> Self { 2125 | v.into_iter().collect() 2126 | } 2127 | } 2128 | 2129 | impl From<&str> for ThinVec { 2130 | /// Allocate a `ThinVec` and fill it with a UTF-8 string. 2131 | /// 2132 | /// # Examples 2133 | /// 2134 | /// ``` 2135 | /// use thin_vec::{ThinVec, thin_vec}; 2136 | /// 2137 | /// assert_eq!(ThinVec::from("123"), thin_vec![b'1', b'2', b'3']); 2138 | /// ``` 2139 | fn from(s: &str) -> ThinVec { 2140 | From::from(s.as_bytes()) 2141 | } 2142 | } 2143 | 2144 | impl TryFrom> for [T; N] { 2145 | type Error = ThinVec; 2146 | 2147 | /// Gets the entire contents of the `ThinVec` as an array, 2148 | /// if its size exactly matches that of the requested array. 2149 | /// 2150 | /// # Examples 2151 | /// 2152 | /// ``` 2153 | /// use thin_vec::{ThinVec, thin_vec}; 2154 | /// use std::convert::TryInto; 2155 | /// 2156 | /// assert_eq!(thin_vec![1, 2, 3].try_into(), Ok([1, 2, 3])); 2157 | /// assert_eq!(>::new().try_into(), Ok([])); 2158 | /// ``` 2159 | /// 2160 | /// If the length doesn't match, the input comes back in `Err`: 2161 | /// ``` 2162 | /// use thin_vec::{ThinVec, thin_vec}; 2163 | /// use std::convert::TryInto; 2164 | /// 2165 | /// let r: Result<[i32; 4], _> = (0..10).collect::>().try_into(); 2166 | /// assert_eq!(r, Err(thin_vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); 2167 | /// ``` 2168 | /// 2169 | /// If you're fine with just getting a prefix of the `ThinVec`, 2170 | /// you can call [`.truncate(N)`](ThinVec::truncate) first. 2171 | /// ``` 2172 | /// use thin_vec::{ThinVec, thin_vec}; 2173 | /// use std::convert::TryInto; 2174 | /// 2175 | /// let mut v = ThinVec::from("hello world"); 2176 | /// v.sort(); 2177 | /// v.truncate(2); 2178 | /// let [a, b]: [_; 2] = v.try_into().unwrap(); 2179 | /// assert_eq!(a, b' '); 2180 | /// assert_eq!(b, b'd'); 2181 | /// ``` 2182 | fn try_from(mut vec: ThinVec) -> Result<[T; N], ThinVec> { 2183 | if vec.len() != N { 2184 | return Err(vec); 2185 | } 2186 | 2187 | // SAFETY: `.set_len(0)` is always sound. 2188 | unsafe { vec.set_len(0) }; 2189 | 2190 | // SAFETY: A `ThinVec`'s pointer is always aligned properly, and 2191 | // the alignment the array needs is the same as the items. 2192 | // We checked earlier that we have sufficient items. 2193 | // The items will not double-drop as the `set_len` 2194 | // tells the `ThinVec` not to also drop them. 2195 | let array = unsafe { ptr::read(vec.data_raw() as *const [T; N]) }; 2196 | Ok(array) 2197 | } 2198 | } 2199 | 2200 | /// An iterator that moves out of a vector. 2201 | /// 2202 | /// This `struct` is created by the [`ThinVec::into_iter`][] 2203 | /// (provided by the [`IntoIterator`] trait). 2204 | /// 2205 | /// # Example 2206 | /// 2207 | /// ``` 2208 | /// use thin_vec::thin_vec; 2209 | /// 2210 | /// let v = thin_vec![0, 1, 2]; 2211 | /// let iter: thin_vec::IntoIter<_> = v.into_iter(); 2212 | /// ``` 2213 | pub struct IntoIter { 2214 | vec: ThinVec, 2215 | start: usize, 2216 | } 2217 | 2218 | impl IntoIter { 2219 | /// Returns the remaining items of this iterator as a slice. 2220 | /// 2221 | /// # Examples 2222 | /// 2223 | /// ``` 2224 | /// use thin_vec::thin_vec; 2225 | /// 2226 | /// let vec = thin_vec!['a', 'b', 'c']; 2227 | /// let mut into_iter = vec.into_iter(); 2228 | /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); 2229 | /// let _ = into_iter.next().unwrap(); 2230 | /// assert_eq!(into_iter.as_slice(), &['b', 'c']); 2231 | /// ``` 2232 | pub fn as_slice(&self) -> &[T] { 2233 | unsafe { slice::from_raw_parts(self.vec.data_raw().add(self.start), self.len()) } 2234 | } 2235 | 2236 | /// Returns the remaining items of this iterator as a mutable slice. 2237 | /// 2238 | /// # Examples 2239 | /// 2240 | /// ``` 2241 | /// use thin_vec::thin_vec; 2242 | /// 2243 | /// let vec = thin_vec!['a', 'b', 'c']; 2244 | /// let mut into_iter = vec.into_iter(); 2245 | /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); 2246 | /// into_iter.as_mut_slice()[2] = 'z'; 2247 | /// assert_eq!(into_iter.next().unwrap(), 'a'); 2248 | /// assert_eq!(into_iter.next().unwrap(), 'b'); 2249 | /// assert_eq!(into_iter.next().unwrap(), 'z'); 2250 | /// ``` 2251 | pub fn as_mut_slice(&mut self) -> &mut [T] { 2252 | unsafe { &mut *self.as_raw_mut_slice() } 2253 | } 2254 | 2255 | fn as_raw_mut_slice(&mut self) -> *mut [T] { 2256 | unsafe { ptr::slice_from_raw_parts_mut(self.vec.data_raw().add(self.start), self.len()) } 2257 | } 2258 | } 2259 | 2260 | impl Iterator for IntoIter { 2261 | type Item = T; 2262 | fn next(&mut self) -> Option { 2263 | if self.start == self.vec.len() { 2264 | None 2265 | } else { 2266 | unsafe { 2267 | let old_start = self.start; 2268 | self.start += 1; 2269 | Some(ptr::read(self.vec.data_raw().add(old_start))) 2270 | } 2271 | } 2272 | } 2273 | 2274 | fn size_hint(&self) -> (usize, Option) { 2275 | let len = self.vec.len() - self.start; 2276 | (len, Some(len)) 2277 | } 2278 | } 2279 | 2280 | impl DoubleEndedIterator for IntoIter { 2281 | fn next_back(&mut self) -> Option { 2282 | if self.start == self.vec.len() { 2283 | None 2284 | } else { 2285 | self.vec.pop() 2286 | } 2287 | } 2288 | } 2289 | 2290 | impl ExactSizeIterator for IntoIter {} 2291 | 2292 | impl core::iter::FusedIterator for IntoIter {} 2293 | 2294 | // SAFETY: the length calculation is trivial, we're an array! And if it's wrong we're So Screwed. 2295 | #[cfg(feature = "unstable")] 2296 | unsafe impl core::iter::TrustedLen for IntoIter {} 2297 | 2298 | impl Drop for IntoIter { 2299 | #[inline] 2300 | fn drop(&mut self) { 2301 | #[cold] 2302 | #[inline(never)] 2303 | fn drop_non_singleton(this: &mut IntoIter) { 2304 | unsafe { 2305 | let mut vec = mem::replace(&mut this.vec, ThinVec::new()); 2306 | ptr::drop_in_place(&mut vec[this.start..]); 2307 | vec.set_len_non_singleton(0) 2308 | } 2309 | } 2310 | 2311 | if !self.vec.is_singleton() { 2312 | drop_non_singleton(self); 2313 | } 2314 | } 2315 | } 2316 | 2317 | impl fmt::Debug for IntoIter { 2318 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 2319 | f.debug_tuple("IntoIter").field(&self.as_slice()).finish() 2320 | } 2321 | } 2322 | 2323 | impl AsRef<[T]> for IntoIter { 2324 | fn as_ref(&self) -> &[T] { 2325 | self.as_slice() 2326 | } 2327 | } 2328 | 2329 | impl Clone for IntoIter { 2330 | #[allow(clippy::into_iter_on_ref)] 2331 | fn clone(&self) -> Self { 2332 | // Just create a new `ThinVec` from the remaining elements and IntoIter it 2333 | self.as_slice() 2334 | .into_iter() 2335 | .cloned() 2336 | .collect::>() 2337 | .into_iter() 2338 | } 2339 | } 2340 | 2341 | /// A draining iterator for `ThinVec`. 2342 | /// 2343 | /// This `struct` is created by [`ThinVec::drain`]. 2344 | /// See its documentation for more. 2345 | /// 2346 | /// # Example 2347 | /// 2348 | /// ``` 2349 | /// use thin_vec::thin_vec; 2350 | /// 2351 | /// let mut v = thin_vec![0, 1, 2]; 2352 | /// let iter: thin_vec::Drain<_> = v.drain(..); 2353 | /// ``` 2354 | pub struct Drain<'a, T> { 2355 | // Ok so ThinVec::drain takes a range of the ThinVec and yields the contents by-value, 2356 | // then backshifts the array. During iteration the array is in an unsound state 2357 | // (big deinitialized hole in it), and this is very dangerous. 2358 | // 2359 | // Our first line of defense is the borrow checker: we have a mutable borrow, so nothing 2360 | // can access the ThinVec while we exist. As long as we make sure the ThinVec is in a valid 2361 | // state again before we release the borrow, everything should be A-OK! We do this cleanup 2362 | // in our Drop impl. 2363 | // 2364 | // Unfortunately, that's unsound, because mem::forget exists and The Leakpocalypse Is Real. 2365 | // So we can't actually guarantee our destructor runs before our borrow expires. Thankfully 2366 | // this isn't fatal: we can just set the ThinVec's len to 0 at the start, so if anyone 2367 | // leaks the Drain, we just leak everything the ThinVec contained out of spite! If they 2368 | // *don't* leak us then we can properly repair the len in our Drop impl. This is known 2369 | // as "leak amplification", and is the same approach std uses. 2370 | // 2371 | // But we can do slightly better than setting the len to 0! The drain breaks us up into 2372 | // these parts: 2373 | // 2374 | // ```text 2375 | // 2376 | // [A, B, C, D, E, F, G, H, _, _] 2377 | // ____ __________ ____ ____ 2378 | // | | | | 2379 | // prefix drain tail spare-cap 2380 | // ``` 2381 | // 2382 | // As the drain iterator is consumed from both ends (DoubleEnded!), we'll start to look 2383 | // like this: 2384 | // 2385 | // ```text 2386 | // [A, B, _, _, E, _, G, H, _, _] 2387 | // ____ __________ ____ ____ 2388 | // | | | | 2389 | // prefix drain tail spare-cap 2390 | // ``` 2391 | // 2392 | // Note that the prefix is always valid and untouched, as such we can set the len 2393 | // to the prefix when doing leak-amplification. As a bonus, we can use this value 2394 | // to remember where the drain range starts. At the end we'll look like this 2395 | // (we exhaust ourselves in our Drop impl): 2396 | // 2397 | // ```text 2398 | // [A, B, _, _, _, _, G, H, _, _] 2399 | // _____ __________ _____ ____ 2400 | // | | | | 2401 | // len drain tail spare-cap 2402 | // ``` 2403 | // 2404 | // And need to become this: 2405 | // 2406 | // ```text 2407 | // [A, B, G, H, _, _, _, _, _, _] 2408 | // ___________ ________________ 2409 | // | | 2410 | // len spare-cap 2411 | // ``` 2412 | // 2413 | // All this requires is moving the tail back to the prefix (stored in `len`) 2414 | // and setting `len` to `len + tail_len` to undo the leak amplification. 2415 | /// An iterator over the elements we're removing. 2416 | /// 2417 | /// As we go we'll be `read`ing out of the mutable refs yielded by this. 2418 | /// It's ok to use IterMut here because it promises to only take mutable 2419 | /// refs to the parts we haven't yielded yet. 2420 | /// 2421 | /// A downside of this (and the *mut below) is that it makes this type invariant, when 2422 | /// technically it could be covariant? 2423 | iter: IterMut<'a, T>, 2424 | /// The actual ThinVec, which we need to hold onto to undo the leak amplification 2425 | /// and backshift the tail into place. This should only be accessed when we're 2426 | /// completely done with the IterMut in the `drop` impl of this type (or miri will get mad). 2427 | /// 2428 | /// Since we set the `len` of this to be before `IterMut`, we can use that `len` 2429 | /// to retrieve the index of the start of the drain range later. 2430 | vec: *mut ThinVec, 2431 | /// The one-past-the-end index of the drain range, or equivalently the start of the tail. 2432 | end: usize, 2433 | /// The length of the tail. 2434 | tail: usize, 2435 | } 2436 | 2437 | impl<'a, T> Iterator for Drain<'a, T> { 2438 | type Item = T; 2439 | fn next(&mut self) -> Option { 2440 | self.iter.next().map(|x| unsafe { ptr::read(x) }) 2441 | } 2442 | 2443 | fn size_hint(&self) -> (usize, Option) { 2444 | self.iter.size_hint() 2445 | } 2446 | } 2447 | 2448 | impl<'a, T> DoubleEndedIterator for Drain<'a, T> { 2449 | fn next_back(&mut self) -> Option { 2450 | self.iter.next_back().map(|x| unsafe { ptr::read(x) }) 2451 | } 2452 | } 2453 | 2454 | impl<'a, T> ExactSizeIterator for Drain<'a, T> {} 2455 | 2456 | // SAFETY: we need to keep track of this perfectly Or Else anyway! 2457 | #[cfg(feature = "unstable")] 2458 | unsafe impl core::iter::TrustedLen for Drain<'_, T> {} 2459 | 2460 | impl core::iter::FusedIterator for Drain<'_, T> {} 2461 | 2462 | impl<'a, T> Drop for Drain<'a, T> { 2463 | fn drop(&mut self) { 2464 | // Consume the rest of the iterator. 2465 | for _ in self.by_ref() {} 2466 | 2467 | // Move the tail over the drained items, and update the length. 2468 | unsafe { 2469 | let vec = &mut *self.vec; 2470 | 2471 | // Don't mutate the empty singleton! 2472 | if !vec.is_singleton() { 2473 | let old_len = vec.len(); 2474 | let start = vec.data_raw().add(old_len); 2475 | let end = vec.data_raw().add(self.end); 2476 | ptr::copy(end, start, self.tail); 2477 | vec.set_len_non_singleton(old_len + self.tail); 2478 | } 2479 | } 2480 | } 2481 | } 2482 | 2483 | impl fmt::Debug for Drain<'_, T> { 2484 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 2485 | f.debug_tuple("Drain").field(&self.iter.as_slice()).finish() 2486 | } 2487 | } 2488 | 2489 | impl<'a, T> Drain<'a, T> { 2490 | /// Returns the remaining items of this iterator as a slice. 2491 | /// 2492 | /// # Examples 2493 | /// 2494 | /// ``` 2495 | /// use thin_vec::thin_vec; 2496 | /// 2497 | /// let mut vec = thin_vec!['a', 'b', 'c']; 2498 | /// let mut drain = vec.drain(..); 2499 | /// assert_eq!(drain.as_slice(), &['a', 'b', 'c']); 2500 | /// let _ = drain.next().unwrap(); 2501 | /// assert_eq!(drain.as_slice(), &['b', 'c']); 2502 | /// ``` 2503 | #[must_use] 2504 | pub fn as_slice(&self) -> &[T] { 2505 | // SAFETY: this is A-OK because the elements that the underlying 2506 | // iterator still points at are still logically initialized and contiguous. 2507 | self.iter.as_slice() 2508 | } 2509 | } 2510 | 2511 | impl<'a, T> AsRef<[T]> for Drain<'a, T> { 2512 | fn as_ref(&self) -> &[T] { 2513 | self.as_slice() 2514 | } 2515 | } 2516 | 2517 | /// A splicing iterator for `ThinVec`. 2518 | /// 2519 | /// This struct is created by [`ThinVec::splice`][]. 2520 | /// See its documentation for more. 2521 | /// 2522 | /// # Example 2523 | /// 2524 | /// ``` 2525 | /// use thin_vec::thin_vec; 2526 | /// 2527 | /// let mut v = thin_vec![0, 1, 2]; 2528 | /// let new = [7, 8]; 2529 | /// let iter: thin_vec::Splice<_> = v.splice(1.., new); 2530 | /// ``` 2531 | #[derive(Debug)] 2532 | pub struct Splice<'a, I: Iterator + 'a> { 2533 | drain: Drain<'a, I::Item>, 2534 | replace_with: I, 2535 | } 2536 | 2537 | impl Iterator for Splice<'_, I> { 2538 | type Item = I::Item; 2539 | 2540 | fn next(&mut self) -> Option { 2541 | self.drain.next() 2542 | } 2543 | 2544 | fn size_hint(&self) -> (usize, Option) { 2545 | self.drain.size_hint() 2546 | } 2547 | } 2548 | 2549 | impl DoubleEndedIterator for Splice<'_, I> { 2550 | fn next_back(&mut self) -> Option { 2551 | self.drain.next_back() 2552 | } 2553 | } 2554 | 2555 | impl ExactSizeIterator for Splice<'_, I> {} 2556 | 2557 | impl Drop for Splice<'_, I> { 2558 | fn drop(&mut self) { 2559 | // Ensure we've fully drained out the range 2560 | self.drain.by_ref().for_each(drop); 2561 | 2562 | unsafe { 2563 | // If there's no tail elements, then the inner ThinVec is already 2564 | // correct and we can just extend it like normal. 2565 | if self.drain.tail == 0 { 2566 | (*self.drain.vec).extend(self.replace_with.by_ref()); 2567 | return; 2568 | } 2569 | 2570 | // First fill the range left by drain(). 2571 | if !self.drain.fill(&mut self.replace_with) { 2572 | return; 2573 | } 2574 | 2575 | // There may be more elements. Use the lower bound as an estimate. 2576 | let (lower_bound, _upper_bound) = self.replace_with.size_hint(); 2577 | if lower_bound > 0 { 2578 | self.drain.move_tail(lower_bound); 2579 | if !self.drain.fill(&mut self.replace_with) { 2580 | return; 2581 | } 2582 | } 2583 | 2584 | // Collect any remaining elements. 2585 | // This is a zero-length vector which does not allocate if `lower_bound` was exact. 2586 | let mut collected = self 2587 | .replace_with 2588 | .by_ref() 2589 | .collect::>() 2590 | .into_iter(); 2591 | // Now we have an exact count. 2592 | if collected.len() > 0 { 2593 | self.drain.move_tail(collected.len()); 2594 | let filled = self.drain.fill(&mut collected); 2595 | debug_assert!(filled); 2596 | debug_assert_eq!(collected.len(), 0); 2597 | } 2598 | } 2599 | // Let `Drain::drop` move the tail back if necessary and restore `vec.len`. 2600 | } 2601 | } 2602 | 2603 | /// Private helper methods for `Splice::drop` 2604 | impl Drain<'_, T> { 2605 | /// The range from `self.vec.len` to `self.tail_start` contains elements 2606 | /// that have been moved out. 2607 | /// Fill that range as much as possible with new elements from the `replace_with` iterator. 2608 | /// Returns `true` if we filled the entire range. (`replace_with.next()` didn’t return `None`.) 2609 | unsafe fn fill>(&mut self, replace_with: &mut I) -> bool { 2610 | let vec = unsafe { &mut *self.vec }; 2611 | let range_start = vec.len(); 2612 | let range_end = self.end; 2613 | let range_slice = unsafe { 2614 | slice::from_raw_parts_mut(vec.data_raw().add(range_start), range_end - range_start) 2615 | }; 2616 | 2617 | for place in range_slice { 2618 | if let Some(new_item) = replace_with.next() { 2619 | unsafe { ptr::write(place, new_item) }; 2620 | vec.set_len(vec.len() + 1); 2621 | } else { 2622 | return false; 2623 | } 2624 | } 2625 | true 2626 | } 2627 | 2628 | /// Makes room for inserting more elements before the tail. 2629 | unsafe fn move_tail(&mut self, additional: usize) { 2630 | let vec = unsafe { &mut *self.vec }; 2631 | let len = self.end + self.tail; 2632 | vec.reserve(len.checked_add(additional).expect("capacity overflow")); 2633 | 2634 | let new_tail_start = self.end + additional; 2635 | unsafe { 2636 | let src = vec.data_raw().add(self.end); 2637 | let dst = vec.data_raw().add(new_tail_start); 2638 | ptr::copy(src, dst, self.tail); 2639 | } 2640 | self.end = new_tail_start; 2641 | } 2642 | } 2643 | 2644 | /// Write is implemented for `ThinVec` by appending to the vector. 2645 | /// The vector will grow as needed. 2646 | /// This implementation is identical to the one for `Vec`. 2647 | #[cfg(feature = "std")] 2648 | impl std::io::Write for ThinVec { 2649 | #[inline] 2650 | fn write(&mut self, buf: &[u8]) -> std::io::Result { 2651 | self.extend_from_slice(buf); 2652 | Ok(buf.len()) 2653 | } 2654 | 2655 | #[inline] 2656 | fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> { 2657 | self.extend_from_slice(buf); 2658 | Ok(()) 2659 | } 2660 | 2661 | #[inline] 2662 | fn flush(&mut self) -> std::io::Result<()> { 2663 | Ok(()) 2664 | } 2665 | } 2666 | 2667 | // TODO: a million Index impls 2668 | 2669 | #[cfg(test)] 2670 | mod tests { 2671 | use super::{ThinVec, MAX_CAP}; 2672 | use crate::alloc::{string::ToString, vec}; 2673 | 2674 | #[test] 2675 | fn test_size_of() { 2676 | use core::mem::size_of; 2677 | assert_eq!(size_of::>(), size_of::<&u8>()); 2678 | 2679 | assert_eq!(size_of::>>(), size_of::<&u8>()); 2680 | } 2681 | 2682 | #[test] 2683 | fn test_drop_empty() { 2684 | ThinVec::::new(); 2685 | } 2686 | 2687 | #[test] 2688 | fn test_data_ptr_alignment() { 2689 | let v = ThinVec::::new(); 2690 | assert!(v.data_raw() as usize % 2 == 0); 2691 | 2692 | let v = ThinVec::::new(); 2693 | assert!(v.data_raw() as usize % 4 == 0); 2694 | 2695 | let v = ThinVec::::new(); 2696 | assert!(v.data_raw() as usize % 8 == 0); 2697 | } 2698 | 2699 | #[test] 2700 | #[cfg_attr(feature = "gecko-ffi", should_panic)] 2701 | fn test_overaligned_type_is_rejected_for_gecko_ffi_mode() { 2702 | #[repr(align(16))] 2703 | struct Align16(u8); 2704 | 2705 | let v = ThinVec::::new(); 2706 | assert!(v.data_raw() as usize % 16 == 0); 2707 | } 2708 | 2709 | #[test] 2710 | fn test_partial_eq() { 2711 | assert_eq!(thin_vec![0], thin_vec![0]); 2712 | assert_ne!(thin_vec![0], thin_vec![1]); 2713 | assert_eq!(thin_vec![1, 2, 3], vec![1, 2, 3]); 2714 | } 2715 | 2716 | #[test] 2717 | fn test_alloc() { 2718 | let mut v = ThinVec::new(); 2719 | assert!(!v.has_allocation()); 2720 | v.push(1); 2721 | assert!(v.has_allocation()); 2722 | v.pop(); 2723 | assert!(v.has_allocation()); 2724 | v.shrink_to_fit(); 2725 | assert!(!v.has_allocation()); 2726 | v.reserve(64); 2727 | assert!(v.has_allocation()); 2728 | v = ThinVec::with_capacity(64); 2729 | assert!(v.has_allocation()); 2730 | v = ThinVec::with_capacity(0); 2731 | assert!(!v.has_allocation()); 2732 | } 2733 | 2734 | #[test] 2735 | fn test_drain_items() { 2736 | let mut vec = thin_vec![1, 2, 3]; 2737 | let mut vec2 = thin_vec![]; 2738 | for i in vec.drain(..) { 2739 | vec2.push(i); 2740 | } 2741 | assert_eq!(vec, []); 2742 | assert_eq!(vec2, [1, 2, 3]); 2743 | } 2744 | 2745 | #[test] 2746 | fn test_drain_items_reverse() { 2747 | let mut vec = thin_vec![1, 2, 3]; 2748 | let mut vec2 = thin_vec![]; 2749 | for i in vec.drain(..).rev() { 2750 | vec2.push(i); 2751 | } 2752 | assert_eq!(vec, []); 2753 | assert_eq!(vec2, [3, 2, 1]); 2754 | } 2755 | 2756 | #[test] 2757 | fn test_drain_items_zero_sized() { 2758 | let mut vec = thin_vec![(), (), ()]; 2759 | let mut vec2 = thin_vec![]; 2760 | for i in vec.drain(..) { 2761 | vec2.push(i); 2762 | } 2763 | assert_eq!(vec, []); 2764 | assert_eq!(vec2, [(), (), ()]); 2765 | } 2766 | 2767 | #[test] 2768 | #[should_panic] 2769 | fn test_drain_out_of_bounds() { 2770 | let mut v = thin_vec![1, 2, 3, 4, 5]; 2771 | v.drain(5..6); 2772 | } 2773 | 2774 | #[test] 2775 | fn test_drain_range() { 2776 | let mut v = thin_vec![1, 2, 3, 4, 5]; 2777 | for _ in v.drain(4..) {} 2778 | assert_eq!(v, &[1, 2, 3, 4]); 2779 | 2780 | let mut v: ThinVec<_> = (1..6).map(|x| x.to_string()).collect(); 2781 | for _ in v.drain(1..4) {} 2782 | assert_eq!(v, &[1.to_string(), 5.to_string()]); 2783 | 2784 | let mut v: ThinVec<_> = (1..6).map(|x| x.to_string()).collect(); 2785 | for _ in v.drain(1..4).rev() {} 2786 | assert_eq!(v, &[1.to_string(), 5.to_string()]); 2787 | 2788 | let mut v: ThinVec<_> = thin_vec![(); 5]; 2789 | for _ in v.drain(1..4).rev() {} 2790 | assert_eq!(v, &[(), ()]); 2791 | } 2792 | 2793 | #[test] 2794 | fn test_drain_max_vec_size() { 2795 | let mut v = ThinVec::<()>::with_capacity(MAX_CAP); 2796 | unsafe { 2797 | v.set_len(MAX_CAP); 2798 | } 2799 | for _ in v.drain(MAX_CAP - 1..) {} 2800 | assert_eq!(v.len(), MAX_CAP - 1); 2801 | } 2802 | 2803 | #[test] 2804 | fn test_clear() { 2805 | let mut v = ThinVec::::new(); 2806 | assert_eq!(v.len(), 0); 2807 | assert_eq!(v.capacity(), 0); 2808 | assert_eq!(&v[..], &[]); 2809 | 2810 | v.clear(); 2811 | assert_eq!(v.len(), 0); 2812 | assert_eq!(v.capacity(), 0); 2813 | assert_eq!(&v[..], &[]); 2814 | 2815 | v.push(1); 2816 | v.push(2); 2817 | assert_eq!(v.len(), 2); 2818 | assert!(v.capacity() >= 2); 2819 | assert_eq!(&v[..], &[1, 2]); 2820 | 2821 | v.clear(); 2822 | assert_eq!(v.len(), 0); 2823 | assert!(v.capacity() >= 2); 2824 | assert_eq!(&v[..], &[]); 2825 | 2826 | v.push(3); 2827 | v.push(4); 2828 | assert_eq!(v.len(), 2); 2829 | assert!(v.capacity() >= 2); 2830 | assert_eq!(&v[..], &[3, 4]); 2831 | 2832 | v.clear(); 2833 | assert_eq!(v.len(), 0); 2834 | assert!(v.capacity() >= 2); 2835 | assert_eq!(&v[..], &[]); 2836 | 2837 | v.clear(); 2838 | assert_eq!(v.len(), 0); 2839 | assert!(v.capacity() >= 2); 2840 | assert_eq!(&v[..], &[]); 2841 | } 2842 | 2843 | #[test] 2844 | fn test_empty_singleton_torture() { 2845 | { 2846 | let mut v = ThinVec::::new(); 2847 | assert_eq!(v.len(), 0); 2848 | assert_eq!(v.capacity(), 0); 2849 | assert!(v.is_empty()); 2850 | assert_eq!(&v[..], &[]); 2851 | assert_eq!(&mut v[..], &mut []); 2852 | 2853 | assert_eq!(v.pop(), None); 2854 | assert_eq!(v.len(), 0); 2855 | assert_eq!(v.capacity(), 0); 2856 | assert_eq!(&v[..], &[]); 2857 | } 2858 | 2859 | { 2860 | let v = ThinVec::::new(); 2861 | assert_eq!(v.into_iter().count(), 0); 2862 | 2863 | let v = ThinVec::::new(); 2864 | #[allow(clippy::never_loop)] 2865 | for _ in v.into_iter() { 2866 | unreachable!(); 2867 | } 2868 | } 2869 | 2870 | { 2871 | let mut v = ThinVec::::new(); 2872 | assert_eq!(v.drain(..).len(), 0); 2873 | 2874 | #[allow(clippy::never_loop)] 2875 | for _ in v.drain(..) { 2876 | unreachable!() 2877 | } 2878 | 2879 | assert_eq!(v.len(), 0); 2880 | assert_eq!(v.capacity(), 0); 2881 | assert_eq!(&v[..], &[]); 2882 | } 2883 | 2884 | { 2885 | let mut v = ThinVec::::new(); 2886 | assert_eq!(v.splice(.., []).len(), 0); 2887 | 2888 | #[allow(clippy::never_loop)] 2889 | for _ in v.splice(.., []) { 2890 | unreachable!() 2891 | } 2892 | 2893 | assert_eq!(v.len(), 0); 2894 | assert_eq!(v.capacity(), 0); 2895 | assert_eq!(&v[..], &[]); 2896 | } 2897 | 2898 | { 2899 | let mut v = ThinVec::::new(); 2900 | v.truncate(1); 2901 | assert_eq!(v.len(), 0); 2902 | assert_eq!(v.capacity(), 0); 2903 | assert_eq!(&v[..], &[]); 2904 | 2905 | v.truncate(0); 2906 | assert_eq!(v.len(), 0); 2907 | assert_eq!(v.capacity(), 0); 2908 | assert_eq!(&v[..], &[]); 2909 | } 2910 | 2911 | { 2912 | let mut v = ThinVec::::new(); 2913 | v.shrink_to_fit(); 2914 | assert_eq!(v.len(), 0); 2915 | assert_eq!(v.capacity(), 0); 2916 | assert_eq!(&v[..], &[]); 2917 | } 2918 | 2919 | { 2920 | let mut v = ThinVec::::new(); 2921 | let new = v.split_off(0); 2922 | assert_eq!(v.len(), 0); 2923 | assert_eq!(v.capacity(), 0); 2924 | assert_eq!(&v[..], &[]); 2925 | 2926 | assert_eq!(new.len(), 0); 2927 | assert_eq!(new.capacity(), 0); 2928 | assert_eq!(&new[..], &[]); 2929 | } 2930 | 2931 | { 2932 | let mut v = ThinVec::::new(); 2933 | let mut other = ThinVec::::new(); 2934 | v.append(&mut other); 2935 | 2936 | assert_eq!(v.len(), 0); 2937 | assert_eq!(v.capacity(), 0); 2938 | assert_eq!(&v[..], &[]); 2939 | 2940 | assert_eq!(other.len(), 0); 2941 | assert_eq!(other.capacity(), 0); 2942 | assert_eq!(&other[..], &[]); 2943 | } 2944 | 2945 | { 2946 | let mut v = ThinVec::::new(); 2947 | v.reserve(0); 2948 | 2949 | assert_eq!(v.len(), 0); 2950 | assert_eq!(v.capacity(), 0); 2951 | assert_eq!(&v[..], &[]); 2952 | } 2953 | 2954 | { 2955 | let mut v = ThinVec::::new(); 2956 | v.reserve_exact(0); 2957 | 2958 | assert_eq!(v.len(), 0); 2959 | assert_eq!(v.capacity(), 0); 2960 | assert_eq!(&v[..], &[]); 2961 | } 2962 | 2963 | { 2964 | let mut v = ThinVec::::new(); 2965 | v.reserve(0); 2966 | 2967 | assert_eq!(v.len(), 0); 2968 | assert_eq!(v.capacity(), 0); 2969 | assert_eq!(&v[..], &[]); 2970 | } 2971 | 2972 | { 2973 | let v = ThinVec::::with_capacity(0); 2974 | 2975 | assert_eq!(v.len(), 0); 2976 | assert_eq!(v.capacity(), 0); 2977 | assert_eq!(&v[..], &[]); 2978 | } 2979 | 2980 | { 2981 | let v = ThinVec::::default(); 2982 | 2983 | assert_eq!(v.len(), 0); 2984 | assert_eq!(v.capacity(), 0); 2985 | assert_eq!(&v[..], &[]); 2986 | } 2987 | 2988 | { 2989 | let mut v = ThinVec::::new(); 2990 | v.retain(|_| unreachable!()); 2991 | 2992 | assert_eq!(v.len(), 0); 2993 | assert_eq!(v.capacity(), 0); 2994 | assert_eq!(&v[..], &[]); 2995 | } 2996 | 2997 | { 2998 | let mut v = ThinVec::::new(); 2999 | v.retain_mut(|_| unreachable!()); 3000 | 3001 | assert_eq!(v.len(), 0); 3002 | assert_eq!(v.capacity(), 0); 3003 | assert_eq!(&v[..], &[]); 3004 | } 3005 | 3006 | { 3007 | let mut v = ThinVec::::new(); 3008 | v.dedup_by_key(|x| *x); 3009 | 3010 | assert_eq!(v.len(), 0); 3011 | assert_eq!(v.capacity(), 0); 3012 | assert_eq!(&v[..], &[]); 3013 | } 3014 | 3015 | { 3016 | let mut v = ThinVec::::new(); 3017 | v.dedup_by(|_, _| unreachable!()); 3018 | 3019 | assert_eq!(v.len(), 0); 3020 | assert_eq!(v.capacity(), 0); 3021 | assert_eq!(&v[..], &[]); 3022 | } 3023 | 3024 | { 3025 | let v = ThinVec::::new(); 3026 | let v = v.clone(); 3027 | 3028 | assert_eq!(v.len(), 0); 3029 | assert_eq!(v.capacity(), 0); 3030 | assert_eq!(&v[..], &[]); 3031 | } 3032 | } 3033 | 3034 | #[test] 3035 | fn test_clone() { 3036 | let mut v = ThinVec::::new(); 3037 | assert!(v.is_singleton()); 3038 | v.push(0); 3039 | v.pop(); 3040 | assert!(!v.is_singleton()); 3041 | 3042 | let v2 = v.clone(); 3043 | assert!(v2.is_singleton()); 3044 | } 3045 | } 3046 | 3047 | #[cfg(test)] 3048 | mod std_tests { 3049 | #![allow(clippy::reversed_empty_ranges)] 3050 | 3051 | use super::*; 3052 | use crate::alloc::{ 3053 | format, 3054 | string::{String, ToString}, 3055 | }; 3056 | use core::mem::size_of; 3057 | use core::usize; 3058 | 3059 | struct DropCounter<'a> { 3060 | count: &'a mut u32, 3061 | } 3062 | 3063 | impl<'a> Drop for DropCounter<'a> { 3064 | fn drop(&mut self) { 3065 | *self.count += 1; 3066 | } 3067 | } 3068 | 3069 | #[test] 3070 | fn test_small_vec_struct() { 3071 | assert!(size_of::>() == size_of::()); 3072 | } 3073 | 3074 | #[test] 3075 | fn test_double_drop() { 3076 | struct TwoVec { 3077 | x: ThinVec, 3078 | y: ThinVec, 3079 | } 3080 | 3081 | let (mut count_x, mut count_y) = (0, 0); 3082 | { 3083 | let mut tv = TwoVec { 3084 | x: ThinVec::new(), 3085 | y: ThinVec::new(), 3086 | }; 3087 | tv.x.push(DropCounter { 3088 | count: &mut count_x, 3089 | }); 3090 | tv.y.push(DropCounter { 3091 | count: &mut count_y, 3092 | }); 3093 | 3094 | // If ThinVec had a drop flag, here is where it would be zeroed. 3095 | // Instead, it should rely on its internal state to prevent 3096 | // doing anything significant when dropped multiple times. 3097 | drop(tv.x); 3098 | 3099 | // Here tv goes out of scope, tv.y should be dropped, but not tv.x. 3100 | } 3101 | 3102 | assert_eq!(count_x, 1); 3103 | assert_eq!(count_y, 1); 3104 | } 3105 | 3106 | #[test] 3107 | fn test_reserve() { 3108 | let mut v = ThinVec::new(); 3109 | assert_eq!(v.capacity(), 0); 3110 | 3111 | v.reserve(2); 3112 | assert!(v.capacity() >= 2); 3113 | 3114 | for i in 0..16 { 3115 | v.push(i); 3116 | } 3117 | 3118 | assert!(v.capacity() >= 16); 3119 | v.reserve(16); 3120 | assert!(v.capacity() >= 32); 3121 | 3122 | v.push(16); 3123 | 3124 | v.reserve(16); 3125 | assert!(v.capacity() >= 33) 3126 | } 3127 | 3128 | #[test] 3129 | fn test_extend() { 3130 | let mut v = ThinVec::::new(); 3131 | let mut w = ThinVec::new(); 3132 | v.extend(w.clone()); 3133 | assert_eq!(v, &[]); 3134 | 3135 | v.extend(0..3); 3136 | for i in 0..3 { 3137 | w.push(i) 3138 | } 3139 | 3140 | assert_eq!(v, w); 3141 | 3142 | v.extend(3..10); 3143 | for i in 3..10 { 3144 | w.push(i) 3145 | } 3146 | 3147 | assert_eq!(v, w); 3148 | 3149 | v.extend(w.clone()); // specializes to `append` 3150 | assert!(v.iter().eq(w.iter().chain(w.iter()))); 3151 | 3152 | // Zero sized types 3153 | #[derive(PartialEq, Debug)] 3154 | struct Foo; 3155 | 3156 | let mut a = ThinVec::new(); 3157 | let b = thin_vec![Foo, Foo]; 3158 | 3159 | a.extend(b); 3160 | assert_eq!(a, &[Foo, Foo]); 3161 | 3162 | // Double drop 3163 | let mut count_x = 0; 3164 | { 3165 | let mut x = ThinVec::new(); 3166 | let y = thin_vec![DropCounter { 3167 | count: &mut count_x 3168 | }]; 3169 | x.extend(y); 3170 | } 3171 | 3172 | assert_eq!(count_x, 1); 3173 | } 3174 | 3175 | /* TODO: implement extend for Iter<&Copy> 3176 | #[test] 3177 | fn test_extend_ref() { 3178 | let mut v = thin_vec![1, 2]; 3179 | v.extend(&[3, 4, 5]); 3180 | 3181 | assert_eq!(v.len(), 5); 3182 | assert_eq!(v, [1, 2, 3, 4, 5]); 3183 | 3184 | let w = thin_vec![6, 7]; 3185 | v.extend(&w); 3186 | 3187 | assert_eq!(v.len(), 7); 3188 | assert_eq!(v, [1, 2, 3, 4, 5, 6, 7]); 3189 | } 3190 | */ 3191 | 3192 | #[test] 3193 | fn test_slice_from_mut() { 3194 | let mut values = thin_vec![1, 2, 3, 4, 5]; 3195 | { 3196 | let slice = &mut values[2..]; 3197 | assert!(slice == [3, 4, 5]); 3198 | for p in slice { 3199 | *p += 2; 3200 | } 3201 | } 3202 | 3203 | assert!(values == [1, 2, 5, 6, 7]); 3204 | } 3205 | 3206 | #[test] 3207 | fn test_slice_to_mut() { 3208 | let mut values = thin_vec![1, 2, 3, 4, 5]; 3209 | { 3210 | let slice = &mut values[..2]; 3211 | assert!(slice == [1, 2]); 3212 | for p in slice { 3213 | *p += 1; 3214 | } 3215 | } 3216 | 3217 | assert!(values == [2, 3, 3, 4, 5]); 3218 | } 3219 | 3220 | #[test] 3221 | fn test_split_at_mut() { 3222 | let mut values = thin_vec![1, 2, 3, 4, 5]; 3223 | { 3224 | let (left, right) = values.split_at_mut(2); 3225 | { 3226 | let left: &[_] = left; 3227 | assert!(left[..left.len()] == [1, 2]); 3228 | } 3229 | for p in left { 3230 | *p += 1; 3231 | } 3232 | 3233 | { 3234 | let right: &[_] = right; 3235 | assert!(right[..right.len()] == [3, 4, 5]); 3236 | } 3237 | for p in right { 3238 | *p += 2; 3239 | } 3240 | } 3241 | 3242 | assert_eq!(values, [2, 3, 5, 6, 7]); 3243 | } 3244 | 3245 | #[test] 3246 | fn test_clone() { 3247 | let v: ThinVec = thin_vec![]; 3248 | let w = thin_vec![1, 2, 3]; 3249 | 3250 | assert_eq!(v, v.clone()); 3251 | 3252 | let z = w.clone(); 3253 | assert_eq!(w, z); 3254 | // they should be disjoint in memory. 3255 | assert!(w.as_ptr() != z.as_ptr()) 3256 | } 3257 | 3258 | #[test] 3259 | fn test_clone_from() { 3260 | let mut v = thin_vec![]; 3261 | let three: ThinVec> = thin_vec![Box::new(1), Box::new(2), Box::new(3)]; 3262 | let two: ThinVec> = thin_vec![Box::new(4), Box::new(5)]; 3263 | // zero, long 3264 | v.clone_from(&three); 3265 | assert_eq!(v, three); 3266 | 3267 | // equal 3268 | v.clone_from(&three); 3269 | assert_eq!(v, three); 3270 | 3271 | // long, short 3272 | v.clone_from(&two); 3273 | assert_eq!(v, two); 3274 | 3275 | // short, long 3276 | v.clone_from(&three); 3277 | assert_eq!(v, three) 3278 | } 3279 | 3280 | #[test] 3281 | fn test_retain() { 3282 | let mut vec = thin_vec![1, 2, 3, 4]; 3283 | vec.retain(|&x| x % 2 == 0); 3284 | assert_eq!(vec, [2, 4]); 3285 | } 3286 | 3287 | #[test] 3288 | fn test_retain_mut() { 3289 | let mut vec = thin_vec![9, 9, 9, 9]; 3290 | let mut i = 0; 3291 | vec.retain_mut(|x| { 3292 | i += 1; 3293 | *x = i; 3294 | i != 4 3295 | }); 3296 | assert_eq!(vec, [1, 2, 3]); 3297 | } 3298 | 3299 | #[test] 3300 | fn test_dedup() { 3301 | fn case(a: ThinVec, b: ThinVec) { 3302 | let mut v = a; 3303 | v.dedup(); 3304 | assert_eq!(v, b); 3305 | } 3306 | case(thin_vec![], thin_vec![]); 3307 | case(thin_vec![1], thin_vec![1]); 3308 | case(thin_vec![1, 1], thin_vec![1]); 3309 | case(thin_vec![1, 2, 3], thin_vec![1, 2, 3]); 3310 | case(thin_vec![1, 1, 2, 3], thin_vec![1, 2, 3]); 3311 | case(thin_vec![1, 2, 2, 3], thin_vec![1, 2, 3]); 3312 | case(thin_vec![1, 2, 3, 3], thin_vec![1, 2, 3]); 3313 | case(thin_vec![1, 1, 2, 2, 2, 3, 3], thin_vec![1, 2, 3]); 3314 | } 3315 | 3316 | #[test] 3317 | fn test_dedup_by_key() { 3318 | fn case(a: ThinVec, b: ThinVec) { 3319 | let mut v = a; 3320 | v.dedup_by_key(|i| *i / 10); 3321 | assert_eq!(v, b); 3322 | } 3323 | case(thin_vec![], thin_vec![]); 3324 | case(thin_vec![10], thin_vec![10]); 3325 | case(thin_vec![10, 11], thin_vec![10]); 3326 | case(thin_vec![10, 20, 30], thin_vec![10, 20, 30]); 3327 | case(thin_vec![10, 11, 20, 30], thin_vec![10, 20, 30]); 3328 | case(thin_vec![10, 20, 21, 30], thin_vec![10, 20, 30]); 3329 | case(thin_vec![10, 20, 30, 31], thin_vec![10, 20, 30]); 3330 | case(thin_vec![10, 11, 20, 21, 22, 30, 31], thin_vec![10, 20, 30]); 3331 | } 3332 | 3333 | #[test] 3334 | fn test_dedup_by() { 3335 | let mut vec = thin_vec!["foo", "bar", "Bar", "baz", "bar"]; 3336 | vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b)); 3337 | 3338 | assert_eq!(vec, ["foo", "bar", "baz", "bar"]); 3339 | 3340 | let mut vec = thin_vec![("foo", 1), ("foo", 2), ("bar", 3), ("bar", 4), ("bar", 5)]; 3341 | vec.dedup_by(|a, b| { 3342 | a.0 == b.0 && { 3343 | b.1 += a.1; 3344 | true 3345 | } 3346 | }); 3347 | 3348 | assert_eq!(vec, [("foo", 3), ("bar", 12)]); 3349 | } 3350 | 3351 | #[test] 3352 | fn test_dedup_unique() { 3353 | let mut v0: ThinVec> = thin_vec![Box::new(1), Box::new(1), Box::new(2), Box::new(3)]; 3354 | v0.dedup(); 3355 | let mut v1: ThinVec> = thin_vec![Box::new(1), Box::new(2), Box::new(2), Box::new(3)]; 3356 | v1.dedup(); 3357 | let mut v2: ThinVec> = thin_vec![Box::new(1), Box::new(2), Box::new(3), Box::new(3)]; 3358 | v2.dedup(); 3359 | // If the boxed pointers were leaked or otherwise misused, valgrind 3360 | // and/or rt should raise errors. 3361 | } 3362 | 3363 | #[test] 3364 | fn zero_sized_values() { 3365 | let mut v = ThinVec::new(); 3366 | assert_eq!(v.len(), 0); 3367 | v.push(()); 3368 | assert_eq!(v.len(), 1); 3369 | v.push(()); 3370 | assert_eq!(v.len(), 2); 3371 | assert_eq!(v.pop(), Some(())); 3372 | assert_eq!(v.pop(), Some(())); 3373 | assert_eq!(v.pop(), None); 3374 | 3375 | assert_eq!(v.iter().count(), 0); 3376 | v.push(()); 3377 | assert_eq!(v.iter().count(), 1); 3378 | v.push(()); 3379 | assert_eq!(v.iter().count(), 2); 3380 | 3381 | for &() in &v {} 3382 | 3383 | assert_eq!(v.iter_mut().count(), 2); 3384 | v.push(()); 3385 | assert_eq!(v.iter_mut().count(), 3); 3386 | v.push(()); 3387 | assert_eq!(v.iter_mut().count(), 4); 3388 | 3389 | for &mut () in &mut v {} 3390 | unsafe { 3391 | v.set_len(0); 3392 | } 3393 | assert_eq!(v.iter_mut().count(), 0); 3394 | } 3395 | 3396 | #[test] 3397 | fn test_partition() { 3398 | assert_eq!( 3399 | thin_vec![].into_iter().partition(|x: &i32| *x < 3), 3400 | (thin_vec![], thin_vec![]) 3401 | ); 3402 | assert_eq!( 3403 | thin_vec![1, 2, 3].into_iter().partition(|x| *x < 4), 3404 | (thin_vec![1, 2, 3], thin_vec![]) 3405 | ); 3406 | assert_eq!( 3407 | thin_vec![1, 2, 3].into_iter().partition(|x| *x < 2), 3408 | (thin_vec![1], thin_vec![2, 3]) 3409 | ); 3410 | assert_eq!( 3411 | thin_vec![1, 2, 3].into_iter().partition(|x| *x < 0), 3412 | (thin_vec![], thin_vec![1, 2, 3]) 3413 | ); 3414 | } 3415 | 3416 | #[test] 3417 | fn test_zip_unzip() { 3418 | let z1 = thin_vec![(1, 4), (2, 5), (3, 6)]; 3419 | 3420 | let (left, right): (ThinVec<_>, ThinVec<_>) = z1.iter().cloned().unzip(); 3421 | 3422 | assert_eq!((1, 4), (left[0], right[0])); 3423 | assert_eq!((2, 5), (left[1], right[1])); 3424 | assert_eq!((3, 6), (left[2], right[2])); 3425 | } 3426 | 3427 | #[test] 3428 | fn test_vec_truncate_drop() { 3429 | static mut DROPS: u32 = 0; 3430 | struct Elem(i32); 3431 | impl Drop for Elem { 3432 | fn drop(&mut self) { 3433 | unsafe { 3434 | DROPS += 1; 3435 | } 3436 | } 3437 | } 3438 | 3439 | let mut v = thin_vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)]; 3440 | assert_eq!(unsafe { DROPS }, 0); 3441 | v.truncate(3); 3442 | assert_eq!(unsafe { DROPS }, 2); 3443 | v.truncate(0); 3444 | assert_eq!(unsafe { DROPS }, 5); 3445 | } 3446 | 3447 | #[test] 3448 | #[should_panic] 3449 | fn test_vec_truncate_fail() { 3450 | struct BadElem(i32); 3451 | impl Drop for BadElem { 3452 | fn drop(&mut self) { 3453 | let BadElem(ref mut x) = *self; 3454 | if *x == 0xbadbeef { 3455 | panic!("BadElem panic: 0xbadbeef") 3456 | } 3457 | } 3458 | } 3459 | 3460 | let mut v = thin_vec![BadElem(1), BadElem(2), BadElem(0xbadbeef), BadElem(4)]; 3461 | v.truncate(0); 3462 | } 3463 | 3464 | #[test] 3465 | fn test_index() { 3466 | let vec = thin_vec![1, 2, 3]; 3467 | assert!(vec[1] == 2); 3468 | } 3469 | 3470 | #[test] 3471 | #[should_panic] 3472 | fn test_index_out_of_bounds() { 3473 | let vec = thin_vec![1, 2, 3]; 3474 | let _ = vec[3]; 3475 | } 3476 | 3477 | #[test] 3478 | #[should_panic] 3479 | fn test_slice_out_of_bounds_1() { 3480 | let x = thin_vec![1, 2, 3, 4, 5]; 3481 | let _ = &x[!0..]; 3482 | } 3483 | 3484 | #[test] 3485 | #[should_panic] 3486 | fn test_slice_out_of_bounds_2() { 3487 | let x = thin_vec![1, 2, 3, 4, 5]; 3488 | let _ = &x[..6]; 3489 | } 3490 | 3491 | #[test] 3492 | #[should_panic] 3493 | fn test_slice_out_of_bounds_3() { 3494 | let x = thin_vec![1, 2, 3, 4, 5]; 3495 | let _ = &x[!0..4]; 3496 | } 3497 | 3498 | #[test] 3499 | #[should_panic] 3500 | fn test_slice_out_of_bounds_4() { 3501 | let x = thin_vec![1, 2, 3, 4, 5]; 3502 | let _ = &x[1..6]; 3503 | } 3504 | 3505 | #[test] 3506 | #[should_panic] 3507 | fn test_slice_out_of_bounds_5() { 3508 | let x = thin_vec![1, 2, 3, 4, 5]; 3509 | let _ = &x[3..2]; 3510 | } 3511 | 3512 | #[test] 3513 | #[should_panic] 3514 | fn test_swap_remove_empty() { 3515 | let mut vec = ThinVec::::new(); 3516 | vec.swap_remove(0); 3517 | } 3518 | 3519 | #[test] 3520 | fn test_move_items() { 3521 | let vec = thin_vec![1, 2, 3]; 3522 | let mut vec2 = thin_vec![]; 3523 | for i in vec { 3524 | vec2.push(i); 3525 | } 3526 | assert_eq!(vec2, [1, 2, 3]); 3527 | } 3528 | 3529 | #[test] 3530 | fn test_move_items_reverse() { 3531 | let vec = thin_vec![1, 2, 3]; 3532 | let mut vec2 = thin_vec![]; 3533 | for i in vec.into_iter().rev() { 3534 | vec2.push(i); 3535 | } 3536 | assert_eq!(vec2, [3, 2, 1]); 3537 | } 3538 | 3539 | #[test] 3540 | fn test_move_items_zero_sized() { 3541 | let vec = thin_vec![(), (), ()]; 3542 | let mut vec2 = thin_vec![]; 3543 | for i in vec { 3544 | vec2.push(i); 3545 | } 3546 | assert_eq!(vec2, [(), (), ()]); 3547 | } 3548 | 3549 | #[test] 3550 | fn test_drain_items() { 3551 | let mut vec = thin_vec![1, 2, 3]; 3552 | let mut vec2 = thin_vec![]; 3553 | for i in vec.drain(..) { 3554 | vec2.push(i); 3555 | } 3556 | assert_eq!(vec, []); 3557 | assert_eq!(vec2, [1, 2, 3]); 3558 | } 3559 | 3560 | #[test] 3561 | fn test_drain_items_reverse() { 3562 | let mut vec = thin_vec![1, 2, 3]; 3563 | let mut vec2 = thin_vec![]; 3564 | for i in vec.drain(..).rev() { 3565 | vec2.push(i); 3566 | } 3567 | assert_eq!(vec, []); 3568 | assert_eq!(vec2, [3, 2, 1]); 3569 | } 3570 | 3571 | #[test] 3572 | fn test_drain_items_zero_sized() { 3573 | let mut vec = thin_vec![(), (), ()]; 3574 | let mut vec2 = thin_vec![]; 3575 | for i in vec.drain(..) { 3576 | vec2.push(i); 3577 | } 3578 | assert_eq!(vec, []); 3579 | assert_eq!(vec2, [(), (), ()]); 3580 | } 3581 | 3582 | #[test] 3583 | #[should_panic] 3584 | fn test_drain_out_of_bounds() { 3585 | let mut v = thin_vec![1, 2, 3, 4, 5]; 3586 | v.drain(5..6); 3587 | } 3588 | 3589 | #[test] 3590 | fn test_drain_range() { 3591 | let mut v = thin_vec![1, 2, 3, 4, 5]; 3592 | for _ in v.drain(4..) {} 3593 | assert_eq!(v, &[1, 2, 3, 4]); 3594 | 3595 | let mut v: ThinVec<_> = (1..6).map(|x| x.to_string()).collect(); 3596 | for _ in v.drain(1..4) {} 3597 | assert_eq!(v, &[1.to_string(), 5.to_string()]); 3598 | 3599 | let mut v: ThinVec<_> = (1..6).map(|x| x.to_string()).collect(); 3600 | for _ in v.drain(1..4).rev() {} 3601 | assert_eq!(v, &[1.to_string(), 5.to_string()]); 3602 | 3603 | let mut v: ThinVec<_> = thin_vec![(); 5]; 3604 | for _ in v.drain(1..4).rev() {} 3605 | assert_eq!(v, &[(), ()]); 3606 | } 3607 | 3608 | #[test] 3609 | fn test_drain_inclusive_range() { 3610 | let mut v = thin_vec!['a', 'b', 'c', 'd', 'e']; 3611 | for _ in v.drain(1..=3) {} 3612 | assert_eq!(v, &['a', 'e']); 3613 | 3614 | let mut v: ThinVec<_> = (0..=5).map(|x| x.to_string()).collect(); 3615 | for _ in v.drain(1..=5) {} 3616 | assert_eq!(v, &["0".to_string()]); 3617 | 3618 | let mut v: ThinVec = (0..=5).map(|x| x.to_string()).collect(); 3619 | for _ in v.drain(0..=5) {} 3620 | assert_eq!(v, ThinVec::::new()); 3621 | 3622 | let mut v: ThinVec<_> = (0..=5).map(|x| x.to_string()).collect(); 3623 | for _ in v.drain(0..=3) {} 3624 | assert_eq!(v, &["4".to_string(), "5".to_string()]); 3625 | 3626 | let mut v: ThinVec<_> = (0..=1).map(|x| x.to_string()).collect(); 3627 | for _ in v.drain(..=0) {} 3628 | assert_eq!(v, &["1".to_string()]); 3629 | } 3630 | 3631 | #[test] 3632 | #[cfg(not(feature = "gecko-ffi"))] 3633 | fn test_drain_max_vec_size() { 3634 | let mut v = ThinVec::<()>::with_capacity(usize::max_value()); 3635 | unsafe { 3636 | v.set_len(usize::max_value()); 3637 | } 3638 | for _ in v.drain(usize::max_value() - 1..) {} 3639 | assert_eq!(v.len(), usize::max_value() - 1); 3640 | 3641 | let mut v = ThinVec::<()>::with_capacity(usize::max_value()); 3642 | unsafe { 3643 | v.set_len(usize::max_value()); 3644 | } 3645 | for _ in v.drain(usize::max_value() - 1..=usize::max_value() - 1) {} 3646 | assert_eq!(v.len(), usize::max_value() - 1); 3647 | } 3648 | 3649 | #[test] 3650 | #[should_panic] 3651 | fn test_drain_inclusive_out_of_bounds() { 3652 | let mut v = thin_vec![1, 2, 3, 4, 5]; 3653 | v.drain(5..=5); 3654 | } 3655 | 3656 | #[test] 3657 | fn test_splice() { 3658 | let mut v = thin_vec![1, 2, 3, 4, 5]; 3659 | let a = [10, 11, 12]; 3660 | v.splice(2..4, a.iter().cloned()); 3661 | assert_eq!(v, &[1, 2, 10, 11, 12, 5]); 3662 | v.splice(1..3, Some(20)); 3663 | assert_eq!(v, &[1, 20, 11, 12, 5]); 3664 | } 3665 | 3666 | #[test] 3667 | fn test_splice_inclusive_range() { 3668 | let mut v = thin_vec![1, 2, 3, 4, 5]; 3669 | let a = [10, 11, 12]; 3670 | let t1: ThinVec<_> = v.splice(2..=3, a.iter().cloned()).collect(); 3671 | assert_eq!(v, &[1, 2, 10, 11, 12, 5]); 3672 | assert_eq!(t1, &[3, 4]); 3673 | let t2: ThinVec<_> = v.splice(1..=2, Some(20)).collect(); 3674 | assert_eq!(v, &[1, 20, 11, 12, 5]); 3675 | assert_eq!(t2, &[2, 10]); 3676 | } 3677 | 3678 | #[test] 3679 | #[should_panic] 3680 | fn test_splice_out_of_bounds() { 3681 | let mut v = thin_vec![1, 2, 3, 4, 5]; 3682 | let a = [10, 11, 12]; 3683 | v.splice(5..6, a.iter().cloned()); 3684 | } 3685 | 3686 | #[test] 3687 | #[should_panic] 3688 | fn test_splice_inclusive_out_of_bounds() { 3689 | let mut v = thin_vec![1, 2, 3, 4, 5]; 3690 | let a = [10, 11, 12]; 3691 | v.splice(5..=5, a.iter().cloned()); 3692 | } 3693 | 3694 | #[test] 3695 | fn test_splice_items_zero_sized() { 3696 | let mut vec = thin_vec![(), (), ()]; 3697 | let vec2 = thin_vec![]; 3698 | let t: ThinVec<_> = vec.splice(1..2, vec2.iter().cloned()).collect(); 3699 | assert_eq!(vec, &[(), ()]); 3700 | assert_eq!(t, &[()]); 3701 | } 3702 | 3703 | #[test] 3704 | fn test_splice_unbounded() { 3705 | let mut vec = thin_vec![1, 2, 3, 4, 5]; 3706 | let t: ThinVec<_> = vec.splice(.., None).collect(); 3707 | assert_eq!(vec, &[]); 3708 | assert_eq!(t, &[1, 2, 3, 4, 5]); 3709 | } 3710 | 3711 | #[test] 3712 | fn test_splice_forget() { 3713 | let mut v = thin_vec![1, 2, 3, 4, 5]; 3714 | let a = [10, 11, 12]; 3715 | ::core::mem::forget(v.splice(2..4, a.iter().cloned())); 3716 | assert_eq!(v, &[1, 2]); 3717 | } 3718 | 3719 | #[test] 3720 | fn test_splice_from_empty() { 3721 | let mut v = thin_vec![]; 3722 | let a = [10, 11, 12]; 3723 | v.splice(.., a.iter().cloned()); 3724 | assert_eq!(v, &[10, 11, 12]); 3725 | } 3726 | 3727 | /* probs won't ever impl this 3728 | #[test] 3729 | fn test_into_boxed_slice() { 3730 | let xs = thin_vec![1, 2, 3]; 3731 | let ys = xs.into_boxed_slice(); 3732 | assert_eq!(&*ys, [1, 2, 3]); 3733 | } 3734 | */ 3735 | 3736 | #[test] 3737 | fn test_append() { 3738 | let mut vec = thin_vec![1, 2, 3]; 3739 | let mut vec2 = thin_vec![4, 5, 6]; 3740 | vec.append(&mut vec2); 3741 | assert_eq!(vec, [1, 2, 3, 4, 5, 6]); 3742 | assert_eq!(vec2, []); 3743 | } 3744 | 3745 | #[test] 3746 | fn test_split_off() { 3747 | let mut vec = thin_vec![1, 2, 3, 4, 5, 6]; 3748 | let vec2 = vec.split_off(4); 3749 | assert_eq!(vec, [1, 2, 3, 4]); 3750 | assert_eq!(vec2, [5, 6]); 3751 | } 3752 | 3753 | #[test] 3754 | fn test_into_iter_as_slice() { 3755 | let vec = thin_vec!['a', 'b', 'c']; 3756 | let mut into_iter = vec.into_iter(); 3757 | assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); 3758 | let _ = into_iter.next().unwrap(); 3759 | assert_eq!(into_iter.as_slice(), &['b', 'c']); 3760 | let _ = into_iter.next().unwrap(); 3761 | let _ = into_iter.next().unwrap(); 3762 | assert_eq!(into_iter.as_slice(), &[]); 3763 | } 3764 | 3765 | #[test] 3766 | fn test_into_iter_as_mut_slice() { 3767 | let vec = thin_vec!['a', 'b', 'c']; 3768 | let mut into_iter = vec.into_iter(); 3769 | assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); 3770 | into_iter.as_mut_slice()[0] = 'x'; 3771 | into_iter.as_mut_slice()[1] = 'y'; 3772 | assert_eq!(into_iter.next().unwrap(), 'x'); 3773 | assert_eq!(into_iter.as_slice(), &['y', 'c']); 3774 | } 3775 | 3776 | #[test] 3777 | fn test_into_iter_debug() { 3778 | let vec = thin_vec!['a', 'b', 'c']; 3779 | let into_iter = vec.into_iter(); 3780 | let debug = format!("{:?}", into_iter); 3781 | assert_eq!(debug, "IntoIter(['a', 'b', 'c'])"); 3782 | } 3783 | 3784 | #[test] 3785 | fn test_into_iter_count() { 3786 | assert_eq!(thin_vec![1, 2, 3].into_iter().count(), 3); 3787 | } 3788 | 3789 | #[test] 3790 | fn test_into_iter_clone() { 3791 | fn iter_equal>(it: I, slice: &[i32]) { 3792 | let v: ThinVec = it.collect(); 3793 | assert_eq!(&v[..], slice); 3794 | } 3795 | let mut it = thin_vec![1, 2, 3].into_iter(); 3796 | iter_equal(it.clone(), &[1, 2, 3]); 3797 | assert_eq!(it.next(), Some(1)); 3798 | let mut it = it.rev(); 3799 | iter_equal(it.clone(), &[3, 2]); 3800 | assert_eq!(it.next(), Some(3)); 3801 | iter_equal(it.clone(), &[2]); 3802 | assert_eq!(it.next(), Some(2)); 3803 | iter_equal(it.clone(), &[]); 3804 | assert_eq!(it.next(), None); 3805 | } 3806 | 3807 | /* TODO: make drain covariant 3808 | #[allow(dead_code)] 3809 | fn assert_covariance() { 3810 | fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { 3811 | d 3812 | } 3813 | fn into_iter<'new>(i: IntoIter<&'static str>) -> IntoIter<&'new str> { 3814 | i 3815 | } 3816 | } 3817 | */ 3818 | 3819 | /* TODO: specialize vec.into_iter().collect::>(); 3820 | #[test] 3821 | fn from_into_inner() { 3822 | let vec = thin_vec![1, 2, 3]; 3823 | let ptr = vec.as_ptr(); 3824 | let vec = vec.into_iter().collect::>(); 3825 | assert_eq!(vec, [1, 2, 3]); 3826 | assert_eq!(vec.as_ptr(), ptr); 3827 | 3828 | let ptr = &vec[1] as *const _; 3829 | let mut it = vec.into_iter(); 3830 | it.next().unwrap(); 3831 | let vec = it.collect::>(); 3832 | assert_eq!(vec, [2, 3]); 3833 | assert!(ptr != vec.as_ptr()); 3834 | } 3835 | */ 3836 | 3837 | #[test] 3838 | #[cfg_attr(feature = "gecko-ffi", ignore)] 3839 | fn overaligned_allocations() { 3840 | #[repr(align(256))] 3841 | struct Foo(usize); 3842 | let mut v = thin_vec![Foo(273)]; 3843 | for i in 0..0x1000 { 3844 | v.reserve_exact(i); 3845 | assert!(v[0].0 == 273); 3846 | assert!(v.as_ptr() as usize & 0xff == 0); 3847 | v.shrink_to_fit(); 3848 | assert!(v[0].0 == 273); 3849 | assert!(v.as_ptr() as usize & 0xff == 0); 3850 | } 3851 | } 3852 | 3853 | /* TODO: implement drain_filter? 3854 | #[test] 3855 | fn drain_filter_empty() { 3856 | let mut vec: ThinVec = thin_vec![]; 3857 | 3858 | { 3859 | let mut iter = vec.drain_filter(|_| true); 3860 | assert_eq!(iter.size_hint(), (0, Some(0))); 3861 | assert_eq!(iter.next(), None); 3862 | assert_eq!(iter.size_hint(), (0, Some(0))); 3863 | assert_eq!(iter.next(), None); 3864 | assert_eq!(iter.size_hint(), (0, Some(0))); 3865 | } 3866 | assert_eq!(vec.len(), 0); 3867 | assert_eq!(vec, thin_vec![]); 3868 | } 3869 | 3870 | #[test] 3871 | fn drain_filter_zst() { 3872 | let mut vec = thin_vec![(), (), (), (), ()]; 3873 | let initial_len = vec.len(); 3874 | let mut count = 0; 3875 | { 3876 | let mut iter = vec.drain_filter(|_| true); 3877 | assert_eq!(iter.size_hint(), (0, Some(initial_len))); 3878 | while let Some(_) = iter.next() { 3879 | count += 1; 3880 | assert_eq!(iter.size_hint(), (0, Some(initial_len - count))); 3881 | } 3882 | assert_eq!(iter.size_hint(), (0, Some(0))); 3883 | assert_eq!(iter.next(), None); 3884 | assert_eq!(iter.size_hint(), (0, Some(0))); 3885 | } 3886 | 3887 | assert_eq!(count, initial_len); 3888 | assert_eq!(vec.len(), 0); 3889 | assert_eq!(vec, thin_vec![]); 3890 | } 3891 | 3892 | #[test] 3893 | fn drain_filter_false() { 3894 | let mut vec = thin_vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 3895 | 3896 | let initial_len = vec.len(); 3897 | let mut count = 0; 3898 | { 3899 | let mut iter = vec.drain_filter(|_| false); 3900 | assert_eq!(iter.size_hint(), (0, Some(initial_len))); 3901 | for _ in iter.by_ref() { 3902 | count += 1; 3903 | } 3904 | assert_eq!(iter.size_hint(), (0, Some(0))); 3905 | assert_eq!(iter.next(), None); 3906 | assert_eq!(iter.size_hint(), (0, Some(0))); 3907 | } 3908 | 3909 | assert_eq!(count, 0); 3910 | assert_eq!(vec.len(), initial_len); 3911 | assert_eq!(vec, thin_vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 3912 | } 3913 | 3914 | #[test] 3915 | fn drain_filter_true() { 3916 | let mut vec = thin_vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 3917 | 3918 | let initial_len = vec.len(); 3919 | let mut count = 0; 3920 | { 3921 | let mut iter = vec.drain_filter(|_| true); 3922 | assert_eq!(iter.size_hint(), (0, Some(initial_len))); 3923 | while let Some(_) = iter.next() { 3924 | count += 1; 3925 | assert_eq!(iter.size_hint(), (0, Some(initial_len - count))); 3926 | } 3927 | assert_eq!(iter.size_hint(), (0, Some(0))); 3928 | assert_eq!(iter.next(), None); 3929 | assert_eq!(iter.size_hint(), (0, Some(0))); 3930 | } 3931 | 3932 | assert_eq!(count, initial_len); 3933 | assert_eq!(vec.len(), 0); 3934 | assert_eq!(vec, thin_vec![]); 3935 | } 3936 | 3937 | #[test] 3938 | fn drain_filter_complex() { 3939 | 3940 | { // [+xxx++++++xxxxx++++x+x++] 3941 | let mut vec = thin_vec![1, 3942 | 2, 4, 6, 3943 | 7, 9, 11, 13, 15, 17, 3944 | 18, 20, 22, 24, 26, 3945 | 27, 29, 31, 33, 3946 | 34, 3947 | 35, 3948 | 36, 3949 | 37, 39]; 3950 | 3951 | let removed = vec.drain_filter(|x| *x % 2 == 0).collect::>(); 3952 | assert_eq!(removed.len(), 10); 3953 | assert_eq!(removed, thin_vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); 3954 | 3955 | assert_eq!(vec.len(), 14); 3956 | assert_eq!(vec, thin_vec![1, 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]); 3957 | } 3958 | 3959 | { // [xxx++++++xxxxx++++x+x++] 3960 | let mut vec = thin_vec![2, 4, 6, 3961 | 7, 9, 11, 13, 15, 17, 3962 | 18, 20, 22, 24, 26, 3963 | 27, 29, 31, 33, 3964 | 34, 3965 | 35, 3966 | 36, 3967 | 37, 39]; 3968 | 3969 | let removed = vec.drain_filter(|x| *x % 2 == 0).collect::>(); 3970 | assert_eq!(removed.len(), 10); 3971 | assert_eq!(removed, thin_vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); 3972 | 3973 | assert_eq!(vec.len(), 13); 3974 | assert_eq!(vec, thin_vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]); 3975 | } 3976 | 3977 | { // [xxx++++++xxxxx++++x+x] 3978 | let mut vec = thin_vec![2, 4, 6, 3979 | 7, 9, 11, 13, 15, 17, 3980 | 18, 20, 22, 24, 26, 3981 | 27, 29, 31, 33, 3982 | 34, 3983 | 35, 3984 | 36]; 3985 | 3986 | let removed = vec.drain_filter(|x| *x % 2 == 0).collect::>(); 3987 | assert_eq!(removed.len(), 10); 3988 | assert_eq!(removed, thin_vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); 3989 | 3990 | assert_eq!(vec.len(), 11); 3991 | assert_eq!(vec, thin_vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35]); 3992 | } 3993 | 3994 | { // [xxxxxxxxxx+++++++++++] 3995 | let mut vec = thin_vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 3996 | 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]; 3997 | 3998 | let removed = vec.drain_filter(|x| *x % 2 == 0).collect::>(); 3999 | assert_eq!(removed.len(), 10); 4000 | assert_eq!(removed, thin_vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]); 4001 | 4002 | assert_eq!(vec.len(), 10); 4003 | assert_eq!(vec, thin_vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]); 4004 | } 4005 | 4006 | { // [+++++++++++xxxxxxxxxx] 4007 | let mut vec = thin_vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 4008 | 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]; 4009 | 4010 | let removed = vec.drain_filter(|x| *x % 2 == 0).collect::>(); 4011 | assert_eq!(removed.len(), 10); 4012 | assert_eq!(removed, thin_vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]); 4013 | 4014 | assert_eq!(vec.len(), 10); 4015 | assert_eq!(vec, thin_vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]); 4016 | } 4017 | } 4018 | */ 4019 | #[test] 4020 | fn test_reserve_exact() { 4021 | // This is all the same as test_reserve 4022 | 4023 | let mut v = ThinVec::new(); 4024 | assert_eq!(v.capacity(), 0); 4025 | 4026 | v.reserve_exact(2); 4027 | assert!(v.capacity() >= 2); 4028 | 4029 | for i in 0..16 { 4030 | v.push(i); 4031 | } 4032 | 4033 | assert!(v.capacity() >= 16); 4034 | v.reserve_exact(16); 4035 | assert!(v.capacity() >= 32); 4036 | 4037 | v.push(16); 4038 | 4039 | v.reserve_exact(16); 4040 | assert!(v.capacity() >= 33) 4041 | } 4042 | 4043 | /* TODO: implement try_reserve 4044 | #[test] 4045 | fn test_try_reserve() { 4046 | 4047 | // These are the interesting cases: 4048 | // * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM) 4049 | // * > isize::MAX should always fail 4050 | // * On 16/32-bit should CapacityOverflow 4051 | // * On 64-bit should OOM 4052 | // * overflow may trigger when adding `len` to `cap` (in number of elements) 4053 | // * overflow may trigger when multiplying `new_cap` by size_of:: (to get bytes) 4054 | 4055 | const MAX_CAP: usize = isize::MAX as usize; 4056 | const MAX_USIZE: usize = usize::MAX; 4057 | 4058 | // On 16/32-bit, we check that allocations don't exceed isize::MAX, 4059 | // on 64-bit, we assume the OS will give an OOM for such a ridiculous size. 4060 | // Any platform that succeeds for these requests is technically broken with 4061 | // ptr::offset because LLVM is the worst. 4062 | let guards_against_isize = size_of::() < 8; 4063 | 4064 | { 4065 | // Note: basic stuff is checked by test_reserve 4066 | let mut empty_bytes: ThinVec = ThinVec::new(); 4067 | 4068 | // Check isize::MAX doesn't count as an overflow 4069 | if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP) { 4070 | panic!("isize::MAX shouldn't trigger an overflow!"); 4071 | } 4072 | // Play it again, frank! (just to be sure) 4073 | if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP) { 4074 | panic!("isize::MAX shouldn't trigger an overflow!"); 4075 | } 4076 | 4077 | if guards_against_isize { 4078 | // Check isize::MAX + 1 does count as overflow 4079 | if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP + 1) { 4080 | } else { panic!("isize::MAX + 1 should trigger an overflow!") } 4081 | 4082 | // Check usize::MAX does count as overflow 4083 | if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { 4084 | } else { panic!("usize::MAX should trigger an overflow!") } 4085 | } else { 4086 | // Check isize::MAX + 1 is an OOM 4087 | if let Err(AllocErr) = empty_bytes.try_reserve(MAX_CAP + 1) { 4088 | } else { panic!("isize::MAX + 1 should trigger an OOM!") } 4089 | 4090 | // Check usize::MAX is an OOM 4091 | if let Err(AllocErr) = empty_bytes.try_reserve(MAX_USIZE) { 4092 | } else { panic!("usize::MAX should trigger an OOM!") } 4093 | } 4094 | } 4095 | 4096 | 4097 | { 4098 | // Same basic idea, but with non-zero len 4099 | let mut ten_bytes: ThinVec = thin_vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 4100 | 4101 | if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { 4102 | panic!("isize::MAX shouldn't trigger an overflow!"); 4103 | } 4104 | if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { 4105 | panic!("isize::MAX shouldn't trigger an overflow!"); 4106 | } 4107 | if guards_against_isize { 4108 | if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { 4109 | } else { panic!("isize::MAX + 1 should trigger an overflow!"); } 4110 | } else { 4111 | if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) { 4112 | } else { panic!("isize::MAX + 1 should trigger an OOM!") } 4113 | } 4114 | // Should always overflow in the add-to-len 4115 | if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_USIZE) { 4116 | } else { panic!("usize::MAX should trigger an overflow!") } 4117 | } 4118 | 4119 | 4120 | { 4121 | // Same basic idea, but with interesting type size 4122 | let mut ten_u32s: ThinVec = thin_vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 4123 | 4124 | if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 10) { 4125 | panic!("isize::MAX shouldn't trigger an overflow!"); 4126 | } 4127 | if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 10) { 4128 | panic!("isize::MAX shouldn't trigger an overflow!"); 4129 | } 4130 | if guards_against_isize { 4131 | if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { 4132 | } else { panic!("isize::MAX + 1 should trigger an overflow!"); } 4133 | } else { 4134 | if let Err(AllocErr) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { 4135 | } else { panic!("isize::MAX + 1 should trigger an OOM!") } 4136 | } 4137 | // Should fail in the mul-by-size 4138 | if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_USIZE - 20) { 4139 | } else { 4140 | panic!("usize::MAX should trigger an overflow!"); 4141 | } 4142 | } 4143 | 4144 | } 4145 | 4146 | #[test] 4147 | fn test_try_reserve_exact() { 4148 | 4149 | // This is exactly the same as test_try_reserve with the method changed. 4150 | // See that test for comments. 4151 | 4152 | const MAX_CAP: usize = isize::MAX as usize; 4153 | const MAX_USIZE: usize = usize::MAX; 4154 | 4155 | let guards_against_isize = size_of::() < 8; 4156 | 4157 | { 4158 | let mut empty_bytes: ThinVec = ThinVec::new(); 4159 | 4160 | if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP) { 4161 | panic!("isize::MAX shouldn't trigger an overflow!"); 4162 | } 4163 | if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP) { 4164 | panic!("isize::MAX shouldn't trigger an overflow!"); 4165 | } 4166 | 4167 | if guards_against_isize { 4168 | if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { 4169 | } else { panic!("isize::MAX + 1 should trigger an overflow!") } 4170 | 4171 | if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_USIZE) { 4172 | } else { panic!("usize::MAX should trigger an overflow!") } 4173 | } else { 4174 | if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { 4175 | } else { panic!("isize::MAX + 1 should trigger an OOM!") } 4176 | 4177 | if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_USIZE) { 4178 | } else { panic!("usize::MAX should trigger an OOM!") } 4179 | } 4180 | } 4181 | 4182 | 4183 | { 4184 | let mut ten_bytes: ThinVec = thin_vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 4185 | 4186 | if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { 4187 | panic!("isize::MAX shouldn't trigger an overflow!"); 4188 | } 4189 | if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { 4190 | panic!("isize::MAX shouldn't trigger an overflow!"); 4191 | } 4192 | if guards_against_isize { 4193 | if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { 4194 | } else { panic!("isize::MAX + 1 should trigger an overflow!"); } 4195 | } else { 4196 | if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { 4197 | } else { panic!("isize::MAX + 1 should trigger an OOM!") } 4198 | } 4199 | if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { 4200 | } else { panic!("usize::MAX should trigger an overflow!") } 4201 | } 4202 | 4203 | 4204 | { 4205 | let mut ten_u32s: ThinVec = thin_vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 4206 | 4207 | if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 10) { 4208 | panic!("isize::MAX shouldn't trigger an overflow!"); 4209 | } 4210 | if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 10) { 4211 | panic!("isize::MAX shouldn't trigger an overflow!"); 4212 | } 4213 | if guards_against_isize { 4214 | if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { 4215 | } else { panic!("isize::MAX + 1 should trigger an overflow!"); } 4216 | } else { 4217 | if let Err(AllocErr) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { 4218 | } else { panic!("isize::MAX + 1 should trigger an OOM!") } 4219 | } 4220 | if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) { 4221 | } else { panic!("usize::MAX should trigger an overflow!") } 4222 | } 4223 | } 4224 | */ 4225 | 4226 | #[test] 4227 | #[cfg_attr(feature = "gecko-ffi", ignore)] 4228 | fn test_header_data() { 4229 | macro_rules! assert_aligned_head_ptr { 4230 | ($typename:ty) => {{ 4231 | let v: ThinVec<$typename> = ThinVec::with_capacity(1 /* ensure allocation */); 4232 | let head_ptr: *mut $typename = v.data_raw(); 4233 | assert_eq!( 4234 | head_ptr as usize % core::mem::align_of::<$typename>(), 4235 | 0, 4236 | "expected Header::data<{}> to be aligned", 4237 | stringify!($typename) 4238 | ); 4239 | }}; 4240 | } 4241 | 4242 | const HEADER_SIZE: usize = core::mem::size_of::
(); 4243 | assert_eq!(2 * core::mem::size_of::(), HEADER_SIZE); 4244 | 4245 | #[repr(C, align(128))] 4246 | struct Funky(T); 4247 | assert_eq!(padding::>(), 128 - HEADER_SIZE); 4248 | assert_aligned_head_ptr!(Funky<()>); 4249 | 4250 | assert_eq!(padding::>(), 128 - HEADER_SIZE); 4251 | assert_aligned_head_ptr!(Funky); 4252 | 4253 | assert_eq!(padding::>(), 128 - HEADER_SIZE); 4254 | assert_aligned_head_ptr!(Funky<[(); 1024]>); 4255 | 4256 | assert_eq!(padding::>(), 128 - HEADER_SIZE); 4257 | assert_aligned_head_ptr!(Funky<[*mut usize; 1024]>); 4258 | } 4259 | 4260 | #[cfg(feature = "serde")] 4261 | use serde_test::{assert_tokens, Token}; 4262 | 4263 | #[test] 4264 | #[cfg(feature = "serde")] 4265 | fn test_ser_de_empty() { 4266 | let vec = ThinVec::::new(); 4267 | 4268 | assert_tokens(&vec, &[Token::Seq { len: Some(0) }, Token::SeqEnd]); 4269 | } 4270 | 4271 | #[test] 4272 | #[cfg(feature = "serde")] 4273 | fn test_ser_de() { 4274 | let mut vec = ThinVec::::new(); 4275 | vec.push(20); 4276 | vec.push(55); 4277 | vec.push(123); 4278 | 4279 | assert_tokens( 4280 | &vec, 4281 | &[ 4282 | Token::Seq { len: Some(3) }, 4283 | Token::U32(20), 4284 | Token::U32(55), 4285 | Token::U32(123), 4286 | Token::SeqEnd, 4287 | ], 4288 | ); 4289 | } 4290 | 4291 | #[test] 4292 | fn test_set_len() { 4293 | let mut vec: ThinVec = thin_vec![]; 4294 | unsafe { 4295 | vec.set_len(0); // at one point this caused a crash 4296 | } 4297 | } 4298 | 4299 | #[test] 4300 | #[should_panic(expected = "invalid set_len(1) on empty ThinVec")] 4301 | fn test_set_len_invalid() { 4302 | let mut vec: ThinVec = thin_vec![]; 4303 | unsafe { 4304 | vec.set_len(1); 4305 | } 4306 | } 4307 | 4308 | #[test] 4309 | #[should_panic(expected = "capacity overflow")] 4310 | fn test_capacity_overflow_header_too_big() { 4311 | let vec: ThinVec = ThinVec::with_capacity(isize::MAX as usize - 2); 4312 | assert!(vec.capacity() > 0); 4313 | } 4314 | #[test] 4315 | #[should_panic(expected = "capacity overflow")] 4316 | fn test_capacity_overflow_cap_too_big() { 4317 | let vec: ThinVec = ThinVec::with_capacity(isize::MAX as usize + 1); 4318 | assert!(vec.capacity() > 0); 4319 | } 4320 | #[test] 4321 | #[should_panic(expected = "capacity overflow")] 4322 | fn test_capacity_overflow_size_mul1() { 4323 | let vec: ThinVec = ThinVec::with_capacity(isize::MAX as usize + 1); 4324 | assert!(vec.capacity() > 0); 4325 | } 4326 | #[test] 4327 | #[should_panic(expected = "capacity overflow")] 4328 | fn test_capacity_overflow_size_mul2() { 4329 | let vec: ThinVec = ThinVec::with_capacity(isize::MAX as usize / 2 + 1); 4330 | assert!(vec.capacity() > 0); 4331 | } 4332 | #[test] 4333 | #[should_panic(expected = "capacity overflow")] 4334 | fn test_capacity_overflow_cap_really_isnt_isize() { 4335 | let vec: ThinVec = ThinVec::with_capacity(isize::MAX as usize); 4336 | assert!(vec.capacity() > 0); 4337 | } 4338 | } 4339 | --------------------------------------------------------------------------------