From 29b777e06e1a4258e1496ce021198828b9f59156 Mon Sep 17 00:00:00 2001 From: Ross Kettleson Date: Thu, 7 Dec 2023 14:35:17 -0800 Subject: Import 'arrayvec' crate Request Document: go/android-rust-importing-crates For CL Reviewers: go/android3p#cl-review For Build Team: go/ab-third-party-imports Bug: http://b/314392583 Test: m arrayvec Change-Id: Iac291c4c16a58eb55da4a8f5b594c4d05b2b26bc --- Android.bp | 72 ++ CHANGELOG.md | 313 ++++++++ Cargo.toml | 81 ++ Cargo.toml.orig | 56 ++ LICENSE | 229 ++++++ LICENSE-APACHE | 201 +++++ LICENSE-MIT | 25 + METADATA | 20 + MODULE_LICENSE_APACHE2 | 0 OWNERS | 1 + README.md | 27 + arrayvec-0.7.4/.cargo_vcs_info.json | 6 + arrayvec-0.7.4/.github/workflows/ci.yml | 61 ++ arrayvec-0.7.4/.gitignore | 12 + benches/arraystring.rs | 90 +++ benches/extend.rs | 78 ++ cargo_embargo.json | 3 + src/array_string.rs | 673 ++++++++++++++++ src/arrayvec.rs | 1300 +++++++++++++++++++++++++++++++ src/arrayvec_impl.rs | 87 +++ src/char.rs | 92 +++ src/errors.rs | 49 ++ src/lib.rs | 63 ++ src/utils.rs | 11 + tests/serde.rs | 79 ++ tests/tests.rs | 793 +++++++++++++++++++ 26 files changed, 4422 insertions(+) create mode 100644 Android.bp create mode 100644 CHANGELOG.md create mode 100644 Cargo.toml create mode 100644 Cargo.toml.orig create mode 100644 LICENSE create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT create mode 100644 METADATA create mode 100644 MODULE_LICENSE_APACHE2 create mode 100644 OWNERS create mode 100644 README.md create mode 100644 arrayvec-0.7.4/.cargo_vcs_info.json create mode 100644 arrayvec-0.7.4/.github/workflows/ci.yml create mode 100644 arrayvec-0.7.4/.gitignore create mode 100644 benches/arraystring.rs create mode 100644 benches/extend.rs create mode 100644 cargo_embargo.json create mode 100644 src/array_string.rs create mode 100644 src/arrayvec.rs create mode 100644 src/arrayvec_impl.rs create mode 100644 src/char.rs create mode 100644 src/errors.rs create mode 100644 src/lib.rs create mode 100644 src/utils.rs create mode 100644 tests/serde.rs create mode 100644 tests/tests.rs diff --git a/Android.bp b/Android.bp new file mode 100644 index 0000000..86e4985 --- /dev/null +++ b/Android.bp @@ -0,0 +1,72 @@ +// This file is generated by cargo_embargo. +// Do not modify this file as changes will be overridden on upgrade. + +// TODO: Add license. +rust_test { + name: "arrayvec_test_src_lib", + host_supported: true, + crate_name: "arrayvec", + cargo_env_compat: true, + cargo_pkg_version: "0.7.4", + srcs: ["src/lib.rs"], + test_suites: ["general-tests"], + auto_gen_config: true, + test_options: { + unit_test: true, + }, + edition: "2018", + features: [ + "default", + "std", + ], + rustlibs: [ + "libbencher", + "libmatches", + "libserde_test", + ], +} + +rust_test { + name: "arrayvec_test_tests_tests", + host_supported: true, + crate_name: "tests", + cargo_env_compat: true, + cargo_pkg_version: "0.7.4", + srcs: ["tests/tests.rs"], + test_suites: ["general-tests"], + auto_gen_config: true, + test_options: { + unit_test: true, + }, + edition: "2018", + features: [ + "default", + "std", + ], + rustlibs: [ + "libarrayvec", + "libbencher", + "libmatches", + "libserde_test", + ], +} + +rust_library { + name: "libarrayvec", + host_supported: true, + crate_name: "arrayvec", + cargo_env_compat: true, + cargo_pkg_version: "0.7.4", + srcs: ["src/lib.rs"], + edition: "2018", + features: [ + "default", + "std", + ], + apex_available: [ + "//apex_available:platform", + "//apex_available:anyapex", + ], + product_available: true, + vendor_available: true, +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..40a646a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,313 @@ +Recent Changes (arrayvec) +========================= + +## 0.7.4 + +- Add feature zeroize to support the `Zeroize` trait by @elichai + +## 0.7.3 + +- Use track_caller on multiple methods like push and similar, for capacity + overflows by @kornelski +- impl BorrowMut for ArrayString by @msrd0 +- Fix stacked borrows violations by @clubby789 +- Update Miri CI by @RalfJung + +## 0.7.2 + +- Add `.as_mut_str()` to `ArrayString` by @clarfonthey +- Add `remaining_capacity` to `ArrayString` by @bhgomes +- Add `zero_filled` constructor by @c410-f3r +- Optimize `retain` by @TennyZhuang and @niklasf +- Make the following methods `const` by @bhgomes: + - len + - is_empty + - capacity + - is_full + - remaining_capacity + - CapacityError::new + +## 0.7.1 + +- Add new ArrayVec methods `.take()` and `.into_inner_unchecked()` by @conradludgate +- `clone_from` now uses `truncate` when needed by @a1phyr + +## 0.7.0 + +- `fn new_const` is now the way to const-construct arrayvec and arraystring, + and `fn new` has been reverted to a regular "non-const" function. + This works around performance issue #182, where the const fn version did not + optimize well. Change by @bluss with thanks to @rodrimati1992 and @niklasf + for analyzing the problem. + +- The deprecated feature flag `unstable-const-fn` was removed, since it's not needed + +- Optimize `.retain()` by using the same algorithm as in std, change by @niklasf, + issue #174. Original optimization in Rust std by @oxalica in rust-lang/rust/pull/81126 + +## 0.6.1 + +- The ``ArrayVec::new`` and ``ArrayString::new`` constructors are properly + const fns on stable and the feature flag ``unstable-const-fn`` is now deprecated. + by @rodrimati1992 + +- Small fix to the capacity check macro by @Xaeroxe +- Typo fix in documentation by @cuviper +- Small code cleanup by @bluss + +## 0.6.0 + +- The **const generics** release šŸŽ‰. Arrayvec finally implements what it + wanted to implement, since its first version: a vector backed by an array, + with generic parameters for the arbitrary element type *and* backing array + capacity. + + The New type syntax is `ArrayVec` where `CAP` is the arrayvec capacity. + For arraystring the syntax is `ArrayString`. + + Length is stored internally as u32; this limits the maximum capacity. The size + of the `ArrayVec` or `ArrayString` structs for the same capacity may grow + slightly compared with the previous version (depending on padding requirements + for the element type). Change by @bluss. + +- Arrayvec's `.extend()` and `FromIterator`/`.collect()` to arrayvec now + **panic** if the capacity of the arrayvec is exceeded. Change by @bluss. + +- Arraystring now implements `TryFrom<&str>` and `TryFrom` by + @c410-f3r + +- Minimum supported rust version is Rust 1.51 + +## 0.5.2 + +- Add `is_empty` methods for ArrayVec and ArrayString by @nicbn +- Implement `TryFrom` for ArrayVec by @paulkernfeld +- Add `unstable-const-fn` to make `new` methods const by @m-ou-se +- Run miri in CI and a few related fixes by @RalfJung +- Fix outdated comment by @Phlosioneer +- Move changelog to a separate file by @Luro02 +- Remove deprecated `Error::description` by @AnderEnder +- Use pointer method `add` by @hbina + +## 0.5.1 + +- Add `as_ptr`, `as_mut_ptr` accessors directly on the `ArrayVec` by @tbu- + (matches the same addition to `Vec` which happened in Rust 1.37). +- Add method `ArrayString::len` (now available directly, not just through deref to str). +- Use raw pointers instead of `&mut [u8]` for encoding chars into `ArrayString` + (uninit best practice fix). +- Use raw pointers instead of `get_unchecked_mut` where the target may be + uninitialized everywhere relevant in the ArrayVec implementation + (uninit best practice fix). +- Changed inline hints on many methods, mainly removing inline hints +- `ArrayVec::dispose` is now deprecated (it has no purpose anymore) + +## 0.4.12 + +- Use raw pointers instead of `get_unchecked_mut` where the target may be + uninitialized everywhere relevant in the ArrayVec implementation. + +## 0.5.0 + +- Use `MaybeUninit` (now unconditionally) in the implementation of + `ArrayVec` +- Use `MaybeUninit` (now unconditionally) in the implementation of + `ArrayString` +- The crate feature for serde serialization is now named `serde`. +- Updated the `Array` trait interface, and it is now easier to use for + users outside the crate. +- Add `FromStr` impl for `ArrayString` by @despawnerer +- Add method `try_extend_from_slice` to `ArrayVec`, which is always + effecient by @Thomasdezeeuw. +- Add method `remaining_capacity` by @Thomasdezeeuw +- Improve performance of the `extend` method. +- The index type of zero capacity vectors is now itself zero size, by + @clarfon +- Use `drop_in_place` for truncate and clear methods. This affects drop order + and resume from panic during drop. +- Use Rust 2018 edition for the implementation +- Require Rust 1.36 or later, for the unconditional `MaybeUninit` + improvements. + +## Older releases + +- 0.4.11 + + - In Rust 1.36 or later, use newly stable `MaybeUninit`. This extends the + soundness work introduced in 0.4.9, we are finally able to use this in + stable. We use feature detection (build script) to enable this at build + time. + +- 0.4.10 + + - Use `repr(C)` in the `union` version that was introduced in 0.4.9, to + allay some soundness concerns. + +- 0.4.9 + + - Use `union` in the implementation on when this is detected to be supported + (nightly only for now). This is a better solution for treating uninitialized + regions correctly, and we'll use it in stable Rust as soon as we are able. + When this is enabled, the `ArrayVec` has no space overhead in its memory + layout, although the size of the vec should not be relied upon. (See [#114](https://github.com/bluss/arrayvec/pull/114)) + - `ArrayString` updated to not use uninitialized memory, it instead zeros its + backing array. This will be refined in the next version, since we + need to make changes to the user visible API. + - The `use_union` feature now does nothing (like its documentation foretold). + + +- 0.4.8 + + - Implement Clone and Debug for `IntoIter` by @clarcharr + - Add more array sizes under crate features. These cover all in the range + up to 128 and 129 to 255 respectively (we have a few of those by default): + + - `array-size-33-128` + - `array-size-129-255` + +- 0.4.7 + + - Fix future compat warning about raw pointer casts + - Use `drop_in_place` when dropping the arrayvec by-value iterator + - Decrease mininum Rust version (see docs) by @jeehoonkang + +- 0.3.25 + + - Fix future compat warning about raw pointer casts + +- 0.4.6 + + - Fix compilation on 16-bit targets. This means, the 65536 array size is not + included on these targets. + +- 0.3.24 + + - Fix compilation on 16-bit targets. This means, the 65536 array size is not + included on these targets. + - Fix license files so that they are both included (was fixed in 0.4 before) + +- 0.4.5 + + - Add methods to `ArrayString` by @DenialAdams: + + - `.pop() -> Option` + - `.truncate(new_len)` + - `.remove(index) -> char` + + - Remove dependency on crate odds + - Document debug assertions in unsafe methods better + +- 0.4.4 + + - Add method `ArrayVec::truncate()` by @niklasf + +- 0.4.3 + + - Improve performance for `ArrayVec::extend` with a lower level + implementation (#74) + - Small cleanup in dependencies (use no std for crates where we don't need more) + +- 0.4.2 + + - Add constructor method `new` to `CapacityError`. + +- 0.4.1 + + - Add `Default` impl to `ArrayString` by @tbu- + +- 0.4.0 + + - Reformed signatures and error handling by @bluss and @tbu-: + + - `ArrayVec`'s `push, insert, remove, swap_remove` now match `Vec`'s + corresponding signature and panic on capacity errors where applicable. + - Add fallible methods `try_push, insert` and checked methods + `pop_at, swap_pop`. + - Similar changes to `ArrayString`'s push methods. + + - Use a local version of the `RangeArgument` trait + - Add array sizes 50, 150, 200 by @daboross + - Support serde 1.0 by @daboross + - New method `.push_unchecked()` by @niklasf + - `ArrayString` implements `PartialOrd, Ord` by @tbu- + - Require Rust 1.14 + - crate feature `use_generic_array` was dropped. + +- 0.3.23 + + - Implement `PartialOrd, Ord` as well as `PartialOrd` for + `ArrayString`. + +- 0.3.22 + + - Implement `Array` for the 65536 size + +- 0.3.21 + + - Use `encode_utf8` from crate odds + - Add constructor `ArrayString::from_byte_string` + +- 0.3.20 + + - Simplify and speed up `ArrayString`ā€™s `.push(char)`- + +- 0.3.19 + + - Add new crate feature `use_generic_array` which allows using their + `GenericArray` just like a regular fixed size array for the storage + of an `ArrayVec`. + +- 0.3.18 + + - Fix bounds check in `ArrayVec::insert`! + It would be buggy if `self.len() < index < self.capacity()`. Take note of + the push out behavior specified in the docs. + +- 0.3.17 + + - Added crate feature `use_union` which forwards to the nodrop crate feature + - Added methods `.is_full()` to `ArrayVec` and `ArrayString`. + +- 0.3.16 + + - Added method `.retain()` to `ArrayVec`. + - Added methods `.as_slice(), .as_mut_slice()` to `ArrayVec` and `.as_str()` + to `ArrayString`. + +- 0.3.15 + + - Add feature std, which you can opt out of to use `no_std` (requires Rust 1.6 + to opt out). + - Implement `Clone::clone_from` for ArrayVec and ArrayString + +- 0.3.14 + + - Add `ArrayString::from(&str)` + +- 0.3.13 + + - Added `DerefMut` impl for `ArrayString`. + - Added method `.simplify()` to drop the element for `CapacityError`. + - Added method `.dispose()` to `ArrayVec` + +- 0.3.12 + + - Added ArrayString, a fixed capacity analogy of String + +- 0.3.11 + + - Added trait impls Default, PartialOrd, Ord, Write for ArrayVec + +- 0.3.10 + + - Go back to using external NoDrop, fixing a panic safety bug (issue #3) + +- 0.3.8 + + - Inline the non-dropping logic to remove one drop flag in the + ArrayVec representation. + +- 0.3.7 + + - Added method .into_inner() + - Added unsafe method .set_len() diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..308c6b2 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,81 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "arrayvec" +version = "0.7.4" +authors = ["bluss"] +description = "A vector with fixed capacity, backed by an array (it can be stored on the stack too). Implements fixed capacity ArrayVec and ArrayString." +documentation = "https://docs.rs/arrayvec/" +readme = "README.md" +keywords = [ + "stack", + "vector", + "array", + "data-structure", + "no_std", +] +categories = [ + "data-structures", + "no-std", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/bluss/arrayvec" + +[package.metadata.docs.rs] +features = [ + "serde", + "zeroize", +] + +[package.metadata.release] +no-dev-version = true +tag-name = "{{version}}" + +[profile.bench] +debug = 2 + +[profile.release] +debug = 2 + +[[bench]] +name = "extend" +harness = false + +[[bench]] +name = "arraystring" +harness = false + +[dependencies.serde] +version = "1.0" +optional = true +default-features = false + +[dependencies.zeroize] +version = "1.4" +optional = true +default-features = false + +[dev-dependencies.bencher] +version = "0.1.4" + +[dev-dependencies.matches] +version = "0.1" + +[dev-dependencies.serde_test] +version = "1.0" + +[build-dependencies] + +[features] +default = ["std"] +std = [] diff --git a/Cargo.toml.orig b/Cargo.toml.orig new file mode 100644 index 0000000..5f4fd2c --- /dev/null +++ b/Cargo.toml.orig @@ -0,0 +1,56 @@ +[package] +name = "arrayvec" +version = "0.7.4" +authors = ["bluss"] +license = "MIT OR Apache-2.0" +edition = "2018" + +description = "A vector with fixed capacity, backed by an array (it can be stored on the stack too). Implements fixed capacity ArrayVec and ArrayString." +documentation = "https://docs.rs/arrayvec/" +repository = "https://github.com/bluss/arrayvec" + +keywords = ["stack", "vector", "array", "data-structure", "no_std"] +categories = ["data-structures", "no-std"] + +[build-dependencies] + +[dependencies.serde] +version = "1.0" +optional = true +default-features = false + +[dependencies.zeroize] +version = "1.4" +optional = true +default-features = false + +[dev-dependencies.serde_test] +version = "1.0" + +[dev-dependencies] +matches = { version = "0.1" } +bencher = "0.1.4" + +[[bench]] +name = "extend" +harness = false + +[[bench]] +name = "arraystring" +harness = false + +[features] +default = ["std"] +std = [] + +[profile.bench] +debug = true +[profile.release] +debug = true + +[package.metadata.docs.rs] +features = ["serde", "zeroize"] + +[package.metadata.release] +no-dev-version = true +tag-name = "{{version}}" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fe1077c --- /dev/null +++ b/LICENSE @@ -0,0 +1,229 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +----- + +Copyright (c) Ulrik Sverdrup "bluss" 2015-2023 + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..db4c067 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) Ulrik Sverdrup "bluss" 2015-2023 + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/METADATA b/METADATA new file mode 100644 index 0000000..c4a014e --- /dev/null +++ b/METADATA @@ -0,0 +1,20 @@ +name: "arrayvec" +description: "A vector with fixed capacity, backed by an array (it can be stored on the stack too). Implements fixed capacity ArrayVec and ArrayString." +third_party { + identifier { + type: "crates.io" + value: "https://crates.io/crates/arrayvec" + } + identifier { + type: "Archive" + value: "https://static.crates.io/crates/arrayvec/arrayvec-0.7.4.crate" + } + version: "0.7.4" + # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same. + license_type: NOTICE + last_upgrade_date { + year: 2023 + month: 12 + day: 7 + } +} diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 diff --git a/OWNERS b/OWNERS new file mode 100644 index 0000000..5a2b844 --- /dev/null +++ b/OWNERS @@ -0,0 +1 @@ +include platform/prebuilts/rust:main:/OWNERS diff --git a/README.md b/README.md new file mode 100644 index 0000000..85ccbd1 --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ + +arrayvec +======== +[![Crates.io: arrayvec](https://img.shields.io/crates/v/arrayvec.svg)](https://crates.io/crates/arrayvec) +[![Documentation](https://docs.rs/arrayvec/badge.svg)](https://docs.rs/arrayvec) +[![Build Status](https://github.com/bluss/arrayvec/workflows/Continuous%20integration/badge.svg?branch=master)](https://github.com/bluss/arrayvec/actions) + + + + +[![License: Apache](https://img.shields.io/badge/License-Apache%202.0-red.svg)](LICENSE-APACHE) +OR +[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) + +A vector with fixed capacity. + +Please read the [`API documentation here`](https://docs.rs/arrayvec) + +# License + +Dual-licensed to be compatible with the Rust project. + +Licensed under the Apache License, Version 2.0 +http://www.apache.org/licenses/LICENSE-2.0 or the MIT license +http://opensource.org/licenses/MIT, at your +option. This file may not be copied, modified, or distributed +except according to those terms. diff --git a/arrayvec-0.7.4/.cargo_vcs_info.json b/arrayvec-0.7.4/.cargo_vcs_info.json new file mode 100644 index 0000000..662c0c7 --- /dev/null +++ b/arrayvec-0.7.4/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "2c92a59bed0d1669cede3806000d2e61d5994c4e" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/arrayvec-0.7.4/.github/workflows/ci.yml b/arrayvec-0.7.4/.github/workflows/ci.yml new file mode 100644 index 0000000..56fdb0f --- /dev/null +++ b/arrayvec-0.7.4/.github/workflows/ci.yml @@ -0,0 +1,61 @@ +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +name: Continuous integration + +env: + CARGO_TERM_COLOR: always + CARGO_INCREMENTAL: 0 + +jobs: + tests: + runs-on: ubuntu-latest + continue-on-error: ${{ matrix.experimental }} + strategy: + matrix: + include: + - rust: 1.51.0 # MSRV + features: serde + experimental: false + - rust: stable + features: + bench: true + experimental: false + - rust: beta + features: serde + experimental: false + - rust: nightly + features: serde, zeroize + experimental: false + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + - name: Tests + run: | + cargo build --verbose --features "${{ matrix.features }}" + cargo doc --verbose --features "${{ matrix.features }}" --no-deps + cargo test --verbose --features "${{ matrix.features }}" + cargo test --release --verbose --features "${{ matrix.features }}" + - name: Test run benchmarks + if: matrix.bench != '' + run: cargo test -v --benches + + miri: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install Miri + run: | + rustup toolchain install nightly --component miri + rustup override set nightly + cargo miri setup + - name: Test with Miri + run: cargo miri test --all-features diff --git a/arrayvec-0.7.4/.gitignore b/arrayvec-0.7.4/.gitignore new file mode 100644 index 0000000..00d0128 --- /dev/null +++ b/arrayvec-0.7.4/.gitignore @@ -0,0 +1,12 @@ +# Compiled files +*.o +*.so +*.rlib +*.dll + +# Executables +*.exe + +# Generated by Cargo +/Cargo.lock +/target diff --git a/benches/arraystring.rs b/benches/arraystring.rs new file mode 100644 index 0000000..5b986fa --- /dev/null +++ b/benches/arraystring.rs @@ -0,0 +1,90 @@ + +extern crate arrayvec; +#[macro_use] extern crate bencher; + +use arrayvec::ArrayString; + +use bencher::Bencher; + +fn try_push_c(b: &mut Bencher) { + let mut v = ArrayString::<512>::new(); + b.iter(|| { + v.clear(); + while v.try_push('c').is_ok() { + } + v.len() + }); + b.bytes = v.capacity() as u64; +} + +fn try_push_alpha(b: &mut Bencher) { + let mut v = ArrayString::<512>::new(); + b.iter(|| { + v.clear(); + while v.try_push('Ī±').is_ok() { + } + v.len() + }); + b.bytes = v.capacity() as u64; +} + +// Yes, pushing a string char-by-char is slow. Use .push_str. +fn try_push_string(b: &mut Bencher) { + let mut v = ArrayString::<512>::new(); + let input = "abcĪ±Ī²Ī³ā€œā€"; + b.iter(|| { + v.clear(); + for ch in input.chars().cycle() { + if !v.try_push(ch).is_ok() { + break; + } + } + v.len() + }); + b.bytes = v.capacity() as u64; +} + +fn push_c(b: &mut Bencher) { + let mut v = ArrayString::<512>::new(); + b.iter(|| { + v.clear(); + while !v.is_full() { + v.push('c'); + } + v.len() + }); + b.bytes = v.capacity() as u64; +} + +fn push_alpha(b: &mut Bencher) { + let mut v = ArrayString::<512>::new(); + b.iter(|| { + v.clear(); + while !v.is_full() { + v.push('Ī±'); + } + v.len() + }); + b.bytes = v.capacity() as u64; +} + +fn push_string(b: &mut Bencher) { + let mut v = ArrayString::<512>::new(); + let input = "abcĪ±Ī²Ī³ā€œā€"; + b.iter(|| { + v.clear(); + for ch in input.chars().cycle() { + if !v.is_full() { + v.push(ch); + } else { + break; + } + } + v.len() + }); + b.bytes = v.capacity() as u64; +} + +benchmark_group!(benches, try_push_c, try_push_alpha, try_push_string, push_c, + push_alpha, push_string); +benchmark_main!(benches); diff --git a/benches/extend.rs b/benches/extend.rs new file mode 100644 index 0000000..ba33a93 --- /dev/null +++ b/benches/extend.rs @@ -0,0 +1,78 @@ + +extern crate arrayvec; +#[macro_use] extern crate bencher; + +use std::io::Write; + +use arrayvec::ArrayVec; + +use bencher::Bencher; +use bencher::black_box; + +fn extend_with_constant(b: &mut Bencher) { + let mut v = ArrayVec::::new(); + let cap = v.capacity(); + b.iter(|| { + v.clear(); + let constant = black_box(1); + v.extend((0..cap).map(move |_| constant)); + v[511] + }); + b.bytes = v.capacity() as u64; +} + +fn extend_with_range(b: &mut Bencher) { + let mut v = ArrayVec::::new(); + let cap = v.capacity(); + b.iter(|| { + v.clear(); + let range = 0..cap; + v.extend(range.map(|x| black_box(x as _))); + v[511] + }); + b.bytes = v.capacity() as u64; +} + +fn extend_with_slice(b: &mut Bencher) { + let mut v = ArrayVec::::new(); + let data = [1; 512]; + b.iter(|| { + v.clear(); + let iter = data.iter().map(|&x| x); + v.extend(iter); + v[511] + }); + b.bytes = v.capacity() as u64; +} + +fn extend_with_write(b: &mut Bencher) { + let mut v = ArrayVec::::new(); + let data = [1; 512]; + b.iter(|| { + v.clear(); + v.write(&data[..]).ok(); + v[511] + }); + b.bytes = v.capacity() as u64; +} + +fn extend_from_slice(b: &mut Bencher) { + let mut v = ArrayVec::::new(); + let data = [1; 512]; + b.iter(|| { + v.clear(); + v.try_extend_from_slice(&data).ok(); + v[511] + }); + b.bytes = v.capacity() as u64; +} + +benchmark_group!(benches, + extend_with_constant, + extend_with_range, + extend_with_slice, + extend_with_write, + extend_from_slice +); + +benchmark_main!(benches); diff --git a/cargo_embargo.json b/cargo_embargo.json new file mode 100644 index 0000000..9a0a579 --- /dev/null +++ b/cargo_embargo.json @@ -0,0 +1,3 @@ +{ + "tests": true +} diff --git a/src/array_string.rs b/src/array_string.rs new file mode 100644 index 0000000..90cfc09 --- /dev/null +++ b/src/array_string.rs @@ -0,0 +1,673 @@ +use std::borrow::{Borrow, BorrowMut}; +use std::cmp; +use std::convert::TryFrom; +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::mem::MaybeUninit; +use std::ops::{Deref, DerefMut}; +use std::ptr; +use std::slice; +use std::str; +use std::str::FromStr; +use std::str::Utf8Error; + +use crate::CapacityError; +use crate::LenUint; +use crate::char::encode_utf8; +use crate::utils::MakeMaybeUninit; + +#[cfg(feature="serde")] +use serde::{Serialize, Deserialize, Serializer, Deserializer}; + + +/// A string with a fixed capacity. +/// +/// The `ArrayString` is a string backed by a fixed size array. It keeps track +/// of its length, and is parameterized by `CAP` for the maximum capacity. +/// +/// `CAP` is of type `usize` but is range limited to `u32::MAX`; attempting to create larger +/// arrayvecs with larger capacity will panic. +/// +/// The string is a contiguous value that you can store directly on the stack +/// if needed. +#[derive(Copy)] +pub struct ArrayString { + // the `len` first elements of the array are initialized + xs: [MaybeUninit; CAP], + len: LenUint, +} + +impl Default for ArrayString +{ + /// Return an empty `ArrayString` + fn default() -> ArrayString { + ArrayString::new() + } +} + +impl ArrayString +{ + /// Create a new empty `ArrayString`. + /// + /// Capacity is inferred from the type parameter. + /// + /// ``` + /// use arrayvec::ArrayString; + /// + /// let mut string = ArrayString::<16>::new(); + /// string.push_str("foo"); + /// assert_eq!(&string[..], "foo"); + /// assert_eq!(string.capacity(), 16); + /// ``` + pub fn new() -> ArrayString { + assert_capacity_limit!(CAP); + unsafe { + ArrayString { xs: MaybeUninit::uninit().assume_init(), len: 0 } + } + } + + /// Create a new empty `ArrayString` (const fn). + /// + /// Capacity is inferred from the type parameter. + /// + /// ``` + /// use arrayvec::ArrayString; + /// + /// static ARRAY: ArrayString<1024> = ArrayString::new_const(); + /// ``` + pub const fn new_const() -> ArrayString { + assert_capacity_limit_const!(CAP); + ArrayString { xs: MakeMaybeUninit::ARRAY, len: 0 } + } + + /// Return the length of the string. + #[inline] + pub const fn len(&self) -> usize { self.len as usize } + + /// Returns whether the string is empty. + #[inline] + pub const fn is_empty(&self) -> bool { self.len() == 0 } + + /// Create a new `ArrayString` from a `str`. + /// + /// Capacity is inferred from the type parameter. + /// + /// **Errors** if the backing array is not large enough to fit the string. + /// + /// ``` + /// use arrayvec::ArrayString; + /// + /// let mut string = ArrayString::<3>::from("foo").unwrap(); + /// assert_eq!(&string[..], "foo"); + /// assert_eq!(string.len(), 3); + /// assert_eq!(string.capacity(), 3); + /// ``` + pub fn from(s: &str) -> Result> { + let mut arraystr = Self::new(); + arraystr.try_push_str(s)?; + Ok(arraystr) + } + + /// Create a new `ArrayString` from a byte string literal. + /// + /// **Errors** if the byte string literal is not valid UTF-8. + /// + /// ``` + /// use arrayvec::ArrayString; + /// + /// let string = ArrayString::from_byte_string(b"hello world").unwrap(); + /// ``` + pub fn from_byte_string(b: &[u8; CAP]) -> Result { + let len = str::from_utf8(b)?.len(); + debug_assert_eq!(len, CAP); + let mut vec = Self::new(); + unsafe { + (b as *const [u8; CAP] as *const [MaybeUninit; CAP]) + .copy_to_nonoverlapping(&mut vec.xs as *mut [MaybeUninit; CAP], 1); + vec.set_len(CAP); + } + Ok(vec) + } + + /// Create a new `ArrayString` value fully filled with ASCII NULL characters (`\0`). Useful + /// to be used as a buffer to collect external data or as a buffer for intermediate processing. + /// + /// ``` + /// use arrayvec::ArrayString; + /// + /// let string = ArrayString::<16>::zero_filled(); + /// assert_eq!(string.len(), 16); + /// ``` + #[inline] + pub fn zero_filled() -> Self { + assert_capacity_limit!(CAP); + // SAFETY: `assert_capacity_limit` asserts that `len` won't overflow and + // `zeroed` fully fills the array with nulls. + unsafe { + ArrayString { + xs: MaybeUninit::zeroed().assume_init(), + len: CAP as _ + } + } + } + + /// Return the capacity of the `ArrayString`. + /// + /// ``` + /// use arrayvec::ArrayString; + /// + /// let string = ArrayString::<3>::new(); + /// assert_eq!(string.capacity(), 3); + /// ``` + #[inline(always)] + pub const fn capacity(&self) -> usize { CAP } + + /// Return if the `ArrayString` is completely filled. + /// + /// ``` + /// use arrayvec::ArrayString; + /// + /// let mut string = ArrayString::<1>::new(); + /// assert!(!string.is_full()); + /// string.push_str("A"); + /// assert!(string.is_full()); + /// ``` + pub const fn is_full(&self) -> bool { self.len() == self.capacity() } + + /// Returns the capacity left in the `ArrayString`. + /// + /// ``` + /// use arrayvec::ArrayString; + /// + /// let mut string = ArrayString::<3>::from("abc").unwrap(); + /// string.pop(); + /// assert_eq!(string.remaining_capacity(), 1); + /// ``` + pub const fn remaining_capacity(&self) -> usize { + self.capacity() - self.len() + } + + /// Adds the given char to the end of the string. + /// + /// ***Panics*** if the backing array is not large enough to fit the additional char. + /// + /// ``` + /// use arrayvec::ArrayString; + /// + /// let mut string = ArrayString::<2>::new(); + /// + /// string.push('a'); + /// string.push('b'); + /// + /// assert_eq!(&string[..], "ab"); + /// ``` + #[track_caller] + pub fn push(&mut self, c: char) { + self.try_push(c).unwrap(); + } + + /// Adds the given char to the end of the string. + /// + /// Returns `Ok` if the push succeeds. + /// + /// **Errors** if the backing array is not large enough to fit the additional char. + /// + /// ``` + /// use arrayvec::ArrayString; + /// + /// let mut string = ArrayString::<2>::new(); + /// + /// string.try_push('a').unwrap(); + /// string.try_push('b').unwrap(); + /// let overflow = string.try_push('c'); + /// + /// assert_eq!(&string[..], "ab"); + /// assert_eq!(overflow.unwrap_err().element(), 'c'); + /// ``` + pub fn try_push(&mut self, c: char) -> Result<(), CapacityError> { + let len = self.len(); + unsafe { + let ptr = self.as_mut_ptr().add(len); + let remaining_cap = self.capacity() - len; + match encode_utf8(c, ptr, remaining_cap) { + Ok(n) => { + self.set_len(len + n); + Ok(()) + } + Err(_) => Err(CapacityError::new(c)), + } + } + } + + /// Adds the given string slice to the end of the string. + /// + /// ***Panics*** if the backing array is not large enough to fit the string. + /// + /// ``` + /// use arrayvec::ArrayString; + /// + /// let mut string = ArrayString::<2>::new(); + /// + /// string.push_str("a"); + /// string.push_str("d"); + /// + /// assert_eq!(&string[..], "ad"); + /// ``` + #[track_caller] + pub fn push_str(&mut self, s: &str) { + self.try_push_str(s).unwrap() + } + + /// Adds the given string slice to the end of the string. + /// + /// Returns `Ok` if the push succeeds. + /// + /// **Errors** if the backing array is not large enough to fit the string. + /// + /// ``` + /// use arrayvec::ArrayString; + /// + /// let mut string = ArrayString::<2>::new(); + /// + /// string.try_push_str("a").unwrap(); + /// let overflow1 = string.try_push_str("bc"); + /// string.try_push_str("d").unwrap(); + /// let overflow2 = string.try_push_str("ef"); + /// + /// assert_eq!(&string[..], "ad"); + /// assert_eq!(overflow1.unwrap_err().element(), "bc"); + /// assert_eq!(overflow2.unwrap_err().element(), "ef"); + /// ``` + pub fn try_push_str<'a>(&mut self, s: &'a str) -> Result<(), CapacityError<&'a str>> { + if s.len() > self.capacity() - self.len() { + return Err(CapacityError::new(s)); + } + unsafe { + let dst = self.as_mut_ptr().add(self.len()); + let src = s.as_ptr(); + ptr::copy_nonoverlapping(src, dst, s.len()); + let newl = self.len() + s.len(); + self.set_len(newl); + } + Ok(()) + } + + /// Removes the last character from the string and returns it. + /// + /// Returns `None` if this `ArrayString` is empty. + /// + /// ``` + /// use arrayvec::ArrayString; + /// + /// let mut s = ArrayString::<3>::from("foo").unwrap(); + /// + /// assert_eq!(s.pop(), Some('o')); + /// assert_eq!(s.pop(), Some('o')); + /// assert_eq!(s.pop(), Some('f')); + /// + /// assert_eq!(s.pop(), None); + /// ``` + pub fn pop(&mut self) -> Option { + let ch = match self.chars().rev().next() { + Some(ch) => ch, + None => return None, + }; + let new_len = self.len() - ch.len_utf8(); + unsafe { + self.set_len(new_len); + } + Some(ch) + } + + /// Shortens this `ArrayString` to the specified length. + /// + /// If `new_len` is greater than the stringā€™s current length, this has no + /// effect. + /// + /// ***Panics*** if `new_len` does not lie on a `char` boundary. + /// + /// ``` + /// use arrayvec::ArrayString; + /// + /// let mut string = ArrayString::<6>::from("foobar").unwrap(); + /// string.truncate(3); + /// assert_eq!(&string[..], "foo"); + /// string.truncate(4); + /// assert_eq!(&string[..], "foo"); + /// ``` + pub fn truncate(&mut self, new_len: usize) { + if new_len <= self.len() { + assert!(self.is_char_boundary(new_len)); + unsafe { + // In libstd truncate is called on the underlying vector, + // which in turns drops each element. + // As we know we don't have to worry about Drop, + // we can just set the length (a la clear.) + self.set_len(new_len); + } + } + } + + /// Removes a `char` from this `ArrayString` at a byte position and returns it. + /// + /// This is an `O(n)` operation, as it requires copying every element in the + /// array. + /// + /// ***Panics*** if `idx` is larger than or equal to the `ArrayString`ā€™s length, + /// or if it does not lie on a `char` boundary. + /// + /// ``` + /// use arrayvec::ArrayString; + /// + /// let mut s = ArrayString::<3>::from("foo").unwrap(); + /// + /// assert_eq!(s.remove(0), 'f'); + /// assert_eq!(s.remove(1), 'o'); + /// assert_eq!(s.remove(0), 'o'); + /// ``` + pub fn remove(&mut self, idx: usize) -> char { + let ch = match self[idx..].chars().next() { + Some(ch) => ch, + None => panic!("cannot remove a char from the end of a string"), + }; + + let next = idx + ch.len_utf8(); + let len = self.len(); + let ptr = self.as_mut_ptr(); + unsafe { + ptr::copy( + ptr.add(next), + ptr.add(idx), + len - next); + self.set_len(len - (next - idx)); + } + ch + } + + /// Make the string empty. + pub fn clear(&mut self) { + unsafe { + self.set_len(0); + } + } + + /// Set the stringsā€™s length. + /// + /// This function is `unsafe` because it changes the notion of the + /// number of ā€œvalidā€ bytes in the string. Use with care. + /// + /// This method uses *debug assertions* to check the validity of `length` + /// and may use other debug assertions. + pub unsafe fn set_len(&mut self, length: usize) { + // type invariant that capacity always fits in LenUint + debug_assert!(length <= self.capacity()); + self.len = length as LenUint; + } + + /// Return a string slice of the whole `ArrayString`. + pub fn as_str(&self) -> &str { + self + } + + /// Return a mutable string slice of the whole `ArrayString`. + pub fn as_mut_str(&mut self) -> &mut str { + self + } + + fn as_ptr(&self) -> *const u8 { + self.xs.as_ptr() as *const u8 + } + + fn as_mut_ptr(&mut self) -> *mut u8 { + self.xs.as_mut_ptr() as *mut u8 + } +} + +impl Deref for ArrayString +{ + type Target = str; + #[inline] + fn deref(&self) -> &str { + unsafe { + let sl = slice::from_raw_parts(self.as_ptr(), self.len()); + str::from_utf8_unchecked(sl) + } + } +} + +impl DerefMut for ArrayString +{ + #[inline] + fn deref_mut(&mut self) -> &mut str { + unsafe { + let len = self.len(); + let sl = slice::from_raw_parts_mut(self.as_mut_ptr(), len); + str::from_utf8_unchecked_mut(sl) + } + } +} + +impl PartialEq for ArrayString +{ + fn eq(&self, rhs: &Self) -> bool { + **self == **rhs + } +} + +impl PartialEq for ArrayString +{ + fn eq(&self, rhs: &str) -> bool { + &**self == rhs + } +} + +impl PartialEq> for str +{ + fn eq(&self, rhs: &ArrayString) -> bool { + self == &**rhs + } +} + +impl Eq for ArrayString +{ } + +impl Hash for ArrayString +{ + fn hash(&self, h: &mut H) { + (**self).hash(h) + } +} + +impl Borrow for ArrayString +{ + fn borrow(&self) -> &str { self } +} + +impl BorrowMut for ArrayString +{ + fn borrow_mut(&mut self) -> &mut str { self } +} + +impl AsRef for ArrayString +{ + fn as_ref(&self) -> &str { self } +} + +impl fmt::Debug for ArrayString +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) } +} + +impl fmt::Display for ArrayString +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) } +} + +/// `Write` appends written data to the end of the string. +impl fmt::Write for ArrayString +{ + fn write_char(&mut self, c: char) -> fmt::Result { + self.try_push(c).map_err(|_| fmt::Error) + } + + fn write_str(&mut self, s: &str) -> fmt::Result { + self.try_push_str(s).map_err(|_| fmt::Error) + } +} + +impl Clone for ArrayString +{ + fn clone(&self) -> ArrayString { + *self + } + fn clone_from(&mut self, rhs: &Self) { + // guaranteed to fit due to types matching. + self.clear(); + self.try_push_str(rhs).ok(); + } +} + +impl PartialOrd for ArrayString +{ + fn partial_cmp(&self, rhs: &Self) -> Option { + (**self).partial_cmp(&**rhs) + } + fn lt(&self, rhs: &Self) -> bool { **self < **rhs } + fn le(&self, rhs: &Self) -> bool { **self <= **rhs } + fn gt(&self, rhs: &Self) -> bool { **self > **rhs } + fn ge(&self, rhs: &Self) -> bool { **self >= **rhs } +} + +impl PartialOrd for ArrayString +{ + fn partial_cmp(&self, rhs: &str) -> Option { + (**self).partial_cmp(rhs) + } + fn lt(&self, rhs: &str) -> bool { &**self < rhs } + fn le(&self, rhs: &str) -> bool { &**self <= rhs } + fn gt(&self, rhs: &str) -> bool { &**self > rhs } + fn ge(&self, rhs: &str) -> bool { &**self >= rhs } +} + +impl PartialOrd> for str +{ + fn partial_cmp(&self, rhs: &ArrayString) -> Option { + self.partial_cmp(&**rhs) + } + fn lt(&self, rhs: &ArrayString) -> bool { self < &**rhs } + fn le(&self, rhs: &ArrayString) -> bool { self <= &**rhs } + fn gt(&self, rhs: &ArrayString) -> bool { self > &**rhs } + fn ge(&self, rhs: &ArrayString) -> bool { self >= &**rhs } +} + +impl Ord for ArrayString +{ + fn cmp(&self, rhs: &Self) -> cmp::Ordering { + (**self).cmp(&**rhs) + } +} + +impl FromStr for ArrayString +{ + type Err = CapacityError; + + fn from_str(s: &str) -> Result { + Self::from(s).map_err(CapacityError::simplify) + } +} + +#[cfg(feature="serde")] +/// Requires crate feature `"serde"` +impl Serialize for ArrayString +{ + fn serialize(&self, serializer: S) -> Result + where S: Serializer + { + serializer.serialize_str(&*self) + } +} + +#[cfg(feature="serde")] +/// Requires crate feature `"serde"` +impl<'de, const CAP: usize> Deserialize<'de> for ArrayString +{ + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> + { + use serde::de::{self, Visitor}; + use std::marker::PhantomData; + + struct ArrayStringVisitor(PhantomData<[u8; CAP]>); + + impl<'de, const CAP: usize> Visitor<'de> for ArrayStringVisitor { + type Value = ArrayString; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "a string no more than {} bytes long", CAP) + } + + fn visit_str(self, v: &str) -> Result + where E: de::Error, + { + ArrayString::from(v).map_err(|_| E::invalid_length(v.len(), &self)) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where E: de::Error, + { + let s = str::from_utf8(v).map_err(|_| E::invalid_value(de::Unexpected::Bytes(v), &self))?; + + ArrayString::from(s).map_err(|_| E::invalid_length(s.len(), &self)) + } + } + + deserializer.deserialize_str(ArrayStringVisitor(PhantomData)) + } +} + +impl<'a, const CAP: usize> TryFrom<&'a str> for ArrayString +{ + type Error = CapacityError<&'a str>; + + fn try_from(f: &'a str) -> Result { + let mut v = Self::new(); + v.try_push_str(f)?; + Ok(v) + } +} + +impl<'a, const CAP: usize> TryFrom> for ArrayString +{ + type Error = CapacityError; + + fn try_from(f: fmt::Arguments<'a>) -> Result { + use fmt::Write; + let mut v = Self::new(); + v.write_fmt(f).map_err(|e| CapacityError::new(e))?; + Ok(v) + } +} + +#[cfg(feature = "zeroize")] +/// "Best efforts" zeroing of the `ArrayString`'s buffer when the `zeroize` feature is enabled. +/// +/// The length is set to 0, and the buffer is dropped and zeroized. +/// Cannot ensure that previous moves of the `ArrayString` did not leave values on the stack. +/// +/// ``` +/// use arrayvec::ArrayString; +/// use zeroize::Zeroize; +/// let mut string = ArrayString::<6>::from("foobar").unwrap(); +/// string.zeroize(); +/// assert_eq!(string.len(), 0); +/// unsafe { string.set_len(string.capacity()) }; +/// assert_eq!(&*string, "\0\0\0\0\0\0"); +/// ``` +impl zeroize::Zeroize for ArrayString { + fn zeroize(&mut self) { + // There are no elements to drop + self.clear(); + // Zeroize the backing array. + self.xs.zeroize(); + } +} diff --git a/src/arrayvec.rs b/src/arrayvec.rs new file mode 100644 index 0000000..37e151a --- /dev/null +++ b/src/arrayvec.rs @@ -0,0 +1,1300 @@ + +use std::cmp; +use std::iter; +use std::mem; +use std::ops::{Bound, Deref, DerefMut, RangeBounds}; +use std::ptr; +use std::slice; + +// extra traits +use std::borrow::{Borrow, BorrowMut}; +use std::hash::{Hash, Hasher}; +use std::fmt; + +#[cfg(feature="std")] +use std::io; + +use std::mem::ManuallyDrop; +use std::mem::MaybeUninit; + +#[cfg(feature="serde")] +use serde::{Serialize, Deserialize, Serializer, Deserializer}; + +use crate::LenUint; +use crate::errors::CapacityError; +use crate::arrayvec_impl::ArrayVecImpl; +use crate::utils::MakeMaybeUninit; + +/// A vector with a fixed capacity. +/// +/// The `ArrayVec` is a vector backed by a fixed size array. It keeps track of +/// the number of initialized elements. The `ArrayVec` is parameterized +/// by `T` for the element type and `CAP` for the maximum capacity. +/// +/// `CAP` is of type `usize` but is range limited to `u32::MAX`; attempting to create larger +/// arrayvecs with larger capacity will panic. +/// +/// The vector is a contiguous value (storing the elements inline) that you can store directly on +/// the stack if needed. +/// +/// It offers a simple API but also dereferences to a slice, so that the full slice API is +/// available. The ArrayVec can be converted into a by value iterator. +pub struct ArrayVec { + // the `len` first elements of the array are initialized + xs: [MaybeUninit; CAP], + len: LenUint, +} + +impl Drop for ArrayVec { + fn drop(&mut self) { + self.clear(); + + // MaybeUninit inhibits array's drop + } +} + +macro_rules! panic_oob { + ($method_name:expr, $index:expr, $len:expr) => { + panic!(concat!("ArrayVec::", $method_name, ": index {} is out of bounds in vector of length {}"), + $index, $len) + } +} + +impl ArrayVec { + /// Capacity + const CAPACITY: usize = CAP; + + /// Create a new empty `ArrayVec`. + /// + /// The maximum capacity is given by the generic parameter `CAP`. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut array = ArrayVec::<_, 16>::new(); + /// array.push(1); + /// array.push(2); + /// assert_eq!(&array[..], &[1, 2]); + /// assert_eq!(array.capacity(), 16); + /// ``` + #[inline] + #[track_caller] + pub fn new() -> ArrayVec { + assert_capacity_limit!(CAP); + unsafe { + ArrayVec { xs: MaybeUninit::uninit().assume_init(), len: 0 } + } + } + + /// Create a new empty `ArrayVec` (const fn). + /// + /// The maximum capacity is given by the generic parameter `CAP`. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// static ARRAY: ArrayVec = ArrayVec::new_const(); + /// ``` + pub const fn new_const() -> ArrayVec { + assert_capacity_limit_const!(CAP); + ArrayVec { xs: MakeMaybeUninit::ARRAY, len: 0 } + } + + /// Return the number of elements in the `ArrayVec`. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut array = ArrayVec::from([1, 2, 3]); + /// array.pop(); + /// assert_eq!(array.len(), 2); + /// ``` + #[inline(always)] + pub const fn len(&self) -> usize { self.len as usize } + + /// Returns whether the `ArrayVec` is empty. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut array = ArrayVec::from([1]); + /// array.pop(); + /// assert_eq!(array.is_empty(), true); + /// ``` + #[inline] + pub const fn is_empty(&self) -> bool { self.len() == 0 } + + /// Return the capacity of the `ArrayVec`. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let array = ArrayVec::from([1, 2, 3]); + /// assert_eq!(array.capacity(), 3); + /// ``` + #[inline(always)] + pub const fn capacity(&self) -> usize { CAP } + + /// Return true if the `ArrayVec` is completely filled to its capacity, false otherwise. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut array = ArrayVec::<_, 1>::new(); + /// assert!(!array.is_full()); + /// array.push(1); + /// assert!(array.is_full()); + /// ``` + pub const fn is_full(&self) -> bool { self.len() == self.capacity() } + + /// Returns the capacity left in the `ArrayVec`. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut array = ArrayVec::from([1, 2, 3]); + /// array.pop(); + /// assert_eq!(array.remaining_capacity(), 1); + /// ``` + pub const fn remaining_capacity(&self) -> usize { + self.capacity() - self.len() + } + + /// Push `element` to the end of the vector. + /// + /// ***Panics*** if the vector is already full. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut array = ArrayVec::<_, 2>::new(); + /// + /// array.push(1); + /// array.push(2); + /// + /// assert_eq!(&array[..], &[1, 2]); + /// ``` + #[track_caller] + pub fn push(&mut self, element: T) { + ArrayVecImpl::push(self, element) + } + + /// Push `element` to the end of the vector. + /// + /// Return `Ok` if the push succeeds, or return an error if the vector + /// is already full. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut array = ArrayVec::<_, 2>::new(); + /// + /// let push1 = array.try_push(1); + /// let push2 = array.try_push(2); + /// + /// assert!(push1.is_ok()); + /// assert!(push2.is_ok()); + /// + /// assert_eq!(&array[..], &[1, 2]); + /// + /// let overflow = array.try_push(3); + /// + /// assert!(overflow.is_err()); + /// ``` + pub fn try_push(&mut self, element: T) -> Result<(), CapacityError> { + ArrayVecImpl::try_push(self, element) + } + + /// Push `element` to the end of the vector without checking the capacity. + /// + /// It is up to the caller to ensure the capacity of the vector is + /// sufficiently large. + /// + /// This method uses *debug assertions* to check that the arrayvec is not full. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut array = ArrayVec::<_, 2>::new(); + /// + /// if array.len() + 2 <= array.capacity() { + /// unsafe { + /// array.push_unchecked(1); + /// array.push_unchecked(2); + /// } + /// } + /// + /// assert_eq!(&array[..], &[1, 2]); + /// ``` + pub unsafe fn push_unchecked(&mut self, element: T) { + ArrayVecImpl::push_unchecked(self, element) + } + + /// Shortens the vector, keeping the first `len` elements and dropping + /// the rest. + /// + /// If `len` is greater than the vectorā€™s current length this has no + /// effect. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut array = ArrayVec::from([1, 2, 3, 4, 5]); + /// array.truncate(3); + /// assert_eq!(&array[..], &[1, 2, 3]); + /// array.truncate(4); + /// assert_eq!(&array[..], &[1, 2, 3]); + /// ``` + pub fn truncate(&mut self, new_len: usize) { + ArrayVecImpl::truncate(self, new_len) + } + + /// Remove all elements in the vector. + pub fn clear(&mut self) { + ArrayVecImpl::clear(self) + } + + + /// Get pointer to where element at `index` would be + unsafe fn get_unchecked_ptr(&mut self, index: usize) -> *mut T { + self.as_mut_ptr().add(index) + } + + /// Insert `element` at position `index`. + /// + /// Shift up all elements after `index`. + /// + /// It is an error if the index is greater than the length or if the + /// arrayvec is full. + /// + /// ***Panics*** if the array is full or the `index` is out of bounds. See + /// `try_insert` for fallible version. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut array = ArrayVec::<_, 2>::new(); + /// + /// array.insert(0, "x"); + /// array.insert(0, "y"); + /// assert_eq!(&array[..], &["y", "x"]); + /// + /// ``` + #[track_caller] + pub fn insert(&mut self, index: usize, element: T) { + self.try_insert(index, element).unwrap() + } + + /// Insert `element` at position `index`. + /// + /// Shift up all elements after `index`; the `index` must be less than + /// or equal to the length. + /// + /// Returns an error if vector is already at full capacity. + /// + /// ***Panics*** `index` is out of bounds. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut array = ArrayVec::<_, 2>::new(); + /// + /// assert!(array.try_insert(0, "x").is_ok()); + /// assert!(array.try_insert(0, "y").is_ok()); + /// assert!(array.try_insert(0, "z").is_err()); + /// assert_eq!(&array[..], &["y", "x"]); + /// + /// ``` + pub fn try_insert(&mut self, index: usize, element: T) -> Result<(), CapacityError> { + if index > self.len() { + panic_oob!("try_insert", index, self.len()) + } + if self.len() == self.capacity() { + return Err(CapacityError::new(element)); + } + let len = self.len(); + + // follows is just like Vec + unsafe { // infallible + // The spot to put the new value + { + let p: *mut _ = self.get_unchecked_ptr(index); + // Shift everything over to make space. (Duplicating the + // `index`th element into two consecutive places.) + ptr::copy(p, p.offset(1), len - index); + // Write it in, overwriting the first copy of the `index`th + // element. + ptr::write(p, element); + } + self.set_len(len + 1); + } + Ok(()) + } + + /// Remove the last element in the vector and return it. + /// + /// Return `Some(` *element* `)` if the vector is non-empty, else `None`. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut array = ArrayVec::<_, 2>::new(); + /// + /// array.push(1); + /// + /// assert_eq!(array.pop(), Some(1)); + /// assert_eq!(array.pop(), None); + /// ``` + pub fn pop(&mut self) -> Option { + ArrayVecImpl::pop(self) + } + + /// Remove the element at `index` and swap the last element into its place. + /// + /// This operation is O(1). + /// + /// Return the *element* if the index is in bounds, else panic. + /// + /// ***Panics*** if the `index` is out of bounds. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut array = ArrayVec::from([1, 2, 3]); + /// + /// assert_eq!(array.swap_remove(0), 1); + /// assert_eq!(&array[..], &[3, 2]); + /// + /// assert_eq!(array.swap_remove(1), 2); + /// assert_eq!(&array[..], &[3]); + /// ``` + pub fn swap_remove(&mut self, index: usize) -> T { + self.swap_pop(index) + .unwrap_or_else(|| { + panic_oob!("swap_remove", index, self.len()) + }) + } + + /// Remove the element at `index` and swap the last element into its place. + /// + /// This is a checked version of `.swap_remove`. + /// This operation is O(1). + /// + /// Return `Some(` *element* `)` if the index is in bounds, else `None`. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut array = ArrayVec::from([1, 2, 3]); + /// + /// assert_eq!(array.swap_pop(0), Some(1)); + /// assert_eq!(&array[..], &[3, 2]); + /// + /// assert_eq!(array.swap_pop(10), None); + /// ``` + pub fn swap_pop(&mut self, index: usize) -> Option { + let len = self.len(); + if index >= len { + return None; + } + self.swap(index, len - 1); + self.pop() + } + + /// Remove the element at `index` and shift down the following elements. + /// + /// The `index` must be strictly less than the length of the vector. + /// + /// ***Panics*** if the `index` is out of bounds. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut array = ArrayVec::from([1, 2, 3]); + /// + /// let removed_elt = array.remove(0); + /// assert_eq!(removed_elt, 1); + /// assert_eq!(&array[..], &[2, 3]); + /// ``` + pub fn remove(&mut self, index: usize) -> T { + self.pop_at(index) + .unwrap_or_else(|| { + panic_oob!("remove", index, self.len()) + }) + } + + /// Remove the element at `index` and shift down the following elements. + /// + /// This is a checked version of `.remove(index)`. Returns `None` if there + /// is no element at `index`. Otherwise, return the element inside `Some`. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut array = ArrayVec::from([1, 2, 3]); + /// + /// assert!(array.pop_at(0).is_some()); + /// assert_eq!(&array[..], &[2, 3]); + /// + /// assert!(array.pop_at(2).is_none()); + /// assert!(array.pop_at(10).is_none()); + /// ``` + pub fn pop_at(&mut self, index: usize) -> Option { + if index >= self.len() { + None + } else { + self.drain(index..index + 1).next() + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&mut e)` returns false. + /// This method operates in place and preserves the order of the retained + /// elements. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut array = ArrayVec::from([1, 2, 3, 4]); + /// array.retain(|x| *x & 1 != 0 ); + /// assert_eq!(&array[..], &[1, 3]); + /// ``` + pub fn retain(&mut self, mut f: F) + where F: FnMut(&mut T) -> bool + { + // Check the implementation of + // https://doc.rust-lang.org/std/vec/struct.Vec.html#method.retain + // for safety arguments (especially regarding panics in f and when + // dropping elements). Implementation closely mirrored here. + + let original_len = self.len(); + unsafe { self.set_len(0) }; + + struct BackshiftOnDrop<'a, T, const CAP: usize> { + v: &'a mut ArrayVec, + processed_len: usize, + deleted_cnt: usize, + original_len: usize, + } + + impl Drop for BackshiftOnDrop<'_, T, CAP> { + fn drop(&mut self) { + if self.deleted_cnt > 0 { + unsafe { + ptr::copy( + self.v.as_ptr().add(self.processed_len), + self.v.as_mut_ptr().add(self.processed_len - self.deleted_cnt), + self.original_len - self.processed_len + ); + } + } + unsafe { + self.v.set_len(self.original_len - self.deleted_cnt); + } + } + } + + let mut g = BackshiftOnDrop { v: self, processed_len: 0, deleted_cnt: 0, original_len }; + + #[inline(always)] + fn process_one bool, T, const CAP: usize, const DELETED: bool>( + f: &mut F, + g: &mut BackshiftOnDrop<'_, T, CAP> + ) -> bool { + let cur = unsafe { g.v.as_mut_ptr().add(g.processed_len) }; + if !f(unsafe { &mut *cur }) { + g.processed_len += 1; + g.deleted_cnt += 1; + unsafe { ptr::drop_in_place(cur) }; + return false; + } + if DELETED { + unsafe { + let hole_slot = cur.sub(g.deleted_cnt); + ptr::copy_nonoverlapping(cur, hole_slot, 1); + } + } + g.processed_len += 1; + true + } + + // Stage 1: Nothing was deleted. + while g.processed_len != original_len { + if !process_one::(&mut f, &mut g) { + break; + } + } + + // Stage 2: Some elements were deleted. + while g.processed_len != original_len { + process_one::(&mut f, &mut g); + } + + drop(g); + } + + /// Set the vectorā€™s length without dropping or moving out elements + /// + /// This method is `unsafe` because it changes the notion of the + /// number of ā€œvalidā€ elements in the vector. Use with care. + /// + /// This method uses *debug assertions* to check that `length` is + /// not greater than the capacity. + pub unsafe fn set_len(&mut self, length: usize) { + // type invariant that capacity always fits in LenUint + debug_assert!(length <= self.capacity()); + self.len = length as LenUint; + } + + /// Copy all elements from the slice and append to the `ArrayVec`. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut vec: ArrayVec = ArrayVec::new(); + /// vec.push(1); + /// vec.try_extend_from_slice(&[2, 3]).unwrap(); + /// assert_eq!(&vec[..], &[1, 2, 3]); + /// ``` + /// + /// # Errors + /// + /// This method will return an error if the capacity left (see + /// [`remaining_capacity`]) is smaller then the length of the provided + /// slice. + /// + /// [`remaining_capacity`]: #method.remaining_capacity + pub fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), CapacityError> + where T: Copy, + { + if self.remaining_capacity() < other.len() { + return Err(CapacityError::new(())); + } + + let self_len = self.len(); + let other_len = other.len(); + + unsafe { + let dst = self.get_unchecked_ptr(self_len); + ptr::copy_nonoverlapping(other.as_ptr(), dst, other_len); + self.set_len(self_len + other_len); + } + Ok(()) + } + + /// Create a draining iterator that removes the specified range in the vector + /// and yields the removed items from start to end. The element range is + /// removed even if the iterator is not consumed until the end. + /// + /// Note: It is unspecified how many elements are removed from the vector, + /// if the `Drain` value is leaked. + /// + /// **Panics** if the starting point is greater than the end point or if + /// the end point is greater than the length of the vector. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut v1 = ArrayVec::from([1, 2, 3]); + /// let v2: ArrayVec<_, 3> = v1.drain(0..2).collect(); + /// assert_eq!(&v1[..], &[3]); + /// assert_eq!(&v2[..], &[1, 2]); + /// ``` + pub fn drain(&mut self, range: R) -> Drain + where R: RangeBounds + { + // Memory safety + // + // When the Drain is first created, it shortens the length of + // the source vector to make sure no uninitialized or moved-from elements + // are accessible at all if the Drain's destructor never gets to run. + // + // Drain will ptr::read out the values to remove. + // When finished, remaining tail of the vec is copied back to cover + // the hole, and the vector length is restored to the new length. + // + let len = self.len(); + let start = match range.start_bound() { + Bound::Unbounded => 0, + Bound::Included(&i) => i, + Bound::Excluded(&i) => i.saturating_add(1), + }; + let end = match range.end_bound() { + Bound::Excluded(&j) => j, + Bound::Included(&j) => j.saturating_add(1), + Bound::Unbounded => len, + }; + self.drain_range(start, end) + } + + fn drain_range(&mut self, start: usize, end: usize) -> Drain + { + let len = self.len(); + + // bounds check happens here (before length is changed!) + let range_slice: *const _ = &self[start..end]; + + // Calling `set_len` creates a fresh and thus unique mutable references, making all + // older aliases we created invalid. So we cannot call that function. + self.len = start as LenUint; + + unsafe { + Drain { + tail_start: end, + tail_len: len - end, + iter: (*range_slice).iter(), + vec: self as *mut _, + } + } + } + + /// Return the inner fixed size array, if it is full to its capacity. + /// + /// Return an `Ok` value with the array if length equals capacity, + /// return an `Err` with self otherwise. + pub fn into_inner(self) -> Result<[T; CAP], Self> { + if self.len() < self.capacity() { + Err(self) + } else { + unsafe { Ok(self.into_inner_unchecked()) } + } + } + + /// Return the inner fixed size array. + /// + /// Safety: + /// This operation is safe if and only if length equals capacity. + pub unsafe fn into_inner_unchecked(self) -> [T; CAP] { + debug_assert_eq!(self.len(), self.capacity()); + let self_ = ManuallyDrop::new(self); + let array = ptr::read(self_.as_ptr() as *const [T; CAP]); + array + } + + /// Returns the ArrayVec, replacing the original with a new empty ArrayVec. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut v = ArrayVec::from([0, 1, 2, 3]); + /// assert_eq!([0, 1, 2, 3], v.take().into_inner().unwrap()); + /// assert!(v.is_empty()); + /// ``` + pub fn take(&mut self) -> Self { + mem::replace(self, Self::new()) + } + + /// Return a slice containing all elements of the vector. + pub fn as_slice(&self) -> &[T] { + ArrayVecImpl::as_slice(self) + } + + /// Return a mutable slice containing all elements of the vector. + pub fn as_mut_slice(&mut self) -> &mut [T] { + ArrayVecImpl::as_mut_slice(self) + } + + /// Return a raw pointer to the vector's buffer. + pub fn as_ptr(&self) -> *const T { + ArrayVecImpl::as_ptr(self) + } + + /// Return a raw mutable pointer to the vector's buffer. + pub fn as_mut_ptr(&mut self) -> *mut T { + ArrayVecImpl::as_mut_ptr(self) + } +} + +impl ArrayVecImpl for ArrayVec { + type Item = T; + const CAPACITY: usize = CAP; + + fn len(&self) -> usize { self.len() } + + unsafe fn set_len(&mut self, length: usize) { + debug_assert!(length <= CAP); + self.len = length as LenUint; + } + + fn as_ptr(&self) -> *const Self::Item { + self.xs.as_ptr() as _ + } + + fn as_mut_ptr(&mut self) -> *mut Self::Item { + self.xs.as_mut_ptr() as _ + } +} + +impl Deref for ArrayVec { + type Target = [T]; + #[inline] + fn deref(&self) -> &Self::Target { + self.as_slice() + } +} + +impl DerefMut for ArrayVec { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + self.as_mut_slice() + } +} + + +/// Create an `ArrayVec` from an array. +/// +/// ``` +/// use arrayvec::ArrayVec; +/// +/// let mut array = ArrayVec::from([1, 2, 3]); +/// assert_eq!(array.len(), 3); +/// assert_eq!(array.capacity(), 3); +/// ``` +impl From<[T; CAP]> for ArrayVec { + #[track_caller] + fn from(array: [T; CAP]) -> Self { + let array = ManuallyDrop::new(array); + let mut vec = >::new(); + unsafe { + (&*array as *const [T; CAP] as *const [MaybeUninit; CAP]) + .copy_to_nonoverlapping(&mut vec.xs as *mut [MaybeUninit; CAP], 1); + vec.set_len(CAP); + } + vec + } +} + + +/// Try to create an `ArrayVec` from a slice. This will return an error if the slice was too big to +/// fit. +/// +/// ``` +/// use arrayvec::ArrayVec; +/// use std::convert::TryInto as _; +/// +/// let array: ArrayVec<_, 4> = (&[1, 2, 3] as &[_]).try_into().unwrap(); +/// assert_eq!(array.len(), 3); +/// assert_eq!(array.capacity(), 4); +/// ``` +impl std::convert::TryFrom<&[T]> for ArrayVec + where T: Clone, +{ + type Error = CapacityError; + + fn try_from(slice: &[T]) -> Result { + if Self::CAPACITY < slice.len() { + Err(CapacityError::new(())) + } else { + let mut array = Self::new(); + array.extend_from_slice(slice); + Ok(array) + } + } +} + + +/// Iterate the `ArrayVec` with references to each element. +/// +/// ``` +/// use arrayvec::ArrayVec; +/// +/// let array = ArrayVec::from([1, 2, 3]); +/// +/// for elt in &array { +/// // ... +/// } +/// ``` +impl<'a, T: 'a, const CAP: usize> IntoIterator for &'a ArrayVec { + type Item = &'a T; + type IntoIter = slice::Iter<'a, T>; + fn into_iter(self) -> Self::IntoIter { self.iter() } +} + +/// Iterate the `ArrayVec` with mutable references to each element. +/// +/// ``` +/// use arrayvec::ArrayVec; +/// +/// let mut array = ArrayVec::from([1, 2, 3]); +/// +/// for elt in &mut array { +/// // ... +/// } +/// ``` +impl<'a, T: 'a, const CAP: usize> IntoIterator for &'a mut ArrayVec { + type Item = &'a mut T; + type IntoIter = slice::IterMut<'a, T>; + fn into_iter(self) -> Self::IntoIter { self.iter_mut() } +} + +/// Iterate the `ArrayVec` with each element by value. +/// +/// The vector is consumed by this operation. +/// +/// ``` +/// use arrayvec::ArrayVec; +/// +/// for elt in ArrayVec::from([1, 2, 3]) { +/// // ... +/// } +/// ``` +impl IntoIterator for ArrayVec { + type Item = T; + type IntoIter = IntoIter; + fn into_iter(self) -> IntoIter { + IntoIter { index: 0, v: self, } + } +} + + +#[cfg(feature = "zeroize")] +/// "Best efforts" zeroing of the `ArrayVec`'s buffer when the `zeroize` feature is enabled. +/// +/// The length is set to 0, and the buffer is dropped and zeroized. +/// Cannot ensure that previous moves of the `ArrayVec` did not leave values on the stack. +/// +/// ``` +/// use arrayvec::ArrayVec; +/// use zeroize::Zeroize; +/// let mut array = ArrayVec::from([1, 2, 3]); +/// array.zeroize(); +/// assert_eq!(array.len(), 0); +/// let data = unsafe { core::slice::from_raw_parts(array.as_ptr(), array.capacity()) }; +/// assert_eq!(data, [0, 0, 0]); +/// ``` +impl zeroize::Zeroize for ArrayVec { + fn zeroize(&mut self) { + // Zeroize all the contained elements. + self.iter_mut().zeroize(); + // Drop all the elements and set the length to 0. + self.clear(); + // Zeroize the backing array. + self.xs.zeroize(); + } +} + +/// By-value iterator for `ArrayVec`. +pub struct IntoIter { + index: usize, + v: ArrayVec, +} + +impl Iterator for IntoIter { + type Item = T; + + fn next(&mut self) -> Option { + if self.index == self.v.len() { + None + } else { + unsafe { + let index = self.index; + self.index = index + 1; + Some(ptr::read(self.v.get_unchecked_ptr(index))) + } + } + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.v.len() - self.index; + (len, Some(len)) + } +} + +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option { + if self.index == self.v.len() { + None + } else { + unsafe { + let new_len = self.v.len() - 1; + self.v.set_len(new_len); + Some(ptr::read(self.v.get_unchecked_ptr(new_len))) + } + } + } +} + +impl ExactSizeIterator for IntoIter { } + +impl Drop for IntoIter { + fn drop(&mut self) { + // panic safety: Set length to 0 before dropping elements. + let index = self.index; + let len = self.v.len(); + unsafe { + self.v.set_len(0); + let elements = slice::from_raw_parts_mut( + self.v.get_unchecked_ptr(index), + len - index); + ptr::drop_in_place(elements); + } + } +} + +impl Clone for IntoIter +where T: Clone, +{ + fn clone(&self) -> IntoIter { + let mut v = ArrayVec::new(); + v.extend_from_slice(&self.v[self.index..]); + v.into_iter() + } +} + +impl fmt::Debug for IntoIter +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list() + .entries(&self.v[self.index..]) + .finish() + } +} + +/// A draining iterator for `ArrayVec`. +pub struct Drain<'a, T: 'a, const CAP: usize> { + /// Index of tail to preserve + tail_start: usize, + /// Length of tail + tail_len: usize, + /// Current remaining range to remove + iter: slice::Iter<'a, T>, + vec: *mut ArrayVec, +} + +unsafe impl<'a, T: Sync, const CAP: usize> Sync for Drain<'a, T, CAP> {} +unsafe impl<'a, T: Send, const CAP: usize> Send for Drain<'a, T, CAP> {} + +impl<'a, T: 'a, const CAP: usize> Iterator for Drain<'a, T, CAP> { + type Item = T; + + fn next(&mut self) -> Option { + self.iter.next().map(|elt| + unsafe { + ptr::read(elt as *const _) + } + ) + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a, T: 'a, const CAP: usize> DoubleEndedIterator for Drain<'a, T, CAP> +{ + fn next_back(&mut self) -> Option { + self.iter.next_back().map(|elt| + unsafe { + ptr::read(elt as *const _) + } + ) + } +} + +impl<'a, T: 'a, const CAP: usize> ExactSizeIterator for Drain<'a, T, CAP> {} + +impl<'a, T: 'a, const CAP: usize> Drop for Drain<'a, T, CAP> { + fn drop(&mut self) { + // len is currently 0 so panicking while dropping will not cause a double drop. + + // exhaust self first + while let Some(_) = self.next() { } + + if self.tail_len > 0 { + unsafe { + let source_vec = &mut *self.vec; + // memmove back untouched tail, update to new length + let start = source_vec.len(); + let tail = self.tail_start; + let ptr = source_vec.as_mut_ptr(); + ptr::copy(ptr.add(tail), ptr.add(start), self.tail_len); + source_vec.set_len(start + self.tail_len); + } + } + } +} + +struct ScopeExitGuard + where F: FnMut(&Data, &mut T) +{ + value: T, + data: Data, + f: F, +} + +impl Drop for ScopeExitGuard + where F: FnMut(&Data, &mut T) +{ + fn drop(&mut self) { + (self.f)(&self.data, &mut self.value) + } +} + + + +/// Extend the `ArrayVec` with an iterator. +/// +/// ***Panics*** if extending the vector exceeds its capacity. +impl Extend for ArrayVec { + /// Extend the `ArrayVec` with an iterator. + /// + /// ***Panics*** if extending the vector exceeds its capacity. + #[track_caller] + fn extend>(&mut self, iter: I) { + unsafe { + self.extend_from_iter::<_, true>(iter) + } + } +} + +#[inline(never)] +#[cold] +#[track_caller] +fn extend_panic() { + panic!("ArrayVec: capacity exceeded in extend/from_iter"); +} + +impl ArrayVec { + /// Extend the arrayvec from the iterable. + /// + /// ## Safety + /// + /// Unsafe because if CHECK is false, the length of the input is not checked. + /// The caller must ensure the length of the input fits in the capacity. + #[track_caller] + pub(crate) unsafe fn extend_from_iter(&mut self, iterable: I) + where I: IntoIterator + { + let take = self.capacity() - self.len(); + let len = self.len(); + let mut ptr = raw_ptr_add(self.as_mut_ptr(), len); + let end_ptr = raw_ptr_add(ptr, take); + // Keep the length in a separate variable, write it back on scope + // exit. To help the compiler with alias analysis and stuff. + // We update the length to handle panic in the iteration of the + // user's iterator, without dropping any elements on the floor. + let mut guard = ScopeExitGuard { + value: &mut self.len, + data: len, + f: move |&len, self_len| { + **self_len = len as LenUint; + } + }; + let mut iter = iterable.into_iter(); + loop { + if let Some(elt) = iter.next() { + if ptr == end_ptr && CHECK { extend_panic(); } + debug_assert_ne!(ptr, end_ptr); + ptr.write(elt); + ptr = raw_ptr_add(ptr, 1); + guard.data += 1; + } else { + return; // success + } + } + } + + /// Extend the ArrayVec with clones of elements from the slice; + /// the length of the slice must be <= the remaining capacity in the arrayvec. + pub(crate) fn extend_from_slice(&mut self, slice: &[T]) + where T: Clone + { + let take = self.capacity() - self.len(); + debug_assert!(slice.len() <= take); + unsafe { + let slice = if take < slice.len() { &slice[..take] } else { slice }; + self.extend_from_iter::<_, false>(slice.iter().cloned()); + } + } +} + +/// Rawptr add but uses arithmetic distance for ZST +unsafe fn raw_ptr_add(ptr: *mut T, offset: usize) -> *mut T { + if mem::size_of::() == 0 { + // Special case for ZST + ptr.cast::().wrapping_add(offset).cast() + } else { + ptr.add(offset) + } +} + +/// Create an `ArrayVec` from an iterator. +/// +/// ***Panics*** if the number of elements in the iterator exceeds the arrayvec's capacity. +impl iter::FromIterator for ArrayVec { + /// Create an `ArrayVec` from an iterator. + /// + /// ***Panics*** if the number of elements in the iterator exceeds the arrayvec's capacity. + fn from_iter>(iter: I) -> Self { + let mut array = ArrayVec::new(); + array.extend(iter); + array + } +} + +impl Clone for ArrayVec + where T: Clone +{ + fn clone(&self) -> Self { + self.iter().cloned().collect() + } + + fn clone_from(&mut self, rhs: &Self) { + // recursive case for the common prefix + let prefix = cmp::min(self.len(), rhs.len()); + self[..prefix].clone_from_slice(&rhs[..prefix]); + + if prefix < self.len() { + // rhs was shorter + self.truncate(prefix); + } else { + let rhs_elems = &rhs[self.len()..]; + self.extend_from_slice(rhs_elems); + } + } +} + +impl Hash for ArrayVec + where T: Hash +{ + fn hash(&self, state: &mut H) { + Hash::hash(&**self, state) + } +} + +impl PartialEq for ArrayVec + where T: PartialEq +{ + fn eq(&self, other: &Self) -> bool { + **self == **other + } +} + +impl PartialEq<[T]> for ArrayVec + where T: PartialEq +{ + fn eq(&self, other: &[T]) -> bool { + **self == *other + } +} + +impl Eq for ArrayVec where T: Eq { } + +impl Borrow<[T]> for ArrayVec { + fn borrow(&self) -> &[T] { self } +} + +impl BorrowMut<[T]> for ArrayVec { + fn borrow_mut(&mut self) -> &mut [T] { self } +} + +impl AsRef<[T]> for ArrayVec { + fn as_ref(&self) -> &[T] { self } +} + +impl AsMut<[T]> for ArrayVec { + fn as_mut(&mut self) -> &mut [T] { self } +} + +impl fmt::Debug for ArrayVec where T: fmt::Debug { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) } +} + +impl Default for ArrayVec { + /// Return an empty array + fn default() -> ArrayVec { + ArrayVec::new() + } +} + +impl PartialOrd for ArrayVec where T: PartialOrd { + fn partial_cmp(&self, other: &Self) -> Option { + (**self).partial_cmp(other) + } + + fn lt(&self, other: &Self) -> bool { + (**self).lt(other) + } + + fn le(&self, other: &Self) -> bool { + (**self).le(other) + } + + fn ge(&self, other: &Self) -> bool { + (**self).ge(other) + } + + fn gt(&self, other: &Self) -> bool { + (**self).gt(other) + } +} + +impl Ord for ArrayVec where T: Ord { + fn cmp(&self, other: &Self) -> cmp::Ordering { + (**self).cmp(other) + } +} + +#[cfg(feature="std")] +/// `Write` appends written data to the end of the vector. +/// +/// Requires `features="std"`. +impl io::Write for ArrayVec { + fn write(&mut self, data: &[u8]) -> io::Result { + let len = cmp::min(self.remaining_capacity(), data.len()); + let _result = self.try_extend_from_slice(&data[..len]); + debug_assert!(_result.is_ok()); + Ok(len) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} + +#[cfg(feature="serde")] +/// Requires crate feature `"serde"` +impl Serialize for ArrayVec { + fn serialize(&self, serializer: S) -> Result + where S: Serializer + { + serializer.collect_seq(self) + } +} + +#[cfg(feature="serde")] +/// Requires crate feature `"serde"` +impl<'de, T: Deserialize<'de>, const CAP: usize> Deserialize<'de> for ArrayVec { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> + { + use serde::de::{Visitor, SeqAccess, Error}; + use std::marker::PhantomData; + + struct ArrayVecVisitor<'de, T: Deserialize<'de>, const CAP: usize>(PhantomData<(&'de (), [T; CAP])>); + + impl<'de, T: Deserialize<'de>, const CAP: usize> Visitor<'de> for ArrayVecVisitor<'de, T, CAP> { + type Value = ArrayVec; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "an array with no more than {} items", CAP) + } + + fn visit_seq(self, mut seq: SA) -> Result + where SA: SeqAccess<'de>, + { + let mut values = ArrayVec::::new(); + + while let Some(value) = seq.next_element()? { + if let Err(_) = values.try_push(value) { + return Err(SA::Error::invalid_length(CAP + 1, &self)); + } + } + + Ok(values) + } + } + + deserializer.deserialize_seq(ArrayVecVisitor::(PhantomData)) + } +} diff --git a/src/arrayvec_impl.rs b/src/arrayvec_impl.rs new file mode 100644 index 0000000..c5ebe7b --- /dev/null +++ b/src/arrayvec_impl.rs @@ -0,0 +1,87 @@ +use std::ptr; +use std::slice; + +use crate::CapacityError; + +/// Implements basic arrayvec methods - based on a few required methods +/// for length and element access. +pub(crate) trait ArrayVecImpl { + type Item; + const CAPACITY: usize; + + fn len(&self) -> usize; + + unsafe fn set_len(&mut self, new_len: usize); + + /// Return a slice containing all elements of the vector. + fn as_slice(&self) -> &[Self::Item] { + let len = self.len(); + unsafe { + slice::from_raw_parts(self.as_ptr(), len) + } + } + + /// Return a mutable slice containing all elements of the vector. + fn as_mut_slice(&mut self) -> &mut [Self::Item] { + let len = self.len(); + unsafe { + std::slice::from_raw_parts_mut(self.as_mut_ptr(), len) + } + } + + /// Return a raw pointer to the vector's buffer. + fn as_ptr(&self) -> *const Self::Item; + + /// Return a raw mutable pointer to the vector's buffer. + fn as_mut_ptr(&mut self) -> *mut Self::Item; + + #[track_caller] + fn push(&mut self, element: Self::Item) { + self.try_push(element).unwrap() + } + + fn try_push(&mut self, element: Self::Item) -> Result<(), CapacityError> { + if self.len() < Self::CAPACITY { + unsafe { + self.push_unchecked(element); + } + Ok(()) + } else { + Err(CapacityError::new(element)) + } + } + + unsafe fn push_unchecked(&mut self, element: Self::Item) { + let len = self.len(); + debug_assert!(len < Self::CAPACITY); + ptr::write(self.as_mut_ptr().add(len), element); + self.set_len(len + 1); + } + + fn pop(&mut self) -> Option { + if self.len() == 0 { + return None; + } + unsafe { + let new_len = self.len() - 1; + self.set_len(new_len); + Some(ptr::read(self.as_ptr().add(new_len))) + } + } + + fn clear(&mut self) { + self.truncate(0) + } + + fn truncate(&mut self, new_len: usize) { + unsafe { + let len = self.len(); + if new_len < len { + self.set_len(new_len); + let tail = slice::from_raw_parts_mut(self.as_mut_ptr().add(new_len), len - new_len); + ptr::drop_in_place(tail); + } + } + } +} + diff --git a/src/char.rs b/src/char.rs new file mode 100644 index 0000000..939b6b4 --- /dev/null +++ b/src/char.rs @@ -0,0 +1,92 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// Original authors: alexchrichton, bluss + +// UTF-8 ranges and tags for encoding characters +const TAG_CONT: u8 = 0b1000_0000; +const TAG_TWO_B: u8 = 0b1100_0000; +const TAG_THREE_B: u8 = 0b1110_0000; +const TAG_FOUR_B: u8 = 0b1111_0000; +const MAX_ONE_B: u32 = 0x80; +const MAX_TWO_B: u32 = 0x800; +const MAX_THREE_B: u32 = 0x10000; + +/// Placeholder +pub struct EncodeUtf8Error; + +/// Encode a char into buf using UTF-8. +/// +/// On success, return the byte length of the encoding (1, 2, 3 or 4).
+/// On error, return `EncodeUtf8Error` if the buffer was too short for the char. +/// +/// Safety: `ptr` must be writable for `len` bytes. +#[inline] +pub unsafe fn encode_utf8(ch: char, ptr: *mut u8, len: usize) -> Result +{ + let code = ch as u32; + if code < MAX_ONE_B && len >= 1 { + ptr.add(0).write(code as u8); + return Ok(1); + } else if code < MAX_TWO_B && len >= 2 { + ptr.add(0).write((code >> 6 & 0x1F) as u8 | TAG_TWO_B); + ptr.add(1).write((code & 0x3F) as u8 | TAG_CONT); + return Ok(2); + } else if code < MAX_THREE_B && len >= 3 { + ptr.add(0).write((code >> 12 & 0x0F) as u8 | TAG_THREE_B); + ptr.add(1).write((code >> 6 & 0x3F) as u8 | TAG_CONT); + ptr.add(2).write((code & 0x3F) as u8 | TAG_CONT); + return Ok(3); + } else if len >= 4 { + ptr.add(0).write((code >> 18 & 0x07) as u8 | TAG_FOUR_B); + ptr.add(1).write((code >> 12 & 0x3F) as u8 | TAG_CONT); + ptr.add(2).write((code >> 6 & 0x3F) as u8 | TAG_CONT); + ptr.add(3).write((code & 0x3F) as u8 | TAG_CONT); + return Ok(4); + }; + Err(EncodeUtf8Error) +} + + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn test_encode_utf8() { + // Test that all codepoints are encoded correctly + let mut data = [0u8; 16]; + for codepoint in 0..=(std::char::MAX as u32) { + if let Some(ch) = std::char::from_u32(codepoint) { + for elt in &mut data { *elt = 0; } + let ptr = data.as_mut_ptr(); + let len = data.len(); + unsafe { + let res = encode_utf8(ch, ptr, len).ok().unwrap(); + assert_eq!(res, ch.len_utf8()); + } + let string = std::str::from_utf8(&data).unwrap(); + assert_eq!(string.chars().next(), Some(ch)); + } + } +} + +#[test] +fn test_encode_utf8_oob() { + // test that we report oob if the buffer is too short + let mut data = [0u8; 16]; + let chars = ['a', 'Ī±', 'ļæ½', 'šˆ']; + for (len, &ch) in (1..=4).zip(&chars) { + assert_eq!(len, ch.len_utf8(), "Len of ch={}", ch); + let ptr = data.as_mut_ptr(); + unsafe { + assert!(matches::matches!(encode_utf8(ch, ptr, len - 1), Err(_))); + assert!(matches::matches!(encode_utf8(ch, ptr, len), Ok(_))); + } + } +} + diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..7ca3ebc --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,49 @@ +use std::fmt; +#[cfg(feature="std")] +use std::any::Any; +#[cfg(feature="std")] +use std::error::Error; + +/// Error value indicating insufficient capacity +#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] +pub struct CapacityError { + element: T, +} + +impl CapacityError { + /// Create a new `CapacityError` from `element`. + pub const fn new(element: T) -> CapacityError { + CapacityError { + element: element, + } + } + + /// Extract the overflowing element + pub fn element(self) -> T { + self.element + } + + /// Convert into a `CapacityError` that does not carry an element. + pub fn simplify(self) -> CapacityError { + CapacityError { element: () } + } +} + +const CAPERROR: &'static str = "insufficient capacity"; + +#[cfg(feature="std")] +/// Requires `features="std"`. +impl Error for CapacityError {} + +impl fmt::Display for CapacityError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", CAPERROR) + } +} + +impl fmt::Debug for CapacityError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}: {}", "CapacityError", CAPERROR) + } +} + diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..f9a2fe6 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,63 @@ +//! **arrayvec** provides the types [`ArrayVec`] and [`ArrayString`]: +//! array-backed vector and string types, which store their contents inline. +//! +//! The arrayvec package has the following cargo features: +//! +//! - `std` +//! - Optional, enabled by default +//! - Use libstd; disable to use `no_std` instead. +//! +//! - `serde` +//! - Optional +//! - Enable serialization for ArrayVec and ArrayString using serde 1.x +//! +//! - `zeroize` +//! - Optional +//! - Implement `Zeroize` for ArrayVec and ArrayString +//! +//! ## Rust Version +//! +//! This version of arrayvec requires Rust 1.51 or later. +//! +#![doc(html_root_url="https://docs.rs/arrayvec/0.7/")] +#![cfg_attr(not(feature="std"), no_std)] + +#[cfg(feature="serde")] +extern crate serde; + +#[cfg(not(feature="std"))] +extern crate core as std; + +pub(crate) type LenUint = u32; + +macro_rules! assert_capacity_limit { + ($cap:expr) => { + if std::mem::size_of::() > std::mem::size_of::() { + if $cap > LenUint::MAX as usize { + panic!("ArrayVec: largest supported capacity is u32::MAX") + } + } + } +} + +macro_rules! assert_capacity_limit_const { + ($cap:expr) => { + if std::mem::size_of::() > std::mem::size_of::() { + if $cap > LenUint::MAX as usize { + [/*ArrayVec: largest supported capacity is u32::MAX*/][$cap] + } + } + } +} + +mod arrayvec_impl; +mod arrayvec; +mod array_string; +mod char; +mod errors; +mod utils; + +pub use crate::array_string::ArrayString; +pub use crate::errors::CapacityError; + +pub use crate::arrayvec::{ArrayVec, IntoIter, Drain}; diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..b8e5ddb --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,11 @@ +use std::marker::PhantomData; +use std::mem::MaybeUninit; + +pub(crate) struct MakeMaybeUninit(PhantomData T>); + +impl MakeMaybeUninit { + pub(crate) const VALUE: MaybeUninit = MaybeUninit::uninit(); + + pub(crate) const ARRAY: [MaybeUninit; N] = [Self::VALUE; N]; +} + diff --git a/tests/serde.rs b/tests/serde.rs new file mode 100644 index 0000000..f02c693 --- /dev/null +++ b/tests/serde.rs @@ -0,0 +1,79 @@ +#![cfg(feature = "serde")] +extern crate arrayvec; +extern crate serde_test; + +mod array_vec { + use arrayvec::ArrayVec; + + use serde_test::{Token, assert_tokens, assert_de_tokens_error}; + + #[test] + fn test_ser_de_empty() { + let vec = ArrayVec::::new(); + + assert_tokens(&vec, &[ + Token::Seq { len: Some(0) }, + Token::SeqEnd, + ]); + } + + + #[test] + fn test_ser_de() { + let mut vec = ArrayVec::::new(); + vec.push(20); + vec.push(55); + vec.push(123); + + assert_tokens(&vec, &[ + Token::Seq { len: Some(3) }, + Token::U32(20), + Token::U32(55), + Token::U32(123), + Token::SeqEnd, + ]); + } + + #[test] + fn test_de_too_large() { + assert_de_tokens_error::>(&[ + Token::Seq { len: Some(3) }, + Token::U32(13), + Token::U32(42), + Token::U32(68), + ], "invalid length 3, expected an array with no more than 2 items"); + } +} + +mod array_string { + use arrayvec::ArrayString; + + use serde_test::{Token, assert_tokens, assert_de_tokens_error}; + + #[test] + fn test_ser_de_empty() { + let string = ArrayString::<0>::new(); + + assert_tokens(&string, &[ + Token::Str(""), + ]); + } + + + #[test] + fn test_ser_de() { + let string = ArrayString::<9>::from("1234 abcd") + .expect("expected exact specified capacity to be enough"); + + assert_tokens(&string, &[ + Token::Str("1234 abcd"), + ]); + } + + #[test] + fn test_de_too_large() { + assert_de_tokens_error::>(&[ + Token::Str("afd") + ], "invalid length 3, expected a string no more than 2 bytes long"); + } +} diff --git a/tests/tests.rs b/tests/tests.rs new file mode 100644 index 0000000..2f8a5ef --- /dev/null +++ b/tests/tests.rs @@ -0,0 +1,793 @@ +extern crate arrayvec; +#[macro_use] extern crate matches; + +use arrayvec::ArrayVec; +use arrayvec::ArrayString; +use std::mem; +use arrayvec::CapacityError; + +use std::collections::HashMap; + + +#[test] +fn test_simple() { + use std::ops::Add; + + let mut vec: ArrayVec, 3> = ArrayVec::new(); + + vec.push(vec![1, 2, 3, 4]); + vec.push(vec![10]); + vec.push(vec![-1, 13, -2]); + + for elt in &vec { + assert_eq!(elt.iter().fold(0, Add::add), 10); + } + + let sum_len = vec.into_iter().map(|x| x.len()).fold(0, Add::add); + assert_eq!(sum_len, 8); +} + +#[test] +fn test_capacity_left() { + let mut vec: ArrayVec = ArrayVec::new(); + assert_eq!(vec.remaining_capacity(), 4); + vec.push(1); + assert_eq!(vec.remaining_capacity(), 3); + vec.push(2); + assert_eq!(vec.remaining_capacity(), 2); + vec.push(3); + assert_eq!(vec.remaining_capacity(), 1); + vec.push(4); + assert_eq!(vec.remaining_capacity(), 0); +} + +#[test] +fn test_extend_from_slice() { + let mut vec: ArrayVec = ArrayVec::new(); + + vec.try_extend_from_slice(&[1, 2, 3]).unwrap(); + assert_eq!(vec.len(), 3); + assert_eq!(&vec[..], &[1, 2, 3]); + assert_eq!(vec.pop(), Some(3)); + assert_eq!(&vec[..], &[1, 2]); +} + +#[test] +fn test_extend_from_slice_error() { + let mut vec: ArrayVec = ArrayVec::new(); + + vec.try_extend_from_slice(&[1, 2, 3]).unwrap(); + let res = vec.try_extend_from_slice(&[0; 8]); + assert_matches!(res, Err(_)); + + let mut vec: ArrayVec = ArrayVec::new(); + let res = vec.try_extend_from_slice(&[0; 1]); + assert_matches!(res, Err(_)); +} + +#[test] +fn test_try_from_slice_error() { + use arrayvec::ArrayVec; + use std::convert::TryInto as _; + + let res: Result, _> = (&[1, 2, 3] as &[_]).try_into(); + assert_matches!(res, Err(_)); +} + +#[test] +fn test_u16_index() { + const N: usize = 4096; + let mut vec: ArrayVec<_, N> = ArrayVec::new(); + for _ in 0..N { + assert!(vec.try_push(1u8).is_ok()); + } + assert!(vec.try_push(0).is_err()); + assert_eq!(vec.len(), N); +} + +#[test] +fn test_iter() { + let mut iter = ArrayVec::from([1, 2, 3]).into_iter(); + assert_eq!(iter.size_hint(), (3, Some(3))); + assert_eq!(iter.next_back(), Some(3)); + assert_eq!(iter.next(), Some(1)); + assert_eq!(iter.next_back(), Some(2)); + assert_eq!(iter.size_hint(), (0, Some(0))); + assert_eq!(iter.next_back(), None); +} + +#[test] +fn test_drop() { + use std::cell::Cell; + + let flag = &Cell::new(0); + + #[derive(Clone)] + struct Bump<'a>(&'a Cell); + + impl<'a> Drop for Bump<'a> { + fn drop(&mut self) { + let n = self.0.get(); + self.0.set(n + 1); + } + } + + { + let mut array = ArrayVec::::new(); + array.push(Bump(flag)); + array.push(Bump(flag)); + } + assert_eq!(flag.get(), 2); + + // test something with the nullable pointer optimization + flag.set(0); + + { + let mut array = ArrayVec::<_, 3>::new(); + array.push(vec![Bump(flag)]); + array.push(vec![Bump(flag), Bump(flag)]); + array.push(vec![]); + let push4 = array.try_push(vec![Bump(flag)]); + assert_eq!(flag.get(), 0); + drop(push4); + assert_eq!(flag.get(), 1); + drop(array.pop()); + assert_eq!(flag.get(), 1); + drop(array.pop()); + assert_eq!(flag.get(), 3); + } + + assert_eq!(flag.get(), 4); + + // test into_inner + flag.set(0); + { + let mut array = ArrayVec::<_, 3>::new(); + array.push(Bump(flag)); + array.push(Bump(flag)); + array.push(Bump(flag)); + let inner = array.into_inner(); + assert!(inner.is_ok()); + assert_eq!(flag.get(), 0); + drop(inner); + assert_eq!(flag.get(), 3); + } + + // test take + flag.set(0); + { + let mut array1 = ArrayVec::<_, 3>::new(); + array1.push(Bump(flag)); + array1.push(Bump(flag)); + array1.push(Bump(flag)); + let array2 = array1.take(); + assert_eq!(flag.get(), 0); + drop(array1); + assert_eq!(flag.get(), 0); + drop(array2); + assert_eq!(flag.get(), 3); + } + + // test cloning into_iter + flag.set(0); + { + let mut array = ArrayVec::<_, 3>::new(); + array.push(Bump(flag)); + array.push(Bump(flag)); + array.push(Bump(flag)); + let mut iter = array.into_iter(); + assert_eq!(flag.get(), 0); + iter.next(); + assert_eq!(flag.get(), 1); + let clone = iter.clone(); + assert_eq!(flag.get(), 1); + drop(clone); + assert_eq!(flag.get(), 3); + drop(iter); + assert_eq!(flag.get(), 5); + } +} + +#[test] +fn test_drop_panics() { + use std::cell::Cell; + use std::panic::catch_unwind; + use std::panic::AssertUnwindSafe; + + let flag = &Cell::new(0); + + struct Bump<'a>(&'a Cell); + + // Panic in the first drop + impl<'a> Drop for Bump<'a> { + fn drop(&mut self) { + let n = self.0.get(); + self.0.set(n + 1); + if n == 0 { + panic!("Panic in Bump's drop"); + } + } + } + // check if rust is new enough + flag.set(0); + { + let array = vec![Bump(flag), Bump(flag)]; + let res = catch_unwind(AssertUnwindSafe(|| { + drop(array); + })); + assert!(res.is_err()); + } + + if flag.get() != 2 { + println!("test_drop_panics: skip, this version of Rust doesn't continue in drop_in_place"); + return; + } + + flag.set(0); + { + let mut array = ArrayVec::::new(); + array.push(Bump(flag)); + array.push(Bump(flag)); + array.push(Bump(flag)); + + let res = catch_unwind(AssertUnwindSafe(|| { + drop(array); + })); + assert!(res.is_err()); + } + // Check that all the elements drop, even if the first drop panics. + assert_eq!(flag.get(), 3); + + + flag.set(0); + { + let mut array = ArrayVec::::new(); + array.push(Bump(flag)); + array.push(Bump(flag)); + array.push(Bump(flag)); + array.push(Bump(flag)); + array.push(Bump(flag)); + + let i = 2; + let tail_len = array.len() - i; + + let res = catch_unwind(AssertUnwindSafe(|| { + array.truncate(i); + })); + assert!(res.is_err()); + // Check that all the tail elements drop, even if the first drop panics. + assert_eq!(flag.get(), tail_len as i32); + } + + +} + +#[test] +fn test_extend() { + let mut range = 0..10; + + let mut array: ArrayVec<_, 5> = range.by_ref().take(5).collect(); + assert_eq!(&array[..], &[0, 1, 2, 3, 4]); + assert_eq!(range.next(), Some(5)); + + array.extend(range.by_ref().take(0)); + assert_eq!(range.next(), Some(6)); + + let mut array: ArrayVec<_, 10> = (0..3).collect(); + assert_eq!(&array[..], &[0, 1, 2]); + array.extend(3..5); + assert_eq!(&array[..], &[0, 1, 2, 3, 4]); +} + +#[should_panic] +#[test] +fn test_extend_capacity_panic_1() { + let mut range = 0..10; + + let _: ArrayVec<_, 5> = range.by_ref().collect(); +} + +#[should_panic] +#[test] +fn test_extend_capacity_panic_2() { + let mut range = 0..10; + + let mut array: ArrayVec<_, 5> = range.by_ref().take(5).collect(); + assert_eq!(&array[..], &[0, 1, 2, 3, 4]); + assert_eq!(range.next(), Some(5)); + array.extend(range.by_ref().take(1)); +} + +#[test] +fn test_is_send_sync() { + let data = ArrayVec::, 5>::new(); + &data as &dyn Send; + &data as &dyn Sync; +} + +#[test] +fn test_compact_size() { + // 4 bytes + padding + length + type ByteArray = ArrayVec; + println!("{}", mem::size_of::()); + assert!(mem::size_of::() <= 2 * mem::size_of::()); + + // just length + type EmptyArray = ArrayVec; + println!("{}", mem::size_of::()); + assert!(mem::size_of::() <= mem::size_of::()); + + // 3 elements + padding + length + type QuadArray = ArrayVec; + println!("{}", mem::size_of::()); + assert!(mem::size_of::() <= 4 * 4 + mem::size_of::()); +} + +#[test] +fn test_still_works_with_option_arrayvec() { + type RefArray = ArrayVec<&'static i32, 2>; + let array = Some(RefArray::new()); + assert!(array.is_some()); + println!("{:?}", array); +} + +#[test] +fn test_drain() { + let mut v = ArrayVec::from([0; 8]); + v.pop(); + v.drain(0..7); + assert_eq!(&v[..], &[]); + + v.extend(0..8); + v.drain(1..4); + assert_eq!(&v[..], &[0, 4, 5, 6, 7]); + let u: ArrayVec<_, 3> = v.drain(1..4).rev().collect(); + assert_eq!(&u[..], &[6, 5, 4]); + assert_eq!(&v[..], &[0, 7]); + v.drain(..); + assert_eq!(&v[..], &[]); +} + +#[test] +fn test_drain_range_inclusive() { + let mut v = ArrayVec::from([0; 8]); + v.drain(0..=7); + assert_eq!(&v[..], &[]); + + v.extend(0..8); + v.drain(1..=4); + assert_eq!(&v[..], &[0, 5, 6, 7]); + let u: ArrayVec<_, 3> = v.drain(1..=2).rev().collect(); + assert_eq!(&u[..], &[6, 5]); + assert_eq!(&v[..], &[0, 7]); + v.drain(..); + assert_eq!(&v[..], &[]); +} + +#[test] +#[should_panic] +fn test_drain_range_inclusive_oob() { + let mut v = ArrayVec::from([0; 0]); + v.drain(0..=0); +} + +#[test] +fn test_retain() { + let mut v = ArrayVec::from([0; 8]); + for (i, elt) in v.iter_mut().enumerate() { + *elt = i; + } + v.retain(|_| true); + assert_eq!(&v[..], &[0, 1, 2, 3, 4, 5, 6, 7]); + v.retain(|elt| { + *elt /= 2; + *elt % 2 == 0 + }); + assert_eq!(&v[..], &[0, 0, 2, 2]); + v.retain(|_| false); + assert_eq!(&v[..], &[]); +} + +#[test] +#[should_panic] +fn test_drain_oob() { + let mut v = ArrayVec::from([0; 8]); + v.pop(); + v.drain(0..8); +} + +#[test] +#[should_panic] +fn test_drop_panic() { + struct DropPanic; + + impl Drop for DropPanic { + fn drop(&mut self) { + panic!("drop"); + } + } + + let mut array = ArrayVec::::new(); + array.push(DropPanic); +} + +#[test] +#[should_panic] +fn test_drop_panic_into_iter() { + struct DropPanic; + + impl Drop for DropPanic { + fn drop(&mut self) { + panic!("drop"); + } + } + + let mut array = ArrayVec::::new(); + array.push(DropPanic); + array.into_iter(); +} + +#[test] +fn test_insert() { + let mut v = ArrayVec::from([]); + assert_matches!(v.try_push(1), Err(_)); + + let mut v = ArrayVec::<_, 3>::new(); + v.insert(0, 0); + v.insert(1, 1); + //let ret1 = v.try_insert(3, 3); + //assert_matches!(ret1, Err(InsertError::OutOfBounds(_))); + assert_eq!(&v[..], &[0, 1]); + v.insert(2, 2); + assert_eq!(&v[..], &[0, 1, 2]); + + let ret2 = v.try_insert(1, 9); + assert_eq!(&v[..], &[0, 1, 2]); + assert_matches!(ret2, Err(_)); + + let mut v = ArrayVec::from([2]); + assert_matches!(v.try_insert(0, 1), Err(CapacityError { .. })); + assert_matches!(v.try_insert(1, 1), Err(CapacityError { .. })); + //assert_matches!(v.try_insert(2, 1), Err(CapacityError { .. })); +} + +#[test] +fn test_into_inner_1() { + let mut v = ArrayVec::from([1, 2]); + v.pop(); + let u = v.clone(); + assert_eq!(v.into_inner(), Err(u)); +} + +#[test] +fn test_into_inner_2() { + let mut v = ArrayVec::::new(); + v.push("a".into()); + v.push("b".into()); + v.push("c".into()); + v.push("d".into()); + assert_eq!(v.into_inner().unwrap(), ["a", "b", "c", "d"]); +} + +#[test] +fn test_into_inner_3() { + let mut v = ArrayVec::::new(); + v.extend(1..=4); + assert_eq!(v.into_inner().unwrap(), [1, 2, 3, 4]); +} + +#[test] +fn test_take() { + let mut v1 = ArrayVec::::new(); + v1.extend(1..=4); + let v2 = v1.take(); + assert!(v1.into_inner().is_err()); + assert_eq!(v2.into_inner().unwrap(), [1, 2, 3, 4]); +} + +#[cfg(feature="std")] +#[test] +fn test_write() { + use std::io::Write; + let mut v = ArrayVec::<_, 8>::new(); + write!(&mut v, "\x01\x02\x03").unwrap(); + assert_eq!(&v[..], &[1, 2, 3]); + let r = v.write(&[9; 16]).unwrap(); + assert_eq!(r, 5); + assert_eq!(&v[..], &[1, 2, 3, 9, 9, 9, 9, 9]); +} + +#[test] +fn array_clone_from() { + let mut v = ArrayVec::<_, 4>::new(); + v.push(vec![1, 2]); + v.push(vec![3, 4, 5]); + v.push(vec![6]); + let reference = v.to_vec(); + let mut u = ArrayVec::<_, 4>::new(); + u.clone_from(&v); + assert_eq!(&u, &reference[..]); + + let mut t = ArrayVec::<_, 4>::new(); + t.push(vec![97]); + t.push(vec![]); + t.push(vec![5, 6, 2]); + t.push(vec![2]); + t.clone_from(&v); + assert_eq!(&t, &reference[..]); + t.clear(); + t.clone_from(&v); + assert_eq!(&t, &reference[..]); +} + +#[cfg(feature="std")] +#[test] +fn test_string() { + use std::error::Error; + + let text = "hello world"; + let mut s = ArrayString::<16>::new(); + s.try_push_str(text).unwrap(); + assert_eq!(&s, text); + assert_eq!(text, &s); + + // Make sure Hash / Eq / Borrow match up so we can use HashMap + let mut map = HashMap::new(); + map.insert(s, 1); + assert_eq!(map[text], 1); + + let mut t = ArrayString::<2>::new(); + assert!(t.try_push_str(text).is_err()); + assert_eq!(&t, ""); + + t.push_str("ab"); + // DerefMut + let tmut: &mut str = &mut t; + assert_eq!(tmut, "ab"); + + // Test Error trait / try + let t = || -> Result<(), Box> { + let mut t = ArrayString::<2>::new(); + t.try_push_str(text)?; + Ok(()) + }(); + assert!(t.is_err()); +} + +#[test] +fn test_string_from() { + let text = "hello world"; + // Test `from` constructor + let u = ArrayString::<11>::from(text).unwrap(); + assert_eq!(&u, text); + assert_eq!(u.len(), text.len()); +} + +#[test] +fn test_string_parse_from_str() { + let text = "hello world"; + let u: ArrayString<11> = text.parse().unwrap(); + assert_eq!(&u, text); + assert_eq!(u.len(), text.len()); +} + +#[test] +fn test_string_from_bytes() { + let text = "hello world"; + let u = ArrayString::from_byte_string(b"hello world").unwrap(); + assert_eq!(&u, text); + assert_eq!(u.len(), text.len()); +} + +#[test] +fn test_string_clone() { + let text = "hi"; + let mut s = ArrayString::<4>::new(); + s.push_str("abcd"); + let t = ArrayString::<4>::from(text).unwrap(); + s.clone_from(&t); + assert_eq!(&t, &s); +} + +#[test] +fn test_string_push() { + let text = "abcĪ±Ī²Ī³"; + let mut s = ArrayString::<8>::new(); + for c in text.chars() { + if let Err(_) = s.try_push(c) { + break; + } + } + assert_eq!("abcĪ±Ī²", &s[..]); + s.push('x'); + assert_eq!("abcĪ±Ī²x", &s[..]); + assert!(s.try_push('x').is_err()); +} + + +#[test] +fn test_insert_at_length() { + let mut v = ArrayVec::<_, 8>::new(); + let result1 = v.try_insert(0, "a"); + let result2 = v.try_insert(1, "b"); + assert!(result1.is_ok() && result2.is_ok()); + assert_eq!(&v[..], &["a", "b"]); +} + +#[should_panic] +#[test] +fn test_insert_out_of_bounds() { + let mut v = ArrayVec::<_, 8>::new(); + let _ = v.try_insert(1, "test"); +} + +/* + * insert that pushes out the last + let mut u = ArrayVec::from([1, 2, 3, 4]); + let ret = u.try_insert(3, 99); + assert_eq!(&u[..], &[1, 2, 3, 99]); + assert_matches!(ret, Err(_)); + let ret = u.try_insert(4, 77); + assert_eq!(&u[..], &[1, 2, 3, 99]); + assert_matches!(ret, Err(_)); +*/ + +#[test] +fn test_drop_in_insert() { + use std::cell::Cell; + + let flag = &Cell::new(0); + + struct Bump<'a>(&'a Cell); + + impl<'a> Drop for Bump<'a> { + fn drop(&mut self) { + let n = self.0.get(); + self.0.set(n + 1); + } + } + + flag.set(0); + + { + let mut array = ArrayVec::<_, 2>::new(); + array.push(Bump(flag)); + array.insert(0, Bump(flag)); + assert_eq!(flag.get(), 0); + let ret = array.try_insert(1, Bump(flag)); + assert_eq!(flag.get(), 0); + assert_matches!(ret, Err(_)); + drop(ret); + assert_eq!(flag.get(), 1); + } + assert_eq!(flag.get(), 3); +} + +#[test] +fn test_pop_at() { + let mut v = ArrayVec::::new(); + let s = String::from; + v.push(s("a")); + v.push(s("b")); + v.push(s("c")); + v.push(s("d")); + + assert_eq!(v.pop_at(4), None); + assert_eq!(v.pop_at(1), Some(s("b"))); + assert_eq!(v.pop_at(1), Some(s("c"))); + assert_eq!(v.pop_at(2), None); + assert_eq!(&v[..], &["a", "d"]); +} + +#[test] +fn test_sizes() { + let v = ArrayVec::from([0u8; 1 << 16]); + assert_eq!(vec![0u8; v.len()], &v[..]); +} + +#[test] +fn test_default() { + use std::net; + let s: ArrayString<4> = Default::default(); + // Something without `Default` implementation. + let v: ArrayVec = Default::default(); + assert_eq!(s.len(), 0); + assert_eq!(v.len(), 0); +} + +#[cfg(feature="array-sizes-33-128")] +#[test] +fn test_sizes_33_128() { + ArrayVec::from([0u8; 52]); + ArrayVec::from([0u8; 127]); +} + +#[cfg(feature="array-sizes-129-255")] +#[test] +fn test_sizes_129_255() { + ArrayVec::from([0u8; 237]); + ArrayVec::from([0u8; 255]); +} + +#[test] +fn test_extend_zst() { + let mut range = 0..10; + #[derive(Copy, Clone, PartialEq, Debug)] + struct Z; // Zero sized type + + let mut array: ArrayVec<_, 5> = range.by_ref().take(5).map(|_| Z).collect(); + assert_eq!(&array[..], &[Z; 5]); + assert_eq!(range.next(), Some(5)); + + array.extend(range.by_ref().take(0).map(|_| Z)); + assert_eq!(range.next(), Some(6)); + + let mut array: ArrayVec<_, 10> = (0..3).map(|_| Z).collect(); + assert_eq!(&array[..], &[Z; 3]); + array.extend((3..5).map(|_| Z)); + assert_eq!(&array[..], &[Z; 5]); + assert_eq!(array.len(), 5); +} + +#[test] +fn test_try_from_argument() { + use core::convert::TryFrom; + let v = ArrayString::<16>::try_from(format_args!("Hello {}", 123)).unwrap(); + assert_eq!(&v, "Hello 123"); +} + +#[test] +fn allow_max_capacity_arrayvec_type() { + // this type is allowed to be used (but can't be constructed) + let _v: ArrayVec<(), {usize::MAX}>; +} + +#[should_panic(expected="largest supported capacity")] +#[test] +fn deny_max_capacity_arrayvec_value() { + if mem::size_of::() <= mem::size_of::() { + panic!("This test does not work on this platform. 'largest supported capacity'"); + } + // this type is allowed to be used (but can't be constructed) + let _v: ArrayVec<(), {usize::MAX}> = ArrayVec::new(); +} + +#[should_panic(expected="index out of bounds")] +#[test] +fn deny_max_capacity_arrayvec_value_const() { + if mem::size_of::() <= mem::size_of::() { + panic!("This test does not work on this platform. 'index out of bounds'"); + } + // this type is allowed to be used (but can't be constructed) + let _v: ArrayVec<(), {usize::MAX}> = ArrayVec::new_const(); +} + +#[test] +fn test_arrayvec_const_constructible() { + const OF_U8: ArrayVec, 10> = ArrayVec::new_const(); + + let mut var = OF_U8; + assert!(var.is_empty()); + assert_eq!(var, ArrayVec::new()); + var.push(vec![3, 5, 8]); + assert_eq!(var[..], [vec![3, 5, 8]]); +} + +#[test] +fn test_arraystring_const_constructible() { + const AS: ArrayString<10> = ArrayString::new_const(); + + let mut var = AS; + assert!(var.is_empty()); + assert_eq!(var, ArrayString::new()); + var.push_str("hello"); + assert_eq!(var, *"hello"); +} + + +#[test] +fn test_arraystring_zero_filled_has_some_sanity_checks() { + let string = ArrayString::<4>::zero_filled(); + assert_eq!(string.as_str(), "\0\0\0\0"); + assert_eq!(string.len(), 4); +} \ No newline at end of file -- cgit v1.2.3