├── .github └── workflows │ ├── build.yml │ └── coverage.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── MIGRATION.md ├── README.md ├── check.sh ├── deny.toml ├── doc.sh ├── fmt.sh ├── rustfmt.toml ├── src ├── iter.rs ├── lib.rs ├── macros.rs ├── range.rs ├── slice │ ├── boxed.rs │ ├── concat.rs │ ├── join.rs │ ├── mod.rs │ └── slice_index.rs ├── test_util.rs └── vec.rs └── tests ├── no-alloc-and-no-std ├── Cargo.toml └── src │ └── main.rs ├── readme.rs └── version.rs /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | 9 | defaults: 10 | run: 11 | shell: bash 12 | 13 | env: 14 | CARGO_TERM_COLOR: always 15 | 16 | jobs: 17 | cargo-fmt: 18 | name: Check formatting 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v4 22 | - run: rustup toolchain install nightly --profile minimal --component rustfmt 23 | - run: cargo +nightly fmt --all -- --check 24 | 25 | cargo-clippy: 26 | name: Run linter 27 | runs-on: ubuntu-latest 28 | strategy: 29 | matrix: 30 | rust-toolchain: 31 | - stable 32 | - beta 33 | - nightly 34 | - 1.85.0 35 | steps: 36 | - uses: actions/checkout@v4 37 | - run: rustup toolchain install ${{ matrix.rust-toolchain }} --profile minimal --component clippy 38 | - run: rustup default ${{ matrix.rust-toolchain }} 39 | - run: cargo clippy --all-targets -- -D warnings 40 | - run: cargo clippy --all-targets --no-default-features -- -D warnings 41 | - run: cargo clippy --all-targets --no-default-features --features "alloc" -- -D warnings 42 | - run: cargo clippy --all-targets --no-default-features --features "std" -- -D warnings 43 | - run: cargo clippy --all-targets --no-default-features --features "serde" -- -D warnings 44 | - run: cargo clippy --all-targets --no-default-features --features "alloc serde" -- -D warnings 45 | - run: cargo clippy --all-targets --no-default-features --features "alloc std serde" -- -D warnings 46 | - run: cargo clippy --all-targets --no-default-features --features "std serde" -- -D warnings 47 | - run: cargo clippy --all-targets --all-features -- -D warnings 48 | 49 | cargo-test: 50 | name: Test sources 51 | runs-on: ubuntu-latest 52 | strategy: 53 | matrix: 54 | rust-toolchain: 55 | - stable 56 | - beta 57 | - nightly 58 | - 1.85.0 59 | cargo-flags: 60 | - "" 61 | - "--release" 62 | steps: 63 | - uses: actions/checkout@v4 64 | - run: rustup toolchain install ${{ matrix.rust-toolchain }} --profile minimal 65 | - run: rustup default ${{ matrix.rust-toolchain }} 66 | - run: cargo test --all-targets ${{ matrix.cargo-flags }} 67 | - run: cargo test --all-targets ${{ matrix.cargo-flags }} --no-default-features 68 | - run: cargo test --all-targets ${{ matrix.cargo-flags }} --no-default-features --features "alloc" 69 | - run: cargo test --all-targets ${{ matrix.cargo-flags }} --no-default-features --features "std" 70 | - run: cargo test --all-targets ${{ matrix.cargo-flags }} --no-default-features --features "serde" 71 | - run: cargo test --all-targets ${{ matrix.cargo-flags }} --no-default-features --features "alloc serde" 72 | - run: cargo test --all-targets ${{ matrix.cargo-flags }} --no-default-features --features "alloc std serde" 73 | - run: cargo test --all-targets ${{ matrix.cargo-flags }} --no-default-features --features "std serde" 74 | - run: cargo test --all-targets ${{ matrix.cargo-flags }} --all-features 75 | 76 | cargo-test-no-alloc-and-no-std: 77 | name: Test no-alloc and no-std compatibility 78 | runs-on: ubuntu-latest 79 | env: 80 | ARGS: --config build.rustflags=["-C","link-arg=-nostartfiles"] 81 | --manifest-path tests/no-alloc-and-no-std/Cargo.toml 82 | steps: 83 | - uses: actions/checkout@v4 84 | - run: rustup toolchain install stable --profile minimal 85 | - run: cargo build $ARGS --features panic-handler 86 | - run: cargo build $ARGS --features alloc,panic-handler,global-allocator 87 | - run: cargo build $ARGS --features alloc,std,global-allocator 88 | - run: if cargo build $ARGS; then false; else true; fi 89 | - run: if cargo build $ARGS --features alloc,panic-handler; then false; else true; fi 90 | - run: if cargo build $ARGS --features alloc,std,panic-handler,global-allocator; then false; else true; fi 91 | 92 | cargo-deny: 93 | name: Check licenses/bans/advisories/sources 94 | runs-on: ubuntu-latest 95 | steps: 96 | - uses: actions/checkout@v4 97 | - run: rustup toolchain install stable --profile minimal 98 | - run: cargo install cargo-deny 99 | - run: cargo deny --workspace --all-features check 100 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: coverage 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | defaults: 9 | run: 10 | shell: bash 11 | 12 | env: 13 | CARGO_TERM_COLOR: always 14 | 15 | jobs: 16 | coverage: 17 | name: Upload coverage to codecov.io 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v4 21 | - run: rustup toolchain install nightly --profile minimal --component llvm-tools 22 | - run: cargo install cargo-llvm-cov 23 | - run: cargo +nightly llvm-cov --doctests --all-features --codecov --output-path codecov.json 24 | - uses: codecov/codecov-action@v4 25 | with: 26 | file: codecov.json 27 | token: ${{ secrets.CODECOV_TOKEN }} 28 | fail_ci_if_error: true 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ## [3.3.0] - 2025-05-05 10 | ### Added 11 | - `bincode` support for `TiSlice`, `Box` and `TiVec` under the 12 | `bincode` feature. 13 | - Compatible methods and trait implementations for `TiSlice` to mirror the 14 | stable Rust API for `[]` up to Rust 1.85.0. 15 | 16 | ### Changed 17 | - The minimum supported Rust version has been increased to 1.85.0. 18 | - Migrated to Rust 2024 edition. 19 | 20 | ## [3.2.3] - 2024-10-03 21 | ### Changed 22 | - Mark `serde-alloc` and `serde-std` features as deprecated, 23 | use `[alloc, serde]` and `[std, serde]` features instead. 24 | - Minor changes in docs and check script. 25 | 26 | ## [3.2.2] - 2024-09-28 27 | ### Added 28 | - Feature required hint in docs. 29 | See for details. 30 | 31 | ## [3.2.1] - 2024-09-26 32 | ### Added 33 | - `Cow<'_, TiSlice>` implementation for `TiSlice`. 34 | - `Read` and `Write` implementations for `TiSlice`. 35 | - Support for `(Bound, Bound)` index and range. 36 | 37 | ### Changed 38 | - Updated and improved tests. 39 | - Test coverage increased up to 99%. 40 | 41 | ## [3.2.0] - 2024-09-23 42 | ### Added 43 | - `ti_vec!` macro similar to `vec!` macro. 44 | - Some previously missed implementations for `TiSlice` and `TiVec`. 45 | - Compatible methods and trait implementations for `TiSlice` and `TiVec` 46 | to mirror the stable Rust API for `[]` and `Vec` up to Rust 1.81.0. 47 | 48 | ### Changed 49 | - The minimum supported Rust version has been increased to 1.81.0. 50 | 51 | ## [3.1.0] - 2022-09-02 52 | ### Changed 53 | - The minimum supported Rust version has been increased to 1.46.0. 54 | - `#[repr(transparent)]` added to `TiSlice` and `TiVec` collections. 55 | 56 | ## [3.0.3] - 2020-05-27 57 | ### Changed 58 | - Fix description for `serde` feature flags in readme and docs. 59 | 60 | ## [3.0.2] - 2020-11-22 61 | ### Added 62 | - `no-std` and `no-alloc` crate tests. 63 | 64 | ### Changed 65 | - `readme-sync` dev-dependency used for docs sync check. 66 | 67 | ## [3.0.1] - 2020-10-30 68 | ### Changed 69 | - Rephrase Introduction and About sections in readme and docs. 70 | 71 | ## [3.0.0] - 2020-10-29 72 | ### Added 73 | - Implement `Extend` for `TiVec`. 74 | 75 | ### Changed 76 | - Set `impl-index-from` feature always enabled because of 77 | compatibility issues between crates that use it and crates that don't. 78 | - Remove `TypedIndex` trait. 79 | 80 | ## [2.0.1] - 2020-08-06 81 | ### Fixed 82 | - Fix compilation when `serde` feature is used with `alloc` or `std` features 83 | without `serde/alloc` or `serde/std`. 84 | - Use `-Z features=dev_dep` to check CI build on nightly Rust 85 | without features from dev-dependencies. 86 | See [rust-lang/cargo#1796](https://github.com/rust-lang/cargo/issues/1796) 87 | and [rust-lang/cargo#7916](https://github.com/rust-lang/cargo/issues/7916) 88 | for more details. 89 | 90 | ### Added 91 | - Add CI build check with `std` and `serde` features. 92 | 93 | ## [2.0.0] - 2020-08-03 94 | ### Changed 95 | - Use `AsRef::as_ref()` and `AsMut::as_mut()` instead `Into::into()` 96 | for zero-cost conversions between `&slice` and `&TiSlice`, `&mut slice` and `&mut TiSlice`, 97 | `&std::Vec` and `&TiVec`, `&mut std::Vec` and `&TiVec`. 98 | - Migrate from Travis CI to GitHub actions. 99 | 100 | ## [1.1.0] - 2020-07-30 101 | ### Added 102 | - `TiSlice` methods. 103 | 104 | ## [1.0.1] - 2020-07-25 105 | ### Added 106 | - Example with a wrong index type that should not compile. 107 | 108 | ### Changed 109 | - Travis config simplified. 110 | - Simplify var names in examples. 111 | 112 | ## [1.0.0] - 2020-07-22 113 | ### Added 114 | - Changelog. 115 | - `TiVec::{from_ref, from_mut, drain_enumerated}` methods. 116 | - No-op convertions between `Vec` and `TiVec` references and mutable references. 117 | - `TiVec` API compatibility tests. 118 | - Format and clippy checks in Travis config. 119 | 120 | ### Changed 121 | - Improve documentation examples readability. 122 | 123 | ### Fixed 124 | - Fix `TiSlice` and `TiVec` documentation typos. 125 | 126 | ## [0.1.2] - 2020-07-17 127 | ### Fixed 128 | - Ignore `Cargo.lock` in repository. 129 | - Relax `TiSlice` and `TiVec` requirements for traits 130 | `Default`, `Eq`, `Hash`, `Ord`, `PartialEq` and `PartialOrd`. 131 | - Add skipped `Clone` trait implementation for `TiVec`. 132 | 133 | ## [0.1.1] - 2020-07-17 134 | ### Fixed 135 | - Fix manifest documentation link. 136 | 137 | ## [0.1.0] - 2020-07-14 138 | ## [0.0.3] - 2020-07-14 139 | ### Added 140 | - `TiVec::{push_and_get_key, pop_key_value}` methods. 141 | 142 | ### Fixed 143 | - Fix previously disabled clippy lints. 144 | - Fix broken links in documentation. 145 | - Fix formatting in documentation. 146 | - Fix `Index` trait requirement instead of `From` for some `TiVec` methods. 147 | 148 | ## [0.0.2] - 2020-07-13 149 | ### Fixed 150 | - Fix typos in documentation. 151 | - Fix skipped links in documentation. 152 | - Fix Travis config. 153 | 154 | ## [0.0.1] - 2020-07-13 155 | ### Added 156 | - Index trait. 157 | - `TiSlice` wrapper for Rust `slice`. 158 | - `TiVec` wrapper for Rust `std::vec::Vec`. 159 | - `TiSlice` API compatibility tests. 160 | - Crate API documentation with examples. 161 | 162 | [Unreleased]: https://github.com/zheland/typed-index-collections/compare/v3.3.0...HEAD 163 | [3.3.0]: https://github.com/zheland/typed-index-collections/compare/v3.2.3...v3.3.0 164 | [3.2.3]: https://github.com/zheland/typed-index-collections/compare/v3.2.2...v3.2.3 165 | [3.2.2]: https://github.com/zheland/typed-index-collections/compare/v3.2.1...v3.2.2 166 | [3.2.1]: https://github.com/zheland/typed-index-collections/compare/v3.2.0...v3.2.1 167 | [3.2.0]: https://github.com/zheland/typed-index-collections/compare/v3.1.0...v3.2.0 168 | [3.1.0]: https://github.com/zheland/typed-index-collections/compare/v3.0.3...v3.1.0 169 | [3.0.3]: https://github.com/zheland/typed-index-collections/compare/v3.0.2...v3.0.3 170 | [3.0.2]: https://github.com/zheland/typed-index-collections/compare/v3.0.1...v3.0.2 171 | [3.0.1]: https://github.com/zheland/typed-index-collections/compare/v3.0.0...v3.0.1 172 | [3.0.0]: https://github.com/zheland/typed-index-collections/compare/v2.0.1...v3.0.0 173 | [2.0.1]: https://github.com/zheland/typed-index-collections/compare/v2.0.0...v2.0.1 174 | [2.0.0]: https://github.com/zheland/typed-index-collections/compare/v1.1.0...v2.0.0 175 | [1.1.0]: https://github.com/zheland/typed-index-collections/compare/v1.0.1...v1.1.0 176 | [1.0.1]: https://github.com/zheland/typed-index-collections/compare/v1.0.0...v1.0.1 177 | [1.0.0]: https://github.com/zheland/typed-index-collections/compare/v0.1.2...v1.0.0 178 | [0.1.2]: https://github.com/zheland/typed-index-collections/compare/v0.1.1...v0.1.2 179 | [0.1.1]: https://github.com/zheland/typed-index-collections/compare/v0.1.0...v0.1.1 180 | [0.1.0]: https://github.com/zheland/typed-index-collections/compare/v0.0.3...v0.1.0 181 | [0.0.3]: https://github.com/zheland/typed-index-collections/compare/v0.0.2...v0.0.3 182 | [0.0.2]: https://github.com/zheland/typed-index-collections/compare/v0.0.1...v0.0.2 183 | [0.0.1]: https://github.com/zheland/typed-index-collections/releases/tag/v0.0.1 184 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "typed-index-collections" 3 | version = "3.3.0" 4 | authors = ["Andrey Zheleznov "] 5 | edition = "2021" 6 | rust-version = "1.85.0" 7 | description = "Typed index version of Rust slice and Vec containers" 8 | readme = "README.md" 9 | repository = "https://github.com/zheland/typed-index-collections" 10 | documentation = "https://docs.rs/typed-index-collections" 11 | license = "MIT OR Apache-2.0" 12 | categories = ["data-structures", "no-std"] 13 | keywords = ["collection", "index", "no_std", "slice", "vec"] 14 | 15 | [features] 16 | default = ["alloc", "std"] 17 | alloc = ["serde?/alloc", "bincode?/alloc"] 18 | std = ["alloc", "serde?/std", "bincode?/std"] 19 | serde = ["dep:serde"] 20 | bincode = ["dep:bincode"] 21 | serde-alloc = ["alloc", "serde"] # Deprecated. 22 | serde-std = ["std", "serde"] # Deprecated. 23 | 24 | [dependencies.serde] 25 | version = "1.0.219" 26 | default-features = false 27 | optional = true 28 | 29 | [dependencies.bincode] 30 | version = "2.0.1" 31 | default-features = false 32 | optional = true 33 | 34 | [dev-dependencies] 35 | derive_more.version = "2.0.1" 36 | derive_more.features = ["from", "into"] 37 | version-sync = "0.9.5" 38 | serde_json = "1.0.140" 39 | readme-sync = "0.3.0" 40 | 41 | [badges.maintenance] 42 | status = "passively-maintained" 43 | 44 | [package.metadata.docs.rs] 45 | all-features = true 46 | rustdoc-args = ["--cfg", "docsrs"] 47 | 48 | [lints.rust] 49 | rust_2018_idioms.level = "warn" 50 | rust_2018_idioms.priority = -1 51 | future_incompatible = "warn" 52 | keyword_idents = "warn" 53 | let_underscore = "warn" 54 | meta_variable_misuse = "warn" 55 | missing_abi = "warn" 56 | missing_copy_implementations = "warn" 57 | missing_debug_implementations = "warn" 58 | missing_docs = "warn" 59 | non_ascii_idents = "warn" 60 | refining_impl_trait = "warn" 61 | single_use_lifetimes = "warn" 62 | trivial_casts = "warn" 63 | trivial_numeric_casts = "warn" 64 | unused_crate_dependencies = "warn" 65 | unused_extern_crates = "warn" 66 | unused_import_braces = "warn" 67 | unused_lifetimes = "warn" 68 | unused_qualifications = "warn" 69 | unused_results = "warn" 70 | variant_size_differences = "warn" 71 | 72 | [lints.clippy] 73 | all.level = "warn" 74 | all.priority = -1 75 | pedantic.level = "warn" 76 | pedantic.priority = -1 77 | alloc_instead_of_core = "warn" 78 | allow_attributes = "warn" 79 | allow_attributes_without_reason = "warn" 80 | arithmetic_side_effects = "warn" 81 | as_conversions = "warn" 82 | branches_sharing_code = "warn" 83 | clone_on_ref_ptr = "warn" 84 | dbg_macro = "warn" 85 | debug_assert_with_mut_call = "warn" 86 | decimal_literal_representation = "warn" 87 | default_trait_access = "warn" 88 | empty_line_after_outer_attr = "warn" 89 | empty_structs_with_brackets = "warn" 90 | error_impl_error = "warn" 91 | exit = "warn" 92 | fallible_impl_from = "warn" 93 | filetype_is_file = "warn" 94 | float_cmp_const = "warn" 95 | future_not_send = "warn" 96 | get_unwrap = "warn" 97 | if_then_some_else_none = "warn" 98 | missing_const_for_fn = "warn" 99 | missing_inline_in_public_items = "warn" 100 | modulo_arithmetic = "warn" 101 | multiple_inherent_impl = "warn" 102 | mut_mut = "warn" 103 | nonstandard_macro_braces = "warn" 104 | option_if_let_else = "warn" 105 | panic = "warn" 106 | print_stderr = "warn" 107 | rc_buffer = "warn" 108 | redundant_pub_crate = "warn" 109 | std_instead_of_core = "warn" 110 | string_lit_as_bytes = "warn" 111 | suboptimal_flops = "warn" 112 | suspicious_operation_groupings = "warn" 113 | todo = "warn" 114 | trivial_regex = "warn" 115 | try_err = "warn" 116 | undocumented_unsafe_blocks = "warn" 117 | unimplemented = "warn" 118 | unwrap_used = "warn" 119 | use_self = "warn" 120 | useless_let_if_seq = "warn" 121 | verbose_file_reads = "warn" 122 | wildcard_enum_match_arm = "warn" 123 | module_name_repetitions = "allow" # items are re-exported to the crate root 124 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Andrey Zheleznov 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /MIGRATION.md: -------------------------------------------------------------------------------- 1 | # Migration guide 2 | 3 | ## [3.0.0] 4 | - Default `impl-index-from` feature is now always enabled. 5 | Use wrappers for `TypedIndex` values 6 | if you use different `From/Into` `usize` and `TypedIndex::{from_usize, into_usize}` implementations. 7 | - Trait `TypedIndex` was removed. 8 | Use `From` and `Into` instead. 9 | 10 | ## [2.0.0] 11 | - Use `TiSlice::from_ref()`, `TiSlice::from_mut()`, 12 | `AsRef::as_ref()` and `AsMut::as_mut()` instead `Into::into()` 13 | for zero-cost conversions between `&slice` and `&TiSlice`, `&mut slice` and `&mut TiSlice`, 14 | `&std::Vec` and `&TiVec`, `&mut std::Vec` and `&TiVec`. 15 | 16 | [3.0.0]: https://github.com/zheland/typed-index-collections/compare/v2.0.1...v3.0.0 17 | [2.0.0]: https://github.com/zheland/typed-index-collections/compare/v1.1.0...v2.0.0 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # typed-index-collections 2 | 3 | [![Build Status](https://github.com/zheland/typed-index-collections/workflows/build/badge.svg)](https://github.com/zheland/typed-index-collections/actions) 4 | [![Latest Version](https://img.shields.io/crates/v/typed-index-collections.svg)](https://crates.io/crates/typed-index-collections) 5 | [![Documentation](https://docs.rs/typed-index-collections/badge.svg)](https://docs.rs/typed-index-collections) 6 | [![Codecov](https://codecov.io/gh/zheland/typed-index-collections/graph/badge.svg)](https://codecov.io/gh/zheland/typed-index-collections) 7 | [![Dependencies status](https://deps.rs/repo/github/zheland/typed-index-collections/status.svg)](https://deps.rs/repo/github/zheland/typed-index-collections) 8 | [![Downloads](https://img.shields.io/crates/d/typed-index-collections)](https://crates.io/crates/typed-index-collections) 9 | [![License](https://img.shields.io/crates/l/typed-index-collections)](https://github.com/zheland/typed-index-collections/#license) 10 | [![MSRV 1.85+](https://img.shields.io/badge/rustc-1.85+-blue.svg)](https://blog.rust-lang.org/2025/02/20/Rust-1.85.0) 11 | 12 | The `typed-index-collections` crate provides [`TiSlice`] and [`TiVec`] 13 | structs that are typed index versions of the Rust [`slice`] and 14 | [`std::vec::Vec`] types. 15 | 16 | ## Introduction 17 | 18 | The extensive use of slices and vectors instead of references 19 | and smart pointers might be useful for optimization, 20 | Data-Oriented Design and when using Struct of Arrays. 21 | But when dealing with a bunch of slices and vectors 22 | it is easy to accidentally use the wrong index, 23 | which is a common source of bugs. 24 | 25 | ## About 26 | 27 | This crate provides [`TiSlice`][`TiSlice`] and 28 | [`TiVec`][`TiVec`] containers that can be indexed only by the 29 | specified index type `K`. These containers are only wrappers around 30 | the slice primitive [`[V]`][`slice`] and the container 31 | [`std::vec::Vec`][`std::vec::Vec`]. Crate containers mirror the stable 32 | API of the matched Rust containers and forward to them as much as possible. 33 | 34 | [`TiSlice`] and [`TiVec`] can be easily converted to matched Rust containers 35 | and back using [`From`], [`Into`], [`AsRef`] and [`AsMut`] traits. 36 | Also, they expose `raw` property with the original data type. 37 | Containers only require the index to implement 38 | [`From`][`From`] and [`Into`][`Into`] traits 39 | that can be easily done with [`derive_more`] crate and 40 | `#[derive(From, Into)]`. 41 | 42 | ## Usage 43 | 44 | First, add the following to your `Cargo.toml`: 45 | 46 | ```toml 47 | [dependencies] 48 | typed-index-collections = "3.3.0" 49 | ``` 50 | 51 | This crate depends on the standard library by default that is useful 52 | for debugging and for some extra functionality. 53 | To use this crate in a `#![no_std]` context, use `default-features = false` 54 | in your `Cargo.toml` as shown below: 55 | 56 | ```toml 57 | [dependencies.typed-index-collections] 58 | version = "3.3.0" 59 | default-features = false 60 | features = ["alloc"] 61 | ``` 62 | 63 | If you want to use [`derive_more`] for 64 | [`From`][`From`] and [`Into`][`Into`] implementation 65 | add it to your `Cargo.toml` as shown below: 66 | 67 | ```toml 68 | [dependencies] 69 | derive_more = "0.99" 70 | typed-index-collections = "3.3.0" 71 | ``` 72 | 73 | ## Examples 74 | 75 | Simple example with [`derive_more`]: 76 | ```rust 77 | use typed_index_collections::TiVec; 78 | use derive_more::{From, Into}; 79 | 80 | #[derive(From, Into)] 81 | struct FooId(usize); 82 | 83 | let mut ti_vec: TiVec = std::vec![10, 11, 13].into(); 84 | ti_vec.insert(FooId(2), 12); 85 | assert_eq!(ti_vec[FooId(2)], 12); 86 | ``` 87 | 88 | If a wrong index type is used, compilation will fail: 89 | ```rust 90 | use typed_index_collections::TiVec; 91 | use derive_more::{From, Into}; 92 | 93 | #[derive(From, Into)] 94 | struct FooId(usize); 95 | 96 | #[derive(From, Into)] 97 | struct BarId(usize); 98 | 99 | let mut ti_vec: TiVec = std::vec![10, 11, 13].into(); 100 | 101 | ti_vec.insert(BarId(2), 12); 102 | // ^^^^^^^^ expected struct `FooId`, found struct `BarId` 103 | assert_eq!(ti_vec[BarId(2)], 12); 104 | // ^^^^^^^^^^^^^^^^ the trait ... is not implemented for `BarId` 105 | ``` 106 | 107 | Another more detailed example with [`derive_more`]: 108 | ```rust 109 | use typed_index_collections::{TiSlice, TiVec}; 110 | use derive_more::{From, Into}; 111 | 112 | #[derive(Clone, Copy, Debug, From, Into, Eq, PartialEq)] 113 | struct FooId(usize); 114 | 115 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] 116 | struct Foo { 117 | value: usize, 118 | } 119 | 120 | let first = Foo { value: 1 }; 121 | let second = Foo { value: 2 }; 122 | 123 | let slice_ref = &[first, second][..]; 124 | let vec = std::vec![first, second]; 125 | let boxed_slice = std::vec![first, second].into_boxed_slice(); 126 | 127 | let ti_slice_ref: &TiSlice = slice_ref.as_ref(); 128 | let ti_vec: TiVec = vec.into(); 129 | let ti_boxed_slice: std::boxed::Box> = 130 | boxed_slice.into(); 131 | 132 | assert_eq!(ti_vec[FooId(1)], second); 133 | assert_eq!(ti_vec.raw[1], second); 134 | assert_eq!(ti_vec.last(), Some(&second)); 135 | assert_eq!(ti_vec.last_key_value(), Some((FooId(1), &second))); 136 | assert_eq!(ti_vec.iter_enumerated().next(), Some((FooId(0), &first))); 137 | 138 | let _slice_ref: &[Foo] = ti_slice_ref.as_ref(); 139 | let _vec: std::vec::Vec = ti_vec.into(); 140 | let _boxed_slice: std::boxed::Box<[Foo]> = ti_boxed_slice.into(); 141 | ``` 142 | 143 | ## Documentation 144 | 145 | [API Documentation] 146 | 147 | ## Feature Flags 148 | 149 | - `alloc` (implied by `std`, enabled by default): Enables the Rust `alloc` 150 | library, enables [`TiVec`] type, [`ti_vec!`] macro, trait implementations 151 | for [`Box`]`<`[`TiSlice`]`>`, and some [`TiSlice`] methods that require 152 | memory allocation. 153 | - `std` (enabled by default): Enables `alloc` feature, the Rust `std` 154 | library, implements [`std::io::Write`] for [`TiVec`] and implements 155 | [`std::io::Read`] and [`std::io::Write`] for [`TiSlice`], 156 | - `serde`: Implements [`Serialize`] trait for [`TiSlice`] and [`TiVec`] 157 | containers and [`Deserialize`] trait for [`Box`]`<`[`TiSlice`]`>` and 158 | [`TiVec`]. 159 | - `bincode`: Implements [`Encode`] trait for [`TiSlice`] and [`TiVec`] 160 | containers and [`Decode`] and [`BorrowDecode`] traits for 161 | [`Box`]`<`[`TiSlice`]`>` and [`TiVec`]. 162 | 163 | ## Similar crates 164 | 165 | - [`typed_index_collection`] provides a `Vec` wrapper with a very limited 166 | API. Indices are u32 wrappers, they are not customizable and can only 167 | index a specific type of container. 168 | - [`indexed_vec`] is the closest copy of the `IndexVec` struct from 169 | `librustc_index`, but API is also different from standard Rust 170 | [`std::vec::Vec`] and it has no typed index [`slice`] alternative. 171 | - [`index_vec`] have both [`slice`] and [`std::vec::Vec`] wrapper and API 172 | closer to standard API. But it implicitly allows you to use `usize` for 173 | get methods and index expressions that reduce type-safety, and the macro 174 | `define_index_type!` which is used to generate a newtyped index struct, 175 | implicitly implements a lot of traits that in my opinion would be better 176 | implemented only when necessary using crates intended for this, such as 177 | [`derive_more`]. 178 | 179 | ## License 180 | 181 | Licensed under either of 182 | 183 | - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) 184 | or ) 185 | - MIT license ([LICENSE-MIT](LICENSE-MIT) 186 | or ) 187 | 188 | at your option. 189 | 190 | ### Contribution 191 | 192 | Unless you explicitly state otherwise, any contribution intentionally 193 | submitted for inclusion in the work by you, as defined in the Apache-2.0 194 | license, shall be dual licensed as above, without any 195 | additional terms or conditions. 196 | 197 | [`TiSlice`]: https://docs.rs/typed-index-collections/*/typed_index_collections/struct.TiSlice.html 198 | [`TiVec`]: https://docs.rs/typed-index-collections/*/typed_index_collections/struct.TiVec.html 199 | [`ti_vec!`]: https://docs.rs/typed-index-collections/*/typed_index_collections/macro.ti_vec.html 200 | [API Documentation]: https://docs.rs/typed-index-collections 201 | [`slice`]: https://doc.rust-lang.org/std/primitive.slice.html 202 | [`Box`]: https://doc.rust-lang.org/std/boxed/struct.Box.html 203 | [`Rc`]: https://doc.rust-lang.org/std/rc/struct.Rc.html 204 | [`Weak`]: https://doc.rust-lang.org/std/rc/struct.Weak.html 205 | [`std::vec::Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html 206 | [`std::io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html 207 | [`std::io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html 208 | [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html 209 | [`Into`]: https://doc.rust-lang.org/std/convert/trait.Into.html 210 | [`AsRef`]: https://doc.rust-lang.org/std/convert/trait.AsRef.html 211 | [`AsMut`]: https://doc.rust-lang.org/std/convert/trait.AsMut.html 212 | [`derive_more`]: https://crates.io/crates/derive_more 213 | [`typed_index_collection`]: https://crates.io/crates/typed_index_collection 214 | [`indexed_vec`]: https://crates.io/crates/indexed_vec 215 | [`index_vec`]: https://crates.io/crates/index_vec 216 | [`Serialize`]: https://docs.serde.rs/serde/trait.Serialize.html 217 | [`Deserialize`]: https://docs.serde.rs/serde/trait.Deserialize.html 218 | [`Encode`]: https://docs.serde.rs/serde/trait.Serialize.html 219 | [`Decode`]: https://docs.rs/bincode/latest/bincode/de/trait.Decode.html 220 | [`BorrowDecode`]: https://docs.rs/bincode/latest/bincode/de/trait.BorrowDecode.html 221 | -------------------------------------------------------------------------------- /check.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Crate-specific settings 4 | toolchains=( stable beta nightly "1.85.0" ) 5 | all_features=( "" "alloc" "std" "serde" ) 6 | max_uncovered_functions=0 7 | max_uncovered_lines=10 8 | max_uncovered_regions=10 9 | 10 | set -Eeuo pipefail 11 | 12 | tmp_dir="" 13 | bold_red=$'\033[1;31m' 14 | bold_green=$'\033[1;32m' 15 | no_color=$'\033[0m' 16 | 17 | cleanup() { 18 | local return_code=$? 19 | if [ -n "$tmp_dir" ]; then 20 | rm -rf -- "$tmp_dir" 21 | fi 22 | exit $return_code 23 | } 24 | 25 | trap cleanup EXIT 26 | 27 | tmp_dir="$( mktemp -d )" 28 | 29 | ok() { echo "${bold_green}OK${no_color}: $@" 1>&2; } 30 | fail() { echo "${bold_red}ERROR${no_color}: $@" 1>&2; exit 1; } 31 | echo_and_run() { echo "$ ${*@Q}"; "$@"; } 32 | 33 | echo_and_try_run() { 34 | set +eo pipefail 35 | echo "$ ${*@Q}" 36 | "$@" 2> >( tee "$tmp_dir/error.txt" ) 37 | echo $? > "$tmp_dir/return_code.txt" 38 | set -eo pipefail 39 | } 40 | 41 | expect_failure() { 42 | if [ "$(cat "$tmp_dir/return_code.txt")" -ne "0" ]; then 43 | ok "Command failed as expected." 44 | if ! cat "$tmp_dir/error.txt" | grep -q "$@"; then 45 | fail "Unexpected error message, expected regex: ${*@Q}." 46 | fi 47 | else 48 | fail "Command did not fail as expected." 49 | fi 50 | } 51 | 52 | echo_and_run cargo +nightly fmt --all -- --check 53 | echo_and_run cargo msrv verify 54 | echo_and_run cargo outdated --exit-code 1 55 | 56 | # Each value is a set of `|`-separated values: 57 | # - comma separated features, 58 | # - expected status on non-nightly toolchains, 59 | # - expected status on nightly toolchain, 60 | # - expected error message regex" 61 | valid_no_alloc_and_no_std_param_sets=( 62 | "|fail|fail|panic_handler.* function required" 63 | "panic-handler|ok|ok|" 64 | "alloc,panic-handler|fail|fail|no global memory allocator found" 65 | "alloc,panic-handler,global-allocator|ok|fail|undefined symbol: rust_eh_personality" 66 | "alloc,std,panic-handler,global-allocator|fail|fail|found duplicate lang item .*panic_impl" 67 | "alloc,std,global-allocator|ok|ok|" 68 | ) 69 | for toolchain in "${toolchains[@]}"; do 70 | ( 71 | echo_and_run export CARGO_TARGET_DIR="target/check-no-alloc-and-no-std-$toolchain" 72 | for param_set in "${valid_no_alloc_and_no_std_param_sets[@]}"; do 73 | features=$(echo "$param_set" | cut -sd"|" -f1) 74 | expected_default=$(echo "$param_set" | cut -sd"|" -f2) 75 | expected_nightly=$(echo "$param_set" | cut -sd"|" -f3) 76 | expected_error_regex=$(echo "$param_set" | cut -sd"|" -f4-) 77 | if [ "$toolchain" = "nightly" ]; then 78 | expected="$expected_nightly" 79 | else 80 | expected="$expected_default" 81 | fi 82 | args="--config build.rustflags=[\"-C\",\"link-arg=-nostartfiles\"]" 83 | args+=" --manifest-path tests/no-alloc-and-no-std/Cargo.toml" 84 | args+=" --no-default-features" 85 | [ -n "$features" ] && args+=" --features $features" 86 | if [ "$expected" = "ok" ]; then 87 | echo_and_run cargo "+$toolchain" clippy $args -- -D warnings 88 | echo_and_run cargo "+$toolchain" build $args 89 | elif [ "$expected" = "fail" ]; then 90 | echo_and_try_run cargo "+$toolchain" build $args 91 | expect_failure "$expected_error_regex" 92 | else 93 | fail "Internal script error: invalid expected result." 94 | fi 95 | done 96 | ) 97 | done 98 | 99 | num_features=${#all_features[@]} 100 | num_combinations=$(echo "2^$num_features" | bc) 101 | feature_sets=() 102 | 103 | # Iterate over all `2^num_features` features combinations if required 104 | # `combination_idx` is used as a bitmask of the enabled features. 105 | for ((combination_idx = 0; combination_idx < num_combinations; combination_idx++)); do 106 | features_set=() 107 | for ((feature_idx = 0; feature_idx < num_features; feature_idx++)); do 108 | mask=$(echo "2^$feature_idx" | bc) # The mask of `feature_idx`-th feature. 109 | 110 | if (( combination_idx & mask )); then 111 | features_set+=(${all_features[$feature_idx]}) 112 | fi 113 | done 114 | features=$(echo "${features_set[@]}" | tr " " ",") 115 | feature_sets+=("$features") 116 | done 117 | 118 | 119 | for toolchain in "${toolchains[@]}"; do 120 | ( 121 | export CARGO_TARGET_DIR="target/check-$toolchain" 122 | for features in "${feature_sets[@]}"; do 123 | cargo="cargo +$toolchain" 124 | if [ -n "$features" ]; then 125 | args="--no-default-features --features $features" 126 | else 127 | args="--no-default-features" 128 | fi 129 | echo_and_run $cargo clippy --all-targets $args -- -D warnings 130 | echo_and_run $cargo build --all-targets $args 131 | echo_and_run $cargo test --all-targets $args 132 | echo_and_run $cargo test --release --all-targets $args 133 | echo_and_run $cargo test --doc $args 134 | echo_and_run $cargo test --doc --release $args 135 | if [[ "$toolchain" == "nightly" ]]; then 136 | echo_and_run $cargo miri test --all-targets $args 137 | fi 138 | echo_and_run $cargo bench --no-run --all-targets $args 139 | done 140 | ) 141 | done 142 | 143 | echo_and_run cargo deny --workspace --all-features check 144 | 145 | echo_and_run cargo +nightly llvm-cov --doctests --all-features --html \ 146 | --fail-uncovered-functions $max_uncovered_functions \ 147 | --fail-uncovered-lines $max_uncovered_lines \ 148 | --fail-uncovered-regions $max_uncovered_regions \ 149 | || true # Ignore failure because of error "N functions have mismatched data" 150 | 151 | for features in "${feature_sets[@]}"; do 152 | args=() 153 | features=$( echo "$features" | tr "," " " ) 154 | for feature in ${features}; do 155 | args+=( --features ) 156 | args+=( $feature ) 157 | done 158 | echo_and_run cargo semver-checks --only-explicit-features "${args[@]}" 159 | done 160 | 161 | ok "All checks succeeded." 1>&2 162 | -------------------------------------------------------------------------------- /deny.toml: -------------------------------------------------------------------------------- 1 | [licenses] 2 | allow = [ 3 | "MIT", 4 | "Apache-2.0", 5 | "Unicode-3.0", 6 | ] 7 | confidence-threshold = 0.99 8 | -------------------------------------------------------------------------------- /doc.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features 4 | -------------------------------------------------------------------------------- /fmt.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cargo +nightly fmt --all 4 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | format_code_in_doc_comments = true 2 | format_macro_bodies = true 3 | format_macro_matchers = true 4 | format_strings = true 5 | group_imports = "StdExternalCrate" 6 | imports_granularity = "Module" 7 | normalize_comments = true 8 | wrap_comments = true 9 | -------------------------------------------------------------------------------- /src/iter.rs: -------------------------------------------------------------------------------- 1 | use core::{iter, ops}; 2 | 3 | use crate::TiSlice; 4 | 5 | /// An iterator over all key-value pairs. 6 | /// 7 | /// This struct is created by the [`TiSlice::iter_enumerated`], 8 | /// [`TiSlice::iter_mut_enumerated`] and [`TiVec::drain_enumerated`] methods. 9 | /// 10 | /// [`TiSlice::iter_enumerated`]: struct.TiSlice.html#method.iter_enumerated 11 | /// [`TiSlice::iter_mut_enumerated`]: struct.TiSlice.html#method.iter_mut_enumerated 12 | /// [`TiVec::drain_enumerated`]: struct.TiVec.html#method.drain_enumerated 13 | pub type TiEnumerated = iter::Map, fn((usize, V)) -> (K, V)>; 14 | 15 | /// An iterator over all keys. 16 | /// 17 | /// This struct is created by the [`TiSlice::keys`] method. 18 | /// 19 | /// [`TiSlice::keys`]: struct.TiSlice.html#method.keys 20 | pub type TiSliceKeys = iter::Map, fn(usize) -> K>; 21 | 22 | /// An iterator wrapper for iterators that yields [`TiSlice`] subslice 23 | /// references. 24 | /// 25 | /// [`TiSlice`]: struct.TiSlice.html 26 | pub type TiSliceRefMap = iter::Map &TiSlice>; 27 | 28 | /// An iterator wrapper for iterators that yields [`TiSlice`] subslice mutable 29 | /// references. 30 | /// 31 | /// [`TiSlice`]: struct.TiSlice.html 32 | pub type TiSliceMutMap = iter::Map &mut TiSlice>; 33 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! The `typed-index-collections` crate provides [`TiSlice`] and [`TiVec`] 2 | //! structs that are typed index versions of the Rust [`slice`] and 3 | //! [`std::vec::Vec`] types. 4 | //! 5 | //! # Introduction 6 | //! 7 | //! The extensive use of slices and vectors instead of references 8 | //! and smart pointers might be useful for optimization, 9 | //! Data-Oriented Design and when using Struct of Arrays. 10 | //! But when dealing with a bunch of slices and vectors 11 | //! it is easy to accidentally use the wrong index, 12 | //! which is a common source of bugs. 13 | //! 14 | //! # About 15 | //! 16 | //! This crate provides [`TiSlice`][`TiSlice`] and 17 | //! [`TiVec`][`TiVec`] containers that can be indexed only by the 18 | //! specified index type `K`. These containers are only wrappers around 19 | //! the slice primitive [`[V]`][`slice`] and the container 20 | //! [`std::vec::Vec`][`std::vec::Vec`]. Crate containers mirror the stable 21 | //! API of the matched Rust containers and forward to them as much as possible. 22 | //! 23 | //! [`TiSlice`] and [`TiVec`] can be easily converted to matched Rust containers 24 | //! and back using [`From`], [`Into`], [`AsRef`] and [`AsMut`] traits. 25 | //! Also, they expose `raw` property with the original data type. 26 | //! Containers only require the index to implement 27 | //! [`From`][`From`] and [`Into`][`Into`] traits 28 | //! that can be easily done with [`derive_more`] crate and 29 | //! `#[derive(From, Into)]`. 30 | //! 31 | //! # Usage 32 | //! 33 | //! First, add the following to your `Cargo.toml`: 34 | //! 35 | //! ```toml 36 | //! [dependencies] 37 | //! typed-index-collections = "3.3.0" 38 | //! ``` 39 | //! 40 | //! This crate depends on the standard library by default that is useful 41 | //! for debugging and for some extra functionality. 42 | //! To use this crate in a `#![no_std]` context, use `default-features = false` 43 | //! in your `Cargo.toml` as shown below: 44 | //! 45 | //! ```toml 46 | //! [dependencies.typed-index-collections] 47 | //! version = "3.3.0" 48 | //! default-features = false 49 | //! features = ["alloc"] 50 | //! ``` 51 | //! 52 | //! If you want to use [`derive_more`] for 53 | //! [`From`][`From`] and [`Into`][`Into`] implementation 54 | //! add it to your `Cargo.toml` as shown below: 55 | //! 56 | //! ```toml 57 | //! [dependencies] 58 | //! derive_more = "0.99" 59 | //! typed-index-collections = "3.3.0" 60 | //! ``` 61 | //! 62 | //! # Examples 63 | //! 64 | //! Simple example with [`derive_more`]: 65 | #![cfg_attr(feature = "alloc", doc = " ```rust")] 66 | #![cfg_attr(not(feature = "alloc"), doc = " ```rust,compile_fail")] 67 | //! use typed_index_collections::TiVec; 68 | //! use derive_more::{From, Into}; 69 | //! 70 | //! #[derive(From, Into)] 71 | //! struct FooId(usize); 72 | //! 73 | //! let mut ti_vec: TiVec = std::vec![10, 11, 13].into(); 74 | //! ti_vec.insert(FooId(2), 12); 75 | //! assert_eq!(ti_vec[FooId(2)], 12); 76 | #![doc = " ```"] 77 | #![doc = ""] 78 | //! If a wrong index type is used, compilation will fail: 79 | //! ```compile_fail 80 | //! use typed_index_collections::TiVec; 81 | //! use derive_more::{From, Into}; 82 | //! 83 | //! #[derive(From, Into)] 84 | //! struct FooId(usize); 85 | //! 86 | //! #[derive(From, Into)] 87 | //! struct BarId(usize); 88 | //! 89 | //! let mut ti_vec: TiVec = std::vec![10, 11, 13].into(); 90 | //! 91 | //! ti_vec.insert(BarId(2), 12); 92 | //! // ^^^^^^^^ expected struct `FooId`, found struct `BarId` 93 | //! assert_eq!(ti_vec[BarId(2)], 12); 94 | //! // ^^^^^^^^^^^^^^^^ the trait ... is not implemented for `BarId` 95 | //! ``` 96 | //! 97 | //! Another more detailed example with [`derive_more`]: 98 | #![cfg_attr(feature = "alloc", doc = " ```rust")] 99 | #![cfg_attr(not(feature = "alloc"), doc = " ```rust,compile_fail")] 100 | //! use typed_index_collections::{TiSlice, TiVec}; 101 | //! use derive_more::{From, Into}; 102 | //! 103 | //! #[derive(Clone, Copy, Debug, From, Into, Eq, PartialEq)] 104 | //! struct FooId(usize); 105 | //! 106 | //! #[derive(Clone, Copy, Debug, Eq, PartialEq)] 107 | //! struct Foo { 108 | //! value: usize, 109 | //! } 110 | //! 111 | //! let first = Foo { value: 1 }; 112 | //! let second = Foo { value: 2 }; 113 | //! 114 | //! let slice_ref = &[first, second][..]; 115 | //! let vec = std::vec![first, second]; 116 | //! let boxed_slice = std::vec![first, second].into_boxed_slice(); 117 | //! 118 | //! let ti_slice_ref: &TiSlice = slice_ref.as_ref(); 119 | //! let ti_vec: TiVec = vec.into(); 120 | //! let ti_boxed_slice: std::boxed::Box> = 121 | //! boxed_slice.into(); 122 | //! 123 | //! assert_eq!(ti_vec[FooId(1)], second); 124 | //! assert_eq!(ti_vec.raw[1], second); 125 | //! assert_eq!(ti_vec.last(), Some(&second)); 126 | //! assert_eq!(ti_vec.last_key_value(), Some((FooId(1), &second))); 127 | //! assert_eq!(ti_vec.iter_enumerated().next(), Some((FooId(0), &first))); 128 | //! 129 | //! let _slice_ref: &[Foo] = ti_slice_ref.as_ref(); 130 | //! let _vec: std::vec::Vec = ti_vec.into(); 131 | //! let _boxed_slice: std::boxed::Box<[Foo]> = ti_boxed_slice.into(); 132 | #![doc = " ```"] 133 | #![doc = ""] 134 | //! # Feature Flags 135 | //! 136 | //! - `alloc` (implied by `std`, enabled by default): Enables the Rust `alloc` 137 | //! library, enables [`TiVec`] type, [`ti_vec!`] macro, trait implementations 138 | //! for [`Box`]`<`[`TiSlice`]`>`, and some [`TiSlice`] methods that require 139 | //! memory allocation. 140 | //! - `std` (enabled by default): Enables `alloc` feature, the Rust `std` 141 | //! library, implements [`std::io::Write`] for [`TiVec`] and implements 142 | //! [`std::io::Read`] and [`std::io::Write`] for [`TiSlice`], 143 | //! - `serde`: Implements [`Serialize`] trait for [`TiSlice`] and [`TiVec`] 144 | //! containers and [`Deserialize`] trait for [`Box`]`<`[`TiSlice`]`>` and 145 | //! [`TiVec`]. 146 | //! - `bincode`: Implements [`Encode`] trait for [`TiSlice`] and [`TiVec`] 147 | //! containers and [`Decode`] and [`BorrowDecode`] traits for 148 | //! [`Box`]`<`[`TiSlice`]`>` and [`TiVec`]. 149 | //! 150 | //! # Similar crates 151 | //! 152 | //! - [`typed_index_collection`] provides a `Vec` wrapper with a very limited 153 | //! API. Indices are u32 wrappers, they are not customizable and can only 154 | //! index a specific type of container. 155 | //! - [`indexed_vec`] is the closest copy of the `IndexVec` struct from 156 | //! `librustc_index`, but API is also different from standard Rust 157 | //! [`std::vec::Vec`] and it has no typed index [`slice`] alternative. 158 | //! - [`index_vec`] have both [`slice`] and [`std::vec::Vec`] wrapper and API 159 | //! closer to standard API. But it implicitly allows you to use `usize` for 160 | //! get methods and index expressions that reduce type-safety, and the macro 161 | //! `define_index_type!` which is used to generate a newtyped index struct, 162 | //! implicitly implements a lot of traits that in my opinion would be better 163 | //! implemented only when necessary using crates intended for this, such as 164 | //! [`derive_more`]. 165 | //! 166 | //! # License 167 | //! 168 | //! Licensed under either of 169 | //! 170 | //! - Apache License, Version 2.0 ([LICENSE-APACHE](https://github.com/zheland/typed-index-collections/blob/master/LICENSE-APACHE) 171 | //! or ) 172 | //! - MIT license ([LICENSE-MIT](https://github.com/zheland/typed-index-collections/blob/master/LICENSE-MIT) 173 | //! or ) 174 | //! 175 | //! at your option. 176 | //! 177 | //! ## Contribution 178 | //! 179 | //! Unless you explicitly state otherwise, any contribution intentionally 180 | //! submitted for inclusion in the work by you, as defined in the Apache-2.0 181 | //! license, shall be dual licensed as above, without any 182 | //! additional terms or conditions. 183 | //! 184 | //! [`TiSlice`]: struct.TiSlice.html 185 | //! [`TiVec`]: struct.TiVec.html 186 | //! [`ti_vec!`]: macro.ti_vec.html 187 | //! [`slice`]: https://doc.rust-lang.org/std/primitive.slice.html 188 | //! [`Box`]: https://doc.rust-lang.org/std/boxed/struct.Box.html 189 | //! [`Rc`]: https://doc.rust-lang.org/std/rc/struct.Rc.html 190 | //! [`Weak`]: https://doc.rust-lang.org/std/rc/struct.Weak.html 191 | //! [`std::vec::Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html 192 | //! [`std::io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html 193 | //! [`std::io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html 194 | //! [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html 195 | //! [`Into`]: https://doc.rust-lang.org/std/convert/trait.Into.html 196 | //! [`AsRef`]: https://doc.rust-lang.org/std/convert/trait.AsRef.html 197 | //! [`AsMut`]: https://doc.rust-lang.org/std/convert/trait.AsMut.html 198 | //! [`derive_more`]: https://crates.io/crates/derive_more 199 | //! [`typed_index_collection`]: https://crates.io/crates/typed_index_collection 200 | //! [`indexed_vec`]: https://crates.io/crates/indexed_vec 201 | //! [`index_vec`]: https://crates.io/crates/index_vec 202 | //! [`Serialize`]: https://docs.serde.rs/serde/trait.Serialize.html 203 | //! [`Deserialize`]: https://docs.serde.rs/serde/trait.Deserialize.html 204 | //! [`Encode`]: https://docs.serde.rs/serde/trait.Serialize.html 205 | //! [`Decode`]: https://docs.rs/bincode/latest/bincode/de/trait.Decode.html 206 | //! [`BorrowDecode`]: https://docs.rs/bincode/latest/bincode/de/trait.BorrowDecode.html 207 | 208 | #![cfg_attr(docsrs, feature(doc_cfg))] 209 | #![no_std] 210 | 211 | #[cfg(any(feature = "alloc", test))] 212 | extern crate alloc; 213 | 214 | #[cfg(feature = "std")] 215 | extern crate std; 216 | 217 | #[cfg(test)] 218 | #[macro_use] 219 | mod test_util; 220 | 221 | mod iter; 222 | mod range; 223 | mod slice; 224 | 225 | #[cfg(feature = "alloc")] 226 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 227 | mod macros; 228 | #[cfg(feature = "alloc")] 229 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 230 | mod vec; 231 | 232 | pub use iter::{TiEnumerated, TiSliceKeys, TiSliceMutMap, TiSliceRefMap}; 233 | pub use range::TiRangeBounds; 234 | pub use slice::{TiSlice, TiSliceIndex}; 235 | #[cfg(feature = "alloc")] 236 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 237 | pub use vec::TiVec; 238 | 239 | #[cfg(test)] 240 | mod integration_tests_deps { 241 | use {readme_sync as _, serde_json as _, version_sync as _}; 242 | } 243 | 244 | #[doc(hidden)] 245 | pub mod macro_deps { 246 | #[cfg(feature = "alloc")] 247 | pub use alloc::vec; 248 | } 249 | -------------------------------------------------------------------------------- /src/macros.rs: -------------------------------------------------------------------------------- 1 | /// Creates a [`TiVec`] containing the arguments. 2 | /// 3 | /// `ti_vec!` allows `TiVec`s to be defined with the same syntax as array 4 | /// expressions. There are two forms of this macro: 5 | /// 6 | /// - Create a [`TiVec`] containing a given list of elements: 7 | /// 8 | /// ``` 9 | /// use derive_more::{From, Into}; 10 | /// use typed_index_collections::{ti_vec, TiVec}; 11 | /// 12 | /// #[derive(From, Into, Debug)] 13 | /// struct FooId(usize); 14 | /// 15 | /// let v: TiVec = ti_vec![1, 2, 3]; 16 | /// assert_eq!(v[FooId(0)], 1); 17 | /// assert_eq!(v[FooId(1)], 2); 18 | /// assert_eq!(v[FooId(2)], 3); 19 | /// ``` 20 | /// 21 | /// - Create a [`TiVec`] from a given element and size: 22 | /// 23 | /// ``` 24 | /// use typed_index_collections::{ti_vec, TiVec}; 25 | /// use derive_more::{From, Into}; 26 | /// 27 | /// #[derive(From, Into, Debug)] 28 | /// struct FooId(usize); 29 | /// 30 | /// let v: TiVec = ti_vec![1; 3]; 31 | /// assert_eq!(v.as_ref(), [1, 1, 1]); 32 | /// ``` 33 | /// 34 | /// Note that unlike array expressions this syntax supports all elements 35 | /// which implement [`Clone`] and the number of elements doesn't have to be 36 | /// a constant. 37 | /// 38 | /// This will use `clone` to duplicate an expression, so one should be careful 39 | /// using this with types having a nonstandard `Clone` implementation. For 40 | /// example, `ti_vec![Rc::new(1); 5]` will create a vector of five references 41 | /// to the same boxed integer value, not five references pointing to 42 | /// independently boxed integers. 43 | /// 44 | /// Also, note that `ti_vec![expr; 0]` is allowed, and produces an empty vector. 45 | /// This will still evaluate `expr`, however, and immediately drop the resulting 46 | /// value, so be mindful of side effects. 47 | /// 48 | /// [`TiVec`]: crate::TiVec 49 | #[macro_export] 50 | macro_rules! ti_vec { 51 | () => ( 52 | $crate::TiVec::new() 53 | ); 54 | ($elem:expr; $n:expr) => ( 55 | $crate::TiVec::from($crate::macro_deps::vec![$elem; $n]) 56 | ); 57 | ($($x:expr),+ $(,)?) => ( 58 | $crate::TiVec::from($crate::macro_deps::vec![$($x),+]) 59 | ); 60 | } 61 | -------------------------------------------------------------------------------- /src/range.rs: -------------------------------------------------------------------------------- 1 | use core::ops; 2 | 3 | /// A helper trait used to convert typed index ranges to `usize` ranges. 4 | /// The trait is implemented for Rust's built-in range types with 5 | /// `K where usize: `[`From`] used as bound endpoints. 6 | /// 7 | /// See [`core::ops::RangeBounds`] for more details. 8 | /// 9 | /// [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html 10 | /// [`core::ops::RangeBounds`]: https://doc.rust-lang.org/core/ops/trait.RangeBounds.html 11 | pub trait TiRangeBounds { 12 | /// Appropriate usize range 13 | type Range: ops::RangeBounds; 14 | /// Converts the `TiRangeBounds` into an appropriate usize range. 15 | fn into_range(self) -> Self::Range; 16 | } 17 | 18 | impl TiRangeBounds for ops::Range 19 | where 20 | usize: From, 21 | { 22 | type Range = ops::Range; 23 | #[inline] 24 | fn into_range(self) -> Self::Range { 25 | self.start.into()..self.end.into() 26 | } 27 | } 28 | 29 | impl TiRangeBounds for ops::RangeFrom 30 | where 31 | usize: From, 32 | { 33 | type Range = ops::RangeFrom; 34 | #[inline] 35 | fn into_range(self) -> Self::Range { 36 | self.start.into().. 37 | } 38 | } 39 | 40 | impl TiRangeBounds for ops::RangeFull 41 | where 42 | usize: From, 43 | { 44 | type Range = Self; 45 | #[inline] 46 | fn into_range(self) -> Self::Range { 47 | Self 48 | } 49 | } 50 | 51 | impl TiRangeBounds for ops::RangeInclusive 52 | where 53 | usize: From, 54 | { 55 | type Range = ops::RangeInclusive; 56 | #[inline] 57 | fn into_range(self) -> Self::Range { 58 | let (start, end) = self.into_inner(); 59 | start.into()..=end.into() 60 | } 61 | } 62 | 63 | impl TiRangeBounds for ops::RangeTo 64 | where 65 | usize: From, 66 | { 67 | type Range = ops::RangeTo; 68 | #[inline] 69 | fn into_range(self) -> Self::Range { 70 | ..self.end.into() 71 | } 72 | } 73 | 74 | impl TiRangeBounds for ops::RangeToInclusive 75 | where 76 | usize: From, 77 | { 78 | type Range = ops::RangeToInclusive; 79 | #[inline] 80 | fn into_range(self) -> Self::Range { 81 | ..=self.end.into() 82 | } 83 | } 84 | 85 | impl TiRangeBounds for (ops::Bound, ops::Bound) 86 | where 87 | usize: From, 88 | { 89 | type Range = (ops::Bound, ops::Bound); 90 | #[inline] 91 | fn into_range(self) -> Self::Range { 92 | (map_bound(self.0), map_bound(self.1)) 93 | } 94 | } 95 | 96 | #[inline] 97 | fn map_bound(bound: ops::Bound) -> ops::Bound 98 | where 99 | usize: From, 100 | { 101 | match bound { 102 | ops::Bound::Included(index) => ops::Bound::Included(index.into()), 103 | ops::Bound::Excluded(index) => ops::Bound::Excluded(index.into()), 104 | ops::Bound::Unbounded => ops::Bound::Unbounded, 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/slice/boxed.rs: -------------------------------------------------------------------------------- 1 | use alloc::boxed::Box; 2 | use alloc::vec; 3 | use core::iter::FromIterator; 4 | use core::mem::transmute; 5 | 6 | #[cfg(feature = "bincode")] 7 | use bincode::de::{BorrowDecode, BorrowDecoder, Decode, Decoder}; 8 | #[cfg(feature = "bincode")] 9 | use bincode::error::DecodeError; 10 | #[cfg(all(feature = "alloc", feature = "serde"))] 11 | use serde::de::{Deserialize, Deserializer}; 12 | 13 | use crate::{TiSlice, TiVec}; 14 | 15 | impl From>> for Box<[V]> { 16 | #[inline] 17 | fn from(slice: Box>) -> Self { 18 | // SAFETY: `TiSlice` is `repr(transparent)` over a `[V]` type. 19 | unsafe { transmute::>, Self>(slice) } 20 | } 21 | } 22 | 23 | impl From> for Box> { 24 | #[inline] 25 | fn from(slice: Box<[V]>) -> Self { 26 | // SAFETY: `TiSlice` is `repr(transparent)` over a `[V]` type. 27 | unsafe { transmute::, Self>(slice) } 28 | } 29 | } 30 | 31 | impl Clone for Box> { 32 | #[inline] 33 | fn clone(&self) -> Self { 34 | self.to_vec().into_boxed_slice() 35 | } 36 | } 37 | 38 | impl IntoIterator for Box> { 39 | type Item = V; 40 | type IntoIter = vec::IntoIter; 41 | 42 | #[inline] 43 | fn into_iter(self) -> Self::IntoIter { 44 | self.into_vec().into_iter() 45 | } 46 | } 47 | 48 | impl Default for Box> { 49 | #[inline] 50 | fn default() -> Self { 51 | TiVec::new().into() 52 | } 53 | } 54 | 55 | impl From<&TiSlice> for Box> { 56 | #[inline] 57 | fn from(slice: &TiSlice) -> Self { 58 | Box::<[V]>::from(&slice.raw).into() 59 | } 60 | } 61 | 62 | impl From>> for TiVec { 63 | #[inline] 64 | fn from(s: Box>) -> Self { 65 | s.into_vec() 66 | } 67 | } 68 | 69 | impl From> for Box> { 70 | #[inline] 71 | fn from(v: TiVec) -> Self { 72 | v.into_boxed_slice() 73 | } 74 | } 75 | 76 | impl FromIterator for Box> { 77 | #[inline] 78 | fn from_iter>(iter: T) -> Self { 79 | iter.into_iter().collect::>().into_boxed_slice() 80 | } 81 | } 82 | 83 | #[cfg(feature = "serde")] 84 | #[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "serde"))))] 85 | impl<'de, K, V> Deserialize<'de> for Box> 86 | where 87 | V: Deserialize<'de>, 88 | { 89 | #[inline] 90 | fn deserialize(deserializer: D) -> Result 91 | where 92 | D: Deserializer<'de>, 93 | { 94 | Box::<[V]>::deserialize(deserializer).map(Into::into) 95 | } 96 | } 97 | 98 | #[cfg(feature = "bincode")] 99 | #[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "bincode"))))] 100 | impl Decode for Box> 101 | where 102 | V: 'static + Decode, 103 | { 104 | #[inline] 105 | fn decode(decoder: &mut D) -> Result 106 | where 107 | D: Decoder, 108 | { 109 | Box::<[V]>::decode(decoder).map(Into::into) 110 | } 111 | } 112 | 113 | #[cfg(feature = "bincode")] 114 | #[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "bincode"))))] 115 | impl<'de, K, V, Context> BorrowDecode<'de, Context> for Box> 116 | where 117 | V: 'de + BorrowDecode<'de, Context>, 118 | { 119 | #[inline] 120 | fn borrow_decode(decoder: &mut D) -> Result 121 | where 122 | D: BorrowDecoder<'de, Context = Context>, 123 | { 124 | Box::<[V]>::borrow_decode(decoder).map(Into::into) 125 | } 126 | } 127 | 128 | #[expect(dead_code, unused_imports, unused_mut, reason = "okay in tests")] 129 | #[cfg(test)] 130 | mod test { 131 | use alloc::borrow::{Cow, ToOwned}; 132 | use alloc::boxed::Box; 133 | use alloc::ffi::CString; 134 | use alloc::string::ToString; 135 | use alloc::vec::Vec; 136 | use core::borrow::{Borrow, BorrowMut}; 137 | use core::hash::{Hash, Hasher}; 138 | use core::ops::Bound; 139 | #[cfg(feature = "std")] 140 | use std::hash::DefaultHasher; 141 | #[cfg(feature = "std")] 142 | use std::io::{IoSlice, Write}; 143 | 144 | use crate::test_util::{AsSliceAndCapacity, Id}; 145 | use crate::{TiSlice, TiVec}; 146 | 147 | #[test] 148 | fn test_boxed_slice_api_compatibility() { 149 | for v in [ 150 | &[0_u32; 0][..], 151 | &[1], 152 | &[1, 1234], 153 | &[1, 2, 4], 154 | &[1, 5, 3, 2], 155 | &[1, 1, 9, 2, 4, 1, 12345, 12], 156 | ] { 157 | let mut cv = (v, TiSlice::from_ref(v)); 158 | assert_eq_api!( 159 | cv, v => Box::>::from(v) == >>::default() 160 | ); 161 | assert_eq_api!(cv, v => Box::>::from(v).into_std()); 162 | assert_eq_api!(cv, v => Box::>::from(v).clone().into_std()); 163 | assert_eq_api!( 164 | cv, v => IntoIterator::into_iter(Box::>::from(v)).collect::>() 165 | ); 166 | assert_eq_api!(cv, v => TheVec::from(Box::>::from(v)).into_std()); 167 | assert_eq_api!(cv, v => Box::>::from(TheVec::from(v)).into_std()); 168 | assert_eq_api!(cv, v => v.iter().copied().collect::>>().into_std()); 169 | } 170 | } 171 | 172 | #[expect(clippy::unwrap_used, reason = "okay in tests")] 173 | #[cfg(feature = "serde")] 174 | #[test] 175 | fn test_boxed_slice_deserialize() { 176 | let s0: Box> = serde_json::from_str("[]").unwrap(); 177 | let s1: Box> = serde_json::from_str("[12]").unwrap(); 178 | let s2: Box> = serde_json::from_str("[23, 34]").unwrap(); 179 | assert_eq!(s0.as_ref().raw, [0; 0][..]); 180 | assert_eq!(s1.as_ref().raw, [12][..]); 181 | assert_eq!(s2.as_ref().raw, [23, 34][..]); 182 | } 183 | 184 | #[expect(clippy::unwrap_used, reason = "okay in tests")] 185 | #[cfg(feature = "bincode")] 186 | #[test] 187 | fn test_boxed_slice_decode() { 188 | fn decode_whole(bytes: &[u8]) -> Box> { 189 | let config = bincode::config::standard(); 190 | let (decoded, len) = bincode::decode_from_slice(bytes, config).unwrap(); 191 | assert_eq!(len, bytes.len()); 192 | decoded 193 | } 194 | 195 | let s0: Box> = decode_whole(&[0]); 196 | let s1: Box> = decode_whole(&[1, 12]); 197 | let s2: Box> = decode_whole(&[2, 23, 34]); 198 | let s3: Box> = 199 | decode_whole(&[2, 252, 0x78, 0x56, 0x34, 0x12, 252, 0x89, 0x67, 0x45, 0x23]); 200 | assert_eq!(s0.as_ref().raw, [0; 0][..]); 201 | assert_eq!(s1.as_ref().raw, [12][..]); 202 | assert_eq!(s2.as_ref().raw, [23, 34][..]); 203 | assert_eq!(s3.as_ref().raw, [0x1234_5678, 0x2345_6789][..]); 204 | } 205 | 206 | #[expect(clippy::unwrap_used, reason = "okay in tests")] 207 | #[cfg(feature = "bincode")] 208 | #[test] 209 | fn test_boxed_slice_borrow_decode() { 210 | fn decode_whole(bytes: &[u8]) -> Box> { 211 | let config = bincode::config::standard(); 212 | let (decoded, len) = bincode::borrow_decode_from_slice(bytes, config).unwrap(); 213 | assert_eq!(len, bytes.len()); 214 | decoded 215 | } 216 | 217 | let s0: Box> = decode_whole(&[0]); 218 | let s1: Box> = decode_whole(&[1, 1, b'a']); 219 | let s2: Box> = decode_whole(&[2, 2, b'b', b'c', 3, b'd', b'e', b'f']); 220 | assert_eq!(s0.as_ref().raw, [""; 0][..]); 221 | assert_eq!(s1.as_ref().raw, ["a"][..]); 222 | assert_eq!(s2.as_ref().raw, ["bc", "def"][..]); 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /src/slice/concat.rs: -------------------------------------------------------------------------------- 1 | use alloc::string::String; 2 | use core::borrow::Borrow; 3 | 4 | use crate::{TiSlice, TiVec}; 5 | 6 | /// A helper trait for [`TiSlice::concat`](crate::TiSlice#method.concat). 7 | pub trait Concat { 8 | /// The resulting type after concatenation 9 | type Output; 10 | 11 | /// Implementation of [`TiSlice::concat`](crate::TiSlice#method.concat) 12 | fn concat(slice: &Self) -> Self::Output; 13 | } 14 | 15 | impl> Concat for TiSlice { 16 | type Output = String; 17 | 18 | #[inline] 19 | fn concat(slice: &Self) -> Self::Output { 20 | slice.raw.concat() 21 | } 22 | } 23 | 24 | impl> Concat for TiSlice { 25 | type Output = TiVec; 26 | 27 | #[inline] 28 | fn concat(slice: &Self) -> Self::Output { 29 | slice.raw.concat().into() 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/slice/join.rs: -------------------------------------------------------------------------------- 1 | use alloc::string::String; 2 | use core::borrow::Borrow; 3 | 4 | use crate::{TiSlice, TiVec}; 5 | 6 | /// A helper trait for [`TiSlice::join`](crate::TiSlice#method.join) 7 | pub trait Join { 8 | /// The resulting type after concatenation 9 | type Output; 10 | 11 | /// Implementation of [`TiSlice::join`](crate::TiSlice#method.join) 12 | fn join(slice: &Self, sep: Separator) -> Self::Output; 13 | } 14 | 15 | impl> Join<&str> for TiSlice { 16 | type Output = String; 17 | 18 | #[inline] 19 | fn join(slice: &Self, sep: &str) -> Self::Output { 20 | slice.raw.join(sep) 21 | } 22 | } 23 | 24 | impl> Join<&T> for TiSlice { 25 | type Output = TiVec; 26 | 27 | #[inline] 28 | fn join(slice: &Self, sep: &T) -> Self::Output { 29 | slice.raw.join(sep).into() 30 | } 31 | } 32 | 33 | impl> Join<&[T]> for TiSlice { 34 | type Output = TiVec; 35 | 36 | #[inline] 37 | fn join(slice: &Self, sep: &[T]) -> Self::Output { 38 | slice.raw.join(sep).into() 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/slice/slice_index.rs: -------------------------------------------------------------------------------- 1 | use core::ops; 2 | 3 | use crate::{TiRangeBounds, TiSlice}; 4 | 5 | mod private { 6 | use core::ops; 7 | 8 | pub trait Sealed {} 9 | 10 | impl Sealed for K {} 11 | impl Sealed for ops::Range {} 12 | impl Sealed for ops::RangeTo {} 13 | impl Sealed for ops::RangeFrom {} 14 | impl Sealed for ops::RangeInclusive {} 15 | impl Sealed for ops::RangeToInclusive {} 16 | impl Sealed for (ops::Bound, ops::Bound) {} 17 | } 18 | 19 | /// A helper trait used for indexing operations. 20 | /// 21 | /// This trait is implemented for `K`, [`Range`], [`RangeTo`], 22 | /// [`RangeFrom`], [`RangeInclusive`] and [`RangeToInclusive`]. 23 | /// The [`RangeFull`] trait is not currently supported. 24 | /// 25 | /// Trait implementations are only forwards to standard Rust [`slice`] 26 | /// operations. 27 | /// 28 | /// [`slice`]: https://doc.rust-lang.org/std/primitive.slice.html 29 | /// [`Range`]: https://doc.rust-lang.org/std/ops/struct.Range.html 30 | /// [`RangeTo`]: https://doc.rust-lang.org/std/ops/struct.RangeTo.html 31 | /// [`RangeFrom`]: https://doc.rust-lang.org/std/ops/struct.RangeFrom.html 32 | /// [`RangeInclusive`]: https://doc.rust-lang.org/std/ops/struct.RangeInclusive.html 33 | /// [`RangeToInclusive`]: https://doc.rust-lang.org/std/ops/struct.RangeToInclusive.html 34 | /// [`RangeFull`]: https://doc.rust-lang.org/std/ops/struct.RangeFull.html 35 | pub trait TiSliceIndex: private::Sealed { 36 | /// The output type returned by methods. 37 | type Output: ?Sized; 38 | 39 | /// Returns a shared reference to the output at this location, if in 40 | /// bounds. 41 | fn get(self, slice: &TiSlice) -> Option<&Self::Output>; 42 | 43 | /// Returns a mutable reference to the output at this location, if in 44 | /// bounds. 45 | fn get_mut(self, slice: &mut TiSlice) -> Option<&mut Self::Output>; 46 | 47 | /// Returns a shared reference to the output at this location, without 48 | /// performing any bounds checking. 49 | /// 50 | /// # Safety 51 | /// 52 | /// Calling this method with an out-of-bounds index is 53 | /// *[undefined behavior]* even if the resulting reference is not used. 54 | /// 55 | /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html 56 | unsafe fn get_unchecked(self, slice: &TiSlice) -> &Self::Output; 57 | 58 | /// Returns a mutable reference to the output at this location, without 59 | /// performing any bounds checking. 60 | /// 61 | /// # Safety 62 | /// 63 | /// Calling this method with an out-of-bounds index is 64 | /// *[undefined behavior]* even if the resulting reference is not used. 65 | /// 66 | /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html 67 | unsafe fn get_unchecked_mut(self, slice: &mut TiSlice) -> &mut Self::Output; 68 | 69 | /// Returns a shared reference to the output at this location, panicking 70 | /// if out of bounds. 71 | fn index(self, slice: &TiSlice) -> &Self::Output; 72 | 73 | /// Returns a mutable reference to the output at this location, panicking 74 | /// if out of bounds. 75 | fn index_mut(self, slice: &mut TiSlice) -> &mut Self::Output; 76 | } 77 | 78 | impl TiSliceIndex for K 79 | where 80 | usize: From, 81 | { 82 | type Output = V; 83 | 84 | #[inline] 85 | fn get(self, slice: &TiSlice) -> Option<&Self::Output> { 86 | slice.raw.get(usize::from(self)) 87 | } 88 | 89 | #[inline] 90 | fn get_mut(self, slice: &mut TiSlice) -> Option<&mut Self::Output> { 91 | slice.raw.get_mut(usize::from(self)) 92 | } 93 | 94 | #[inline] 95 | unsafe fn get_unchecked(self, slice: &TiSlice) -> &Self::Output { 96 | // SAFETY: Guaranteed by the caller. 97 | unsafe { slice.raw.get_unchecked(usize::from(self)) } 98 | } 99 | 100 | #[inline] 101 | unsafe fn get_unchecked_mut(self, slice: &mut TiSlice) -> &mut Self::Output { 102 | // SAFETY: Guaranteed by the caller. 103 | unsafe { slice.raw.get_unchecked_mut(usize::from(self)) } 104 | } 105 | 106 | #[inline] 107 | fn index(self, slice: &TiSlice) -> &Self::Output { 108 | &slice.raw[usize::from(self)] 109 | } 110 | 111 | #[inline] 112 | fn index_mut(self, slice: &mut TiSlice) -> &mut Self::Output { 113 | &mut slice.raw[usize::from(self)] 114 | } 115 | } 116 | 117 | macro_rules! impl_ti_slice_range { 118 | ($ty:ty) => { 119 | impl TiSliceIndex for $ty 120 | where 121 | usize: From, 122 | { 123 | type Output = TiSlice; 124 | 125 | #[inline] 126 | fn get(self, slice: &TiSlice) -> Option<&Self::Output> { 127 | slice.raw.get(self.into_range()).map(TiSlice::from_ref) 128 | } 129 | 130 | #[inline] 131 | fn get_mut(self, slice: &mut TiSlice) -> Option<&mut Self::Output> { 132 | slice.raw.get_mut(self.into_range()).map(TiSlice::from_mut) 133 | } 134 | 135 | #[inline] 136 | unsafe fn get_unchecked(self, slice: &TiSlice) -> &Self::Output { 137 | // SAFETY: Guaranteed by the caller. 138 | TiSlice::from_ref(unsafe { slice.raw.get_unchecked(self.into_range()) }) 139 | } 140 | 141 | #[inline] 142 | unsafe fn get_unchecked_mut(self, slice: &mut TiSlice) -> &mut Self::Output { 143 | // SAFETY: Guaranteed by the caller. 144 | TiSlice::from_mut(unsafe { slice.raw.get_unchecked_mut(self.into_range()) }) 145 | } 146 | 147 | #[inline] 148 | fn index(self, slice: &TiSlice) -> &Self::Output { 149 | TiSlice::from_ref(&slice.raw[self.into_range()]) 150 | } 151 | 152 | #[inline] 153 | fn index_mut(self, slice: &mut TiSlice) -> &mut Self::Output { 154 | TiSlice::from_mut(&mut slice.raw[self.into_range()]) 155 | } 156 | } 157 | }; 158 | } 159 | 160 | impl_ti_slice_range!(ops::Range); 161 | impl_ti_slice_range!(ops::RangeFrom); 162 | impl_ti_slice_range!(ops::RangeInclusive); 163 | impl_ti_slice_range!(ops::RangeTo); 164 | impl_ti_slice_range!(ops::RangeToInclusive); 165 | impl_ti_slice_range!((ops::Bound, ops::Bound)); 166 | -------------------------------------------------------------------------------- /src/test_util.rs: -------------------------------------------------------------------------------- 1 | // This module is used only for tests. 2 | 3 | use alloc::vec::Vec; 4 | 5 | use derive_more::{From, Into}; 6 | 7 | use crate::TiSlice; 8 | 9 | #[derive(From, Into, Clone, Copy, Debug, Eq, PartialEq)] 10 | pub struct Id(usize); 11 | 12 | pub trait IntoStdType { 13 | type Std; 14 | fn into_std(self) -> Self::Std; 15 | } 16 | 17 | pub trait IntoTicType { 18 | type Tic; 19 | fn into_tic(self) -> Self::Tic; 20 | } 21 | 22 | pub trait MapIntoStdType { 23 | type StdIter; 24 | fn map_into_std(self) -> Self::StdIter; 25 | } 26 | 27 | impl MapIntoStdType for I 28 | where 29 | I: IntoIterator, 30 | T: IntoStdType, 31 | { 32 | type StdIter = MapIntoStdIter; 33 | 34 | fn map_into_std(self) -> Self::StdIter { 35 | MapIntoStdIter(self.into_iter()) 36 | } 37 | } 38 | 39 | pub struct MapIntoStdIter(I); 40 | 41 | impl Iterator for MapIntoStdIter 42 | where 43 | I: Iterator, 44 | T: IntoStdType, 45 | { 46 | type Item = T::Std; 47 | 48 | #[inline] 49 | fn next(&mut self) -> Option { 50 | self.0.next().map(T::into_std) 51 | } 52 | } 53 | 54 | pub trait FakeConversion: Sized { 55 | fn into_std(self) -> Self { 56 | self 57 | } 58 | 59 | fn into_tic(self) -> Self { 60 | self 61 | } 62 | 63 | fn map_into_std(self) -> Self { 64 | self 65 | } 66 | } 67 | 68 | impl FakeConversion for T {} 69 | 70 | pub trait CollectToVec: Sized + IntoIterator { 71 | fn collect_to_vec(self) -> Vec<::Item> { 72 | self.into_iter().collect() 73 | } 74 | } 75 | 76 | impl CollectToVec for T where T: IntoIterator {} 77 | 78 | pub trait Reborrow { 79 | type Output<'a> 80 | where 81 | Self: 'a; 82 | fn reborrow(&mut self) -> Self::Output<'_>; 83 | } 84 | 85 | impl Reborrow for &T 86 | where 87 | T: ?Sized, 88 | { 89 | type Output<'a> 90 | = &'a T 91 | where 92 | Self: 'a; 93 | 94 | fn reborrow(&mut self) -> Self::Output<'_> { 95 | &**self 96 | } 97 | } 98 | 99 | impl Reborrow for &mut T 100 | where 101 | T: ?Sized, 102 | { 103 | type Output<'a> 104 | = &'a mut T 105 | where 106 | Self: 'a; 107 | 108 | fn reborrow(&mut self) -> Self::Output<'_> { 109 | &mut **self 110 | } 111 | } 112 | 113 | pub trait AsSliceAndCapacity { 114 | type Item; 115 | fn as_slice_and_capacity(&self) -> (&[Self::Item], usize); 116 | } 117 | 118 | impl AsSliceAndCapacity for &T 119 | where 120 | T: ?Sized + AsSliceAndCapacity, 121 | { 122 | type Item = T::Item; 123 | fn as_slice_and_capacity(&self) -> (&[Self::Item], usize) { 124 | T::as_slice_and_capacity(self) 125 | } 126 | } 127 | 128 | impl AsSliceAndCapacity for &mut T 129 | where 130 | T: ?Sized + AsSliceAndCapacity, 131 | { 132 | type Item = T::Item; 133 | fn as_slice_and_capacity(&self) -> (&[Self::Item], usize) { 134 | T::as_slice_and_capacity(self) 135 | } 136 | } 137 | 138 | impl AsSliceAndCapacity for [T] { 139 | type Item = T; 140 | fn as_slice_and_capacity(&self) -> (&[Self::Item], usize) { 141 | (self, self.len()) 142 | } 143 | } 144 | 145 | impl AsSliceAndCapacity for TiSlice { 146 | type Item = V; 147 | fn as_slice_and_capacity(&self) -> (&[Self::Item], usize) { 148 | (self.as_ref(), self.len()) 149 | } 150 | } 151 | 152 | #[cfg(feature = "alloc")] 153 | impl AsSliceAndCapacity for Vec { 154 | type Item = T; 155 | fn as_slice_and_capacity(&self) -> (&[Self::Item], usize) { 156 | let capacity = self.capacity(); 157 | (self, capacity) 158 | } 159 | } 160 | 161 | #[cfg(feature = "alloc")] 162 | impl AsSliceAndCapacity for crate::TiVec { 163 | type Item = V; 164 | fn as_slice_and_capacity(&self) -> (&[Self::Item], usize) { 165 | let capacity = self.capacity(); 166 | (self.as_ref(), capacity) 167 | } 168 | } 169 | 170 | macro_rules! impl_into_std { 171 | ( 172 | $( for [$($args:tt)*] )?, 173 | $source:ty => $target:ty, 174 | $self:ident => $expr:expr 175 | $(, where $($bounds:tt)* )? 176 | ) => { 177 | impl $( < $($args)* > )? IntoStdType for $source 178 | $( where $($bounds)* )? 179 | { 180 | type Std = $target; 181 | fn into_std($self) -> Self::Std { 182 | $expr 183 | } 184 | } 185 | }; 186 | } 187 | 188 | macro_rules! impl_into_tic { 189 | ( 190 | $( for [ $($args:tt)* ] )?, 191 | $source:ty => $target:ty, 192 | $self:ident => $expr:expr 193 | $(, where $($bounds:tt)* )? 194 | ) => { 195 | impl $( < $($args)* > )? IntoTicType for $source 196 | $( where $($bounds)* )? 197 | { 198 | type Tic = $target; 199 | fn into_tic($self) -> Self::Tic { 200 | $expr 201 | } 202 | } 203 | }; 204 | } 205 | 206 | mod core_impls { 207 | #[cfg(feature = "alloc")] 208 | use alloc::borrow::Cow; 209 | use core::ops::{Bound, Range, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive}; 210 | 211 | use crate::test_util::{Id, IntoStdType, IntoTicType}; 212 | use crate::TiSlice; 213 | 214 | impl_into_tic!(, usize => Id, self => self.into()); 215 | impl_into_std!(, Id => usize, self => self.into()); 216 | impl_into_tic!(for ['a, T], &'a [T] => &'a TiSlice, self => self.as_ref()); 217 | impl_into_std!(for ['a, T], &'a TiSlice => &'a [T], self => self.as_ref()); 218 | impl_into_tic!(for ['a, T], &'a mut [T] => &'a mut TiSlice, self => self.as_mut()); 219 | impl_into_std!(for ['a, T], &'a mut TiSlice => &'a mut [T], self => self.as_mut()); 220 | 221 | impl_into_tic!(, 222 | Range => Range, 223 | self => self.start.into_tic()..self.end.into_tic() 224 | ); 225 | impl_into_tic!(, 226 | RangeInclusive => RangeInclusive, 227 | self => self.start().into_tic()..=self.end().into_tic() 228 | ); 229 | impl_into_tic!(,RangeFrom => RangeFrom, self => self.start.into_tic()..); 230 | impl_into_tic!(,RangeTo => RangeTo, self => ..self.end.into_tic()); 231 | impl_into_tic!(, 232 | RangeToInclusive => RangeToInclusive, 233 | self => ..=self.end.into_tic() 234 | ); 235 | impl_into_tic!(, 236 | (Bound, Bound) => (Bound, Bound), 237 | self => (self.0.into_tic(), self.1.into_tic()) 238 | ); 239 | impl_into_tic!(, 240 | Bound => Bound, 241 | self => match self { 242 | Bound::Included(index) => Bound::Included(index.into_tic()), 243 | Bound::Excluded(index) => Bound::Excluded(index.into_tic()), 244 | Bound::Unbounded => Bound::Unbounded, 245 | } 246 | ); 247 | 248 | impl_into_tic!( 249 | for [T, U], 250 | Option => Option, 251 | self => self.map(IntoTicType::into_tic), 252 | where T: IntoTicType 253 | ); 254 | impl_into_std!( 255 | for [T, U], 256 | Option => Option, 257 | self => self.map(IntoStdType::into_std), 258 | where T: IntoStdType 259 | ); 260 | impl_into_tic!( 261 | for [T, U, E, Y], 262 | Result => Result, 263 | self => self.map(IntoTicType::into_tic).map_err(IntoTicType::into_tic), 264 | where T: IntoTicType, E: IntoTicType 265 | ); 266 | impl_into_std!( 267 | for [T, U, E, Y], 268 | Result => Result, 269 | self => self.map(IntoStdType::into_std).map_err(IntoStdType::into_std), 270 | where T: IntoStdType, E: IntoStdType 271 | ); 272 | 273 | #[cfg(feature = "alloc")] 274 | impl_into_std!( 275 | for ['a, T], Cow<'a, TiSlice> => Cow<'a, [T]>, 276 | self => match self { 277 | Cow::Borrowed(value) => Cow::Borrowed(value.as_ref()), 278 | Cow::Owned(value) => Cow::Owned(value.into()), 279 | }, 280 | where T: Clone 281 | ); 282 | 283 | impl_into_std!( 284 | for ['a, T, U], 285 | (&'a TiSlice, &'a TiSlice) => (&'a [T], &'a [U]), 286 | self => (self.0.into_std(), self.1.into_std()) 287 | ); 288 | impl_into_std!( 289 | for ['a, T, U], 290 | (&'a mut TiSlice, &'a mut TiSlice) => (&'a mut [T], &'a mut [U]), 291 | self => (self.0.into_std(), self.1.into_std()) 292 | ); 293 | impl_into_std!( 294 | for ['a, T, U, V], 295 | (&'a TiSlice, &'a TiSlice, &'a TiSlice) => (&'a [T], &'a [U], &'a [V]), 296 | self => (self.0.into_std(), self.1.into_std(), self.2.into_std()) 297 | ); 298 | impl_into_std!( 299 | for ['a, T, U, V], 300 | ( 301 | &'a mut TiSlice, &'a mut TiSlice, &'a mut TiSlice 302 | ) => (&'a mut [T], &'a mut [U], &'a mut [V]), 303 | self => (self.0.into_std(), self.1.into_std(), self.2.into_std()) 304 | ); 305 | 306 | impl_into_std!( 307 | for ['a, T], 308 | (&'a T, &'a TiSlice) => (&'a T, &'a [T]), 309 | self => (self.0, self.1.into_std()) 310 | ); 311 | impl_into_std!( 312 | for ['a, T], 313 | (&'a mut T, &'a mut TiSlice) => (&'a mut T, &'a mut [T]), 314 | self => (self.0, self.1.into_std()) 315 | ); 316 | impl_into_std!( 317 | for ['a, T, U, V], 318 | (&'a TiSlice, &'a U, &'a TiSlice) => (&'a [T], &'a U, &'a [V]), 319 | self => (self.0.into_std(), self.1, self.2.into_std()) 320 | ); 321 | impl_into_std!( 322 | for ['a, T, U, V], 323 | ( 324 | &'a mut TiSlice, &'a mut U, &'a mut TiSlice 325 | ) => (&'a mut [T], &'a mut U, &'a mut [V]), 326 | self => (self.0.into_std(), self.1, self.2.into_std()) 327 | ); 328 | 329 | #[cfg(feature = "alloc")] 330 | impl_into_std!( 331 | for ['a, T], 332 | alloc::vec::Vec<&'a TiSlice> => alloc::vec::Vec<&'a [T]>, 333 | self => self.into_iter().map(TiSlice::as_ref).collect() 334 | ); 335 | #[cfg(feature = "alloc")] 336 | impl_into_std!( 337 | for ['a, T], 338 | alloc::vec::Vec<&'a mut TiSlice> => alloc::vec::Vec<&'a mut [T]>, 339 | self => self.into_iter().map(TiSlice::as_mut).collect() 340 | ); 341 | } 342 | 343 | #[cfg(feature = "alloc")] 344 | mod alloc_impls { 345 | use alloc::boxed::Box; 346 | use alloc::vec::Vec; 347 | 348 | use crate::test_util::{Id, IntoStdType, IntoTicType}; 349 | use crate::{TiSlice, TiVec}; 350 | 351 | impl_into_tic!(for [T], Box<[T]> => Box>, self => self.into()); 352 | impl_into_std!(for [T], Box> => Box<[T]>, self => self.into()); 353 | impl_into_tic!(for [T], Vec => TiVec, self => self.into()); 354 | impl_into_std!(for [T], TiVec => Vec, self => self.into()); 355 | impl_into_tic!(for ['a, T], &'a Vec => &'a TiVec, self => self.as_ref()); 356 | impl_into_std!(for ['a, T], &'a TiVec => &'a Vec, self => self.as_ref()); 357 | impl_into_tic!(for ['a, T], &'a mut Vec => &'a mut TiVec, self => self.as_mut()); 358 | impl_into_std!(for ['a, T], &'a mut TiVec => &'a mut Vec, self => self.as_mut()); 359 | } 360 | 361 | macro_rules! assert_eq_api { 362 | ($in_value:expr, $in_arg:ident => $expr:expr) => {{ 363 | let (std_in, tic_in) = ( 364 | $crate::test_util::Reborrow::reborrow(&mut $in_value.0), 365 | $crate::test_util::Reborrow::reborrow(&mut $in_value.1), 366 | ); 367 | let mut $in_arg = std_in; 368 | let std_out = { 369 | use crate::test_util::FakeConversion; 370 | type TheSlice = [T]; 371 | #[cfg(feature = "alloc")] 372 | type TheVec = alloc::vec::Vec; 373 | $expr 374 | }; 375 | let mut $in_arg = tic_in; 376 | let tic_out = { 377 | use crate::test_util::{IntoStdType, IntoTicType, MapIntoStdType}; 378 | type TheSlice = crate::TiSlice; 379 | #[cfg(feature = "alloc")] 380 | type TheVec = crate::TiVec; 381 | $expr 382 | }; 383 | 384 | assert_eq!(tic_out, std_out, "where expr: {}", stringify!($expr)); 385 | assert_eq!( 386 | crate::test_util::AsSliceAndCapacity::as_slice_and_capacity(&$in_value.0), 387 | crate::test_util::AsSliceAndCapacity::as_slice_and_capacity(&$in_value.1), 388 | "where expr: {}", 389 | stringify!($expr) 390 | ); 391 | }}; 392 | } 393 | -------------------------------------------------------------------------------- /src/vec.rs: -------------------------------------------------------------------------------- 1 | use alloc::borrow::Cow; 2 | use alloc::boxed::Box; 3 | use alloc::collections::TryReserveError; 4 | use alloc::ffi::CString; 5 | use alloc::string::String; 6 | use alloc::vec::{self, Drain, Splice, Vec}; 7 | use core::borrow::{Borrow, BorrowMut}; 8 | use core::cmp::Ordering; 9 | use core::hash::{Hash, Hasher}; 10 | use core::iter::FromIterator; 11 | use core::marker::PhantomData; 12 | use core::mem::MaybeUninit; 13 | use core::ops::{Deref, DerefMut, Index, IndexMut, RangeBounds}; 14 | use core::{fmt, slice}; 15 | #[cfg(feature = "std")] 16 | use std::io::{IoSlice, Result as IoResult, Write}; 17 | 18 | #[cfg(feature = "bincode")] 19 | use bincode::de::{BorrowDecode, BorrowDecoder, Decode, Decoder}; 20 | #[cfg(feature = "bincode")] 21 | use bincode::enc::{Encode, Encoder}; 22 | #[cfg(feature = "bincode")] 23 | use bincode::error::{DecodeError, EncodeError}; 24 | #[cfg(all(feature = "alloc", feature = "serde"))] 25 | use serde::de::{Deserialize, Deserializer}; 26 | #[cfg(feature = "serde")] 27 | use serde::ser::{Serialize, Serializer}; 28 | 29 | use crate::{TiEnumerated, TiRangeBounds, TiSlice, TiSliceIndex}; 30 | 31 | /// A contiguous growable array type 32 | /// that only accepts keys of the type `K`. 33 | /// 34 | /// `TiVec` is a wrapper around Rust container type [`std::vec::Vec`]. 35 | /// The struct mirrors the stable API of Rust [`std::vec::Vec`] 36 | /// and forwards to it as much as possible. 37 | /// 38 | /// `TiVec` uses `K` instead of `usize` for element indices and 39 | /// require the index to implement 40 | /// [`From`][`From`] and [`Into`][`Into`] traits. 41 | /// Their implementation can be easily done 42 | /// with [`derive_more`] crate and `#[derive(From, Into)]`. 43 | /// 44 | /// `TiVec` can be converted to [`std::vec::Vec`][`std::vec::Vec`] and 45 | /// back using [`From`] and [`Into`]. 46 | /// 47 | /// There are also zero-cost conversions available between references: 48 | /// - [`&std::vec::Vec`][`std::vec::Vec`] and `&TiVec` with [`AsRef`], 49 | /// - [`&mut std::vec::Vec`][`std::vec::Vec`] and `&mut TiVec` with 50 | /// [`AsMut`], 51 | /// 52 | /// Added methods: 53 | /// - [`from_ref`] - Converts a [`&std::vec::Vec`][`std::vec::Vec`] into a 54 | /// `&TiVec`. 55 | /// - [`from_mut`] - Converts a [`&mut std::vec::Vec`][`std::vec::Vec`] into 56 | /// a `&mut TiVec`. 57 | /// - [`push_and_get_key`] - Appends an element to the back of a collection and 58 | /// returns its index of type `K`. 59 | /// - [`pop_key_value`] - Removes the last element from a vector and returns it 60 | /// with its index of type `K`, or [`None`] if the vector is empty. 61 | /// - [`drain_enumerated`] - Creates a draining iterator that removes the 62 | /// specified range in the vector and yields the current count and the removed 63 | /// items. It acts like `self.drain(range).enumerate()`, but instead of 64 | /// `usize` it returns index of type `K`. 65 | /// - [`into_iter_enumerated`] - Converts the vector into iterator over all 66 | /// key-value pairs with `K` used for iteration indices. It acts like 67 | /// `self.into_iter().enumerate()`, but use `K` instead of `usize` for 68 | /// iteration indices. 69 | /// 70 | /// # Example 71 | /// 72 | /// ``` 73 | /// use derive_more::{From, Into}; 74 | /// use typed_index_collections::TiVec; 75 | /// 76 | /// #[derive(From, Into)] 77 | /// struct FooId(usize); 78 | /// 79 | /// let mut foos: TiVec = std::vec![10, 11, 13].into(); 80 | /// foos.insert(FooId(2), 12); 81 | /// assert_eq!(foos[FooId(2)], 12); 82 | /// ``` 83 | /// 84 | /// [`from_ref`]: #method.from_ref 85 | /// [`from_mut`]: #method.from_mut 86 | /// [`push_and_get_key`]: #method.push_and_get_key 87 | /// [`pop_key_value`]: #method.pop_key_value 88 | /// [`drain_enumerated`]: #method.drain_enumerated 89 | /// [`into_iter_enumerated`]: #method.into_iter_enumerated 90 | /// [`std::vec::Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html 91 | /// [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html 92 | /// [`Into`]: https://doc.rust-lang.org/std/convert/trait.Into.html 93 | /// [`AsRef`]: https://doc.rust-lang.org/std/convert/trait.AsRef.html 94 | /// [`AsMut`]: https://doc.rust-lang.org/std/convert/trait.AsMut.html 95 | /// [`derive_more`]: https://crates.io/crates/derive_more 96 | #[repr(transparent)] 97 | pub struct TiVec { 98 | /// Raw slice property 99 | pub raw: Vec, 100 | 101 | /// Tied slice index type 102 | /// 103 | /// `fn(T) -> T` is *[PhantomData pattern][phantomdata patterns]* 104 | /// used to relax auto trait implementations bounds for 105 | /// [`Send`], [`Sync`], [`Unpin`], [`UnwindSafe`] and [`RefUnwindSafe`]. 106 | /// 107 | /// Derive attribute is not used for trait implementations because it also 108 | /// requires the same trait implemented for K that is an unnecessary 109 | /// requirement. 110 | /// 111 | /// [phantomdata patterns]: https://doc.rust-lang.org/nomicon/phantom-data.html#table-of-phantomdata-patterns 112 | /// [`Send`]: https://doc.rust-lang.org/core/marker/trait.Send.html 113 | /// [`Sync`]: https://doc.rust-lang.org/core/marker/trait.Sync.html 114 | /// [`Unpin`]: https://doc.rust-lang.org/core/marker/trait.Unpin.html 115 | /// [`UnwindSafe`]: https://doc.rust-lang.org/core/std/panic/trait.UnwindSafe.html 116 | /// [`RefUnwindSafe`]: https://doc.rust-lang.org/core/std/panic/trait.RefUnwindSafe.html 117 | _marker: PhantomData K>, 118 | } 119 | 120 | impl TiVec { 121 | /// Constructs a new, empty `TiVec`. 122 | /// 123 | /// See [`Vec::new`] for more details. 124 | /// 125 | /// [`Vec::new`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.new 126 | #[inline] 127 | #[must_use] 128 | pub const fn new() -> Self { 129 | Self { 130 | raw: Vec::new(), 131 | _marker: PhantomData, 132 | } 133 | } 134 | 135 | /// Constructs a new, empty `TiVec` with the specified capacity. 136 | /// 137 | /// See [`Vec::with_capacity`] for more details. 138 | /// 139 | /// [`Vec::with_capacity`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.with_capacity 140 | #[inline] 141 | #[must_use] 142 | pub fn with_capacity(capacity: usize) -> Self { 143 | Self { 144 | raw: Vec::with_capacity(capacity), 145 | _marker: PhantomData, 146 | } 147 | } 148 | 149 | /// Creates a `TiVec` directly from the raw components of another 150 | /// vector. 151 | /// 152 | /// See [`Vec::from_raw_parts`] for more details. 153 | /// 154 | /// # Safety 155 | /// 156 | /// This is highly unsafe, due to the number of invariants that aren't 157 | /// checked. 158 | /// See [`Vec::from_raw_parts`] for more details. 159 | /// 160 | /// [`Vec::from_raw_parts`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.from_raw_parts 161 | #[inline] 162 | pub unsafe fn from_raw_parts(ptr: *mut V, length: usize, capacity: usize) -> Self { 163 | Self { 164 | // SAFETY: Guaranteed by the caller. 165 | raw: unsafe { Vec::from_raw_parts(ptr, length, capacity) }, 166 | _marker: PhantomData, 167 | } 168 | } 169 | 170 | /// Converts a [`&std::vec::Vec`] into a `&TiVec`. 171 | /// 172 | /// Vector reference is intentionally used in the argument 173 | /// instead of slice reference for conversion with no-op. 174 | /// 175 | /// # Example 176 | /// 177 | /// ``` 178 | /// # use typed_index_collections::TiVec; 179 | /// pub struct Id(usize); 180 | /// let vec: &TiVec = TiVec::from_ref(&vec![1, 2, 4]); 181 | /// ``` 182 | /// 183 | /// [`&std::vec::Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html 184 | #[inline] 185 | #[must_use] 186 | pub const fn from_ref(raw: &Vec) -> &Self { 187 | // SAFETY: `TiVec` is `repr(transparent)` over a `Vec` type. 188 | unsafe { &*core::ptr::from_ref::>(raw).cast::() } 189 | } 190 | 191 | /// Converts a [`&mut std::vec::Vec`] into a `&mut TiVec`. 192 | /// 193 | /// # Example 194 | /// 195 | /// ``` 196 | /// # use typed_index_collections::TiVec; 197 | /// pub struct Id(usize); 198 | /// let vec: &mut TiVec = TiVec::from_mut(&mut vec![1, 2, 4]); 199 | /// ``` 200 | /// 201 | /// [`&mut std::vec::Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html 202 | #[inline] 203 | pub fn from_mut(raw: &mut Vec) -> &mut Self { 204 | // SAFETY: `TiVec` is `repr(transparent)` over a `Vec` type. 205 | unsafe { &mut *core::ptr::from_mut::>(raw).cast::() } 206 | } 207 | 208 | /// Returns the number of elements the vector can hold without 209 | /// reallocating. 210 | /// 211 | /// See [`Vec::capacity`] for more details. 212 | /// 213 | /// [`Vec::capacity`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.capacity 214 | #[inline] 215 | #[must_use] 216 | pub fn capacity(&self) -> usize { 217 | self.raw.capacity() 218 | } 219 | 220 | /// Reserves capacity for at least `additional` more elements to be inserted 221 | /// in the given `TiVec`. The collection may reserve more space to 222 | /// avoid frequent reallocations. After calling `reserve`, capacity will 223 | /// be greater than or equal to `self.len() + additional`. Does nothing 224 | /// if capacity is already sufficient. 225 | /// 226 | /// See [`Vec::reserve`] for more details. 227 | /// 228 | /// [`Vec::reserve`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.reserve 229 | #[inline] 230 | pub fn reserve(&mut self, additional: usize) { 231 | self.raw.reserve(additional); 232 | } 233 | 234 | /// Reserves the minimum capacity for exactly `additional` more elements to 235 | /// be inserted in the given `TiVec`. After calling `reserve_exact`, 236 | /// capacity will be greater than or equal to `self.len() + additional`. 237 | /// Does nothing if the capacity is already sufficient. 238 | /// 239 | /// See [`Vec::reserve_exact`] for more details. 240 | /// 241 | /// [`Vec::reserve_exact`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.reserve_exact 242 | #[inline] 243 | pub fn reserve_exact(&mut self, additional: usize) { 244 | self.raw.reserve_exact(additional); 245 | } 246 | 247 | /// Tries to reserve capacity for at least `additional` more elements to be 248 | /// inserted in the given `Vec`. 249 | /// 250 | /// See [`Vec::try_reserve`] for more details. 251 | /// 252 | /// # Errors 253 | /// 254 | /// If the capacity overflows, or the allocator reports a failure, then an 255 | /// error is returned. 256 | /// 257 | /// [`Vec::try_reserve`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.try_reserve 258 | #[inline] 259 | pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { 260 | self.raw.try_reserve(additional) 261 | } 262 | 263 | /// Tries to reserve the minimum capacity for at least `additional` 264 | /// elements to be inserted in the given `Vec`. 265 | /// 266 | /// See [`Vec::try_reserve_exact`] for more details. 267 | /// 268 | /// # Errors 269 | /// 270 | /// If the capacity overflows, or the allocator reports a failure, then an 271 | /// error is returned. 272 | /// 273 | /// [`Vec::try_reserve_exact`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.try_reserve_exact 274 | #[inline] 275 | pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { 276 | self.raw.try_reserve_exact(additional) 277 | } 278 | 279 | /// Shrinks the capacity of the vector as much as possible. 280 | /// 281 | /// See [`Vec::shrink_to_fit`] for more details. 282 | /// 283 | /// [`Vec::shrink_to_fit`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.shrink_to_fit 284 | #[inline] 285 | pub fn shrink_to_fit(&mut self) { 286 | self.raw.shrink_to_fit(); 287 | } 288 | 289 | /// Shrinks the capacity of the vector with a lower bound. 290 | /// 291 | /// See [`Vec::shrink_to`] for more details. 292 | /// 293 | /// [`Vec::shrink_to`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.shrink_to 294 | #[inline] 295 | pub fn shrink_to(&mut self, min_capacity: usize) { 296 | self.raw.shrink_to(min_capacity); 297 | } 298 | /// Converts the vector into [`Box>`][`Box`]. 299 | /// 300 | /// See [`Vec::into_boxed_slice`] for more details. 301 | /// 302 | /// [`Vec::into_boxed_slice`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.into_boxed_slice 303 | /// [`Box`]: https://doc.rust-lang.org/std/boxed/struct.Box.html 304 | #[inline] 305 | #[must_use] 306 | pub fn into_boxed_slice(self) -> Box> { 307 | self.raw.into_boxed_slice().into() 308 | } 309 | 310 | /// Shortens the vector, keeping the first `len` elements and dropping 311 | /// the rest. 312 | /// 313 | /// See [`Vec::truncate`] for more details. 314 | /// 315 | /// [`Vec::truncate`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.truncate 316 | #[inline] 317 | pub fn truncate(&mut self, len: usize) { 318 | self.raw.truncate(len); 319 | } 320 | 321 | /// Extracts a slice containing the entire vector. 322 | /// 323 | /// See [`Vec::as_slice`] for more details. 324 | /// 325 | /// [`Vec::as_slice`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.as_slice 326 | #[inline] 327 | #[must_use] 328 | pub fn as_slice(&self) -> &TiSlice { 329 | self.raw.as_slice().as_ref() 330 | } 331 | 332 | /// Extracts a mutable slice of the entire vector. 333 | /// 334 | /// See [`Vec::as_mut_slice`] for more details. 335 | /// 336 | /// [`Vec::as_mut_slice`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.as_mut_slice 337 | #[inline] 338 | pub fn as_mut_slice(&mut self) -> &mut TiSlice { 339 | self.raw.as_mut_slice().as_mut() 340 | } 341 | 342 | /// Returns a raw pointer to the vector's buffer. 343 | /// 344 | /// See [`Vec::as_ptr`] for more details. 345 | /// 346 | /// [`Vec::as_ptr`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.as_ptr 347 | #[inline] 348 | #[must_use] 349 | pub fn as_ptr(&self) -> *const V { 350 | self.raw.as_ptr() 351 | } 352 | 353 | /// Returns an unsafe mutable pointer to the vector's buffer. 354 | /// 355 | /// See [`Vec::as_mut_ptr`] for more details. 356 | /// 357 | /// [`Vec::as_mut_ptr`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.as_mut_ptr 358 | #[inline] 359 | pub fn as_mut_ptr(&mut self) -> *mut V { 360 | self.raw.as_mut_ptr() 361 | } 362 | 363 | /// Forces the length of the vector to `new_len`. 364 | /// 365 | /// See [`Vec::set_len`] for more details. 366 | /// 367 | /// # Safety 368 | /// 369 | /// - `new_len` must be less than or equal to [`capacity()`]. 370 | /// - The elements at `old_len..new_len` must be initialized. 371 | /// 372 | /// [`Vec::set_len`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.set_len 373 | /// [`capacity()`]: #method.capacity 374 | #[inline] 375 | pub unsafe fn set_len(&mut self, new_len: usize) { 376 | // SAFETY: Guaranteed by the caller. 377 | unsafe { self.raw.set_len(new_len) }; 378 | } 379 | 380 | /// Removes an element from the vector and returns it. 381 | /// 382 | /// The removed element is replaced by the last element of the vector. 383 | /// 384 | /// See [`Vec::swap_remove`] for more details. 385 | /// 386 | /// [`Vec::swap_remove`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.swap_remove 387 | #[inline] 388 | pub fn swap_remove(&mut self, index: K) -> V 389 | where 390 | usize: From, 391 | { 392 | self.raw.swap_remove(index.into()) 393 | } 394 | 395 | /// Inserts an element at position `index` within the vector, shifting all 396 | /// elements after it to the right. 397 | /// 398 | /// See [`Vec::insert`] for more details. 399 | /// 400 | /// [`Vec::insert`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.insert 401 | #[inline] 402 | pub fn insert(&mut self, index: K, element: V) 403 | where 404 | usize: From, 405 | { 406 | self.raw.insert(index.into(), element); 407 | } 408 | 409 | /// Removes and returns the element at position `index` within the vector, 410 | /// shifting all elements after it to the left. 411 | /// 412 | /// See [`Vec::remove`] for more details. 413 | /// 414 | /// [`Vec::remove`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.remove 415 | #[inline] 416 | pub fn remove(&mut self, index: K) -> V 417 | where 418 | usize: From, 419 | { 420 | self.raw.remove(index.into()) 421 | } 422 | 423 | /// Retains only the elements specified by the predicate. 424 | /// 425 | /// See [`Vec::retain`] for more details. 426 | /// 427 | /// [`Vec::retain`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.retain 428 | #[inline] 429 | pub fn retain(&mut self, f: F) 430 | where 431 | F: FnMut(&V) -> bool, 432 | { 433 | self.raw.retain(f); 434 | } 435 | 436 | /// Retains only the elements specified by the predicate, passing a mutable 437 | /// reference to it. 438 | /// 439 | /// See [`Vec::retain_mut`] for more details. 440 | /// 441 | /// [`Vec::retain_mut`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.retain_mut 442 | #[inline] 443 | pub fn retain_mut(&mut self, f: F) 444 | where 445 | F: FnMut(&mut V) -> bool, 446 | { 447 | self.raw.retain_mut(f); 448 | } 449 | 450 | /// Removes all but the first of consecutive elements in the vector that 451 | /// resolve to the same key. 452 | /// 453 | /// See [`Vec::dedup_by_key`] for more details. 454 | /// 455 | /// [`Vec::dedup_by_key`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.dedup_by_key 456 | #[inline] 457 | pub fn dedup_by_key(&mut self, key: F) 458 | where 459 | F: FnMut(&mut V) -> K2, 460 | K2: PartialEq, 461 | { 462 | self.raw.dedup_by_key(key); 463 | } 464 | 465 | /// Removes all but the first of consecutive elements in the vector 466 | /// satisfying a given equality relation. 467 | /// 468 | /// See [`Vec::dedup_by`] for more details. 469 | /// 470 | /// [`Vec::dedup_by`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.dedup_by 471 | #[inline] 472 | pub fn dedup_by(&mut self, same_bucket: F) 473 | where 474 | F: FnMut(&mut V, &mut V) -> bool, 475 | { 476 | self.raw.dedup_by(same_bucket); 477 | } 478 | 479 | /// Appends an element to the back of a collection. 480 | /// 481 | /// See [`Vec::push`] for more details. 482 | /// 483 | /// [`Vec::push`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.push 484 | #[inline] 485 | pub fn push(&mut self, value: V) { 486 | self.raw.push(value); 487 | } 488 | 489 | /// Appends an element to the back of a collection and returns its index of 490 | /// type `K`. 491 | /// 492 | /// It acts like `{ vec.push(...); vec.last_key().unwrap() }`, 493 | /// but is optimized better. 494 | /// 495 | /// See [`Vec::push`] for more details. 496 | /// 497 | /// # Example 498 | /// 499 | /// ``` 500 | /// # use derive_more::{From, Into}; 501 | /// # use typed_index_collections::TiVec; 502 | /// #[derive(Eq, Debug, From, Into, PartialEq)] 503 | /// pub struct Id(usize); 504 | /// let mut vec: TiVec = vec![1, 2, 4].into(); 505 | /// assert_eq!(vec.push_and_get_key(8), Id(3)); 506 | /// assert_eq!(vec.push_and_get_key(16), Id(4)); 507 | /// assert_eq!(vec.push_and_get_key(32), Id(5)); 508 | /// ``` 509 | /// 510 | /// [`Vec::push`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.push 511 | #[inline] 512 | pub fn push_and_get_key(&mut self, value: V) -> K 513 | where 514 | K: From, 515 | { 516 | let key = self.next_key(); 517 | self.raw.push(value); 518 | key 519 | } 520 | 521 | /// Removes the last element from a vector and returns it, or [`None`] if it 522 | /// is empty. 523 | /// 524 | /// See [`Vec::pop`] for more details. 525 | /// 526 | /// [`Vec::pop`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.pop 527 | #[inline] 528 | pub fn pop(&mut self) -> Option { 529 | self.raw.pop() 530 | } 531 | 532 | /// Removes the last element from a vector and returns it with 533 | /// its index of type `K`, or [`None`] if the vector is empty. 534 | /// 535 | /// See [`Vec::pop`] for more details. 536 | /// 537 | /// [`Vec::pop`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.pop 538 | /// 539 | /// # Example 540 | /// 541 | /// ``` 542 | /// # use derive_more::{From, Into}; 543 | /// # use typed_index_collections::TiVec; 544 | /// #[derive(Eq, Debug, From, Into, PartialEq)] 545 | /// pub struct Id(usize); 546 | /// let mut vec: TiVec = vec![1, 2, 4].into(); 547 | /// assert_eq!(vec.pop_key_value(), Some((Id(2), 4))); 548 | /// assert_eq!(vec.pop_key_value(), Some((Id(1), 2))); 549 | /// assert_eq!(vec.pop_key_value(), Some((Id(0), 1))); 550 | /// assert_eq!(vec.pop_key_value(), None); 551 | /// ``` 552 | /// 553 | /// [`Vec::push`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.push 554 | #[inline] 555 | pub fn pop_key_value(&mut self) -> Option<(K, V)> 556 | where 557 | K: From, 558 | { 559 | self.raw.pop().map(|value| (self.raw.len().into(), value)) 560 | } 561 | 562 | /// Moves all the elements of `other` into `Self`, leaving `other` empty. 563 | /// 564 | /// See [`Vec::append`] for more details. 565 | /// 566 | /// [`Vec::append`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.append 567 | #[inline] 568 | pub fn append(&mut self, other: &mut Self) { 569 | self.raw.append(&mut other.raw); 570 | } 571 | 572 | /// Creates a draining iterator that removes the specified range in the 573 | /// vector and yields the removed items. 574 | /// 575 | /// See [`Vec::drain`] for more details. 576 | /// 577 | /// [`Vec::drain`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.drain 578 | #[inline] 579 | pub fn drain(&mut self, range: R) -> Drain<'_, V> 580 | where 581 | R: TiRangeBounds, 582 | { 583 | self.raw.drain(range.into_range()) 584 | } 585 | 586 | /// Creates a draining iterator that removes the specified 587 | /// range in the vector and yields the current count and the removed items. 588 | /// 589 | /// It acts like `self.drain(range).enumerate()`, 590 | /// but instead of `usize` it returns index of type `K`. 591 | /// 592 | /// Note that the indices started from `K::from_usize(0)`, 593 | /// regardless of the range starting point. 594 | /// 595 | /// See [`Vec::drain`] for more details. 596 | /// 597 | /// # Example 598 | /// 599 | /// ``` 600 | /// # use derive_more::{From, Into}; 601 | /// # use typed_index_collections::{TiSlice, TiVec}; 602 | /// #[derive(Eq, Debug, From, Into, PartialEq)] 603 | /// pub struct Id(usize); 604 | /// let mut vec: TiVec = vec![1, 2, 4].into(); 605 | /// { 606 | /// let mut iterator = vec.drain_enumerated(Id(1)..); 607 | /// assert_eq!(iterator.next(), Some((Id(0), 2))); 608 | /// assert_eq!(iterator.next(), Some((Id(1), 4))); 609 | /// assert_eq!(iterator.next(), None); 610 | /// } 611 | /// assert_eq!(vec.as_slice(), TiSlice::from_ref(&[1])); 612 | /// ``` 613 | /// 614 | /// [`Vec::drain`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.drain 615 | #[inline] 616 | pub fn drain_enumerated(&mut self, range: R) -> TiEnumerated, K, V> 617 | where 618 | K: From, 619 | R: TiRangeBounds, 620 | { 621 | self.raw 622 | .drain(range.into_range()) 623 | .enumerate() 624 | .map(|(key, value)| (key.into(), value)) 625 | } 626 | 627 | /// Clears the vector, removing all values. 628 | /// 629 | /// See [`Vec::clear`] for more details. 630 | /// 631 | /// [`Vec::clear`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.clear 632 | #[inline] 633 | pub fn clear(&mut self) { 634 | self.raw.clear(); 635 | } 636 | 637 | /// Returns the number of elements in the vector, also referred to 638 | /// as its 'length'. 639 | /// 640 | /// See [`Vec::len`] for more details. 641 | /// 642 | /// [`Vec::len`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.len 643 | #[inline] 644 | #[must_use] 645 | pub fn len(&self) -> usize { 646 | self.raw.len() 647 | } 648 | 649 | /// Returns `true` if the vector contains no elements. 650 | /// 651 | /// See [`Vec::is_empty`] for more details. 652 | /// 653 | /// [`Vec::is_empty`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.is_empty 654 | #[inline] 655 | #[must_use] 656 | pub fn is_empty(&self) -> bool { 657 | self.raw.is_empty() 658 | } 659 | 660 | /// Splits the collection into two at the given index. 661 | /// 662 | /// See [`Vec::split_off`] for more details. 663 | /// 664 | /// [`Vec::split_off`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.split_off 665 | #[inline] 666 | #[must_use = "use `.truncate()` if you don't need the other half"] 667 | pub fn split_off(&mut self, at: K) -> Self 668 | where 669 | usize: From, 670 | { 671 | self.raw.split_off(at.into()).into() 672 | } 673 | 674 | /// Resizes the `TiVec` in-place so that `len` is equal to `new_len`. 675 | /// 676 | /// See [`Vec::resize_with`] for more details. 677 | /// 678 | /// [`Vec::resize_with`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.resize_with 679 | #[inline] 680 | pub fn resize_with(&mut self, new_len: usize, f: F) 681 | where 682 | F: FnMut() -> V, 683 | { 684 | self.raw.resize_with(new_len, f); 685 | } 686 | 687 | /// Resizes the `TiVec` in-place so that `len` is equal to `new_len`. 688 | /// 689 | /// See [`Vec::resize`] for more details. 690 | /// 691 | /// [`Vec::resize`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.resize 692 | #[inline] 693 | pub fn resize(&mut self, new_len: usize, value: V) 694 | where 695 | V: Clone, 696 | { 697 | self.raw.resize(new_len, value); 698 | } 699 | 700 | /// Consumes and leaks the `Vec`, returning a mutable reference to the 701 | /// contents, `&'a mut [T]`. Note that the type `T` must outlive the 702 | /// chosen lifetime `'a`. If the type has only static references, or 703 | /// none at all, then this may be chosen to be `'static`. 704 | /// 705 | /// See [`Vec::leak`] for more details. 706 | /// 707 | /// [`Vec::leak`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.leak 708 | #[expect(clippy::must_use_candidate, reason = "not used in `Vec::leak`")] 709 | #[inline] 710 | pub fn leak<'a>(self) -> &'a mut TiSlice { 711 | self.raw.leak().as_mut() 712 | } 713 | 714 | /// Returns the remaining spare capacity of the vector as a slice of 715 | /// `MaybeUninit`. 716 | /// 717 | /// See [`Vec::spare_capacity_mut`] for more details. 718 | /// 719 | /// [`Vec::spare_capacity_mut`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.spare_capacity_mut 720 | #[inline] 721 | pub fn spare_capacity_mut(&mut self) -> &mut TiSlice> { 722 | self.raw.spare_capacity_mut().as_mut() 723 | } 724 | 725 | /// Clones and appends all elements in a slice to the `TiVec`. 726 | /// 727 | /// See [`Vec::extend_from_slice`] for more details. 728 | /// 729 | /// [`Vec::extend_from_slice`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.extend_from_slice 730 | #[inline] 731 | pub fn extend_from_slice(&mut self, other: &TiSlice) 732 | where 733 | V: Clone, 734 | { 735 | self.raw.extend_from_slice(&other.raw); 736 | } 737 | 738 | /// Copies elements from `src` range to the end of the vector. 739 | /// 740 | /// See [`Vec::extend_from_within`] for more details. 741 | /// 742 | /// # Panics 743 | /// 744 | /// Panics if the starting point is greater than the end point or if 745 | /// the end point is greater than the length of the vector. 746 | /// 747 | /// [`Vec::extend_from_within`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.extend_from_within 748 | #[inline] 749 | pub fn extend_from_within(&mut self, src: R) 750 | where 751 | V: Clone, 752 | R: RangeBounds, 753 | { 754 | self.raw.extend_from_within(src); 755 | } 756 | 757 | /// Removes consecutive repeated elements in the vector according to the 758 | /// [`PartialEq`] trait implementation. 759 | /// 760 | /// See [`Vec::dedup`] for more details. 761 | /// 762 | /// [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html 763 | /// [`Vec::dedup`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.dedup 764 | #[inline] 765 | pub fn dedup(&mut self) 766 | where 767 | V: PartialEq, 768 | { 769 | self.raw.dedup(); 770 | } 771 | 772 | /// Creates a splicing iterator that replaces the specified range in the 773 | /// vector with the given `replace_with` iterator and yields the removed 774 | /// items. `replace_with` does not need to be the same length as 775 | /// `range`. 776 | /// 777 | /// See [`Vec::splice`] for more details. 778 | /// 779 | /// [`Vec::splice`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.splice 780 | #[inline] 781 | pub fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter> 782 | where 783 | R: TiRangeBounds, 784 | I: IntoIterator, 785 | { 786 | self.raw.splice(range.into_range(), replace_with) 787 | } 788 | 789 | /// Converts the vector into iterator over all key-value pairs 790 | /// with `K` used for iteration indices. 791 | /// 792 | /// It acts like `self.into_iter().enumerate()`, 793 | /// but use `K` instead of `usize` for iteration indices. 794 | /// 795 | /// # Example 796 | /// 797 | /// ``` 798 | /// # use derive_more::{From, Into}; 799 | /// # use typed_index_collections::TiVec; 800 | /// #[derive(Eq, Debug, From, Into, PartialEq)] 801 | /// pub struct Id(usize); 802 | /// let vec: TiVec = vec![1, 2, 4].into(); 803 | /// let mut iterator = vec.into_iter_enumerated(); 804 | /// assert_eq!(iterator.next(), Some((Id(0), 1))); 805 | /// assert_eq!(iterator.next(), Some((Id(1), 2))); 806 | /// assert_eq!(iterator.next(), Some((Id(2), 4))); 807 | /// assert_eq!(iterator.next(), None); 808 | /// ``` 809 | #[inline] 810 | pub fn into_iter_enumerated(self) -> TiEnumerated, K, V> 811 | where 812 | K: From, 813 | { 814 | self.raw 815 | .into_iter() 816 | .enumerate() 817 | .map(|(key, value)| (key.into(), value)) 818 | } 819 | } 820 | 821 | impl fmt::Debug for TiVec 822 | where 823 | K: fmt::Debug + From, 824 | V: fmt::Debug, 825 | { 826 | #[allow(clippy::allow_attributes, reason = "rust-lang/rust#130021")] 827 | #[allow( 828 | clippy::missing_inline_in_public_items, 829 | reason = "use default inlining behavior" 830 | )] 831 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 832 | f.debug_map().entries(self.iter_enumerated()).finish() 833 | } 834 | } 835 | 836 | impl AsRef for TiVec { 837 | #[inline] 838 | fn as_ref(&self) -> &Self { 839 | self 840 | } 841 | } 842 | 843 | impl AsMut for TiVec { 844 | #[inline] 845 | fn as_mut(&mut self) -> &mut Self { 846 | self 847 | } 848 | } 849 | 850 | impl AsRef> for TiVec { 851 | #[inline] 852 | fn as_ref(&self) -> &TiSlice { 853 | self 854 | } 855 | } 856 | 857 | impl AsMut> for TiVec { 858 | #[inline] 859 | fn as_mut(&mut self) -> &mut TiSlice { 860 | self 861 | } 862 | } 863 | 864 | impl AsRef> for TiVec { 865 | #[inline] 866 | fn as_ref(&self) -> &Vec { 867 | &self.raw 868 | } 869 | } 870 | 871 | impl AsMut> for TiVec { 872 | #[inline] 873 | fn as_mut(&mut self) -> &mut Vec { 874 | &mut self.raw 875 | } 876 | } 877 | 878 | impl AsRef<[V]> for TiVec { 879 | #[inline] 880 | fn as_ref(&self) -> &[V] { 881 | &self.raw 882 | } 883 | } 884 | 885 | impl AsMut<[V]> for TiVec { 886 | #[inline] 887 | fn as_mut(&mut self) -> &mut [V] { 888 | &mut self.raw 889 | } 890 | } 891 | 892 | impl AsRef> for Vec { 893 | #[inline] 894 | fn as_ref(&self) -> &TiVec { 895 | TiVec::from_ref(self) 896 | } 897 | } 898 | 899 | impl AsMut> for Vec { 900 | #[inline] 901 | fn as_mut(&mut self) -> &mut TiVec { 902 | TiVec::from_mut(self) 903 | } 904 | } 905 | 906 | impl Borrow> for TiVec { 907 | #[inline] 908 | fn borrow(&self) -> &TiSlice { 909 | self.as_slice() 910 | } 911 | } 912 | 913 | impl BorrowMut> for TiVec { 914 | #[inline] 915 | fn borrow_mut(&mut self) -> &mut TiSlice { 916 | self.as_mut_slice() 917 | } 918 | } 919 | 920 | impl Deref for TiVec { 921 | type Target = TiSlice; 922 | 923 | #[inline] 924 | fn deref(&self) -> &TiSlice { 925 | Self::Target::from_ref(&self.raw) 926 | } 927 | } 928 | 929 | impl DerefMut for TiVec { 930 | #[inline] 931 | fn deref_mut(&mut self) -> &mut TiSlice { 932 | Self::Target::from_mut(&mut self.raw) 933 | } 934 | } 935 | 936 | impl From> for TiVec { 937 | #[inline] 938 | fn from(vec: Vec) -> Self { 939 | Self { 940 | raw: vec, 941 | _marker: PhantomData, 942 | } 943 | } 944 | } 945 | 946 | impl From> for Vec { 947 | #[inline] 948 | fn from(vec: TiVec) -> Self { 949 | vec.raw 950 | } 951 | } 952 | 953 | impl From<&TiSlice> for TiVec 954 | where 955 | V: Clone, 956 | { 957 | #[inline] 958 | fn from(slice: &TiSlice) -> Self { 959 | slice.to_vec() 960 | } 961 | } 962 | 963 | impl From<&mut TiSlice> for TiVec 964 | where 965 | V: Clone, 966 | { 967 | #[inline] 968 | fn from(slice: &mut TiSlice) -> Self { 969 | slice.to_vec() 970 | } 971 | } 972 | 973 | impl From>> for TiVec 974 | where 975 | V: Clone, 976 | { 977 | #[inline] 978 | fn from(slice: Cow<'_, TiSlice>) -> Self { 979 | slice.into_owned() 980 | } 981 | } 982 | 983 | impl From> for Cow<'_, TiSlice> 984 | where 985 | V: Clone, 986 | { 987 | #[inline] 988 | fn from(vec: TiVec) -> Self { 989 | Cow::Owned(vec) 990 | } 991 | } 992 | 993 | impl From<&str> for TiVec { 994 | #[inline] 995 | fn from(s: &str) -> Self { 996 | s.as_bytes().to_vec().into() 997 | } 998 | } 999 | 1000 | impl From for TiVec { 1001 | #[inline] 1002 | fn from(s: String) -> Self { 1003 | s.into_bytes().into() 1004 | } 1005 | } 1006 | 1007 | impl From for TiVec { 1008 | #[inline] 1009 | fn from(s: CString) -> Self { 1010 | s.into_bytes().into() 1011 | } 1012 | } 1013 | 1014 | impl Clone for TiVec 1015 | where 1016 | V: Clone, 1017 | { 1018 | #[inline] 1019 | fn clone(&self) -> Self { 1020 | self.raw.clone().into() 1021 | } 1022 | } 1023 | 1024 | impl Eq for TiVec where V: Eq {} 1025 | 1026 | impl PartialEq> for TiVec 1027 | where 1028 | A: PartialEq, 1029 | { 1030 | #[inline] 1031 | fn eq(&self, other: &TiVec) -> bool { 1032 | self.raw == other.raw 1033 | } 1034 | } 1035 | 1036 | impl PartialEq> for TiVec 1037 | where 1038 | A: PartialEq, 1039 | { 1040 | #[inline] 1041 | fn eq(&self, other: &TiSlice) -> bool { 1042 | *self.raw == other.raw 1043 | } 1044 | } 1045 | 1046 | impl PartialEq> for TiSlice 1047 | where 1048 | A: PartialEq, 1049 | { 1050 | #[inline] 1051 | fn eq(&self, other: &TiVec) -> bool { 1052 | self.raw == *other.raw 1053 | } 1054 | } 1055 | 1056 | impl<'a, K, A, B> PartialEq<&'a TiSlice> for TiVec 1057 | where 1058 | A: PartialEq, 1059 | { 1060 | #[inline] 1061 | fn eq(&self, other: &&'a TiSlice) -> bool { 1062 | *self.raw == other.raw 1063 | } 1064 | } 1065 | 1066 | impl PartialEq> for &TiSlice 1067 | where 1068 | A: PartialEq, 1069 | { 1070 | #[inline] 1071 | fn eq(&self, other: &TiVec) -> bool { 1072 | self.raw == *other.raw 1073 | } 1074 | } 1075 | 1076 | impl<'a, K, A, B> PartialEq<&'a mut TiSlice> for TiVec 1077 | where 1078 | A: PartialEq, 1079 | { 1080 | #[inline] 1081 | fn eq(&self, other: &&'a mut TiSlice) -> bool { 1082 | *self.raw == other.raw 1083 | } 1084 | } 1085 | 1086 | impl PartialEq> for &mut TiSlice 1087 | where 1088 | A: PartialEq, 1089 | { 1090 | #[inline] 1091 | fn eq(&self, other: &TiVec) -> bool { 1092 | self.raw == *other.raw 1093 | } 1094 | } 1095 | 1096 | impl Ord for TiVec 1097 | where 1098 | V: Ord, 1099 | { 1100 | #[inline] 1101 | fn cmp(&self, other: &Self) -> Ordering { 1102 | self.raw.cmp(&other.raw) 1103 | } 1104 | } 1105 | 1106 | impl PartialOrd for TiVec 1107 | where 1108 | V: PartialOrd, 1109 | { 1110 | #[inline] 1111 | fn partial_cmp(&self, other: &Self) -> Option { 1112 | self.raw.partial_cmp(&other.raw) 1113 | } 1114 | } 1115 | 1116 | impl Hash for TiVec 1117 | where 1118 | V: Hash, 1119 | { 1120 | #[inline] 1121 | fn hash(&self, state: &mut H) { 1122 | self.raw.hash(state); 1123 | } 1124 | } 1125 | 1126 | impl Default for TiVec { 1127 | #[inline] 1128 | fn default() -> Self { 1129 | Vec::default().into() 1130 | } 1131 | } 1132 | 1133 | impl Index for TiVec 1134 | where 1135 | I: TiSliceIndex, 1136 | { 1137 | type Output = I::Output; 1138 | 1139 | #[inline] 1140 | fn index(&self, index: I) -> &Self::Output { 1141 | index.index(self) 1142 | } 1143 | } 1144 | 1145 | impl IndexMut for TiVec 1146 | where 1147 | I: TiSliceIndex, 1148 | { 1149 | #[inline] 1150 | fn index_mut(&mut self, index: I) -> &mut Self::Output { 1151 | index.index_mut(self) 1152 | } 1153 | } 1154 | 1155 | impl Extend for TiVec { 1156 | #[inline] 1157 | fn extend>(&mut self, iter: I) { 1158 | self.raw.extend(iter); 1159 | } 1160 | } 1161 | 1162 | impl<'a, K, V: 'a + Copy> Extend<&'a V> for TiVec { 1163 | #[inline] 1164 | fn extend>(&mut self, iter: I) { 1165 | self.raw.extend(iter); 1166 | } 1167 | } 1168 | 1169 | impl FromIterator for TiVec { 1170 | #[inline] 1171 | fn from_iter>(iter: I) -> Self { 1172 | Self { 1173 | raw: Vec::from_iter(iter), 1174 | _marker: PhantomData, 1175 | } 1176 | } 1177 | } 1178 | 1179 | impl IntoIterator for TiVec { 1180 | type Item = V; 1181 | type IntoIter = vec::IntoIter; 1182 | 1183 | #[inline] 1184 | fn into_iter(self) -> vec::IntoIter { 1185 | self.raw.into_iter() 1186 | } 1187 | } 1188 | 1189 | impl<'a, K, V> IntoIterator for &'a TiVec { 1190 | type Item = &'a V; 1191 | type IntoIter = slice::Iter<'a, V>; 1192 | 1193 | #[inline] 1194 | fn into_iter(self) -> slice::Iter<'a, V> { 1195 | self.raw.iter() 1196 | } 1197 | } 1198 | 1199 | impl<'a, K, V> IntoIterator for &'a mut TiVec { 1200 | type Item = &'a mut V; 1201 | type IntoIter = slice::IterMut<'a, V>; 1202 | 1203 | #[inline] 1204 | fn into_iter(self) -> slice::IterMut<'a, V> { 1205 | self.raw.iter_mut() 1206 | } 1207 | } 1208 | 1209 | /// Write is implemented for `Vec` by appending to the vector. 1210 | /// The vector will grow as needed. 1211 | #[cfg(feature = "std")] 1212 | #[cfg_attr(docsrs, doc(cfg(feature = "std")))] 1213 | impl Write for TiVec { 1214 | #[inline] 1215 | fn write(&mut self, buf: &[u8]) -> IoResult { 1216 | self.raw.write(buf) 1217 | } 1218 | 1219 | #[inline] 1220 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> IoResult { 1221 | self.raw.write_vectored(bufs) 1222 | } 1223 | 1224 | #[inline] 1225 | fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { 1226 | self.raw.write_all(buf) 1227 | } 1228 | 1229 | #[inline] 1230 | fn flush(&mut self) -> IoResult<()> { 1231 | self.raw.flush() 1232 | } 1233 | } 1234 | 1235 | #[cfg(feature = "serde")] 1236 | #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] 1237 | impl Serialize for TiVec 1238 | where 1239 | V: Serialize, 1240 | { 1241 | #[inline] 1242 | fn serialize(&self, serializer: S) -> Result 1243 | where 1244 | S: Serializer, 1245 | { 1246 | self.raw.as_slice().serialize(serializer) 1247 | } 1248 | } 1249 | 1250 | #[cfg(feature = "serde")] 1251 | #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] 1252 | impl<'de, K, V> Deserialize<'de> for TiVec 1253 | where 1254 | V: Deserialize<'de>, 1255 | { 1256 | #[inline] 1257 | fn deserialize(deserializer: D) -> Result 1258 | where 1259 | D: Deserializer<'de>, 1260 | { 1261 | Vec::deserialize(deserializer).map(Into::into) 1262 | } 1263 | } 1264 | 1265 | #[cfg(feature = "bincode")] 1266 | #[cfg_attr(docsrs, doc(cfg(feature = "bincode")))] 1267 | impl Encode for TiVec 1268 | where 1269 | V: Encode, 1270 | { 1271 | #[inline] 1272 | fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> 1273 | where 1274 | E: Encoder, 1275 | { 1276 | self.raw.encode(encoder) 1277 | } 1278 | } 1279 | 1280 | #[cfg(feature = "bincode")] 1281 | #[cfg_attr(docsrs, doc(cfg(feature = "bincode")))] 1282 | impl Decode for TiVec 1283 | where 1284 | V: Decode, 1285 | { 1286 | #[inline] 1287 | fn decode(decoder: &mut D) -> Result 1288 | where 1289 | D: Decoder, 1290 | { 1291 | Vec::decode(decoder).map(Into::into) 1292 | } 1293 | } 1294 | 1295 | #[cfg(feature = "bincode")] 1296 | #[cfg_attr(docsrs, doc(cfg(feature = "bincode")))] 1297 | impl<'de, K, V, Context> BorrowDecode<'de, Context> for TiVec 1298 | where 1299 | V: BorrowDecode<'de, Context>, 1300 | { 1301 | #[inline] 1302 | fn borrow_decode(decoder: &mut D) -> Result 1303 | where 1304 | D: BorrowDecoder<'de, Context = Context>, 1305 | { 1306 | Vec::borrow_decode(decoder).map(Into::into) 1307 | } 1308 | } 1309 | 1310 | #[expect( 1311 | dead_code, 1312 | unused_imports, 1313 | unused_mut, 1314 | clippy::into_iter_on_ref, 1315 | clippy::op_ref, 1316 | clippy::too_many_lines, 1317 | clippy::undocumented_unsafe_blocks, 1318 | clippy::unwrap_used, 1319 | reason = "okay in tests" 1320 | )] 1321 | #[cfg(test)] 1322 | mod test { 1323 | use alloc::borrow::{Cow, ToOwned}; 1324 | use alloc::boxed::Box; 1325 | use alloc::ffi::CString; 1326 | use alloc::string::ToString; 1327 | use alloc::vec::Vec; 1328 | use core::borrow::{Borrow, BorrowMut}; 1329 | use core::hash::{Hash, Hasher}; 1330 | use core::ops::Bound; 1331 | #[cfg(feature = "std")] 1332 | use std::hash::DefaultHasher; 1333 | #[cfg(feature = "std")] 1334 | use std::io::{IoSlice, Write}; 1335 | 1336 | use crate::test_util::{AsSliceAndCapacity, Id}; 1337 | use crate::{TiSlice, TiVec}; 1338 | 1339 | #[test] 1340 | fn test_vec_read_api_compatibility() { 1341 | assert_eq!( 1342 | TiVec::::new().as_slice_and_capacity(), 1343 | Vec::::new().as_slice_and_capacity(), 1344 | ); 1345 | for c in [0, 1, 2, 4] { 1346 | assert_eq!( 1347 | TiVec::::with_capacity(c).as_slice_and_capacity(), 1348 | Vec::::with_capacity(c).as_slice_and_capacity(), 1349 | ); 1350 | } 1351 | 1352 | for v in [ 1353 | &[0_u32; 0][..], 1354 | &[1], 1355 | &[1, 1234], 1356 | &[1, 2, 4], 1357 | &[1, 5, 3, 2], 1358 | &[1, 1, 9, 2, 4, 1, 12345, 12], 1359 | ] { 1360 | let cv = (v.to_vec(), TiVec::::from(v.to_vec())); 1361 | let mut cv = (&cv.0, &cv.1); 1362 | 1363 | let mut mv = (v.to_vec(), TiVec::::from(v.to_vec())); 1364 | let mut mv = (&mut mv.0, &mut mv.1); 1365 | 1366 | assert_eq_api!(cv, v => AsRef::<[_]>::as_ref(v)); 1367 | assert_eq_api!(mv, v => AsMut::<[_]>::as_mut(v)); 1368 | assert_eq_api!(cv, v => AsRef::>::as_ref(v)); 1369 | assert_eq_api!(mv, v => AsMut::>::as_mut(v)); 1370 | assert_eq_api!(cv, v => AsRef::>::as_ref(v)); 1371 | assert_eq_api!(mv, v => AsMut::>::as_mut(v)); 1372 | assert_eq!( 1373 | AsRef::<[_]>::as_ref(cv.0), 1374 | AsRef::<[_]>::as_ref(AsRef::>::as_ref(cv.1)) 1375 | ); 1376 | assert_eq!( 1377 | AsMut::<[_]>::as_mut(mv.0), 1378 | AsMut::<[_]>::as_mut(AsMut::>::as_mut(mv.1)) 1379 | ); 1380 | assert_eq!( 1381 | Borrow::<[_]>::borrow(cv.0), 1382 | AsRef::<[_]>::as_ref(Borrow::>::borrow(cv.1)) 1383 | ); 1384 | assert_eq!( 1385 | BorrowMut::<[_]>::borrow_mut(mv.0), 1386 | AsMut::<[_]>::as_mut(BorrowMut::>::borrow_mut(mv.1)) 1387 | ); 1388 | 1389 | assert_eq_api!(cv, v => v.len()); 1390 | assert_eq_api!(cv, v => v.is_empty()); 1391 | assert_eq_api!(cv, v => v.capacity()); 1392 | assert_eq_api!(cv, v => v.as_slice().into_std()); 1393 | assert_eq_api!(mv, v => v.as_mut_slice().into_std()); 1394 | assert_eq_api!(cv, v => TheVec::from(v.as_slice()).into_std()); 1395 | assert_eq_api!(mv, v => TheVec::from(v.as_mut_slice()).into_std()); 1396 | assert_eq_api!(cv, v => TheVec::from(Cow::Borrowed(v.as_slice())).into_std()); 1397 | assert_eq_api!(mv, v => Cow::from(v.clone()).into_std()); 1398 | 1399 | if !v.is_empty() { 1400 | assert_ne!(cv.0.as_ptr(), cv.1.as_ptr()); 1401 | assert_ne!(cv.0.as_ptr_range(), cv.1.as_ptr_range()); 1402 | assert_ne!(mv.0.as_mut_ptr(), mv.1.as_mut_ptr()); 1403 | assert_ne!(mv.0.as_mut_ptr_range(), mv.1.as_mut_ptr_range()); 1404 | } 1405 | 1406 | assert_eq_api!(cv, v => *v == TheVec::::default()); 1407 | assert_eq_api!(cv, v => v == v.as_slice()); 1408 | assert_eq_api!(cv, v => v.as_slice() == v); 1409 | assert_eq_api!(cv, v => v == &v.as_slice()); 1410 | assert_eq_api!(cv, v => &v.as_slice() == v); 1411 | assert_eq_api!(mv, v => v == &(&mut [1_u32, 1234][..]).into_tic()); 1412 | assert_eq_api!(mv, v => &(&mut [1_u32, 1234][..]).into_tic() == v); 1413 | assert_eq_api!(cv, v => v.cmp(&alloc::vec![1, 1234].into_tic())); 1414 | assert_eq_api!(cv, v => v.partial_cmp(&alloc::vec![1, 1234].into_tic())); 1415 | 1416 | for i in 0..v.len() { 1417 | assert_eq_api!(cv, v => v[i.into_tic()]); 1418 | assert_eq_api!(mv, v => v[i.into_tic()] = v[i.into_tic()]); 1419 | } 1420 | 1421 | unsafe { 1422 | assert_eq_api!(cv, v => { 1423 | let mut v = core::mem::ManuallyDrop::new(v.clone()); 1424 | TheVec::from_raw_parts(v.as_mut_ptr(), v.len(), v.capacity()).into_std() 1425 | }); 1426 | } 1427 | } 1428 | } 1429 | 1430 | #[test] 1431 | fn test_vec_write_api_compatibility() { 1432 | for v in [ 1433 | &[0_u32; 0][..], 1434 | &[1], 1435 | &[1, 1234], 1436 | &[1, 2, 4], 1437 | &[1, 5, 3, 2], 1438 | &[1, 1, 9, 2, 4, 1, 12345, 12], 1439 | ] { 1440 | let mut mv = (v.to_vec(), TiVec::::from(v.to_vec())); 1441 | let mut mv = (&mut mv.0, &mut mv.1); 1442 | 1443 | let restore = |mv: &mut (&mut Vec, &mut TiVec)| { 1444 | *mv.0 = v.to_vec(); 1445 | *mv.1 = TiVec::from(v.to_vec()); 1446 | }; 1447 | 1448 | restore(&mut mv); 1449 | assert_eq_api!(mv, v => v.try_reserve(usize::MAX)); 1450 | restore(&mut mv); 1451 | assert_eq_api!(mv, v => v.try_reserve_exact(usize::MAX)); 1452 | 1453 | for i in 0..8 { 1454 | restore(&mut mv); 1455 | assert_eq_api!(mv, v => v.resize(i, 123)); 1456 | restore(&mut mv); 1457 | assert_eq_api!(mv, v => { let mut a = 1; v.resize_with(i, || { a *= 2; a }) }); 1458 | restore(&mut mv); 1459 | assert_eq_api!(mv, v => v.reserve(i)); 1460 | assert_eq_api!(mv, v => v.spare_capacity_mut().len()); 1461 | restore(&mut mv); 1462 | assert_eq_api!(mv, v => v.try_reserve(i)); 1463 | restore(&mut mv); 1464 | assert_eq_api!(mv, v => v.reserve_exact(i)); 1465 | restore(&mut mv); 1466 | assert_eq_api!(mv, v => v.try_reserve_exact(i)); 1467 | restore(&mut mv); 1468 | assert_eq_api!(mv, v => v.reserve_exact(i)); 1469 | assert_eq_api!(mv, v => v.shrink_to_fit()); 1470 | restore(&mut mv); 1471 | assert_eq_api!(mv, v => v.reserve_exact(i * 2)); 1472 | assert_eq_api!(mv, v => v.shrink_to(i)); 1473 | restore(&mut mv); 1474 | assert_eq_api!(mv, v => v.truncate(i)); 1475 | } 1476 | 1477 | let l1: Vec<_> = mv.0.clone(); 1478 | let l1c = l1.capacity(); 1479 | let l1 = l1.leak(); 1480 | let l2: TiVec<_, _> = mv.1.clone(); 1481 | let l2c = l2.capacity(); 1482 | let l2 = l2.leak(); 1483 | assert_eq!(l1, &l2.raw); 1484 | drop(unsafe { Vec::from_raw_parts(l1.as_mut_ptr(), l1.len(), l1c) }); 1485 | drop(unsafe { TiVec::::from_raw_parts(l2.as_mut_ptr(), l2.len(), l2c) }); 1486 | 1487 | restore(&mut mv); 1488 | assert_eq_api!(mv, v => (&*v).into_iter().copied().collect::>()); 1489 | assert_eq_api!(mv, v => v.iter_mut().collect::>()); 1490 | assert_eq_api!(mv, v => v.clone().into_iter().collect::>()); 1491 | 1492 | restore(&mut mv); 1493 | assert_eq_api!(mv, v => v.pop()); 1494 | assert_eq_api!(mv, v => v.push(123)); 1495 | assert_eq_api!(mv, v => v.pop()); 1496 | assert_eq_api!(mv, v => v.append(&mut v.clone())); 1497 | restore(&mut mv); 1498 | assert_eq_api!(mv, v => v.extend(v.clone().as_slice())); 1499 | restore(&mut mv); 1500 | assert_eq_api!(mv, v => v.extend(v.clone().iter().copied())); 1501 | restore(&mut mv); 1502 | assert_eq_api!(mv, v => v.extend_from_slice(&v.clone())); 1503 | restore(&mut mv); 1504 | assert_eq_api!(mv, v => v.into_iter().collect::>().into_std()); 1505 | 1506 | restore(&mut mv); 1507 | assert_eq_api!(mv, v => v.retain(|value| value % 3 == 0 || value % 4 == 0)); 1508 | 1509 | restore(&mut mv); 1510 | assert_eq_api!(mv, v => v.retain_mut(|value| { 1511 | *value += 1; 1512 | *value % 3 == 0 || *value % 4 == 0 1513 | })); 1514 | 1515 | restore(&mut mv); 1516 | assert_eq_api!(mv, v => v.dedup()); 1517 | 1518 | restore(&mut mv); 1519 | assert_eq_api!(mv, v => v.dedup_by(|lhs, rhs| lhs < rhs)); 1520 | 1521 | restore(&mut mv); 1522 | assert_eq_api!(mv, v => v.dedup_by_key(|value| *value % 3)); 1523 | 1524 | for i in 0..v.len() { 1525 | restore(&mut mv); 1526 | assert_eq_api!(mv, v => v.swap_remove(i.into_tic())); 1527 | restore(&mut mv); 1528 | assert_eq_api!(mv, v => v.insert(i.into_tic(), 123)); 1529 | restore(&mut mv); 1530 | assert_eq_api!(mv, v => v.remove(i.into_tic())); 1531 | restore(&mut mv); 1532 | unsafe { assert_eq_api!(mv, v => v.set_len(i)) }; 1533 | restore(&mut mv); 1534 | assert_eq_api!(mv, v => v.split_off(i.into_tic()).into_std()); 1535 | } 1536 | 1537 | for a in 0..v.len() { 1538 | for b in a..v.len() { 1539 | restore(&mut mv); 1540 | assert_eq_api!(mv, v => v.drain((a..b).into_tic()).collect::>()); 1541 | restore(&mut mv); 1542 | assert_eq_api!(mv, v => v.extend_from_within(a..b)); 1543 | restore(&mut mv); 1544 | assert_eq_api!( 1545 | mv, v => v.splice((a..b).into_tic(), [1, 2, 3]).collect::>() 1546 | ); 1547 | } 1548 | } 1549 | restore(&mut mv); 1550 | assert_eq_api!(mv, v => v.splice(.., [1, 2, 3]).collect::>()); 1551 | 1552 | restore(&mut mv); 1553 | assert_eq_api!(mv, v => v.clear()); 1554 | } 1555 | } 1556 | 1557 | #[cfg(feature = "std")] 1558 | #[test] 1559 | fn test_vec_hash_compatibility() { 1560 | for v in [ 1561 | &[0_u32; 0][..], 1562 | &[1], 1563 | &[1, 1234], 1564 | &[1, 2, 4], 1565 | &[1, 5, 3, 2], 1566 | &[1, 1, 9, 2, 4, 1, 12345, 12], 1567 | ] { 1568 | let cv = (v.to_vec(), TiVec::::from(v.to_vec())); 1569 | let mut cv = (&cv.0, &cv.1); 1570 | assert_eq_api!(cv, v => { 1571 | let mut hasher = DefaultHasher::new(); 1572 | v.hash(&mut hasher); 1573 | hasher.finish() 1574 | }); 1575 | } 1576 | } 1577 | 1578 | #[test] 1579 | fn test_u8_vec_api_compatibility() { 1580 | assert_eq!( 1581 | Vec::from(TiVec::::from("abc")), 1582 | Vec::::from("abc"), 1583 | ); 1584 | assert_eq!( 1585 | Vec::from(TiVec::::from("abc".to_owned())), 1586 | Vec::::from("abc".to_owned()), 1587 | ); 1588 | assert_eq!( 1589 | Vec::from(TiVec::::from(CString::new("abc").unwrap())), 1590 | Vec::::from(CString::new("abc").unwrap()), 1591 | ); 1592 | 1593 | for v in [&b"abc"[..], b"aBc", b"ABC", b"abd", b"a\x80\x81b"] { 1594 | let cv = (v.to_vec(), TiVec::::from(v.to_vec())); 1595 | let mut cv = (&cv.0, &cv.1); 1596 | 1597 | assert_eq_api!(cv, v => TheVec::from(v.as_slice()).into_std()); 1598 | } 1599 | } 1600 | 1601 | #[test] 1602 | fn test_vec_debug() { 1603 | let s0: TiVec = TiVec::from(alloc::vec![]); 1604 | let s1: TiVec = TiVec::from(alloc::vec![12]); 1605 | let s2: TiVec = TiVec::from(alloc::vec![23, 34]); 1606 | assert_eq!(&alloc::format!("{s0:?}"), "{}"); 1607 | assert_eq!(&alloc::format!("{s1:?}"), "{Id(0): 12}"); 1608 | assert_eq!(&alloc::format!("{s2:?}"), "{Id(0): 23, Id(1): 34}"); 1609 | } 1610 | 1611 | #[cfg(feature = "std")] 1612 | #[test] 1613 | fn test_vec_write() { 1614 | let mut mv = (Vec::::new(), TiVec::::new()); 1615 | let mut mv = (&mut mv.0, &mut mv.1); 1616 | 1617 | assert_eq_api!(mv, v => v.write(&[1, 2, 3]).unwrap()); 1618 | assert_eq_api!(mv, v => v.write_vectored( 1619 | &[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5])] 1620 | ).unwrap()); 1621 | assert_eq_api!(mv, v => v.write_all(&[1, 2, 3]).unwrap()); 1622 | assert_eq_api!(mv, v => v.flush().unwrap()); 1623 | } 1624 | 1625 | #[cfg(feature = "serde")] 1626 | #[test] 1627 | fn test_vec_serialize() { 1628 | let s0: TiVec = TiVec::from(alloc::vec![]); 1629 | let s1: TiVec = TiVec::from(alloc::vec![12]); 1630 | let s2: TiVec = TiVec::from(alloc::vec![23, 34]); 1631 | assert_eq!(&serde_json::to_string(&s0).unwrap(), "[]"); 1632 | assert_eq!(&serde_json::to_string(&s1).unwrap(), "[12]"); 1633 | assert_eq!(&serde_json::to_string(&s2).unwrap(), "[23,34]"); 1634 | } 1635 | 1636 | #[cfg(feature = "serde")] 1637 | #[test] 1638 | fn test_vec_deserialize() { 1639 | let s0: TiVec = serde_json::from_str("[]").unwrap(); 1640 | let s1: TiVec = serde_json::from_str("[12]").unwrap(); 1641 | let s2: TiVec = serde_json::from_str("[23, 34]").unwrap(); 1642 | assert_eq!(s0.as_slice().raw, [0; 0][..]); 1643 | assert_eq!(s1.as_slice().raw, [12][..]); 1644 | assert_eq!(s2.as_slice().raw, [23, 34][..]); 1645 | } 1646 | 1647 | #[cfg(feature = "bincode")] 1648 | #[test] 1649 | fn test_vec_encode() { 1650 | let config = bincode::config::standard(); 1651 | let s0: TiVec = TiVec::from(alloc::vec![]); 1652 | let s1: TiVec = TiVec::from(alloc::vec![12]); 1653 | let s2: TiVec = TiVec::from(alloc::vec![23, 34]); 1654 | let s3: TiVec = TiVec::from(alloc::vec![0x1234_5678, 0x2345_6789]); 1655 | assert_eq!(&bincode::encode_to_vec(s0, config).unwrap(), &[0]); 1656 | assert_eq!(&bincode::encode_to_vec(s1, config).unwrap(), &[1, 12]); 1657 | assert_eq!(&bincode::encode_to_vec(s2, config).unwrap(), &[2, 23, 34]); 1658 | assert_eq!( 1659 | &bincode::encode_to_vec(s3, config).unwrap(), 1660 | &[2, 252, 0x78, 0x56, 0x34, 0x12, 252, 0x89, 0x67, 0x45, 0x23] 1661 | ); 1662 | } 1663 | 1664 | #[cfg(feature = "bincode")] 1665 | #[test] 1666 | fn test_vec_decode() { 1667 | fn decode_whole(bytes: &[u8]) -> TiVec { 1668 | let config = bincode::config::standard(); 1669 | let (decoded, len) = bincode::decode_from_slice(bytes, config).unwrap(); 1670 | assert_eq!(len, bytes.len()); 1671 | decoded 1672 | } 1673 | 1674 | let s0: TiVec = decode_whole(&[0]); 1675 | let s1: TiVec = decode_whole(&[1, 12]); 1676 | let s2: TiVec = decode_whole(&[2, 23, 34]); 1677 | let s3: TiVec = 1678 | decode_whole(&[2, 252, 0x78, 0x56, 0x34, 0x12, 252, 0x89, 0x67, 0x45, 0x23]); 1679 | assert_eq!(s0.as_slice().raw, [0; 0][..]); 1680 | assert_eq!(s1.as_slice().raw, [12][..]); 1681 | assert_eq!(s2.as_slice().raw, [23, 34][..]); 1682 | assert_eq!(s3.as_slice().raw, [0x1234_5678, 0x2345_6789][..]); 1683 | } 1684 | 1685 | #[cfg(feature = "bincode")] 1686 | #[test] 1687 | fn test_boxed_slice_borrow_decode() { 1688 | fn decode_whole(bytes: &[u8]) -> TiVec { 1689 | let config = bincode::config::standard(); 1690 | let (decoded, len) = bincode::borrow_decode_from_slice(bytes, config).unwrap(); 1691 | assert_eq!(len, bytes.len()); 1692 | decoded 1693 | } 1694 | 1695 | let s0: TiVec = decode_whole(&[0]); 1696 | let s1: TiVec = decode_whole(&[1, 1, b'a']); 1697 | let s2: TiVec = decode_whole(&[2, 2, b'b', b'c', 3, b'd', b'e', b'f']); 1698 | assert_eq!(s0.as_slice().raw, [""; 0][..]); 1699 | assert_eq!(s1.as_slice().raw, ["a"][..]); 1700 | assert_eq!(s2.as_slice().raw, ["bc", "def"][..]); 1701 | } 1702 | } 1703 | -------------------------------------------------------------------------------- /tests/no-alloc-and-no-std/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "no-alloc-and-std-test" 3 | version = "0.1.0" 4 | authors = ["Andrey Zheleznov "] 5 | edition = "2024" 6 | publish = false 7 | 8 | [features] 9 | alloc = ["typed-index-collections/alloc"] 10 | std = ["typed-index-collections/std"] 11 | panic-handler = [] 12 | global-allocator = [] 13 | 14 | [dependencies.typed-index-collections] 15 | path = "../.." 16 | default-features = false 17 | features = [] 18 | 19 | [profile.dev] 20 | panic = "abort" 21 | 22 | [profile.release] 23 | panic = "abort" 24 | 25 | [lints.rust] 26 | rust_2018_idioms.level = "warn" 27 | rust_2018_idioms.priority = -1 28 | future_incompatible = "warn" 29 | keyword_idents = "warn" 30 | let_underscore = "warn" 31 | meta_variable_misuse = "warn" 32 | missing_abi = "warn" 33 | missing_copy_implementations = "warn" 34 | missing_debug_implementations = "warn" 35 | missing_docs = "warn" 36 | non_ascii_idents = "warn" 37 | refining_impl_trait = "warn" 38 | single_use_lifetimes = "warn" 39 | trivial_casts = "warn" 40 | trivial_numeric_casts = "warn" 41 | unused_crate_dependencies = "warn" 42 | unused_extern_crates = "warn" 43 | unused_import_braces = "warn" 44 | unused_lifetimes = "warn" 45 | unused_qualifications = "warn" 46 | unused_results = "warn" 47 | variant_size_differences = "warn" 48 | 49 | [lints.clippy] 50 | all.level = "warn" 51 | all.priority = -1 52 | pedantic.level = "warn" 53 | pedantic.priority = -1 54 | alloc_instead_of_core = "warn" 55 | allow_attributes = "warn" 56 | allow_attributes_without_reason = "warn" 57 | arithmetic_side_effects = "warn" 58 | as_conversions = "warn" 59 | branches_sharing_code = "warn" 60 | clone_on_ref_ptr = "warn" 61 | dbg_macro = "warn" 62 | debug_assert_with_mut_call = "warn" 63 | decimal_literal_representation = "warn" 64 | default_trait_access = "warn" 65 | empty_line_after_outer_attr = "warn" 66 | empty_structs_with_brackets = "warn" 67 | error_impl_error = "warn" 68 | exit = "warn" 69 | fallible_impl_from = "warn" 70 | filetype_is_file = "warn" 71 | float_cmp_const = "warn" 72 | future_not_send = "warn" 73 | get_unwrap = "warn" 74 | if_then_some_else_none = "warn" 75 | missing_const_for_fn = "warn" 76 | missing_inline_in_public_items = "warn" 77 | modulo_arithmetic = "warn" 78 | multiple_inherent_impl = "warn" 79 | mut_mut = "warn" 80 | nonstandard_macro_braces = "warn" 81 | option_if_let_else = "warn" 82 | panic = "warn" 83 | print_stderr = "warn" 84 | rc_buffer = "warn" 85 | redundant_pub_crate = "warn" 86 | std_instead_of_core = "warn" 87 | string_lit_as_bytes = "warn" 88 | suboptimal_flops = "warn" 89 | suspicious_operation_groupings = "warn" 90 | todo = "warn" 91 | trivial_regex = "warn" 92 | try_err = "warn" 93 | undocumented_unsafe_blocks = "warn" 94 | unimplemented = "warn" 95 | unwrap_used = "warn" 96 | use_self = "warn" 97 | useless_let_if_seq = "warn" 98 | verbose_file_reads = "warn" 99 | wildcard_enum_match_arm = "warn" 100 | module_name_repetitions = "allow" # items are re-exported to the crate root 101 | -------------------------------------------------------------------------------- /tests/no-alloc-and-no-std/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | #![allow( 4 | dead_code, 5 | missing_docs, 6 | clippy::empty_loop, 7 | clippy::missing_panics_doc, 8 | clippy::panic, 9 | clippy::undocumented_unsafe_blocks, 10 | clippy::unimplemented, 11 | reason = "okay in tests" 12 | )] 13 | 14 | #[cfg(feature = "std")] 15 | extern crate std; 16 | 17 | #[cfg(feature = "global-allocator")] 18 | use core::alloc::{GlobalAlloc, Layout}; 19 | #[cfg(feature = "panic-handler")] 20 | use core::panic::PanicInfo; 21 | 22 | #[cfg(feature = "global-allocator")] 23 | struct DummyAllocator; 24 | 25 | #[cfg(feature = "global-allocator")] 26 | #[global_allocator] 27 | static GLOBAL_ALLOCATOR: DummyAllocator = DummyAllocator; 28 | 29 | #[cfg(feature = "panic-handler")] 30 | #[panic_handler] 31 | const fn panic(_: &PanicInfo<'_>) -> ! { 32 | loop {} 33 | } 34 | 35 | #[unsafe(no_mangle)] 36 | pub const extern "C" fn _start() -> ! { 37 | loop {} 38 | } 39 | 40 | #[cfg(feature = "global-allocator")] 41 | unsafe impl GlobalAlloc for DummyAllocator { 42 | unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { 43 | unimplemented!() 44 | } 45 | 46 | unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) { 47 | unimplemented!() 48 | } 49 | } 50 | 51 | #[unsafe(no_mangle)] 52 | pub const extern "C" fn test_core() { 53 | use typed_index_collections::TiSlice; 54 | struct K(usize); 55 | let slice = &[1, 2, 3]; 56 | let ti_slice: &TiSlice = TiSlice::from_ref(slice); 57 | let _ = ti_slice; 58 | } 59 | 60 | #[cfg(feature = "alloc")] 61 | #[unsafe(no_mangle)] 62 | pub extern "C" fn test_alloc() { 63 | use typed_index_collections::TiVec; 64 | 65 | struct K(usize); 66 | let mut ti_vec: TiVec = TiVec::new(); 67 | ti_vec.extend([1, 2, 3]); 68 | drop(ti_vec); 69 | } 70 | 71 | #[cfg(feature = "std")] 72 | #[unsafe(no_mangle)] 73 | pub extern "C" fn test_std() { 74 | use std::io::Write; 75 | use typed_index_collections::TiVec; 76 | 77 | struct K(usize); 78 | let mut ti_vec: TiVec = TiVec::new(); 79 | let _res = ti_vec.write_all(&[4, 5, 6]); 80 | drop(ti_vec); 81 | } 82 | -------------------------------------------------------------------------------- /tests/readme.rs: -------------------------------------------------------------------------------- 1 | #![allow(missing_docs, reason = "okay in tests")] 2 | #![expect( 3 | unused_crate_dependencies, 4 | clippy::unwrap_used, 5 | reason = "okay in tests" 6 | )] 7 | 8 | #[cfg(all(test, not(miri)))] 9 | #[test] 10 | fn test_readme_sync() { 11 | use readme_sync::{assert_sync, CMarkDocs, CMarkReadme, Config, Package}; 12 | 13 | let package = Package::from_path(env!("CARGO_MANIFEST_DIR").into()).unwrap(); 14 | let config = Config::from_package_docs_rs_features(&package); 15 | let readme = CMarkReadme::from_package(&package).unwrap(); 16 | let docs = CMarkDocs::from_package_and_config(&package, &config).unwrap(); 17 | 18 | let readme = readme 19 | .remove_badges_paragraph() 20 | .remove_documentation_section() 21 | .disallow_absolute_repository_blob_links() 22 | .unwrap() 23 | .use_absolute_repository_blob_urls() 24 | .unwrap(); 25 | 26 | let docs = docs 27 | .increment_heading_levels() 28 | .add_package_title() 29 | .remove_codeblock_rust_test_tags() 30 | .use_default_codeblock_rust_tag() 31 | .remove_hidden_rust_code() 32 | .disallow_absolute_package_docs_links() 33 | .unwrap() 34 | .use_absolute_package_docs_urls() 35 | .unwrap(); 36 | 37 | assert_sync(&readme, &docs); 38 | } 39 | -------------------------------------------------------------------------------- /tests/version.rs: -------------------------------------------------------------------------------- 1 | #![allow(missing_docs, reason = "okay in tests")] 2 | #![expect(unused_crate_dependencies, reason = "okay in tests")] 3 | 4 | #[cfg(all(test, not(miri)))] 5 | #[test] 6 | fn test_readme_deps() { 7 | version_sync::assert_markdown_deps_updated!("README.md"); 8 | } 9 | 10 | #[cfg(all(test, not(miri)))] 11 | #[test] 12 | fn test_html_root_url() { 13 | version_sync::assert_html_root_url_updated!("src/lib.rs"); 14 | } 15 | 16 | #[cfg(all(test, not(miri)))] 17 | #[test] 18 | fn test_changelog_mentions_version() { 19 | version_sync::assert_contains_regex!("CHANGELOG.md", "^## \\[{version}\\] - "); 20 | version_sync::assert_contains_regex!("CHANGELOG.md", "\\[{version}\\]: "); 21 | } 22 | --------------------------------------------------------------------------------