├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches ├── complex.rs └── simple.rs ├── examples ├── array_vs_fixed.rs ├── basic.rs ├── composite.rs └── values_iter.rs ├── fixed-map-derive ├── Cargo.toml ├── README.md └── src │ ├── any_variants.rs │ ├── attrs.rs │ ├── context.rs │ ├── lib.rs │ ├── symbol.rs │ └── unit_variants.rs ├── src ├── key.rs ├── lib.rs ├── macro_support.rs ├── map.rs ├── map │ ├── entry.rs │ ├── storage.rs │ └── storage │ │ ├── boolean.rs │ │ ├── hashbrown.rs │ │ ├── option.rs │ │ └── singleton.rs ├── option_bucket.rs ├── option_bucket │ └── tests.rs ├── raw.rs ├── set.rs └── set │ ├── intersection.rs │ ├── storage.rs │ └── storage │ ├── boolean.rs │ ├── hashbrown.rs │ ├── option.rs │ └── singleton.rs └── tests ├── empty.rs ├── entry.rs └── map_feature.rs /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: {} 5 | push: 6 | branches: 7 | - main 8 | schedule: 9 | - cron: '38 21 * * 6' 10 | 11 | concurrency: 12 | group: ${{ github.workflow }}-${{ github.ref }} 13 | cancel-in-progress: true 14 | 15 | jobs: 16 | msrv: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | - uses: dtolnay/rust-toolchain@1.72 21 | - run: cargo build --workspace --lib 22 | - run: cargo build --workspace --no-default-features --lib 23 | 24 | test: 25 | runs-on: ubuntu-latest 26 | steps: 27 | - uses: actions/checkout@v4 28 | - uses: dtolnay/rust-toolchain@stable 29 | - run: cargo test --workspace --all-targets --all-features 30 | - run: cargo test --workspace --doc --all-features 31 | 32 | clippy: 33 | runs-on: ubuntu-latest 34 | steps: 35 | - uses: actions/checkout@v4 36 | - uses: dtolnay/rust-toolchain@stable 37 | with: 38 | components: clippy 39 | - run: cargo clippy --workspace --all-features --all-targets -- -D warnings 40 | 41 | rustfmt: 42 | runs-on: ubuntu-latest 43 | steps: 44 | - uses: actions/checkout@v4 45 | - uses: dtolnay/rust-toolchain@stable 46 | with: 47 | components: clippy 48 | - run: cargo fmt --check --all 49 | 50 | docs: 51 | runs-on: ubuntu-latest 52 | steps: 53 | - uses: actions/checkout@v4 54 | - uses: dtolnay/rust-toolchain@nightly 55 | - uses: Swatinem/rust-cache@v2 56 | - run: cargo doc --lib --no-deps --document-private-items 57 | env: 58 | RUSTFLAGS: --cfg doc_cfg 59 | RUSTDOCFLAGS: --cfg doc_cfg -D warnings 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | /target 3 | /fixed-map-derive/target 4 | **/*.rs.bk 5 | .vscode 6 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fixed-map" 3 | version = "0.9.5" 4 | authors = ["John-John Tedro ", "Peter Jaszkowiak "] 5 | edition = "2021" 6 | rust-version = "1.72" 7 | description = "A fixed map where storage layout is calculated by a procedural macro." 8 | documentation = "https://docs.rs/fixed-map" 9 | readme = "README.md" 10 | homepage = "https://github.com/udoprog/fixed-map" 11 | repository = "https://github.com/udoprog/fixed-map" 12 | license = "MIT OR Apache-2.0" 13 | keywords = ["container", "data-structure", "map", "no_std"] 14 | categories = ["data-structures"] 15 | 16 | [package.metadata.docs.rs] 17 | all-features = true 18 | 19 | [features] 20 | default = ["hashbrown", "std"] 21 | std = ["serde?/std"] 22 | 23 | [dependencies] 24 | fixed-map-derive = { version = "=0.9.5", path = "fixed-map-derive" } 25 | hashbrown = { version = "0.13.2", optional = true } 26 | serde = { version = "1.0.145", optional = true, default-features = false } 27 | 28 | [dev-dependencies] 29 | criterion = "0.4.0" 30 | hashbrown = "0.13.2" 31 | 32 | [[bench]] 33 | name = "complex" 34 | harness = false 35 | 36 | [[bench]] 37 | name = "simple" 38 | harness = false 39 | 40 | [workspace] 41 | members = [ 42 | "fixed-map-derive" 43 | ] 44 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 John-John Tedro 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fixed-map 2 | 3 | [github](https://github.com/udoprog/fixed-map) 4 | [crates.io](https://crates.io/crates/fixed-map) 5 | [docs.rs](https://docs.rs/fixed-map) 6 | [build status](https://github.com/udoprog/fixed-map/actions?query=branch%3Amain) 7 | 8 | This crate provides a [`Map`] and [`Set`] container that can make use of a 9 | pre-calculated backing storage. This enables the Rust compiler to heavily 10 | optimize operations over them and avoid allocating. 11 | 12 | See [documentation] for information on how to use this crate. 13 | 14 |
15 | 16 | ## Usage 17 | 18 | Add `fixed-map` to your `Cargo.toml`: 19 | 20 | ```toml 21 | [dependencies] 22 | fixed-map = "0.9.5" 23 | ``` 24 | 25 | Anything used as a key in either a [`Map`] or a [`Set`] needs to implement 26 | the [`Key`] trait. This should be derived: 27 | 28 | ```rust 29 | use fixed_map::{Key, Map}; 30 | 31 | #[derive(Clone, Copy, Key)] 32 | enum MyKey { 33 | North, 34 | South, 35 | East, 36 | West, 37 | } 38 | ``` 39 | 40 | After this you can use one of our containers: 41 | 42 | ```rust 43 | use fixed_map::{Map, Set}; 44 | 45 | let mut map = Map::new(); 46 | map.insert(MyKey::North, 200); 47 | map.insert(MyKey::South, 100); 48 | 49 | assert_eq!(map.get(MyKey::North), Some(&200)); 50 | assert_eq!(map.get(MyKey::East), None); 51 | 52 | let mut set = Set::new(); 53 | set.insert(MyKey::North); 54 | set.insert(MyKey::South); 55 | 56 | assert!(set.contains(MyKey::South)); 57 | assert!(!set.contains(MyKey::East)); 58 | ``` 59 | 60 |
61 | 62 | ## Features 63 | 64 | The following features are available: 65 | 66 | * `std` - Disabling this feature causes this crate to be no-std. This means 67 | that dynamic types cannot be used in keys, like ones enabled by the `map` 68 | feature (default). 69 | * `hashbrown` - Causes [`Storage`] to be implemented by dynamic types such 70 | as `&'static str` or `u32`. These are backed by a `hashbrown` (default). 71 | * `entry` - Enables an [`entry`] API similar to that found on [`HashMap`]. 72 | * `serde` - Causes [`Map`] and [`Set`] to implement [`Serialize`] and 73 | [`Deserialize`] if it's implemented by the key and value. 74 | 75 |
76 | 77 | ## Specialized storage through the [`Key`] trait 78 | 79 | The [`Key` derive] is provided to instruct our containers on how to build 80 | optimized storage for a given [`Key`]. We also require any key to be [`Copy`]. 81 | 82 | ```rust 83 | use fixed_map::Key; 84 | 85 | #[derive(Clone, Copy, Key)] 86 | enum MyKey { 87 | North, 88 | South, 89 | East, 90 | West, 91 | } 92 | ``` 93 | 94 | What happens behind the scenes is that a proc macro is used to build a 95 | struct optimized for storing and indexing exactly 4 values - one for each 96 | variant. 97 | 98 | Something exactly like this: 99 | 100 | ```rust 101 | struct Storage { 102 | data: [Option; 4], 103 | } 104 | ``` 105 | 106 | It becomes a bit more complicated once we start considering *composite 107 | keys*. See the [`Key`] documentation for more information. 108 | 109 |
110 | 111 | ## Why does this crate exist? 112 | 113 | There are many cases where you want associate a value with a small, fixed 114 | number of elements identified by an enum. 115 | 116 | Let's say you have a game where each room has something in four directions. 117 | We can model this relationship between the direction and the item using two 118 | enums. 119 | 120 | ```rust 121 | #[repr(usize)] 122 | pub enum Dir { 123 | North, 124 | East, 125 | South, 126 | West, 127 | } 128 | 129 | pub enum Item { 130 | Bow, 131 | Sword, 132 | Axe, 133 | } 134 | ``` 135 | 136 | The goal is for the performance of fixed map to be identical to storing the 137 | data linearly in memory like you could through an array like `[Option; 138 | N]` where each *index* corresponds to a variant in `Dir`. 139 | 140 | Doing this manually could look like this: 141 | 142 | ```rust 143 | let mut map: [Option; 4] = [None, None, None, None]; 144 | map[Dir::North as usize] = Some(Item::Bow); 145 | 146 | if let Some(item) = &map[Dir::North as usize] { 147 | println!("found item: {:?}", item); 148 | } 149 | ``` 150 | 151 | But with a fixed [`Map`] you can do it idiomatically like this, without 152 | incurring a drop in performance: 153 | 154 | ```rust 155 | use fixed_map::{Key, Map}; 156 | 157 | #[derive(Clone, Copy, Key)] 158 | pub enum Dir { 159 | North, 160 | East, 161 | South, 162 | West, 163 | } 164 | 165 | #[derive(Debug)] 166 | pub enum Item { 167 | Bow, 168 | Sword, 169 | Axe, 170 | } 171 | 172 | let mut map = Map::new(); 173 | map.insert(Dir::North, Item::Bow); 174 | 175 | if let Some(item) = map.get(Dir::North) { 176 | println!("found item: {:?}", item); 177 | } 178 | ``` 179 | 180 |
181 | 182 | ## Unsafe use 183 | 184 | The Entry API uses `unwrap_unchecked` to obtain mutable references to the 185 | inner value of `Some`s, and to skip `drop` when overwriting `None`s. 186 | 187 |
188 | 189 | ## Benchmarks 190 | 191 | We include benchmarks to ensure that we abide by the expectation that a 192 | fixed map or set should perform roughly the same as an array with the same 193 | number of elements. 194 | 195 | In the following benchmarks fixed-map is compared to: 196 | 197 | * `fixed` - A [`Map`] with a derived [`Key`] with `N` variants. 198 | * [`hashbrown`] - A high performance hash map. This is only included for 199 | reference. 200 | - Note: Maps are created with `HashMap::with_capacity(N)`. 201 | * `array` - A simple `[Option; N]` array. 202 | 203 | Note: for all `insert` benchmarks the underlying storage is cloned in each 204 | iteration. 205 | 206 | ```text 207 | get/fixed/4 time: [208.96 ps 209.57 ps 210.17 ps] 208 | get/fixed/8 time: [211.12 ps 211.86 ps 212.55 ps] 209 | get/fixed/16 time: [211.50 ps 211.84 ps 212.23 ps] 210 | get/fixed/32 time: [211.02 ps 211.40 ps 211.79 ps] 211 | get/array/4 time: [215.76 ps 216.56 ps 217.68 ps] 212 | get/array/8 time: [216.80 ps 217.28 ps 217.83 ps] 213 | get/array/16 time: [215.88 ps 216.21 ps 216.58 ps] 214 | get/array/32 time: [216.39 ps 216.82 ps 217.33 ps] 215 | get/hashbrown/4 time: [2.9134 ns 2.9168 ns 2.9210 ns] 216 | get/hashbrown/8 time: [2.9143 ns 2.9175 ns 2.9212 ns] 217 | get/hashbrown/16 time: [2.9258 ns 2.9293 ns 2.9328 ns] 218 | get/hashbrown/32 time: [2.9387 ns 2.9428 ns 2.9466 ns] 219 | 220 | insert/fixed/4 time: [421.82 ps 422.47 ps 423.22 ps] 221 | insert/fixed/8 time: [635.46 ps 636.91 ps 638.55 ps] 222 | insert/fixed/16 time: [1.0579 ns 1.0599 ns 1.0621 ns] 223 | insert/fixed/32 time: [1.6991 ns 1.7016 ns 1.7043 ns] 224 | insert/array/4 time: [419.26 ps 419.76 ps 420.30 ps] 225 | insert/array/8 time: [624.30 ps 626.27 ps 628.33 ps] 226 | insert/array/16 time: [1.0444 ns 1.0467 ns 1.0490 ns] 227 | insert/array/32 time: [1.6828 ns 1.6904 ns 1.6990 ns] 228 | insert/hashbrown/4 time: [87.002 ns 87.233 ns 87.475 ns] 229 | insert/hashbrown/8 time: [96.995 ns 97.287 ns 97.589 ns] 230 | insert/hashbrown/16 time: [517.89 ns 518.66 ns 519.57 ns] 231 | insert/hashbrown/32 time: [156.10 ns 156.67 ns 157.30 ns] 232 | 233 | values/fixed/4 time: [209.09 ps 209.51 ps 209.91 ps] 234 | values/fixed/8 time: [213.99 ps 215.34 ps 217.08 ps] 235 | values/fixed/16 time: [213.24 ps 213.94 ps 214.72 ps] 236 | values/fixed/32 time: [212.71 ps 213.82 ps 215.15 ps] 237 | values/array/4 time: [211.07 ps 211.78 ps 212.59 ps] 238 | values/array/8 time: [211.48 ps 212.03 ps 212.65 ps] 239 | values/array/16 time: [213.04 ps 213.49 ps 213.99 ps] 240 | values/array/32 time: [213.18 ps 213.78 ps 214.60 ps] 241 | values/hashbrown/4 time: [3.3965 ns 3.4007 ns 3.4056 ns] 242 | values/hashbrown/8 time: [3.8443 ns 3.8627 ns 3.8895 ns] 243 | values/hashbrown/16 time: [5.6312 ns 5.6666 ns 5.7029 ns] 244 | values/hashbrown/32 time: [8.7221 ns 8.7674 ns 8.8117 ns] 245 | 246 | array/sum_values time: [3.0394 ns 3.0463 ns 3.0534 ns] 247 | fixed/sum_values time: [3.0503 ns 3.0559 ns 3.0619 ns] 248 | ``` 249 | 250 |
251 | 252 | ## Examples 253 | 254 | Most examples are in place to test what kind of assembler they compile to. 255 | 256 | To do this, run: 257 | 258 | ```sh 259 | RUSTFLAGS="--emit asm" cargo build --release --example 260 | ``` 261 | 262 | You should be able to find the assembler generated in the target folder: 263 | 264 | ```sh 265 | ls target/release/examples/ 266 | ``` 267 | 268 | [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html 269 | [`Deserialize`]: https://docs.rs/serde/1/serde/trait.Deserialize.html 270 | [`hashbrown`]: https://github.com/Amanieu/hashbrown 271 | [`Key` derive]: https://docs.rs/fixed-map/latest/fixed_map/derive.Key.html 272 | [`Key`]: https://docs.rs/fixed-map/latest/fixed_map/derive.Key.html 273 | [`Map`]: https://docs.rs/fixed-map/latest/fixed_map/map/struct.Map.html 274 | [`entry`]: https://docs.rs/fixed-map/latest/fixed_map/map/struct.Map.html#method.entry 275 | [`HashMap`]: https://doc.rust-lang.org/stable/std/collections/hash_map/struct.HashMap.html#method.entry 276 | [`Serialize`]: https://docs.rs/serde/1/serde/trait.Serialize.html 277 | [`Set`]: https://docs.rs/fixed-map/latest/fixed_map/set/struct.Set.html 278 | [`Storage`]: https://docs.rs/fixed-map/latest/fixed_map/storage/trait.Storage.html 279 | [documentation]: https://docs.rs/fixed-map 280 | -------------------------------------------------------------------------------- /benches/complex.rs: -------------------------------------------------------------------------------- 1 | use core::mem; 2 | 3 | use criterion::{Bencher, BenchmarkId, Criterion}; 4 | 5 | macro_rules! benches { 6 | ( 7 | $({ 8 | $len:expr, ($($member:ident),* $(,)?), 9 | insert = [$($insert:ident),* $(,)?], 10 | get => $get:ident, 11 | entry => [$($entry:ident),* $(,)?], 12 | };)* 13 | ) => { 14 | fn get_benches(criterion: &mut Criterion) { 15 | let mut group = criterion.benchmark_group("get"); 16 | 17 | $({ 18 | #[allow(unused)] 19 | #[derive(Clone, Copy, fixed_map::Key)] 20 | pub enum Key { $($member,)* } 21 | 22 | // Assert that size of Key is identical to array. 23 | const _: () = assert!( 24 | mem::size_of::<::MapStorage>() == mem::size_of::<[Option; $len]>() 25 | ); 26 | 27 | group.bench_with_input(BenchmarkId::new("fixed", $len), &$len, |b: &mut Bencher, _| { 28 | let mut it = 1u32..; 29 | let mut map = fixed_map::Map::new(); 30 | $(map.insert(Key::$insert, it.next().unwrap());)* 31 | 32 | b.iter(|| map.get(Key::$get)) 33 | }); 34 | })* 35 | 36 | $({ 37 | #[allow(unused)] 38 | #[derive(PartialEq, Eq, Hash)] 39 | pub enum Key { $($member,)* } 40 | 41 | group.bench_with_input(BenchmarkId::new("hashbrown", $len), &$len, |b: &mut Bencher, _| { 42 | let mut it = 1u32..; 43 | let mut map = hashbrown::HashMap::with_capacity($len); 44 | $(map.insert(Key::$insert, it.next().unwrap());)* 45 | 46 | b.iter(|| map.get(&Key::$get)) 47 | }); 48 | })* 49 | 50 | $({ 51 | #[allow(unused)] 52 | #[repr(usize)] 53 | pub enum Key { $($member,)* } 54 | 55 | group.bench_with_input(BenchmarkId::new("array", $len), &$len, |b: &mut Bencher, _| { 56 | let mut it = 1u32..; 57 | let mut map = [None; $len]; 58 | $(map[Key::$insert as usize] = Some(it.next().unwrap());)* 59 | 60 | b.iter(|| map[Key::$get as usize]) 61 | }); 62 | })* 63 | } 64 | 65 | fn insert_benches(criterion: &mut Criterion) { 66 | let mut group = criterion.benchmark_group("insert"); 67 | 68 | $({ 69 | #[allow(unused)] 70 | #[derive(Clone, Copy, fixed_map::Key)] 71 | pub enum Key { $($member,)* } 72 | 73 | group.bench_with_input(BenchmarkId::new("fixed", $len), &$len, |b: &mut Bencher, _| { 74 | b.iter(|| { 75 | let mut map = fixed_map::Map::::new(); 76 | $(map.insert(Key::$insert, 42u32);)* 77 | ($(map.get(Key::$insert).cloned(),)*) 78 | }) 79 | }); 80 | })* 81 | 82 | $({ 83 | #[allow(unused)] 84 | #[derive(Clone, PartialEq, Eq, Hash)] 85 | pub enum Key { $($member,)* } 86 | 87 | group.bench_with_input(BenchmarkId::new("hashbrown", $len), &$len, |b: &mut Bencher, _| { 88 | b.iter(|| { 89 | let mut map = hashbrown::HashMap::<_, u32>::with_capacity($len); 90 | $(map.insert(Key::$insert, 42u32);)* 91 | ($(map.get(&Key::$insert).cloned(),)*) 92 | }) 93 | }); 94 | })* 95 | 96 | $({ 97 | #[allow(unused)] 98 | #[repr(usize)] 99 | pub enum Key { $($member,)* } 100 | 101 | group.bench_with_input(BenchmarkId::new("array", $len), &$len, |b: &mut Bencher, _| { 102 | b.iter(|| { 103 | let mut map = [None; $len]; 104 | $(map[Key::$insert as usize] = Some(42u32);)* 105 | ($(map[Key::$insert as usize].as_ref().cloned(),)*) 106 | }) 107 | }); 108 | })* 109 | } 110 | 111 | fn values_benches(criterion: &mut Criterion) { 112 | let mut group = criterion.benchmark_group("values"); 113 | 114 | $({ 115 | #[allow(unused)] 116 | #[derive(Clone, Copy, fixed_map::Key)] 117 | pub enum Key { $($member,)* } 118 | 119 | group.bench_with_input(BenchmarkId::new("fixed", $len), &$len, |b: &mut Bencher, _| { 120 | let mut it = 1u32..; 121 | let mut map = fixed_map::Map::new(); 122 | $(map.insert(Key::$insert, it.next().unwrap());)* 123 | 124 | b.iter(|| map.values().copied().sum::()) 125 | }); 126 | })* 127 | 128 | $({ 129 | #[allow(unused)] 130 | #[derive(PartialEq, Eq, Hash)] 131 | pub enum Key { $($member,)* } 132 | 133 | group.bench_with_input(BenchmarkId::new("hashbrown", $len), &$len, |b: &mut Bencher, len| { 134 | let mut it = 1u32..; 135 | let mut map = hashbrown::HashMap::with_capacity(*len); 136 | $(map.insert(Key::$insert, it.next().unwrap());)* 137 | 138 | b.iter(|| map.values().copied().sum::()) 139 | }); 140 | })* 141 | 142 | $({ 143 | #[allow(unused)] 144 | #[repr(usize)] 145 | pub enum Key { $($member,)* } 146 | 147 | group.bench_with_input(BenchmarkId::new("array", $len), &$len, |b: &mut Bencher, _| { 148 | let mut it = 1u32..; 149 | let mut map = [None; $len]; 150 | $(map[Key::$insert as usize] = Some(it.next().unwrap());)* 151 | 152 | b.iter(|| map.iter().flatten().copied().sum::()) 153 | }); 154 | })* 155 | } 156 | 157 | fn entry_benches(criterion: &mut Criterion) { 158 | let mut group = criterion.benchmark_group("entry"); 159 | 160 | $({ 161 | #[allow(unused)] 162 | #[derive(Clone, Copy, fixed_map::Key)] 163 | pub enum Key { $($member,)* } 164 | 165 | group.bench_with_input(BenchmarkId::new("fixed", $len), &$len, |b: &mut Bencher, _| { 166 | let mut it = 1u32..; 167 | let mut map = fixed_map::Map::new(); 168 | $(map.insert(Key::$insert, it.next().unwrap());)* 169 | 170 | b.iter(|| { 171 | let mut value = 0; 172 | let mut map = map.clone(); 173 | 174 | $({ 175 | let v = map.entry(Key::$entry).or_default(); 176 | *v += 1; 177 | value += *v; 178 | })* 179 | 180 | value 181 | }); 182 | }); 183 | })* 184 | 185 | $({ 186 | #[allow(unused)] 187 | #[derive(Clone, PartialEq, Eq, Hash)] 188 | pub enum Key { $($member,)* } 189 | 190 | group.bench_with_input(BenchmarkId::new("hashbrown", $len), &$len, |b: &mut Bencher, _| { 191 | let mut it = 1u32..; 192 | let mut map = hashbrown::HashMap::with_capacity($len); 193 | $(map.insert(Key::$insert, it.next().unwrap());)* 194 | 195 | b.iter(|| { 196 | let mut map = map.clone(); 197 | let mut value = 0; 198 | 199 | $({ 200 | let v = map.entry(Key::$entry).or_default(); 201 | *v += 1; 202 | value += *v; 203 | })* 204 | 205 | value 206 | }); 207 | }); 208 | })* 209 | 210 | $({ 211 | #[allow(unused)] 212 | #[repr(usize)] 213 | pub enum Key { $($member,)* } 214 | 215 | group.bench_with_input(BenchmarkId::new("array", $len), &$len, |b: &mut Bencher, _| { 216 | let mut it = 1u32..; 217 | let mut map = [None; $len]; 218 | $(map[Key::$insert as usize] = Some(it.next().unwrap());)* 219 | 220 | b.iter(|| { 221 | let mut map = map; 222 | let mut value = 0; 223 | 224 | $({ 225 | let v = map[Key::$entry as usize].get_or_insert_with(Default::default); 226 | *v += 1; 227 | value += *v; 228 | })* 229 | 230 | value 231 | }); 232 | }); 233 | })* 234 | }} 235 | } 236 | 237 | benches! { 238 | { 239 | 4, 240 | (T00, T01, T02, T03), 241 | insert = [T00, T03], 242 | get => T03, 243 | entry => [T02, T03], 244 | }; 245 | 246 | { 247 | 8, 248 | (T00, T01, T02, T03, T04, T05, T06, T07), 249 | insert = [T00, T03, T06], 250 | get => T03, 251 | entry => [T02, T03], 252 | }; 253 | 254 | { 255 | 16, 256 | (T00, T01, T02, T03, T04, T05, T06, T07, T8, T9, T10, T11, T12, T13, T14, T15), 257 | insert = [T00, T03, T06, T12, T14], 258 | get => T14, 259 | entry => [T02, T14], 260 | }; 261 | 262 | { 263 | 32, 264 | ( 265 | T00, T01, T02, T03, T04, T05, T06, T07, T08, T09, T10, T11, T12, T13, T14, T15, 266 | T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31 267 | ), 268 | insert = [T00, T03, T06, T12, T14, T23, T28, T31], 269 | get => T28, 270 | entry => [T11, T28], 271 | }; 272 | } 273 | 274 | criterion::criterion_group! { 275 | name = complex; 276 | config = Criterion::default(); 277 | targets = get_benches, insert_benches, values_benches, entry_benches 278 | } 279 | 280 | criterion::criterion_main!(complex); 281 | -------------------------------------------------------------------------------- /benches/simple.rs: -------------------------------------------------------------------------------- 1 | use criterion::Criterion; 2 | 3 | macro_rules! expand { 4 | ($len:expr, ($($member:ident),*), $get:ident) => { 5 | #[allow(unused)] 6 | #[derive(Clone, Copy, fixed_map::Key)] 7 | pub enum FixedKey { 8 | $($member,)* 9 | } 10 | 11 | #[no_mangle] 12 | #[inline(never)] 13 | pub fn sum_fixed(map: &fixed_map::Map) -> u32 { 14 | map.values().copied().sum() 15 | } 16 | 17 | #[allow(unused)] 18 | #[repr(usize)] 19 | pub enum ArrayKey { 20 | $($member,)* 21 | } 22 | 23 | #[no_mangle] 24 | #[inline(never)] 25 | pub fn sum_array(map: &[Option; $len]) -> u32 { 26 | map.iter().flatten().copied().sum() 27 | } 28 | } 29 | } 30 | 31 | expand! { 32 | 16, 33 | (T00, T01, T02, T03, T04, T05, T06, T07, T8, T9, T10, T11, T12, T13, T14, T15), 34 | T14 35 | } 36 | 37 | fn benches(criterion: &mut Criterion) { 38 | { 39 | let mut group = criterion.benchmark_group("array"); 40 | 41 | group.bench_function("sum_values", |iter| { 42 | let mut array = [None; 16]; 43 | array[ArrayKey::T07 as usize] = Some(4); 44 | array[ArrayKey::T10 as usize] = Some(13); 45 | 46 | iter.iter(|| sum_array(&array)) 47 | }); 48 | } 49 | 50 | { 51 | let mut group = criterion.benchmark_group("fixed"); 52 | 53 | group.bench_function("sum_values", |iter| { 54 | let mut map = fixed_map::Map::<_, u32>::new(); 55 | map.insert(FixedKey::T07, 4); 56 | map.insert(FixedKey::T10, 13); 57 | 58 | iter.iter(|| sum_fixed(&map)) 59 | }); 60 | } 61 | } 62 | 63 | criterion::criterion_group! { 64 | name = simple; 65 | config = Criterion::default(); 66 | targets = benches 67 | } 68 | 69 | criterion::criterion_main!(simple); 70 | -------------------------------------------------------------------------------- /examples/array_vs_fixed.rs: -------------------------------------------------------------------------------- 1 | //! These two should expand to roughly the same implementation. 2 | 3 | macro_rules! expand { 4 | ($len:expr, ($($member:ident),*), $get:ident) => { 5 | #[allow(unused)] 6 | #[derive(Clone, Copy, fixed_map::Key)] 7 | pub enum FixedKey { 8 | $($member,)* 9 | } 10 | 11 | #[no_mangle] 12 | #[inline(never)] 13 | pub fn test_fixed(map: &fixed_map::Map) -> Option { 14 | map.get(FixedKey::$get).cloned() 15 | } 16 | 17 | #[allow(unused)] 18 | #[repr(usize)] 19 | pub enum ArrayKey { 20 | $($member,)* 21 | } 22 | 23 | #[no_mangle] 24 | #[inline(never)] 25 | pub fn test_array(map: &[Option; $len]) -> Option { 26 | map[ArrayKey::$get as usize].as_ref().cloned() 27 | } 28 | } 29 | } 30 | 31 | expand! { 32 | 16, 33 | (T00, T01, T02, T03, T04, T05, T06, T07, T8, T9, T10, T11, T12, T13, T14, T15), 34 | T14 35 | } 36 | 37 | fn main() { 38 | let mut map = fixed_map::Map::new(); 39 | map.insert(FixedKey::T10, 42u32); 40 | 41 | let mut array = [None; 16]; 42 | array[ArrayKey::T10 as usize] = Some(42u32); 43 | 44 | println!("Fixed: {:?}", test_fixed(&map)); 45 | println!("Array: {:?}", test_array(&array)); 46 | } 47 | -------------------------------------------------------------------------------- /examples/basic.rs: -------------------------------------------------------------------------------- 1 | use fixed_map::{Key, Map}; 2 | 3 | #[derive(Debug, Clone, Copy, Key)] 4 | enum MyKey { 5 | First, 6 | Second, 7 | } 8 | 9 | fn main() { 10 | let mut map = Map::new(); 11 | map.insert(MyKey::First, 42); 12 | assert_eq!(map.get(MyKey::First), Some(&42)); 13 | assert_eq!(map.get(MyKey::Second), None); 14 | } 15 | -------------------------------------------------------------------------------- /examples/composite.rs: -------------------------------------------------------------------------------- 1 | use fixed_map::{Key, Map}; 2 | 3 | #[derive(Clone, Copy, Key)] 4 | enum Part { 5 | One, 6 | Two, 7 | } 8 | 9 | #[derive(Clone, Copy, Key)] 10 | enum MyKey { 11 | Simple, 12 | Composite(Part), 13 | Singleton(()), 14 | } 15 | 16 | fn main() { 17 | let mut map = Map::new(); 18 | map.insert(MyKey::Composite(Part::One), 42); 19 | assert_eq!(map.get(MyKey::Composite(Part::One)), Some(&42)); 20 | assert_eq!(map.get(MyKey::Simple), None); 21 | } 22 | -------------------------------------------------------------------------------- /examples/values_iter.rs: -------------------------------------------------------------------------------- 1 | //! These two should expand to roughly the same implementation. 2 | 3 | macro_rules! expand { 4 | ($len:expr, ($($member:ident),*), $get:ident) => { 5 | #[allow(unused)] 6 | #[derive(Clone, Copy, fixed_map::Key)] 7 | pub enum FixedKey { 8 | $($member,)* 9 | } 10 | 11 | #[no_mangle] 12 | #[inline(never)] 13 | pub fn test_fixed(map: &fixed_map::Map) -> u32 { 14 | map.values().copied().sum() 15 | } 16 | 17 | #[allow(unused)] 18 | #[repr(usize)] 19 | pub enum ArrayKey { 20 | $($member,)* 21 | } 22 | 23 | #[no_mangle] 24 | #[inline(never)] 25 | pub fn test_array(map: &[Option; $len]) -> u32 { 26 | map.iter().flat_map(|v| v).copied().sum() 27 | } 28 | } 29 | } 30 | 31 | expand! { 32 | 16, 33 | (T00, T01, T02, T03, T04, T05, T06, T07, T8, T9, T10, T11, T12, T13, T14, T15), 34 | T14 35 | } 36 | 37 | fn main() { 38 | let mut map = fixed_map::Map::<_, u32>::new(); 39 | map.insert(FixedKey::T07, 4); 40 | map.insert(FixedKey::T10, 13); 41 | 42 | let mut array = [None; 16]; 43 | array[ArrayKey::T07 as usize] = Some(4); 44 | array[ArrayKey::T10 as usize] = Some(13); 45 | 46 | println!("Fixed: {:?}", test_fixed(&map)); 47 | println!("Array: {:?}", test_array(&array)); 48 | } 49 | -------------------------------------------------------------------------------- /fixed-map-derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fixed-map-derive" 3 | version = "0.9.5" 4 | authors = ["John-John Tedro "] 5 | edition = "2018" 6 | rust-version = "1.72" 7 | description = """ 8 | A fixed map where storage layout is calculated by a procedural macro. 9 | 10 | This crate contains the procedural macros. 11 | """ 12 | documentation = "https://docs.rs/fixed-map" 13 | readme = "README.md" 14 | homepage = "https://github.com/udoprog/fixed-map" 15 | repository = "https://github.com/udoprog/fixed-map" 16 | license = "MIT OR Apache-2.0" 17 | keywords = ["container", "data-structure", "map", "no_std"] 18 | categories = ["data-structures"] 19 | 20 | [dependencies] 21 | syn = { version = "2.0.15", features = ["full"] } 22 | quote = "1.0.26" 23 | proc-macro2 = "1.0.56" 24 | 25 | [lib] 26 | proc-macro = true 27 | -------------------------------------------------------------------------------- /fixed-map-derive/README.md: -------------------------------------------------------------------------------- 1 | # fixed-map-derive 2 | 3 | [github](https://github.com/udoprog/fixed-map) 4 | [crates.io](https://crates.io/crates/fixed-map-derive) 5 | [docs.rs](https://docs.rs/fixed-map-derive) 6 | [build status](https://github.com/udoprog/fixed-map/actions?query=branch%3Amain) 7 | 8 | This crate contains the procedural macros used in [fixed-map]. 9 | 10 | [fixed-map]: https://github.com/udoprog/fixed-map 11 | -------------------------------------------------------------------------------- /fixed-map-derive/src/attrs.rs: -------------------------------------------------------------------------------- 1 | use crate::context::{Ctxt, Opts}; 2 | use crate::symbol; 3 | 4 | /// Parse attributes. 5 | pub(crate) fn parse(cx: &Ctxt<'_>) -> Result { 6 | let mut opts = Opts::default(); 7 | 8 | for attr in &cx.ast.attrs { 9 | if attr.path() != symbol::KEY { 10 | continue; 11 | } 12 | 13 | let result = attr.parse_nested_meta(|input| { 14 | if input.path == symbol::BITSET { 15 | opts.bitset = Some(input.input.span()); 16 | } else { 17 | return Err(syn::Error::new(input.input.span(), "Unsupported attribute")); 18 | } 19 | 20 | Ok(()) 21 | }); 22 | 23 | if let Err(error) = result { 24 | cx.error(error); 25 | } 26 | } 27 | 28 | Ok(opts) 29 | } 30 | -------------------------------------------------------------------------------- /fixed-map-derive/src/context.rs: -------------------------------------------------------------------------------- 1 | use core::cell::RefCell; 2 | use core::fmt; 3 | 4 | use proc_macro2::Span; 5 | use syn::{DeriveInput, Path}; 6 | 7 | // Builder function to use when constructing token. 8 | type Builder = fn(&Toks<'_>) -> Path; 9 | 10 | // Helper macro to define re-usable token paths. 11 | macro_rules! toks { 12 | ($vis:vis struct $ident:ident <$lt:lifetime> { $($field:ident = [$($path:tt)*]),* $(,)? }) => { 13 | $vis struct $ident<$lt> { 14 | core: Path, 15 | crate_prefix: &$lt Path, 16 | $($field: Builder,)* 17 | } 18 | 19 | impl<$lt> $ident<$lt> { 20 | /// Construct path tokens with the given prefix. 21 | pub(crate) fn new(crate_prefix: &$lt Path) -> Self { 22 | let core = leading_path(["core"]); 23 | 24 | Self { 25 | core, 26 | crate_prefix, 27 | $($field: toks!(@path $($path)*),)* 28 | } 29 | } 30 | 31 | $( 32 | #[inline] 33 | #[allow(clippy::wrong_self_convention)] 34 | $vis fn $field(&self) -> Path { 35 | let f = self.$field; 36 | f(self) 37 | } 38 | )* 39 | } 40 | }; 41 | 42 | (@path core $(:: $rest:tt)*) => { 43 | |s| suffixed(&s.core, [$(stringify!($rest)),*]) 44 | }; 45 | 46 | (@path crate $(:: $rest:tt)*) => { 47 | |s| suffixed(&s.crate_prefix, [$(stringify!($rest)),*]) 48 | }; 49 | } 50 | 51 | toks! { 52 | pub(crate) struct Toks<'a> { 53 | array_into_iter = [core::array::IntoIter], 54 | bool_type = [core::primitive::bool], 55 | clone_t = [core::clone::Clone], 56 | copy_t = [core::marker::Copy], 57 | double_ended_iterator_t = [core::iter::DoubleEndedIterator], 58 | entry_enum = [crate::map::Entry], 59 | eq_t = [core::cmp::Eq], 60 | hash_t = [core::hash::Hash], 61 | hasher_t = [core::hash::Hasher], 62 | into_iterator_t = [core::iter::IntoIterator], 63 | iterator_cmp = [crate::macro_support::__storage_iterator_cmp], 64 | iterator_cmp_bool = [crate::macro_support::__storage_iterator_cmp_bool], 65 | iterator_flat_map = [core::iter::FlatMap], 66 | iterator_flatten = [core::iter::Flatten], 67 | iterator_partial_cmp = [crate::macro_support::__storage_iterator_partial_cmp], 68 | iterator_partial_cmp_bool = [crate::macro_support::__storage_iterator_partial_cmp_bool], 69 | iterator_t = [core::iter::Iterator], 70 | key_t = [crate::Key], 71 | mem = [core::mem], 72 | occupied_entry_t = [crate::map::OccupiedEntry], 73 | option = [core::option::Option], 74 | option_bucket_none = [crate::option_bucket::NoneBucket], 75 | option_bucket_option = [crate::option_bucket::OptionBucket], 76 | option_bucket_some = [crate::option_bucket::SomeBucket], 77 | ord_t = [core::cmp::Ord], 78 | ordering = [core::cmp::Ordering], 79 | partial_eq_t = [core::cmp::PartialEq], 80 | partial_ord_t = [core::cmp::PartialOrd], 81 | slice_iter = [core::slice::Iter], 82 | slice_iter_mut = [core::slice::IterMut], 83 | map_storage_t = [crate::map::MapStorage], 84 | set_storage_t = [crate::set::SetStorage], 85 | raw_storage_t = [crate::raw::RawStorage], 86 | vacant_entry_t = [crate::map::VacantEntry], 87 | } 88 | } 89 | 90 | /// Construct a leading path. 91 | pub(crate) fn leading_path(parts: [&'static str; N]) -> Path { 92 | let mut path = Path { 93 | leading_colon: Some(::default()), 94 | segments: syn::punctuated::Punctuated::default(), 95 | }; 96 | 97 | for part in parts { 98 | let segment = syn::PathSegment::from(syn::Ident::new(part, Span::call_site())); 99 | path.segments.push(segment); 100 | } 101 | 102 | path 103 | } 104 | 105 | /// Add the given parts as suffix to the specified prefix path. 106 | fn suffixed(prefix: &Path, parts: [&'static str; N]) -> Path { 107 | let mut path = prefix.clone(); 108 | 109 | for part in parts { 110 | let segment = syn::PathSegment::from(syn::Ident::new(part, Span::call_site())); 111 | path.segments.push(segment); 112 | } 113 | 114 | path 115 | } 116 | 117 | /// Options for derive. 118 | #[derive(Default)] 119 | pub(crate) struct Opts { 120 | /// Implements sets as bitsets when possible. 121 | pub(crate) bitset: Option, 122 | } 123 | 124 | pub(crate) struct Ctxt<'a> { 125 | /// Errors collected in the context. 126 | errors: RefCell>, 127 | /// Generated tokens. 128 | pub(crate) toks: &'a Toks<'a>, 129 | /// Input ast. 130 | pub(crate) ast: &'a DeriveInput, 131 | /// Usable lifetime parameter. 132 | pub(crate) lt: &'a syn::Lifetime, 133 | } 134 | 135 | impl<'a> Ctxt<'a> { 136 | pub(crate) fn new(tokens: &'a Toks<'a>, ast: &'a DeriveInput, lt: &'a syn::Lifetime) -> Self { 137 | Self { 138 | errors: RefCell::new(Vec::new()), 139 | toks: tokens, 140 | ast, 141 | lt, 142 | } 143 | } 144 | 145 | /// Emit an error. 146 | pub(crate) fn error(&self, error: syn::Error) { 147 | self.errors.borrow_mut().push(error); 148 | } 149 | 150 | /// Emit an error. 151 | pub(crate) fn span_error(&self, span: Span, message: impl fmt::Display) { 152 | self.error(syn::Error::new(span, message)); 153 | } 154 | 155 | /// Convert into interior errors. 156 | pub(crate) fn into_errors(self) -> Vec { 157 | self.errors.into_inner() 158 | } 159 | 160 | /// Perform a fallible operation and capture an error (if any). 161 | pub(crate) fn fallible(&self, op: T) -> Result 162 | where 163 | T: FnOnce() -> Result, 164 | { 165 | match op() { 166 | Ok(output) => Ok(output), 167 | Err(error) => { 168 | self.errors.borrow_mut().push(error); 169 | Err(()) 170 | } 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /fixed-map-derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! [github](https://github.com/udoprog/fixed-map) 2 | //! [crates.io](https://crates.io/crates/fixed-map-derive) 3 | //! [docs.rs](https://docs.rs/fixed-map-derive) 4 | //! 5 | //! This crate contains the procedural macros used in [fixed-map]. 6 | //! 7 | //! [fixed-map]: https://github.com/udoprog/fixed-map 8 | 9 | #![recursion_limit = "256"] 10 | #![deny(missing_docs)] 11 | #![allow(clippy::expl_impl_clone_on_copy)] 12 | #![allow(clippy::module_name_repetitions)] 13 | #![allow(clippy::too_many_lines)] 14 | #![allow(clippy::type_repetition_in_bounds)] 15 | #![allow(clippy::unnecessary_wraps)] 16 | #![allow(missing_docs)] 17 | 18 | use proc_macro2::TokenStream; 19 | use quote::quote; 20 | use syn::spanned::Spanned; 21 | use syn::{Data, DataEnum, DeriveInput, Fields}; 22 | 23 | mod any_variants; 24 | mod attrs; 25 | mod context; 26 | mod symbol; 27 | mod unit_variants; 28 | 29 | /// See . 30 | #[proc_macro_derive(Key, attributes(key))] 31 | pub fn storage_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { 32 | let ast = syn::parse_macro_input!(input as DeriveInput); 33 | 34 | let lt = syn::Lifetime::new("'a", ast.span()); 35 | let crate_prefix = context::leading_path(["fixed_map"]); 36 | let tokens = context::Toks::new(&crate_prefix); 37 | let cx = context::Ctxt::new(&tokens, &ast, <); 38 | 39 | let result = impl_storage(&cx); 40 | 41 | if let Ok(g) = result { 42 | return g.into(); 43 | } 44 | 45 | let errors = cx.into_errors(); 46 | let compile_errors = errors.iter().map(syn::Error::to_compile_error); 47 | quote!(#(#compile_errors)*).into() 48 | } 49 | 50 | fn impl_storage(cx: &context::Ctxt<'_>) -> Result { 51 | let opts = attrs::parse(cx)?; 52 | 53 | if let Data::Enum(en) = &cx.ast.data { 54 | if is_all_unit_variants(en) { 55 | unit_variants::implement(cx, &opts, en) 56 | } else { 57 | any_variants::implement(cx, en) 58 | } 59 | } else { 60 | cx.span_error(cx.ast.span(), "named fields are not supported"); 61 | Err(()) 62 | } 63 | } 64 | 65 | fn is_all_unit_variants(en: &DataEnum) -> bool { 66 | for v in &en.variants { 67 | if !matches!(&v.fields, Fields::Unit) { 68 | return false; 69 | } 70 | } 71 | 72 | true 73 | } 74 | -------------------------------------------------------------------------------- /fixed-map-derive/src/symbol.rs: -------------------------------------------------------------------------------- 1 | use core::fmt; 2 | use core::ops::Deref; 3 | use syn::{Ident, Path}; 4 | 5 | #[derive(Copy, Clone)] 6 | pub struct Symbol(&'static str); 7 | 8 | pub(crate) const KEY: Symbol = Symbol("key"); 9 | pub(crate) const BITSET: Symbol = Symbol("bitset"); 10 | 11 | impl PartialEq for Ident { 12 | fn eq(&self, word: &Symbol) -> bool { 13 | self == word.0 14 | } 15 | } 16 | 17 | impl PartialEq for &Ident { 18 | fn eq(&self, word: &Symbol) -> bool { 19 | *self == word.0 20 | } 21 | } 22 | 23 | impl PartialEq for Path { 24 | fn eq(&self, word: &Symbol) -> bool { 25 | self.is_ident(word.0) 26 | } 27 | } 28 | 29 | impl PartialEq for &Path { 30 | fn eq(&self, word: &Symbol) -> bool { 31 | self.is_ident(word.0) 32 | } 33 | } 34 | 35 | impl fmt::Display for Symbol { 36 | fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 37 | formatter.write_str(self.0) 38 | } 39 | } 40 | 41 | impl Deref for Symbol { 42 | type Target = str; 43 | 44 | fn deref(&self) -> &Self::Target { 45 | self.0 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /fixed-map-derive/src/unit_variants.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::{Span, TokenStream}; 2 | use quote::{format_ident, quote}; 3 | use syn::spanned::Spanned; 4 | use syn::{DataEnum, Ident, LitInt}; 5 | 6 | use crate::context::{Ctxt, Opts}; 7 | 8 | /// Every variant is a unit variant. 9 | pub(crate) fn implement(cx: &Ctxt<'_>, opts: &Opts, en: &DataEnum) -> Result { 10 | let map_storage = format_ident!("__MapStorage"); 11 | let set_storage = format_ident!("__SetStorage"); 12 | 13 | let count = en.variants.len(); 14 | let mut names = Vec::with_capacity(count); 15 | 16 | for (index, _) in en.variants.iter().enumerate() { 17 | names.push(format_ident!("_{}", index)); 18 | } 19 | 20 | let entry_impl = impl_entry(cx, &map_storage)?; 21 | let map_storage_impl = impl_map(cx, en, &map_storage, &names)?; 22 | 23 | let set_storage_impl = if opts.bitset.is_some() { 24 | impl_bitset(cx, en, &set_storage)? 25 | } else { 26 | impl_set(cx, en, &set_storage, &names)? 27 | }; 28 | 29 | let ident = &cx.ast.ident; 30 | let key_t = cx.toks.key_t(); 31 | 32 | Ok(quote! { 33 | const _: () = { 34 | #entry_impl 35 | #map_storage_impl 36 | #set_storage_impl 37 | 38 | #[automatically_derived] 39 | impl #key_t for #ident { 40 | type MapStorage = #map_storage; 41 | type SetStorage = #set_storage; 42 | } 43 | }; 44 | }) 45 | } 46 | 47 | fn impl_entry(cx: &Ctxt<'_>, map_storage: &Ident) -> Result { 48 | let ident = &cx.ast.ident; 49 | let lt = cx.lt; 50 | let vis = &cx.ast.vis; 51 | 52 | let vacant_entry_t = cx.toks.vacant_entry_t(); 53 | let occupied_entry_t = cx.toks.occupied_entry_t(); 54 | let option_bucket_none = cx.toks.option_bucket_none(); 55 | let option_bucket_option = cx.toks.option_bucket_option(); 56 | let option_bucket_some = cx.toks.option_bucket_some(); 57 | let option = cx.toks.option(); 58 | let entry_enum = cx.toks.entry_enum(); 59 | 60 | Ok(quote! { 61 | #vis struct VacantEntry<#lt, V> { 62 | key: #ident, 63 | inner: #option_bucket_none<#lt, V>, 64 | } 65 | 66 | #[automatically_derived] 67 | impl<#lt, V> #vacant_entry_t<#lt, #ident, V> for VacantEntry<#lt, V> { 68 | #[inline] 69 | fn key(&self) -> #ident { 70 | self.key 71 | } 72 | 73 | #[inline] 74 | fn insert(self, value: V) -> &#lt mut V { 75 | #option_bucket_none::insert(self.inner, value) 76 | } 77 | } 78 | 79 | #vis struct OccupiedEntry<#lt, V> { 80 | key: #ident, 81 | inner: #option_bucket_some<#lt, V>, 82 | } 83 | 84 | #[automatically_derived] 85 | impl<#lt, V> #occupied_entry_t<#lt, #ident, V> for OccupiedEntry<#lt, V> { 86 | #[inline] 87 | fn key(&self) -> #ident { 88 | self.key 89 | } 90 | 91 | #[inline] 92 | fn get(&self) -> &V { 93 | #option_bucket_some::as_ref(&self.inner) 94 | } 95 | 96 | #[inline] 97 | fn get_mut(&mut self) -> &mut V { 98 | #option_bucket_some::as_mut(&mut self.inner) 99 | } 100 | 101 | #[inline] 102 | fn into_mut(self) -> &#lt mut V { 103 | #option_bucket_some::into_mut(self.inner) 104 | } 105 | 106 | #[inline] 107 | fn insert(&mut self, value: V) -> V { 108 | #option_bucket_some::replace(&mut self.inner, value) 109 | } 110 | 111 | #[inline] 112 | fn remove(self) -> V { 113 | #option_bucket_some::take(self.inner) 114 | } 115 | } 116 | 117 | #[inline] 118 | fn option_to_entry(opt: &mut #option, key: #ident) -> #entry_enum<'_, #map_storage, #ident, V> { 119 | match #option_bucket_option::new(opt) { 120 | #option_bucket_option::Some(inner) => #entry_enum::Occupied(OccupiedEntry { key, inner }), 121 | #option_bucket_option::None(inner) => #entry_enum::Vacant(VacantEntry { key, inner }), 122 | } 123 | } 124 | }) 125 | } 126 | 127 | fn impl_map( 128 | cx: &Ctxt<'_>, 129 | en: &DataEnum, 130 | map_storage: &Ident, 131 | names: &[Ident], 132 | ) -> Result { 133 | let ident = &cx.ast.ident; 134 | let lt = &cx.lt; 135 | let vis = &cx.ast.vis; 136 | 137 | let iterator_t = cx.toks.iterator_t(); 138 | let into_iterator_t = cx.toks.into_iterator_t(); 139 | let array_into_iter = cx.toks.array_into_iter(); 140 | let clone_t = cx.toks.clone_t(); 141 | let copy_t = cx.toks.copy_t(); 142 | let entry_enum = cx.toks.entry_enum(); 143 | let eq_t = cx.toks.eq_t(); 144 | let hash_t = cx.toks.hash_t(); 145 | let hasher_t = cx.toks.hasher_t(); 146 | let iterator_cmp = cx.toks.iterator_cmp(); 147 | let iterator_flat_map = cx.toks.iterator_flat_map(); 148 | let iterator_flatten = cx.toks.iterator_flatten(); 149 | let iterator_partial_cmp = cx.toks.iterator_partial_cmp(); 150 | let mem = cx.toks.mem(); 151 | let option = cx.toks.option(); 152 | let ord_t = cx.toks.ord_t(); 153 | let ordering = cx.toks.ordering(); 154 | let partial_eq_t = cx.toks.partial_eq_t(); 155 | let partial_ord_t = cx.toks.partial_ord_t(); 156 | let slice_iter = cx.toks.slice_iter(); 157 | let slice_iter_mut = cx.toks.slice_iter_mut(); 158 | let map_storage_t = cx.toks.map_storage_t(); 159 | 160 | let variants = en.variants.iter().map(|v| &v.ident).collect::>(); 161 | let init = en 162 | .variants 163 | .iter() 164 | .map(|_| quote!(#option::None)) 165 | .collect::>(); 166 | let count = en.variants.len(); 167 | 168 | Ok(quote! { 169 | #[repr(transparent)] 170 | #vis struct #map_storage { 171 | data: [#option; #count], 172 | } 173 | 174 | #[automatically_derived] 175 | impl #clone_t for #map_storage where V: #clone_t { 176 | #[inline] 177 | fn clone(&self) -> Self { 178 | Self { 179 | data: #clone_t::clone(&self.data), 180 | } 181 | } 182 | } 183 | 184 | #[automatically_derived] 185 | impl #copy_t for #map_storage where V: #copy_t { 186 | } 187 | 188 | #[automatically_derived] 189 | impl #partial_eq_t for #map_storage where V: #partial_eq_t { 190 | #[inline] 191 | fn eq(&self, other: &Self) -> bool { 192 | #partial_eq_t::eq(&self.data, &other.data) 193 | } 194 | } 195 | 196 | #[automatically_derived] 197 | impl #eq_t for #map_storage where V: #eq_t {} 198 | 199 | #[automatically_derived] 200 | impl #hash_t for #map_storage where V: #hash_t { 201 | #[inline] 202 | fn hash(&self, state: &mut H) 203 | where 204 | H: #hasher_t, 205 | { 206 | #hash_t::hash(&self.data, state); 207 | } 208 | } 209 | 210 | #[automatically_derived] 211 | impl #partial_ord_t for #map_storage where V: #partial_ord_t { 212 | #[inline] 213 | fn partial_cmp(&self, other: &Self) -> Option<#ordering> { 214 | #iterator_partial_cmp(&self.data, &other.data) 215 | } 216 | } 217 | 218 | #[automatically_derived] 219 | impl #ord_t for #map_storage where V: #ord_t { 220 | #[inline] 221 | fn cmp(&self, other: &Self) -> #ordering { 222 | #iterator_cmp(&self.data, &other.data) 223 | } 224 | } 225 | 226 | #[automatically_derived] 227 | impl #map_storage_t<#ident, V> for #map_storage { 228 | type Iter<#lt> = #iterator_flat_map< 229 | #array_into_iter<(#ident, &#lt #option), #count>, 230 | #option<(#ident, &#lt V)>, 231 | fn((#ident, &#lt #option)) -> #option<(#ident, &#lt V)> 232 | > where V: #lt; 233 | type Keys<#lt> = #iterator_flatten<#array_into_iter<#option<#ident>, #count>> where V: #lt; 234 | type Values<#lt> = #iterator_flatten<#slice_iter<#lt, #option>> where V: #lt; 235 | type IterMut<#lt> = #iterator_flat_map< 236 | #array_into_iter<(#ident, &#lt mut #option), #count>, 237 | #option<(#ident, &#lt mut V)>, 238 | fn((#ident, &#lt mut #option)) -> #option<(#ident, &#lt mut V)> 239 | > where V: #lt; 240 | type ValuesMut<#lt> = #iterator_flatten<#slice_iter_mut<#lt, #option>> where V: #lt; 241 | type IntoIter = #iterator_flat_map< 242 | #array_into_iter<(#ident, #option), #count>, 243 | #option<(#ident, V)>, 244 | fn((#ident, #option)) -> #option<(#ident, V)> 245 | >; 246 | type Occupied<#lt> = OccupiedEntry<#lt, V> where V: #lt; 247 | type Vacant<#lt> = VacantEntry<#lt, V> where V: #lt; 248 | 249 | #[inline] 250 | fn empty() -> Self { 251 | Self { 252 | data: [#(#init),*], 253 | } 254 | } 255 | 256 | #[inline] 257 | fn len(&self) -> usize { 258 | let [#(#names),*] = &self.data; 259 | 0 #(+ usize::from(#option::is_some(#names)))* 260 | } 261 | 262 | #[inline] 263 | fn is_empty(&self) -> bool { 264 | let [#(#names),*] = &self.data; 265 | true #(&& #option::is_none(#names))* 266 | } 267 | 268 | #[inline] 269 | fn insert(&mut self, key: #ident, value: V) -> #option { 270 | let [#(#names),*] = &mut self.data; 271 | 272 | match key { 273 | #(#ident::#variants => #option::replace(#names, value),)* 274 | } 275 | } 276 | 277 | #[inline] 278 | fn contains_key(&self, value: #ident) -> bool { 279 | let [#(#names),*] = &self.data; 280 | 281 | match value { 282 | #(#ident::#variants => #option::is_some(#names),)* 283 | } 284 | } 285 | 286 | #[inline] 287 | fn get(&self, value: #ident) -> #option<&V> { 288 | let [#(#names),*] = &self.data; 289 | 290 | match value { 291 | #(#ident::#variants => #option::as_ref(#names),)* 292 | } 293 | } 294 | 295 | #[inline] 296 | fn get_mut(&mut self, value: #ident) -> #option<&mut V> { 297 | let [#(#names),*] = &mut self.data; 298 | 299 | match value { 300 | #(#ident::#variants => #option::as_mut(#names),)* 301 | } 302 | } 303 | 304 | #[inline] 305 | fn remove(&mut self, value: #ident) -> #option { 306 | let [#(#names),*] = &mut self.data; 307 | 308 | match value { 309 | #(#ident::#variants => #mem::take(#names),)* 310 | } 311 | } 312 | 313 | #[inline] 314 | fn retain(&mut self, mut func: F) 315 | where 316 | F: FnMut(#ident, &mut V) -> bool 317 | { 318 | let [#(#names),*] = &mut self.data; 319 | 320 | #(if let #option::Some(val) = #option::as_mut(#names) { 321 | if !func(#ident::#variants, val) { 322 | *#names = None; 323 | } 324 | })* 325 | } 326 | 327 | #[inline] 328 | fn clear(&mut self) { 329 | self.data = [#(#init),*]; 330 | } 331 | 332 | #[inline] 333 | fn iter(&self) -> Self::Iter<'_> { 334 | let [#(#names),*] = &self.data; 335 | #iterator_t::flat_map(#into_iterator_t::into_iter([#((#ident::#variants, #names)),*]), |(k, v)| #option::Some((k, #option::as_ref(v)?))) 336 | } 337 | 338 | #[inline] 339 | fn keys(&self) -> Self::Keys<'_> { 340 | let [#(#names),*] = &self.data; 341 | #iterator_t::flatten(#into_iterator_t::into_iter([#(if #names.is_some() { Some(#ident::#variants) } else { None }),*])) 342 | } 343 | 344 | #[inline] 345 | fn values(&self) -> Self::Values<'_> { 346 | #iterator_t::flatten(#into_iterator_t::into_iter(&self.data)) 347 | } 348 | 349 | #[inline] 350 | fn iter_mut(&mut self) -> Self::IterMut<'_> { 351 | let [#(#names),*] = &mut self.data; 352 | #iterator_t::flat_map(#into_iterator_t::into_iter([#((#ident::#variants, #names)),*]), |(k, v)| #option::Some((k, #option::as_mut(v)?))) 353 | } 354 | 355 | #[inline] 356 | fn values_mut(&mut self) -> Self::ValuesMut<'_> { 357 | #iterator_t::flatten(#into_iterator_t::into_iter(&mut self.data)) 358 | } 359 | 360 | #[inline] 361 | fn into_iter(self) -> Self::IntoIter { 362 | let [#(#names),*] = self.data; 363 | #iterator_t::flat_map(#into_iterator_t::into_iter([#((#ident::#variants, #names)),*]), |(k, v)| #option::Some((k, v?))) 364 | } 365 | 366 | #[inline] 367 | fn entry(&mut self, key: #ident) -> #entry_enum<'_, Self, #ident, V> { 368 | let [#(#names),*] = &mut self.data; 369 | 370 | match key { 371 | #(#ident::#variants => option_to_entry(#names, key),)* 372 | } 373 | } 374 | } 375 | }) 376 | } 377 | 378 | /// Implement as bitset storage. 379 | fn impl_bitset(cx: &Ctxt<'_>, en: &DataEnum, set_storage: &Ident) -> Result { 380 | let (ty, _) = determine_bits(cx, en)?; 381 | 382 | let vis = &cx.ast.vis; 383 | let ident = &cx.ast.ident; 384 | let lt = cx.lt; 385 | 386 | let iterator_t = cx.toks.iterator_t(); 387 | let count = en.variants.len(); 388 | let into_iterator_t = cx.toks.into_iterator_t(); 389 | let array_into_iter = cx.toks.array_into_iter(); 390 | let clone_t = cx.toks.clone_t(); 391 | let copy_t = cx.toks.copy_t(); 392 | let eq_t = cx.toks.eq_t(); 393 | let hash_t = cx.toks.hash_t(); 394 | let iterator_flatten = cx.toks.iterator_flatten(); 395 | let mem = cx.toks.mem(); 396 | let option = cx.toks.option(); 397 | let ord_t = cx.toks.ord_t(); 398 | let ordering = cx.toks.ordering(); 399 | let partial_eq_t = cx.toks.partial_eq_t(); 400 | let partial_ord_t = cx.toks.partial_ord_t(); 401 | let set_storage_t = cx.toks.set_storage_t(); 402 | let raw_storage_t = cx.toks.raw_storage_t(); 403 | 404 | let variants = en.variants.iter().map(|v| &v.ident).collect::>(); 405 | 406 | let numbers = en 407 | .variants 408 | .iter() 409 | .enumerate() 410 | .map(|(n, v)| LitInt::new(&format!("{}", 1u128 << n), v.span())) 411 | .collect::>(); 412 | 413 | Ok(quote! { 414 | #[inline] 415 | const fn to_bits(value: #ident) -> #ty { 416 | match value { 417 | #(#ident::#variants => #numbers,)* 418 | } 419 | } 420 | 421 | #[repr(transparent)] 422 | #[derive(#clone_t, #copy_t, #partial_eq_t, #eq_t, #hash_t)] 423 | #vis struct #set_storage { 424 | data: #ty, 425 | } 426 | 427 | #[automatically_derived] 428 | impl #partial_ord_t for #set_storage { 429 | #[inline] 430 | fn partial_cmp(&self, other: &Self) -> Option<#ordering> { 431 | #partial_ord_t::partial_cmp(&self.data, &other.data) 432 | } 433 | } 434 | 435 | #[automatically_derived] 436 | impl #ord_t for #set_storage { 437 | #[inline] 438 | fn cmp(&self, other: &Self) -> #ordering { 439 | #ord_t::cmp(&self.data, &other.data) 440 | } 441 | } 442 | 443 | #[automatically_derived] 444 | impl #set_storage_t<#ident> for #set_storage { 445 | type Iter<#lt> = #iterator_flatten<#array_into_iter<#option<#ident>, #count>>; 446 | type IntoIter = #iterator_flatten<#array_into_iter<#option<#ident>, #count>>; 447 | 448 | #[inline] 449 | fn empty() -> Self { 450 | Self { 451 | data: 0, 452 | } 453 | } 454 | 455 | #[inline] 456 | fn len(&self) -> usize { 457 | <#ty>::count_ones(self.data) as usize 458 | } 459 | 460 | #[inline] 461 | fn is_empty(&self) -> bool { 462 | self.data == 0 463 | } 464 | 465 | #[inline] 466 | fn insert(&mut self, value: #ident) -> bool { 467 | let mask = to_bits(value); 468 | let update = self.data | mask; 469 | #mem::replace(&mut self.data, update) & mask == 0 470 | } 471 | 472 | #[inline] 473 | fn contains(&self, value: #ident) -> bool { 474 | self.data & to_bits(value) != 0 475 | } 476 | 477 | #[inline] 478 | fn remove(&mut self, value: #ident) -> bool { 479 | let mask = to_bits(value); 480 | let update = self.data & !mask; 481 | #mem::replace(&mut self.data, update) & mask != 0 482 | } 483 | 484 | #[inline] 485 | fn retain(&mut self, mut f: F) 486 | where 487 | F: FnMut(#ident) -> bool 488 | { 489 | let mut update = 0; 490 | 491 | #(if self.data & #numbers != 0 { 492 | if f(#ident::#variants) { 493 | update |= #numbers; 494 | } 495 | })* 496 | 497 | self.data = update; 498 | } 499 | 500 | #[inline] 501 | fn clear(&mut self) { 502 | self.data = 0; 503 | } 504 | 505 | #[inline] 506 | fn iter(&self) -> Self::Iter<'_> { 507 | #iterator_t::flatten(#into_iterator_t::into_iter([#(if self.data & #numbers != 0 { Some(#ident::#variants) } else { None }),*])) 508 | } 509 | 510 | #[inline] 511 | fn into_iter(self) -> Self::IntoIter { 512 | #iterator_t::flatten(#into_iterator_t::into_iter([#(if self.data & #numbers != 0 { Some(#ident::#variants) } else { None }),*])) 513 | } 514 | } 515 | 516 | #[automatically_derived] 517 | impl #raw_storage_t for #set_storage { 518 | type Value = #ty; 519 | 520 | #[inline] 521 | fn as_raw(&self) -> #ty { 522 | self.data 523 | } 524 | 525 | #[inline] 526 | fn from_raw(data: #ty) -> #set_storage { 527 | #set_storage { data } 528 | } 529 | } 530 | }) 531 | } 532 | 533 | fn determine_bits(cx: &Ctxt<'_>, en: &DataEnum) -> Result<(Ident, usize), ()> { 534 | Ok(match en.variants.len() { 535 | 0..=8 => (Ident::new("u8", Span::call_site()), 8), 536 | 9..=16 => (Ident::new("u16", Span::call_site()), 16), 537 | 17..=32 => (Ident::new("u32", Span::call_site()), 32), 538 | 33..=64 => (Ident::new("u64", Span::call_site()), 64), 539 | 65..=128 => (Ident::new("u128", Span::call_site()), 128), 540 | other => { 541 | cx.span_error( 542 | cx.ast.ident.span(), 543 | format_args!("only support up until 128 variants, got {other}"), 544 | ); 545 | return Err(()); 546 | } 547 | }) 548 | } 549 | 550 | /// Implement set storage. 551 | fn impl_set( 552 | cx: &Ctxt<'_>, 553 | en: &DataEnum, 554 | set_storage: &Ident, 555 | names: &[Ident], 556 | ) -> Result { 557 | let vis = &cx.ast.vis; 558 | let ident = &cx.ast.ident; 559 | let lt = cx.lt; 560 | 561 | let iterator_t = cx.toks.iterator_t(); 562 | let count = en.variants.len(); 563 | let into_iterator_t = cx.toks.into_iterator_t(); 564 | let array_into_iter = cx.toks.array_into_iter(); 565 | let clone_t = cx.toks.clone_t(); 566 | let copy_t = cx.toks.copy_t(); 567 | let eq_t = cx.toks.eq_t(); 568 | let hash_t = cx.toks.hash_t(); 569 | let iterator_cmp_bool = cx.toks.iterator_cmp_bool(); 570 | let iterator_flatten = cx.toks.iterator_flatten(); 571 | let iterator_partial_cmp_bool = cx.toks.iterator_partial_cmp_bool(); 572 | let mem = cx.toks.mem(); 573 | let option = cx.toks.option(); 574 | let ord_t = cx.toks.ord_t(); 575 | let ordering = cx.toks.ordering(); 576 | let partial_eq_t = cx.toks.partial_eq_t(); 577 | let partial_ord_t = cx.toks.partial_ord_t(); 578 | let set_storage_t = cx.toks.set_storage_t(); 579 | 580 | let variants = en.variants.iter().map(|v| &v.ident).collect::>(); 581 | let init = en 582 | .variants 583 | .iter() 584 | .map(|_| quote!(false)) 585 | .collect::>(); 586 | 587 | Ok(quote! { 588 | #[repr(transparent)] 589 | #[derive(#clone_t, #copy_t, #partial_eq_t, #eq_t, #hash_t)] 590 | #vis struct #set_storage { 591 | data: [bool; #count], 592 | } 593 | 594 | #[automatically_derived] 595 | impl #partial_ord_t for #set_storage { 596 | #[inline] 597 | fn partial_cmp(&self, other: &Self) -> Option<#ordering> { 598 | #iterator_partial_cmp_bool(&self.data, &other.data) 599 | } 600 | } 601 | 602 | #[automatically_derived] 603 | impl #ord_t for #set_storage { 604 | #[inline] 605 | fn cmp(&self, other: &Self) -> #ordering { 606 | #iterator_cmp_bool(&self.data, &other.data) 607 | } 608 | } 609 | 610 | #[automatically_derived] 611 | impl #set_storage_t<#ident> for #set_storage { 612 | type Iter<#lt> = #iterator_flatten<#array_into_iter<#option<#ident>, #count>>; 613 | type IntoIter = #iterator_flatten<#array_into_iter<#option<#ident>, #count>>; 614 | 615 | #[inline] 616 | fn empty() -> Self { 617 | Self { 618 | data: [#(#init),*], 619 | } 620 | } 621 | 622 | #[inline] 623 | fn len(&self) -> usize { 624 | let [#(#names),*] = &self.data; 625 | 0 #(+ usize::from(*#names))* 626 | } 627 | 628 | #[inline] 629 | fn is_empty(&self) -> bool { 630 | let [#(#names),*] = &self.data; 631 | true #(&& !*#names)* 632 | } 633 | 634 | #[inline] 635 | fn insert(&mut self, value: #ident) -> bool { 636 | let [#(#names),*] = &mut self.data; 637 | 638 | match value { 639 | #(#ident::#variants => !#mem::replace(#names, true),)* 640 | } 641 | } 642 | 643 | #[inline] 644 | fn contains(&self, value: #ident) -> bool { 645 | let [#(#names),*] = &self.data; 646 | 647 | match value { 648 | #(#ident::#variants => *#names,)* 649 | } 650 | } 651 | 652 | #[inline] 653 | fn remove(&mut self, value: #ident) -> bool { 654 | let [#(#names),*] = &mut self.data; 655 | 656 | match value { 657 | #(#ident::#variants => #mem::replace(#names, false),)* 658 | } 659 | } 660 | 661 | #[inline] 662 | fn retain(&mut self, mut f: F) 663 | where 664 | F: FnMut(#ident) -> bool 665 | { 666 | let [#(#names),*] = &mut self.data; 667 | 668 | #(if *#names { 669 | *#names = f(#ident::#variants); 670 | })* 671 | } 672 | 673 | #[inline] 674 | fn clear(&mut self) { 675 | self.data = [#(#init),*]; 676 | } 677 | 678 | #[inline] 679 | fn iter(&self) -> Self::Iter<'_> { 680 | let [#(#names),*] = &self.data; 681 | #iterator_t::flatten(#into_iterator_t::into_iter([#(if *#names { Some(#ident::#variants) } else { None }),*])) 682 | } 683 | 684 | #[inline] 685 | fn into_iter(self) -> Self::IntoIter { 686 | let [#(#names),*] = &self.data; 687 | #iterator_t::flatten(#into_iterator_t::into_iter([#(if *#names { Some(#ident::#variants) } else { None }),*])) 688 | } 689 | } 690 | }) 691 | } 692 | -------------------------------------------------------------------------------- /src/key.rs: -------------------------------------------------------------------------------- 1 | //! Module for the trait to define a `Key`. 2 | 3 | #[cfg(feature = "hashbrown")] 4 | use crate::map::storage::HashbrownMapStorage; 5 | use crate::map::storage::{BooleanMapStorage, MapStorage, OptionMapStorage, SingletonMapStorage}; 6 | #[cfg(feature = "hashbrown")] 7 | use crate::set::storage::HashbrownSetStorage; 8 | use crate::set::storage::{BooleanSetStorage, OptionSetStorage, SetStorage, SingletonSetStorage}; 9 | 10 | /// The trait for a key that can be used to store values in a 11 | /// [`Map`][crate::Set] or [`Set`][crate::Set]. 12 | /// 13 | /// This is implemented automatically from enums through the 14 | /// [`Key`][key-derive]. The following is a *simple* key which has no nested 15 | /// keys: 16 | /// 17 | /// ``` 18 | /// use fixed_map::Key; 19 | /// 20 | /// #[derive(Clone, Copy, Key)] 21 | /// enum MyKey { 22 | /// First, 23 | /// Second, 24 | /// } 25 | /// ``` 26 | /// 27 | /// *Composite keys* are when keys structurally includes other keys. They have 28 | /// slightly worse performance than simple keys because they can't be simply 29 | /// arranged as arrays internally. `bool` below here implements [`Key`] and 30 | /// using it in one key constructs a composite key. It's a simple form of key 31 | /// since it can only inhabit two values - `true` or `false`. `Option` can 32 | /// also be used as a composite key: 33 | /// 34 | /// ``` 35 | /// use fixed_map::Key; 36 | /// 37 | /// #[derive(Clone, Copy, Key)] 38 | /// enum MyKey { 39 | /// First(bool), 40 | /// Second(Option), 41 | /// } 42 | /// ``` 43 | /// 44 | /// Some composite keys require dynamic storage since they can inhabit a large 45 | /// number of values, and preferrably should be avoided in favor of using a 46 | /// `HashMap` directly. But if you absolutely have to you can enable the `map` 47 | /// feature: 48 | /// 49 | /// ``` 50 | /// use fixed_map::Key; 51 | /// 52 | /// #[derive(Clone, Copy, Key)] 53 | /// enum MyKey { 54 | /// # #[cfg(feature = "hashbrown")] 55 | /// First(u32), 56 | /// Second, 57 | /// } 58 | /// ``` 59 | /// 60 | /// ## Ordering 61 | /// 62 | /// Keys provide their own ordering semantics instead of relying on the 63 | /// [`PartialOrd`] and [`Ord`] traits. 64 | /// 65 | /// Therefore keys when stored in a collection such as [`Map`] and [`Set`] are 66 | /// always ordered in *declaration order*. This allows those containers 67 | /// themselves to be ordered if the underlying key supports, it similarly to how 68 | /// [`BTreeMap`] and [`BTreeSet`] works. 69 | /// 70 | /// ``` 71 | /// use fixed_map::{Key, Set}; 72 | /// 73 | /// #[derive(Clone, Copy, Key)] 74 | /// enum MyKey { 75 | /// First, 76 | /// Second, 77 | /// Third, 78 | /// } 79 | /// 80 | /// let mut a = Set::new(); 81 | /// a.insert(MyKey::First); 82 | /// 83 | /// let mut b = Set::new(); 84 | /// b.insert(MyKey::Third); 85 | /// 86 | /// let mut c = Set::new(); 87 | /// c.insert(MyKey::First); 88 | /// c.insert(MyKey::Third); 89 | /// 90 | /// assert!(a < b); 91 | /// assert!(c < b); 92 | /// assert!(a < c); 93 | /// ``` 94 | /// 95 | /// The same example with [`BTreeSet`]: 96 | /// 97 | /// ``` 98 | /// use std::collections::BTreeSet; 99 | /// 100 | /// #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] 101 | /// enum MyKey { 102 | /// First, 103 | /// Second, 104 | /// Third, 105 | /// } 106 | /// 107 | /// let mut a = BTreeSet::new(); 108 | /// a.insert(MyKey::First); 109 | /// 110 | /// let mut b = BTreeSet::new(); 111 | /// b.insert(MyKey::Third); 112 | /// 113 | /// let mut c = BTreeSet::new(); 114 | /// c.insert(MyKey::First); 115 | /// c.insert(MyKey::Third); 116 | /// 117 | /// assert!(a < b); 118 | /// assert!(c < b); 119 | /// assert!(a < c); 120 | /// ``` 121 | /// 122 | /// [`BTreeMap`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html 123 | /// [`BTreeSet`]: https://doc.rust-lang.org/std/collections/struct.BTreeSet.html 124 | /// [`Map`]: crate::Map 125 | /// [`Set`]: crate::Set 126 | /// [key-derive]: derive@crate::Key 127 | pub trait Key: Copy { 128 | /// The [`Map`][crate::Map] storage implementation to use for the key 129 | /// implementing this trait. 130 | type MapStorage: MapStorage; 131 | 132 | /// The [`Set`][crate::Set] storage implementation to use for the key 133 | /// implementing this trait. 134 | type SetStorage: SetStorage; 135 | } 136 | 137 | impl Key for bool { 138 | type MapStorage = BooleanMapStorage; 139 | type SetStorage = BooleanSetStorage; 140 | } 141 | 142 | impl Key for Option 143 | where 144 | K: Key, 145 | { 146 | type MapStorage = OptionMapStorage; 147 | type SetStorage = OptionSetStorage; 148 | } 149 | 150 | macro_rules! map_key { 151 | ($ty:ty) => { 152 | #[cfg(feature = "hashbrown")] 153 | impl Key for $ty { 154 | type MapStorage = HashbrownMapStorage<$ty, V>; 155 | type SetStorage = HashbrownSetStorage<$ty>; 156 | } 157 | }; 158 | } 159 | 160 | macro_rules! singleton_key { 161 | ($ty:ty) => { 162 | impl Key for $ty { 163 | type MapStorage = SingletonMapStorage; 164 | type SetStorage = SingletonSetStorage; 165 | } 166 | }; 167 | } 168 | 169 | map_key!(char); 170 | map_key!(u8); 171 | map_key!(u32); 172 | map_key!(u64); 173 | map_key!(u128); 174 | map_key!(usize); 175 | map_key!(i8); 176 | map_key!(i32); 177 | map_key!(i64); 178 | map_key!(i128); 179 | map_key!(isize); 180 | map_key!(&'static str); 181 | map_key!(&'static [u8]); 182 | singleton_key!(()); 183 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! [github](https://github.com/udoprog/fixed-map) 2 | //! [crates.io](https://crates.io/crates/fixed-map) 3 | //! [docs.rs](https://docs.rs/fixed-map) 4 | //! 5 | //! This crate provides a [`Map`] and [`Set`] container that can make use of a 6 | //! pre-calculated backing storage. This enables the Rust compiler to heavily 7 | //! optimize operations over them and avoid allocating. 8 | //! 9 | //! See [documentation] for information on how to use this crate. 10 | //! 11 | //!
12 | //! 13 | //! ## Usage 14 | //! 15 | //! Add `fixed-map` to your `Cargo.toml`: 16 | //! 17 | //! ```toml 18 | //! [dependencies] 19 | //! fixed-map = "0.9.5" 20 | //! ``` 21 | //! 22 | //! Anything used as a key in either a [`Map`] or a [`Set`] needs to implement 23 | //! the [`Key`] trait. This should be derived: 24 | //! 25 | //! ``` 26 | //! use fixed_map::{Key, Map}; 27 | //! 28 | //! #[derive(Clone, Copy, Key)] 29 | //! enum MyKey { 30 | //! North, 31 | //! South, 32 | //! East, 33 | //! West, 34 | //! } 35 | //! ``` 36 | //! 37 | //! After this you can use one of our containers: 38 | //! 39 | //! ``` 40 | //! # #[derive(Clone, Copy, fixed_map::Key)] 41 | //! # enum MyKey { North, South, East, West } 42 | //! use fixed_map::{Map, Set}; 43 | //! 44 | //! let mut map = Map::new(); 45 | //! map.insert(MyKey::North, 200); 46 | //! map.insert(MyKey::South, 100); 47 | //! 48 | //! assert_eq!(map.get(MyKey::North), Some(&200)); 49 | //! assert_eq!(map.get(MyKey::East), None); 50 | //! 51 | //! let mut set = Set::new(); 52 | //! set.insert(MyKey::North); 53 | //! set.insert(MyKey::South); 54 | //! 55 | //! assert!(set.contains(MyKey::South)); 56 | //! assert!(!set.contains(MyKey::East)); 57 | //! ``` 58 | //! 59 | //!
60 | //! 61 | //! ## Features 62 | //! 63 | //! The following features are available: 64 | //! 65 | //! * `std` - Disabling this feature causes this crate to be no-std. This means 66 | //! that dynamic types cannot be used in keys, like ones enabled by the `map` 67 | //! feature (default). 68 | //! * `hashbrown` - Causes [`Storage`] to be implemented by dynamic types such 69 | //! as `&'static str` or `u32`. These are backed by a `hashbrown` (default). 70 | //! * `entry` - Enables an [`entry`] API similar to that found on [`HashMap`]. 71 | //! * `serde` - Causes [`Map`] and [`Set`] to implement [`Serialize`] and 72 | //! [`Deserialize`] if it's implemented by the key and value. 73 | //! 74 | //!
75 | //! 76 | //! ## Specialized storage through the [`Key`] trait 77 | //! 78 | //! The [`Key` derive] is provided to instruct our containers on how to build 79 | //! optimized storage for a given [`Key`]. We also require any key to be [`Copy`]. 80 | //! 81 | //! ``` 82 | //! use fixed_map::Key; 83 | //! 84 | //! #[derive(Clone, Copy, Key)] 85 | //! enum MyKey { 86 | //! North, 87 | //! South, 88 | //! East, 89 | //! West, 90 | //! } 91 | //! ``` 92 | //! 93 | //! What happens behind the scenes is that a proc macro is used to build a 94 | //! struct optimized for storing and indexing exactly 4 values - one for each 95 | //! variant. 96 | //! 97 | //! Something exactly like this: 98 | //! 99 | //! ```no_run 100 | //! struct Storage { 101 | //! data: [Option; 4], 102 | //! } 103 | //! ``` 104 | //! 105 | //! It becomes a bit more complicated once we start considering *composite 106 | //! keys*. See the [`Key`] documentation for more information. 107 | //! 108 | //!
109 | //! 110 | //! ## Why does this crate exist? 111 | //! 112 | //! There are many cases where you want associate a value with a small, fixed 113 | //! number of elements identified by an enum. 114 | //! 115 | //! Let's say you have a game where each room has something in four directions. 116 | //! We can model this relationship between the direction and the item using two 117 | //! enums. 118 | //! 119 | //! ``` 120 | //! #[repr(usize)] 121 | //! pub enum Dir { 122 | //! North, 123 | //! East, 124 | //! South, 125 | //! West, 126 | //! } 127 | //! 128 | //! pub enum Item { 129 | //! Bow, 130 | //! Sword, 131 | //! Axe, 132 | //! } 133 | //! ``` 134 | //! 135 | //! The goal is for the performance of fixed map to be identical to storing the 136 | //! data linearly in memory like you could through an array like `[Option; 137 | //! N]` where each *index* corresponds to a variant in `Dir`. 138 | //! 139 | //! Doing this manually could look like this: 140 | //! 141 | //! ``` 142 | //! # #[repr(usize)] 143 | //! # pub enum Dir { North, East, South, West } 144 | //! # #[derive(Debug)] 145 | //! # pub enum Item { Bow, Sword, Axe } 146 | //! let mut map: [Option; 4] = [None, None, None, None]; 147 | //! map[Dir::North as usize] = Some(Item::Bow); 148 | //! 149 | //! if let Some(item) = &map[Dir::North as usize] { 150 | //! println!("found item: {:?}", item); 151 | //! } 152 | //! ``` 153 | //! 154 | //! But with a fixed [`Map`] you can do it idiomatically like this, without 155 | //! incurring a drop in performance: 156 | //! 157 | //! ``` 158 | //! use fixed_map::{Key, Map}; 159 | //! 160 | //! #[derive(Clone, Copy, Key)] 161 | //! pub enum Dir { 162 | //! North, 163 | //! East, 164 | //! South, 165 | //! West, 166 | //! } 167 | //! 168 | //! #[derive(Debug)] 169 | //! pub enum Item { 170 | //! Bow, 171 | //! Sword, 172 | //! Axe, 173 | //! } 174 | //! 175 | //! let mut map = Map::new(); 176 | //! map.insert(Dir::North, Item::Bow); 177 | //! 178 | //! if let Some(item) = map.get(Dir::North) { 179 | //! println!("found item: {:?}", item); 180 | //! } 181 | //! ``` 182 | //! 183 | //!
184 | //! 185 | //! ## Unsafe use 186 | //! 187 | //! The Entry API uses `unwrap_unchecked` to obtain mutable references to the 188 | //! inner value of `Some`s, and to skip `drop` when overwriting `None`s. 189 | //! 190 | //!
191 | //! 192 | //! ## Benchmarks 193 | //! 194 | //! We include benchmarks to ensure that we abide by the expectation that a 195 | //! fixed map or set should perform roughly the same as an array with the same 196 | //! number of elements. 197 | //! 198 | //! In the following benchmarks fixed-map is compared to: 199 | //! 200 | //! * `fixed` - A [`Map`] with a derived [`Key`] with `N` variants. 201 | //! * [`hashbrown`] - A high performance hash map. This is only included for 202 | //! reference. 203 | //! - Note: Maps are created with `HashMap::with_capacity(N)`. 204 | //! * `array` - A simple `[Option; N]` array. 205 | //! 206 | //! Note: for all `insert` benchmarks the underlying storage is cloned in each 207 | //! iteration. 208 | //! 209 | //! ```text 210 | //! get/fixed/4 time: [208.96 ps 209.57 ps 210.17 ps] 211 | //! get/fixed/8 time: [211.12 ps 211.86 ps 212.55 ps] 212 | //! get/fixed/16 time: [211.50 ps 211.84 ps 212.23 ps] 213 | //! get/fixed/32 time: [211.02 ps 211.40 ps 211.79 ps] 214 | //! get/array/4 time: [215.76 ps 216.56 ps 217.68 ps] 215 | //! get/array/8 time: [216.80 ps 217.28 ps 217.83 ps] 216 | //! get/array/16 time: [215.88 ps 216.21 ps 216.58 ps] 217 | //! get/array/32 time: [216.39 ps 216.82 ps 217.33 ps] 218 | //! get/hashbrown/4 time: [2.9134 ns 2.9168 ns 2.9210 ns] 219 | //! get/hashbrown/8 time: [2.9143 ns 2.9175 ns 2.9212 ns] 220 | //! get/hashbrown/16 time: [2.9258 ns 2.9293 ns 2.9328 ns] 221 | //! get/hashbrown/32 time: [2.9387 ns 2.9428 ns 2.9466 ns] 222 | //! 223 | //! insert/fixed/4 time: [421.82 ps 422.47 ps 423.22 ps] 224 | //! insert/fixed/8 time: [635.46 ps 636.91 ps 638.55 ps] 225 | //! insert/fixed/16 time: [1.0579 ns 1.0599 ns 1.0621 ns] 226 | //! insert/fixed/32 time: [1.6991 ns 1.7016 ns 1.7043 ns] 227 | //! insert/array/4 time: [419.26 ps 419.76 ps 420.30 ps] 228 | //! insert/array/8 time: [624.30 ps 626.27 ps 628.33 ps] 229 | //! insert/array/16 time: [1.0444 ns 1.0467 ns 1.0490 ns] 230 | //! insert/array/32 time: [1.6828 ns 1.6904 ns 1.6990 ns] 231 | //! insert/hashbrown/4 time: [87.002 ns 87.233 ns 87.475 ns] 232 | //! insert/hashbrown/8 time: [96.995 ns 97.287 ns 97.589 ns] 233 | //! insert/hashbrown/16 time: [517.89 ns 518.66 ns 519.57 ns] 234 | //! insert/hashbrown/32 time: [156.10 ns 156.67 ns 157.30 ns] 235 | //! 236 | //! values/fixed/4 time: [209.09 ps 209.51 ps 209.91 ps] 237 | //! values/fixed/8 time: [213.99 ps 215.34 ps 217.08 ps] 238 | //! values/fixed/16 time: [213.24 ps 213.94 ps 214.72 ps] 239 | //! values/fixed/32 time: [212.71 ps 213.82 ps 215.15 ps] 240 | //! values/array/4 time: [211.07 ps 211.78 ps 212.59 ps] 241 | //! values/array/8 time: [211.48 ps 212.03 ps 212.65 ps] 242 | //! values/array/16 time: [213.04 ps 213.49 ps 213.99 ps] 243 | //! values/array/32 time: [213.18 ps 213.78 ps 214.60 ps] 244 | //! values/hashbrown/4 time: [3.3965 ns 3.4007 ns 3.4056 ns] 245 | //! values/hashbrown/8 time: [3.8443 ns 3.8627 ns 3.8895 ns] 246 | //! values/hashbrown/16 time: [5.6312 ns 5.6666 ns 5.7029 ns] 247 | //! values/hashbrown/32 time: [8.7221 ns 8.7674 ns 8.8117 ns] 248 | //! 249 | //! array/sum_values time: [3.0394 ns 3.0463 ns 3.0534 ns] 250 | //! fixed/sum_values time: [3.0503 ns 3.0559 ns 3.0619 ns] 251 | //! ``` 252 | //! 253 | //!
254 | //! 255 | //! ## Examples 256 | //! 257 | //! Most examples are in place to test what kind of assembler they compile to. 258 | //! 259 | //! To do this, run: 260 | //! 261 | //! ```sh 262 | //! RUSTFLAGS="--emit asm" cargo build --release --example 263 | //! ``` 264 | //! 265 | //! You should be able to find the assembler generated in the target folder: 266 | //! 267 | //! ```sh 268 | //! ls target/release/examples/ 269 | //! ``` 270 | //! 271 | //! [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html 272 | //! [`Deserialize`]: https://docs.rs/serde/1/serde/trait.Deserialize.html 273 | //! [`hashbrown`]: https://github.com/Amanieu/hashbrown 274 | //! [`Key` derive]: https://docs.rs/fixed-map/latest/fixed_map/derive.Key.html 275 | //! [`Key`]: https://docs.rs/fixed-map/latest/fixed_map/derive.Key.html 276 | //! [`Map`]: https://docs.rs/fixed-map/latest/fixed_map/map/struct.Map.html 277 | //! [`entry`]: https://docs.rs/fixed-map/latest/fixed_map/map/struct.Map.html#method.entry 278 | //! [`HashMap`]: https://doc.rust-lang.org/stable/std/collections/hash_map/struct.HashMap.html#method.entry 279 | //! [`Serialize`]: https://docs.rs/serde/1/serde/trait.Serialize.html 280 | //! [`Set`]: https://docs.rs/fixed-map/latest/fixed_map/set/struct.Set.html 281 | //! [`Storage`]: https://docs.rs/fixed-map/latest/fixed_map/storage/trait.Storage.html 282 | //! [documentation]: https://docs.rs/fixed-map 283 | 284 | #![no_std] 285 | #![deny(missing_docs)] 286 | #![allow(clippy::expl_impl_clone_on_copy)] 287 | #![allow(clippy::module_name_repetitions)] 288 | #![allow(clippy::type_repetition_in_bounds)] 289 | 290 | pub mod raw; 291 | 292 | mod key; 293 | pub use self::key::Key; 294 | 295 | pub mod map; 296 | #[doc(inline)] 297 | pub use self::map::Map; 298 | 299 | pub mod set; 300 | #[doc(inline)] 301 | pub use self::set::Set; 302 | 303 | // Re-export the option bucket types for use in `derive(Key)` 304 | #[doc(hidden)] 305 | pub mod option_bucket; 306 | 307 | #[doc(hidden)] 308 | pub mod macro_support; 309 | 310 | /// Derive to implement the [`Key`] trait. 311 | /// 312 | /// This derive implements the [`Key`] trait for a given type. 313 | /// 314 | /// The [`Key`] trait is what allows `fixed_map` to set up storage for a type 315 | /// that will be the key in a fixed map. 316 | /// 317 | /// > Note: this requires the `::fixed_map` crate to be in scope when it's 318 | /// > derived. 319 | /// 320 | ///
321 | /// 322 | /// ## Container attributes 323 | /// 324 | ///
325 | /// 326 | /// Container attributes are attributes which apply directly onto container 327 | /// types. For [`Key`] this is just enums. 328 | /// 329 | ///
330 | /// 331 | /// #### `#[key(bitset)]` 332 | /// 333 | /// This ensures that backing storage is performed with a bitset when used with 334 | /// a [`Set`]. 335 | /// 336 | /// ``` 337 | /// use fixed_map::{Key, Set}; 338 | /// 339 | /// #[derive(Clone, Copy, Key)] 340 | /// pub enum Regular { 341 | /// First, 342 | /// Second, 343 | /// Third, 344 | /// } 345 | /// 346 | /// #[derive(Clone, Copy, Key)] 347 | /// #[key(bitset)] 348 | /// pub enum Bits { 349 | /// First, 350 | /// Second, 351 | /// Third, 352 | /// } 353 | /// 354 | /// // Normal storage uses an array of booleans: 355 | /// assert_eq!(core::mem::size_of::>(), 3); 356 | /// 357 | /// // Bitset storage uses a single u8 (or other appropriate type based on size): 358 | /// assert_eq!(core::mem::size_of::>(), 1); 359 | /// ``` 360 | /// 361 | /// > **Note:** not all operations will be implemented when this attribute is 362 | /// > present, so some container methods might not work. 363 | /// 364 | ///
365 | /// 366 | /// ## Guide 367 | /// 368 | /// Given the following enum: 369 | /// 370 | /// ``` 371 | /// use fixed_map::Key; 372 | /// 373 | /// #[derive(Clone, Copy, Key)] 374 | /// pub enum MyKey { 375 | /// First, 376 | /// Second, 377 | /// Third, 378 | /// } 379 | /// ``` 380 | /// 381 | /// It performs the following expansion: 382 | /// 383 | /// ```ignore 384 | /// use fixed_map::Key; 385 | /// 386 | /// #[derive(Clone, Copy)] 387 | /// pub enum MyKey { 388 | /// First, 389 | /// Second, 390 | /// Third, 391 | /// } 392 | /// 393 | /// /// Build a storage struct containing an item for each key: 394 | /// pub struct MyKeyMapStorage { 395 | /// /// Storage for `MyKey::First`. 396 | /// f1: Option, 397 | /// /// Storage for `MyKey::Second`. 398 | /// f2: Option, 399 | /// /// Storage for `MyKey::Third`. 400 | /// f3: Option, 401 | /// } 402 | /// 403 | /// /// Build a storage struct containing an element for each key: 404 | /// pub struct MyKeySetStorage { 405 | /// data: [bool; 3], 406 | /// } 407 | /// 408 | /// /// Implement map storage for key. 409 | /// impl ::fixed_map::map::MapStorage for MyKeyMapStorage { 410 | /// fn get(&self, key: MyKey) -> Option<&V> { 411 | /// match key { 412 | /// MyKey::First => self.f1.as_ref(), 413 | /// MyKey::Second => self.f2.as_ref(), 414 | /// MyKey::Third => self.f3.as_ref(), 415 | /// } 416 | /// } 417 | /// 418 | /// /* skipped */ 419 | /// } 420 | /// 421 | /// /// Implement set storage for key. 422 | /// impl ::fixed_map::set::SetStorage for MyKeySetStorage { 423 | /// fn contains(&self, key: MyKey) -> bool { 424 | /// let [a, b, c] = &self.data; 425 | /// 426 | /// match key { 427 | /// MyKey::First => *a, 428 | /// MyKey::Second => *b, 429 | /// MyKey::Third => *c, 430 | /// } 431 | /// } 432 | /// 433 | /// /* skipped */ 434 | /// } 435 | /// 436 | /// impl Default for MyKeyMapStorage { 437 | /// fn default() -> Self { 438 | /// Self { 439 | /// f1: None, 440 | /// f2: None, 441 | /// f3: None, 442 | /// } 443 | /// } 444 | /// } 445 | /// 446 | /// impl Default for MyKeySetStorage { 447 | /// fn default() -> Self { 448 | /// Self { 449 | /// data: [false, false, false] 450 | /// } 451 | /// } 452 | /// } 453 | /// 454 | /// /// Implement the Key trait to point out storage. 455 | /// impl ::fixed_map::Key for MyKey { 456 | /// type MapStorage = MyKeyMapStorage; 457 | /// type SetStorage = MyKeySetStorage; 458 | /// } 459 | /// ``` 460 | #[doc(inline)] 461 | pub use fixed_map_derive::Key; 462 | -------------------------------------------------------------------------------- /src/macro_support.rs: -------------------------------------------------------------------------------- 1 | //! ## PRIVATE API 2 | //! 3 | //! This API is private, for use only in the `derive(Key)` macro. Usage for 4 | //! other purposes is not supported, and this API will not abide by semver 5 | //! stability guarantees. 6 | 7 | #![allow(clippy::missing_inline_in_public_items)] 8 | 9 | use core::cmp::Ordering; 10 | 11 | #[inline] 12 | fn flatten(value: (usize, &Option)) -> Option<(usize, &T)> { 13 | match value { 14 | (index, Some(value)) => Some((index, value)), 15 | _ => None, 16 | } 17 | } 18 | 19 | /// `partial_cmp` implementation over iterators which ensures that storage 20 | /// ordering between `None` and `Some` is handled in a reasonable manner. 21 | pub fn __storage_iterator_partial_cmp<'a, A, B, T>(a: A, b: B) -> Option 22 | where 23 | A: IntoIterator>, 24 | B: IntoIterator>, 25 | T: 'a + PartialOrd, 26 | { 27 | let a = a.into_iter().enumerate().filter_map(flatten); 28 | let b = b.into_iter().enumerate().filter_map(flatten); 29 | a.partial_cmp(b) 30 | } 31 | 32 | /// `cmp` implementation over iterators which ensures that storage ordering 33 | /// between `None` and `Some` is handled in a reasonable manner. 34 | pub fn __storage_iterator_cmp<'a, A, B, T>(a: A, b: B) -> Ordering 35 | where 36 | A: IntoIterator>, 37 | B: IntoIterator>, 38 | T: 'a + Ord, 39 | { 40 | let a = a.into_iter().enumerate().filter_map(flatten); 41 | let b = b.into_iter().enumerate().filter_map(flatten); 42 | a.cmp(b) 43 | } 44 | 45 | #[inline] 46 | fn filter_bool(&(_, value): &(usize, &bool)) -> bool { 47 | *value 48 | } 49 | 50 | /// `partial_cmp` implementation over iterators which ensures that storage 51 | /// ordering between `false` and `true` is handled in a reasonable manner. 52 | pub fn __storage_iterator_partial_cmp_bool<'a, A, B>(a: A, b: B) -> Option 53 | where 54 | A: IntoIterator, 55 | B: IntoIterator, 56 | { 57 | let a = a.into_iter().enumerate().filter(filter_bool); 58 | let b = b.into_iter().enumerate().filter(filter_bool); 59 | a.partial_cmp(b) 60 | } 61 | 62 | /// `cmp` implementation over iterators which ensures that storage ordering 63 | /// between `false` and `true` is handled in a reasonable manner. 64 | pub fn __storage_iterator_cmp_bool<'a, A, B>(a: A, b: B) -> Ordering 65 | where 66 | A: IntoIterator, 67 | B: IntoIterator, 68 | { 69 | let a = a.into_iter().enumerate().filter(filter_bool); 70 | let b = b.into_iter().enumerate().filter(filter_bool); 71 | a.cmp(b) 72 | } 73 | -------------------------------------------------------------------------------- /src/map/entry.rs: -------------------------------------------------------------------------------- 1 | use crate::map::{MapStorage, OccupiedEntry, VacantEntry}; 2 | 3 | /// A view into a single entry in a map, which may either be vacant or occupied. 4 | /// 5 | /// This enum is constructed from the [`entry`][crate::Map::entry] method on [`Map`][crate::Map]. 6 | pub enum Entry<'a, S: 'a, K, V> 7 | where 8 | S: MapStorage, 9 | { 10 | /// An occupied entry. 11 | Occupied(S::Occupied<'a>), 12 | /// A vacant entry. 13 | Vacant(S::Vacant<'a>), 14 | } 15 | 16 | impl<'a, S: 'a, K, V> Entry<'a, S, K, V> 17 | where 18 | S: MapStorage, 19 | { 20 | /// Ensures a value is in the entry by inserting the default if empty, 21 | /// and returns a mutable reference to the value in the entry. 22 | /// 23 | /// # Examples 24 | /// 25 | /// ``` 26 | /// use fixed_map::{Key, Map}; 27 | /// 28 | /// #[derive(Clone, Copy, Key)] 29 | /// enum MyKey { 30 | /// First, 31 | /// Second, 32 | /// } 33 | /// 34 | /// let mut map: Map = Map::new(); 35 | /// 36 | /// map.entry(MyKey::First).or_insert(3); 37 | /// assert_eq!(map.get(MyKey::First), Some(&3)); 38 | /// 39 | /// *map.entry(MyKey::First).or_insert(10) *= 2; 40 | /// assert_eq!(map.get(MyKey::First), Some(&6)); 41 | /// ``` 42 | /// 43 | /// Using a composite key: 44 | /// 45 | /// ``` 46 | /// use fixed_map::{Key, Map}; 47 | /// 48 | /// #[derive(Clone, Copy, Key)] 49 | /// enum MyKey { 50 | /// First(bool), 51 | /// Second, 52 | /// } 53 | /// 54 | /// let mut map: Map = Map::new(); 55 | /// 56 | /// map.entry(MyKey::First(false)).or_insert(3); 57 | /// assert_eq!(map.get(MyKey::First(false)), Some(&3)); 58 | /// 59 | /// *map.entry(MyKey::First(false)).or_insert(10) *= 2; 60 | /// assert_eq!(map.get(MyKey::First(false)), Some(&6)); 61 | /// ``` 62 | #[inline] 63 | pub fn or_insert(self, default: V) -> &'a mut V { 64 | match self { 65 | Entry::Occupied(entry) => entry.into_mut(), 66 | Entry::Vacant(entry) => entry.insert(default), 67 | } 68 | } 69 | 70 | /// Ensures a value is in the entry by inserting the result of the default function if empty, 71 | /// and returns a mutable reference to the value in the entry. 72 | /// 73 | /// # Examples 74 | /// 75 | /// ``` 76 | /// use fixed_map::{Key, Map}; 77 | /// 78 | /// #[derive(Clone, Copy, Key)] 79 | /// enum MyKey { 80 | /// First, 81 | /// Second, 82 | /// } 83 | /// 84 | /// let mut map: Map = Map::new(); 85 | /// 86 | /// map.entry(MyKey::First).or_insert_with(|| format!("{}", 3)); 87 | /// assert_eq!(map.get(MyKey::First), Some(&"3".to_string())); 88 | /// ``` 89 | /// 90 | /// Using a composite key: 91 | /// 92 | /// ``` 93 | /// use fixed_map::{Key, Map}; 94 | /// 95 | /// #[derive(Clone, Copy, Key)] 96 | /// enum MyKey { 97 | /// First(bool), 98 | /// Second, 99 | /// } 100 | /// 101 | /// let mut map: Map = Map::new(); 102 | /// 103 | /// map.entry(MyKey::First(false)).or_insert_with(|| format!("{}", 3)); 104 | /// assert_eq!(map.get(MyKey::First(false)), Some(&"3".to_string())); 105 | /// ``` 106 | #[inline] 107 | pub fn or_insert_with(self, default: F) -> &'a mut V 108 | where 109 | F: FnOnce() -> V, 110 | { 111 | match self { 112 | Entry::Occupied(entry) => entry.into_mut(), 113 | Entry::Vacant(entry) => entry.insert(default()), 114 | } 115 | } 116 | 117 | /// Ensures a value is in the entry by inserting, if empty, the result of the default function. 118 | /// This method allows for generating key-derived values for insertion by providing the default 119 | /// function a copy of the key that was passed to the `.entry(key)` method call. 120 | /// 121 | /// # Examples 122 | /// 123 | /// ``` 124 | /// use fixed_map::{Key, Map}; 125 | /// 126 | /// #[derive(Clone, Copy, Key, Debug)] 127 | /// enum MyKey { 128 | /// First, 129 | /// Second, 130 | /// } 131 | /// 132 | /// let mut map: Map = Map::new(); 133 | /// 134 | /// map.entry(MyKey::First).or_insert_with_key(|k| format!("{:?} = {}", k, 3)); 135 | /// assert_eq!(map.get(MyKey::First), Some(&"First = 3".to_string())); 136 | /// ``` 137 | /// 138 | /// Using a composite key: 139 | /// 140 | /// ``` 141 | /// use fixed_map::{Key, Map}; 142 | /// 143 | /// #[derive(Clone, Copy, Key, Debug)] 144 | /// enum MyKey { 145 | /// First(bool), 146 | /// Second, 147 | /// } 148 | /// 149 | /// let mut map: Map = Map::new(); 150 | /// 151 | /// map.entry(MyKey::First(false)).or_insert_with_key(|k| format!("{:?} = {}", k, 3)); 152 | /// assert_eq!(map.get(MyKey::First(false)), Some(&"First(false) = 3".to_string())); 153 | /// ``` 154 | #[inline] 155 | pub fn or_insert_with_key(self, default: F) -> &'a mut V 156 | where 157 | F: FnOnce(K) -> V, 158 | { 159 | match self { 160 | Entry::Occupied(entry) => entry.into_mut(), 161 | Entry::Vacant(entry) => { 162 | let value = default(entry.key()); 163 | entry.insert(value) 164 | } 165 | } 166 | } 167 | 168 | /// Returns a copy of this entry's key. 169 | /// 170 | /// # Examples 171 | /// 172 | /// ``` 173 | /// use fixed_map::{Key, Map}; 174 | /// 175 | /// #[derive(Clone, Copy, Key, Debug, PartialEq)] 176 | /// enum MyKey { 177 | /// First, 178 | /// Second, 179 | /// } 180 | /// 181 | /// let mut map: Map = Map::new(); 182 | /// assert_eq!(map.entry(MyKey::First).key(), MyKey::First); 183 | /// ``` 184 | /// 185 | /// Using a composite key: 186 | /// 187 | /// ``` 188 | /// use fixed_map::{Key, Map}; 189 | /// 190 | /// #[derive(Clone, Copy, Key, Debug, PartialEq)] 191 | /// enum MyKey { 192 | /// First(bool), 193 | /// Second, 194 | /// } 195 | /// 196 | /// let mut map: Map = Map::new(); 197 | /// assert_eq!(map.entry(MyKey::First(false)).key(), MyKey::First(false)); 198 | /// ``` 199 | #[inline] 200 | pub fn key(&self) -> K { 201 | match self { 202 | Entry::Occupied(entry) => entry.key(), 203 | Entry::Vacant(entry) => entry.key(), 204 | } 205 | } 206 | 207 | /// Provides in-place mutable access to an occupied entry before any 208 | /// potential inserts into the map. 209 | /// 210 | /// # Examples 211 | /// 212 | /// ``` 213 | /// use fixed_map::{Key, Map}; 214 | /// 215 | /// #[derive(Clone, Copy, Key)] 216 | /// enum MyKey { 217 | /// First, 218 | /// Second, 219 | /// } 220 | /// 221 | /// let mut map: Map = Map::new(); 222 | /// 223 | /// map.entry(MyKey::First) 224 | /// .and_modify(|e| { *e += 1 }) 225 | /// .or_insert(42); 226 | /// assert_eq!(map.get(MyKey::First), Some(&42)); 227 | /// 228 | /// map.entry(MyKey::First) 229 | /// .and_modify(|e| { *e += 1 }) 230 | /// .or_insert(42); 231 | /// assert_eq!(map.get(MyKey::First), Some(&43)); 232 | /// ``` 233 | /// 234 | /// Using a composite key: 235 | /// 236 | /// ``` 237 | /// use fixed_map::{Key, Map}; 238 | /// 239 | /// #[derive(Clone, Copy, Key)] 240 | /// enum MyKey { 241 | /// First(bool), 242 | /// Second, 243 | /// } 244 | /// 245 | /// let mut map: Map = Map::new(); 246 | /// 247 | /// map.entry(MyKey::First(true)) 248 | /// .and_modify(|e| { *e += 1 }) 249 | /// .or_insert(42); 250 | /// assert_eq!(map.get(MyKey::First(true)), Some(&42)); 251 | /// 252 | /// map.entry(MyKey::First(true)) 253 | /// .and_modify(|e| { *e += 1 }) 254 | /// .or_insert(42); 255 | /// assert_eq!(map.get(MyKey::First(true)), Some(&43)); 256 | /// ``` 257 | #[inline] 258 | #[must_use] 259 | pub fn and_modify(self, f: F) -> Self 260 | where 261 | F: FnOnce(&mut V), 262 | { 263 | match self { 264 | Entry::Occupied(mut entry) => { 265 | f(entry.get_mut()); 266 | Entry::Occupied(entry) 267 | } 268 | Entry::Vacant(entry) => Entry::Vacant(entry), 269 | } 270 | } 271 | 272 | /// Ensures a value is in the entry by inserting the default value if empty, 273 | /// and returns a mutable reference to the value in the entry. 274 | /// 275 | /// # Examples 276 | /// 277 | /// ``` 278 | /// use fixed_map::{Key, Map}; 279 | /// 280 | /// #[derive(Clone, Copy, Key)] 281 | /// enum MyKey { 282 | /// First, 283 | /// Second, 284 | /// } 285 | /// 286 | /// let mut map: Map = Map::new(); 287 | /// 288 | /// map.entry(MyKey::First).or_default(); 289 | /// assert_eq!(map.get(MyKey::First), Some(&0)); 290 | /// ``` 291 | /// 292 | /// Using a composite key: 293 | /// 294 | /// ``` 295 | /// use fixed_map::{Key, Map}; 296 | /// 297 | /// #[derive(Clone, Copy, Key)] 298 | /// enum MyKey { 299 | /// First(bool), 300 | /// Second, 301 | /// } 302 | /// 303 | /// let mut map: Map = Map::new(); 304 | /// 305 | /// map.entry(MyKey::First(false)).or_default(); 306 | /// assert_eq!(map.get(MyKey::First(false)), Some(&0)); 307 | /// ``` 308 | #[inline] 309 | pub fn or_default(self) -> &'a mut V 310 | where 311 | V: Default, 312 | { 313 | match self { 314 | Entry::Occupied(entry) => entry.into_mut(), 315 | Entry::Vacant(entry) => entry.insert(Default::default()), 316 | } 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /src/map/storage.rs: -------------------------------------------------------------------------------- 1 | //! Module that defines the [`MapStorage`] trait. 2 | 3 | mod boolean; 4 | pub(crate) use self::boolean::BooleanMapStorage; 5 | 6 | #[cfg(feature = "hashbrown")] 7 | mod hashbrown; 8 | #[cfg(feature = "hashbrown")] 9 | pub(crate) use self::hashbrown::HashbrownMapStorage; 10 | 11 | mod option; 12 | pub(crate) use self::option::OptionMapStorage; 13 | 14 | mod singleton; 15 | pub(crate) use self::singleton::SingletonMapStorage; 16 | 17 | use crate::map::Entry; 18 | 19 | /// The trait defining how storage works. 20 | /// 21 | /// # Type Arguments 22 | /// 23 | /// - `K` is the key being stored. 24 | /// - `V` is the value being stored. 25 | pub trait MapStorage: Sized { 26 | /// Immutable iterator over storage. 27 | type Iter<'this>: Iterator 28 | where 29 | Self: 'this, 30 | V: 'this; 31 | 32 | /// Immutable iterator over keys in storage. 33 | type Keys<'this>: Iterator 34 | where 35 | Self: 'this; 36 | 37 | /// Immutable iterator over values in storage. 38 | type Values<'this>: Iterator 39 | where 40 | Self: 'this, 41 | V: 'this; 42 | 43 | /// Mutable iterator over storage. 44 | type IterMut<'this>: Iterator 45 | where 46 | Self: 'this, 47 | V: 'this; 48 | 49 | /// Mutable iterator over values in storage. 50 | type ValuesMut<'this>: Iterator 51 | where 52 | Self: 'this, 53 | V: 'this; 54 | 55 | /// Consuming iterator. 56 | type IntoIter: Iterator; 57 | 58 | /// An occupied entry. 59 | type Occupied<'this>: OccupiedEntry<'this, K, V> 60 | where 61 | Self: 'this; 62 | 63 | /// A vacant entry. 64 | type Vacant<'this>: VacantEntry<'this, K, V> 65 | where 66 | Self: 'this; 67 | 68 | /// Construct empty storage. 69 | fn empty() -> Self; 70 | 71 | /// Get the length of storage. 72 | fn len(&self) -> usize; 73 | 74 | /// Check if storage is empty. 75 | fn is_empty(&self) -> bool; 76 | 77 | /// This is the storage abstraction for [`Map::insert`][crate::Map::insert]. 78 | fn insert(&mut self, key: K, value: V) -> Option; 79 | 80 | /// This is the storage abstraction for [`Map::contains_key`][crate::Map::contains_key]. 81 | fn contains_key(&self, key: K) -> bool; 82 | 83 | /// This is the storage abstraction for [`Map::get`][crate::Map::get]. 84 | fn get(&self, key: K) -> Option<&V>; 85 | 86 | /// This is the storage abstraction for [`Map::get_mut`][crate::Map::get_mut]. 87 | fn get_mut(&mut self, key: K) -> Option<&mut V>; 88 | 89 | /// This is the storage abstraction for [`Map::remove`][crate::Map::remove]. 90 | fn remove(&mut self, key: K) -> Option; 91 | 92 | /// This is the storage abstraction for [`Map::retain`][crate::Map::retain]. 93 | fn retain(&mut self, f: F) 94 | where 95 | F: FnMut(K, &mut V) -> bool; 96 | 97 | /// This is the storage abstraction for [`Map::clear`][crate::Map::clear]. 98 | fn clear(&mut self); 99 | 100 | /// This is the storage abstraction for [`Map::iter`][crate::Map::iter]. 101 | fn iter(&self) -> Self::Iter<'_>; 102 | 103 | /// This is the storage abstraction for [`Map::keys`][crate::Map::keys]. 104 | fn keys(&self) -> Self::Keys<'_>; 105 | 106 | /// This is the storage abstraction for [`Map::values`][crate::Map::values]. 107 | fn values(&self) -> Self::Values<'_>; 108 | 109 | /// This is the storage abstraction for [`Map::iter_mut`][crate::Map::iter_mut]. 110 | fn iter_mut(&mut self) -> Self::IterMut<'_>; 111 | 112 | /// This is the storage abstraction for [`Map::values_mut`][crate::Map::values_mut]. 113 | fn values_mut(&mut self) -> Self::ValuesMut<'_>; 114 | 115 | /// This is the storage abstraction for [`Map::into_iter`][crate::Map::into_iter]. 116 | fn into_iter(self) -> Self::IntoIter; 117 | 118 | /// This is the storage abstraction for [`Map::entry`][crate::Map::entry]. 119 | fn entry(&mut self, key: K) -> Entry<'_, Self, K, V>; 120 | } 121 | 122 | /// A view into an occupied entry in a [`Map`][crate::Map]. It is part of the 123 | /// [`Entry`] enum. 124 | pub trait OccupiedEntry<'a, K, V> { 125 | /// Gets a copy of the key in the entry. 126 | /// 127 | /// # Examples 128 | /// 129 | /// ``` 130 | /// use fixed_map::{Key, Map}; 131 | /// use fixed_map::map::{Entry, OccupiedEntry}; 132 | /// 133 | /// #[derive(Clone, Copy, Key, Debug, PartialEq)] 134 | /// enum MyKey { 135 | /// First, 136 | /// Second, 137 | /// } 138 | /// 139 | /// let mut map: Map = Map::new(); 140 | /// map.insert(MyKey::First, 12); 141 | /// 142 | /// let occupied = match map.entry(MyKey::First) { 143 | /// Entry::Occupied(entry) => entry, 144 | /// _ => unreachable!(), 145 | /// }; 146 | /// 147 | /// assert_eq!(occupied.key(), MyKey::First); 148 | /// ``` 149 | /// 150 | /// Using a composite key: 151 | /// 152 | /// ``` 153 | /// use fixed_map::{Key, Map}; 154 | /// use fixed_map::map::{Entry, OccupiedEntry}; 155 | /// 156 | /// #[derive(Clone, Copy, Key, Debug, PartialEq)] 157 | /// enum MyKey { 158 | /// First(bool), 159 | /// Second, 160 | /// } 161 | /// 162 | /// let mut map: Map = Map::new(); 163 | /// map.insert(MyKey::First(false), 12); 164 | /// 165 | /// let occupied = match map.entry(MyKey::First(false)) { 166 | /// Entry::Occupied(entry) => entry, 167 | /// _ => unreachable!(), 168 | /// }; 169 | /// 170 | /// assert_eq!(occupied.key(), MyKey::First(false)); 171 | /// ``` 172 | fn key(&self) -> K; 173 | 174 | /// Gets a reference to the value in the entry. 175 | /// 176 | /// # Examples 177 | /// 178 | /// ``` 179 | /// use fixed_map::{Key, Map}; 180 | /// use fixed_map::map::{Entry, OccupiedEntry}; 181 | /// 182 | /// #[derive(Clone, Copy, Key)] 183 | /// enum MyKey { 184 | /// First, 185 | /// Second, 186 | /// } 187 | /// 188 | /// let mut map: Map = Map::new(); 189 | /// map.insert(MyKey::First, 12); 190 | /// 191 | /// let occupied = match map.entry(MyKey::First) { 192 | /// Entry::Occupied(entry) => entry, 193 | /// _ => unreachable!(), 194 | /// }; 195 | /// 196 | /// assert_eq!(occupied.get(), &12); 197 | /// ``` 198 | /// 199 | /// Using a composite key: 200 | /// 201 | /// ``` 202 | /// use fixed_map::{Key, Map}; 203 | /// use fixed_map::map::{Entry, OccupiedEntry}; 204 | /// 205 | /// #[derive(Clone, Copy, Key)] 206 | /// enum MyKey { 207 | /// First(bool), 208 | /// Second, 209 | /// } 210 | /// 211 | /// let mut map: Map = Map::new(); 212 | /// map.insert(MyKey::First(false), 12); 213 | /// 214 | /// let occupied = match map.entry(MyKey::First(false)) { 215 | /// Entry::Occupied(entry) => entry, 216 | /// _ => unreachable!(), 217 | /// }; 218 | /// 219 | /// assert_eq!(occupied.get(), &12); 220 | /// ``` 221 | fn get(&self) -> &V; 222 | 223 | /// Gets a mutable reference to the value in the entry. 224 | /// 225 | /// If you need a reference to the `OccupiedEntry` which may 226 | /// outlive the destruction of the `Entry` value, see [`into_mut`][Self::into_mut]. 227 | /// 228 | /// # Examples 229 | /// 230 | /// ``` 231 | /// use fixed_map::{Key, Map}; 232 | /// use fixed_map::map::{Entry, OccupiedEntry}; 233 | /// 234 | /// #[derive(Clone, Copy, Key)] 235 | /// enum MyKey { 236 | /// First, 237 | /// Second, 238 | /// } 239 | /// 240 | /// let mut map: Map = Map::new(); 241 | /// map.insert(MyKey::First, 12); 242 | /// 243 | /// let mut occupied = match map.entry(MyKey::First) { 244 | /// Entry::Occupied(entry) => entry, 245 | /// _ => unreachable!(), 246 | /// }; 247 | /// 248 | /// assert_eq!(occupied.get_mut(), &12); 249 | /// ``` 250 | /// 251 | /// Using a composite key: 252 | /// 253 | /// ``` 254 | /// use fixed_map::{Key, Map}; 255 | /// use fixed_map::map::{Entry, OccupiedEntry}; 256 | /// 257 | /// #[derive(Clone, Copy, Key)] 258 | /// enum MyKey { 259 | /// First(bool), 260 | /// Second, 261 | /// } 262 | /// 263 | /// let mut map: Map = Map::new(); 264 | /// map.insert(MyKey::First(false), 12); 265 | /// 266 | /// let mut occupied = match map.entry(MyKey::First(false)) { 267 | /// Entry::Occupied(entry) => entry, 268 | /// _ => unreachable!(), 269 | /// }; 270 | /// 271 | /// *occupied.get_mut() *= 2; 272 | /// assert_eq!(occupied.get(), &24); 273 | /// // We can use the same Entry multiple times. 274 | /// *occupied.get_mut() -= 10; 275 | /// assert_eq!(occupied.get(), &14); 276 | /// ``` 277 | fn get_mut(&mut self) -> &mut V; 278 | 279 | /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry 280 | /// with a lifetime bound to the map itself. 281 | /// 282 | /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`][Self::get_mut]. 283 | /// 284 | /// # Examples 285 | /// 286 | /// ``` 287 | /// use fixed_map::{Key, Map}; 288 | /// use fixed_map::map::{Entry, OccupiedEntry}; 289 | /// 290 | /// #[derive(Clone, Copy, Key)] 291 | /// enum MyKey { 292 | /// First, 293 | /// Second, 294 | /// } 295 | /// 296 | /// let mut map: Map = Map::new(); 297 | /// map.insert(MyKey::First, 12); 298 | /// 299 | /// if let Entry::Occupied(occupied) = map.entry(MyKey::First) { 300 | /// *occupied.into_mut() += 10; 301 | /// }; 302 | /// 303 | /// assert_eq!(map.get(MyKey::First), Some(&22)); 304 | /// ``` 305 | /// 306 | /// Using a composite key: 307 | /// 308 | /// ``` 309 | /// use fixed_map::{Key, Map}; 310 | /// use fixed_map::map::{Entry, OccupiedEntry}; 311 | /// 312 | /// #[derive(Clone, Copy, Key)] 313 | /// enum MyKey { 314 | /// First(bool), 315 | /// Second, 316 | /// } 317 | /// 318 | /// let mut map: Map = Map::new(); 319 | /// map.insert(MyKey::First(false), 12); 320 | /// 321 | /// if let Entry::Occupied(occupied) = map.entry(MyKey::First(false)) { 322 | /// *occupied.into_mut() += 10; 323 | /// }; 324 | /// 325 | /// assert_eq!(map.get(MyKey::First(false)), Some(&22)); 326 | /// ``` 327 | fn into_mut(self) -> &'a mut V; 328 | 329 | /// Sets the value of the entry, and returns the entry's old value. 330 | /// 331 | /// # Examples 332 | /// 333 | /// ``` 334 | /// use fixed_map::{Key, Map}; 335 | /// use fixed_map::map::{Entry, OccupiedEntry}; 336 | /// 337 | /// #[derive(Clone, Copy, Key)] 338 | /// enum MyKey { 339 | /// First, 340 | /// Second, 341 | /// } 342 | /// 343 | /// let mut map: Map = Map::new(); 344 | /// map.insert(MyKey::First, 12); 345 | /// 346 | /// if let Entry::Occupied(mut occupied) = map.entry(MyKey::First) { 347 | /// assert_eq!(occupied.insert(10), 12); 348 | /// }; 349 | /// 350 | /// assert_eq!(map.get(MyKey::First), Some(&10)); 351 | /// ``` 352 | /// 353 | /// Using a composite key: 354 | /// 355 | /// ``` 356 | /// use fixed_map::{Key, Map}; 357 | /// use fixed_map::map::{Entry, OccupiedEntry}; 358 | /// 359 | /// #[derive(Clone, Copy, Key)] 360 | /// enum MyKey { 361 | /// First(bool), 362 | /// Second, 363 | /// } 364 | /// 365 | /// let mut map: Map = Map::new(); 366 | /// map.insert(MyKey::First(false), 12); 367 | /// 368 | /// if let Entry::Occupied(mut occupied) = map.entry(MyKey::First(false)) { 369 | /// assert_eq!(occupied.insert(10), 12); 370 | /// }; 371 | /// 372 | /// assert_eq!(map.get(MyKey::First(false)), Some(&10)); 373 | /// ``` 374 | fn insert(&mut self, value: V) -> V; 375 | 376 | /// Takes the value out of the entry, and returns it. 377 | /// 378 | /// # Examples 379 | /// 380 | /// ``` 381 | /// use fixed_map::{Key, Map}; 382 | /// use fixed_map::map::{Entry, OccupiedEntry}; 383 | /// 384 | /// #[derive(Clone, Copy, Key)] 385 | /// enum MyKey { 386 | /// First, 387 | /// Second, 388 | /// } 389 | /// 390 | /// let mut map: Map = Map::new(); 391 | /// map.insert(MyKey::First, 12); 392 | /// 393 | /// if let Entry::Occupied(occupied) = map.entry(MyKey::First) { 394 | /// assert_eq!(occupied.remove(), 12); 395 | /// }; 396 | /// 397 | /// assert_eq!(map.contains_key(MyKey::First), false); 398 | /// ``` 399 | /// 400 | /// Using a composite key: 401 | /// 402 | /// ``` 403 | /// use fixed_map::{Key, Map}; 404 | /// use fixed_map::map::{Entry, OccupiedEntry}; 405 | /// 406 | /// #[derive(Clone, Copy, Key)] 407 | /// enum MyKey { 408 | /// First(bool), 409 | /// Second, 410 | /// } 411 | /// 412 | /// let mut map: Map = Map::new(); 413 | /// map.insert(MyKey::First(true), 12); 414 | /// 415 | /// if let Entry::Occupied(occupied) = map.entry(MyKey::First(true)) { 416 | /// assert_eq!(occupied.remove(), 12); 417 | /// }; 418 | /// 419 | /// assert_eq!(map.contains_key(MyKey::First(true)), false); 420 | /// ``` 421 | fn remove(self) -> V; 422 | } 423 | 424 | /// A view into a vacant entry in a [`Map`][crate::Map]. 425 | /// It is part of the [`Entry`] enum. 426 | pub trait VacantEntry<'a, K, V> { 427 | /// Gets a copy of the key that would be used 428 | /// when inserting a value through the `VacantEntry`. 429 | /// 430 | /// # Examples 431 | /// 432 | /// ``` 433 | /// use fixed_map::{Key, Map}; 434 | /// use fixed_map::map::{Entry, VacantEntry}; 435 | /// 436 | /// #[derive(Clone, Copy, Key, Debug, PartialEq)] 437 | /// enum MyKey { 438 | /// First, 439 | /// Second, 440 | /// } 441 | /// 442 | /// let mut map: Map = Map::new(); 443 | /// let vacant = match map.entry(MyKey::First) { 444 | /// Entry::Vacant(entry) => entry, 445 | /// _ => unreachable!(), 446 | /// }; 447 | /// 448 | /// assert_eq!(vacant.key(), MyKey::First); 449 | /// ``` 450 | /// 451 | /// Using a composite key: 452 | /// 453 | /// ``` 454 | /// use fixed_map::{Key, Map}; 455 | /// use fixed_map::map::{Entry, VacantEntry}; 456 | /// 457 | /// #[derive(Clone, Copy, Key, Debug, PartialEq)] 458 | /// enum MyKey { 459 | /// First(bool), 460 | /// Second, 461 | /// } 462 | /// 463 | /// let mut map: Map = Map::new(); 464 | /// let vacant = match map.entry(MyKey::First(false)) { 465 | /// Entry::Vacant(entry) => entry, 466 | /// _ => unreachable!(), 467 | /// }; 468 | /// 469 | /// assert_eq!(vacant.key(), MyKey::First(false)); 470 | /// ``` 471 | fn key(&self) -> K; 472 | 473 | /// Sets the value of the entry with the `VacantEntry`’s key, 474 | /// and returns a mutable reference to it. 475 | /// 476 | /// # Examples 477 | /// 478 | /// ``` 479 | /// use fixed_map::{Key, Map}; 480 | /// use fixed_map::map::{Entry, VacantEntry}; 481 | /// 482 | /// #[derive(Clone, Copy, Key)] 483 | /// enum MyKey { 484 | /// First, 485 | /// Second, 486 | /// } 487 | /// 488 | /// let mut map: Map = Map::new(); 489 | /// 490 | /// if let Entry::Vacant(vacant) = map.entry(MyKey::First) { 491 | /// assert_eq!(vacant.insert(37), &37); 492 | /// } 493 | /// 494 | /// assert_eq!(map.get(MyKey::First), Some(&37)); 495 | /// ``` 496 | /// 497 | /// Using a composite key: 498 | /// 499 | /// ``` 500 | /// use fixed_map::{Key, Map}; 501 | /// use fixed_map::map::{Entry, VacantEntry}; 502 | /// 503 | /// #[derive(Clone, Copy, Key)] 504 | /// enum MyKey { 505 | /// First(bool), 506 | /// Second, 507 | /// } 508 | /// 509 | /// let mut map: Map = Map::new(); 510 | /// 511 | /// if let Entry::Vacant(vacant) = map.entry(MyKey::First(false)) { 512 | /// assert_eq!(vacant.insert(37), &37); 513 | /// } 514 | /// 515 | /// assert_eq!(map.get(MyKey::First(false)), Some(&37)); 516 | /// ``` 517 | fn insert(self, value: V) -> &'a mut V; 518 | } 519 | -------------------------------------------------------------------------------- /src/map/storage/boolean.rs: -------------------------------------------------------------------------------- 1 | // Iterators are confusing if they impl `Copy`. 2 | 3 | #![allow(missing_copy_implementations)] 4 | 5 | use core::iter; 6 | use core::option; 7 | 8 | use crate::map::{Entry, MapStorage, OccupiedEntry, VacantEntry}; 9 | use crate::option_bucket::{NoneBucket, OptionBucket, SomeBucket}; 10 | 11 | const TRUE_BIT: u8 = 0b10; 12 | const FALSE_BIT: u8 = 0b01; 13 | 14 | type Iter<'a, V> = iter::Chain< 15 | iter::Map, fn(&'a V) -> (bool, &'a V)>, 16 | iter::Map, fn(&'a V) -> (bool, &'a V)>, 17 | >; 18 | type Values<'a, V> = iter::Chain, option::Iter<'a, V>>; 19 | type IterMut<'a, V> = iter::Chain< 20 | iter::Map, fn(&'a mut V) -> (bool, &'a mut V)>, 21 | iter::Map, fn(&'a mut V) -> (bool, &'a mut V)>, 22 | >; 23 | type ValuesMut<'a, V> = iter::Chain, option::IterMut<'a, V>>; 24 | type IntoIter = iter::Chain< 25 | iter::Map, fn(V) -> (bool, V)>, 26 | iter::Map, fn(V) -> (bool, V)>, 27 | >; 28 | 29 | /// [`MapStorage`] for [`bool`] types. 30 | /// 31 | /// # Examples 32 | /// 33 | /// ``` 34 | /// use fixed_map::{Key, Map}; 35 | /// 36 | /// #[derive(Debug, Clone, Copy, PartialEq, Key)] 37 | /// enum MyKey { 38 | /// First(bool), 39 | /// Second, 40 | /// } 41 | /// 42 | /// let mut a = Map::new(); 43 | /// a.insert(MyKey::First(false), 1); 44 | /// 45 | /// assert_eq!(a.get(MyKey::First(true)), None); 46 | /// assert_eq!(a.get(MyKey::First(false)), Some(&1)); 47 | /// assert_eq!(a.get(MyKey::Second), None); 48 | /// 49 | /// assert!(a.iter().eq([(MyKey::First(false), &1)])); 50 | /// assert!(a.values().copied().eq([1])); 51 | /// assert!(a.keys().eq([MyKey::First(false)])); 52 | /// ``` 53 | /// 54 | /// Iterator over boolean storage: 55 | /// 56 | /// ``` 57 | /// use fixed_map::{Key, Map}; 58 | /// 59 | /// #[derive(Debug, Clone, Copy, PartialEq, Key)] 60 | /// enum MyKey { 61 | /// Bool(bool), 62 | /// Other, 63 | /// } 64 | /// 65 | /// let mut a = Map::new(); 66 | /// a.insert(MyKey::Bool(true), 1); 67 | /// a.insert(MyKey::Bool(false), 2); 68 | /// 69 | /// assert!(a.iter().eq([(MyKey::Bool(true), &1), (MyKey::Bool(false), &2)])); 70 | /// assert_eq!(a.iter().rev().collect::>(), vec![(MyKey::Bool(false), &2), (MyKey::Bool(true), &1)]); 71 | /// ``` 72 | 73 | #[derive(Clone, Copy, PartialEq, Eq)] 74 | pub struct BooleanMapStorage { 75 | t: Option, 76 | f: Option, 77 | } 78 | 79 | /// See [`BooleanMapStorage::keys`]. 80 | pub struct Keys { 81 | bits: u8, 82 | } 83 | 84 | impl Clone for Keys { 85 | #[inline] 86 | fn clone(&self) -> Keys { 87 | Keys { bits: self.bits } 88 | } 89 | } 90 | 91 | impl Iterator for Keys { 92 | type Item = bool; 93 | 94 | #[inline] 95 | fn next(&mut self) -> Option { 96 | if self.bits & TRUE_BIT != 0 { 97 | self.bits &= !TRUE_BIT; 98 | return Some(true); 99 | } 100 | 101 | if self.bits & FALSE_BIT != 0 { 102 | self.bits &= !FALSE_BIT; 103 | return Some(false); 104 | } 105 | 106 | None 107 | } 108 | 109 | #[inline] 110 | fn size_hint(&self) -> (usize, Option) { 111 | let len = self.bits.count_ones() as usize; 112 | (len, Some(len)) 113 | } 114 | } 115 | 116 | impl DoubleEndedIterator for Keys { 117 | #[inline] 118 | fn next_back(&mut self) -> Option { 119 | if self.bits & FALSE_BIT != 0 { 120 | self.bits &= !FALSE_BIT; 121 | return Some(false); 122 | } 123 | 124 | if self.bits & TRUE_BIT != 0 { 125 | self.bits &= !TRUE_BIT; 126 | return Some(true); 127 | } 128 | 129 | None 130 | } 131 | } 132 | 133 | impl ExactSizeIterator for Keys { 134 | #[inline] 135 | fn len(&self) -> usize { 136 | self.bits.count_ones() as usize 137 | } 138 | } 139 | 140 | pub struct Vacant<'a, V> { 141 | key: bool, 142 | inner: NoneBucket<'a, V>, 143 | } 144 | 145 | pub struct Occupied<'a, V> { 146 | key: bool, 147 | inner: SomeBucket<'a, V>, 148 | } 149 | 150 | impl<'a, V> VacantEntry<'a, bool, V> for Vacant<'a, V> { 151 | #[inline] 152 | fn key(&self) -> bool { 153 | self.key 154 | } 155 | 156 | #[inline] 157 | fn insert(self, value: V) -> &'a mut V { 158 | self.inner.insert(value) 159 | } 160 | } 161 | 162 | impl<'a, V> OccupiedEntry<'a, bool, V> for Occupied<'a, V> { 163 | #[inline] 164 | fn key(&self) -> bool { 165 | self.key 166 | } 167 | 168 | #[inline] 169 | fn get(&self) -> &V { 170 | self.inner.as_ref() 171 | } 172 | 173 | #[inline] 174 | fn get_mut(&mut self) -> &mut V { 175 | self.inner.as_mut() 176 | } 177 | 178 | #[inline] 179 | fn into_mut(self) -> &'a mut V { 180 | self.inner.into_mut() 181 | } 182 | 183 | #[inline] 184 | fn insert(&mut self, value: V) -> V { 185 | self.inner.replace(value) 186 | } 187 | 188 | #[inline] 189 | fn remove(self) -> V { 190 | self.inner.take() 191 | } 192 | } 193 | 194 | impl MapStorage for BooleanMapStorage { 195 | type Iter<'this> 196 | = Iter<'this, V> 197 | where 198 | V: 'this; 199 | type Keys<'this> 200 | = Keys 201 | where 202 | V: 'this; 203 | type Values<'this> 204 | = Values<'this, V> 205 | where 206 | V: 'this; 207 | type IterMut<'this> 208 | = IterMut<'this, V> 209 | where 210 | V: 'this; 211 | type ValuesMut<'this> 212 | = ValuesMut<'this, V> 213 | where 214 | V: 'this; 215 | type IntoIter = IntoIter; 216 | type Occupied<'this> 217 | = Occupied<'this, V> 218 | where 219 | V: 'this; 220 | type Vacant<'this> 221 | = Vacant<'this, V> 222 | where 223 | V: 'this; 224 | 225 | #[inline] 226 | fn empty() -> Self { 227 | Self { 228 | t: Option::default(), 229 | f: Option::default(), 230 | } 231 | } 232 | 233 | #[inline] 234 | fn len(&self) -> usize { 235 | usize::from(self.t.is_some()).saturating_add(usize::from(self.f.is_some())) 236 | } 237 | 238 | #[inline] 239 | fn is_empty(&self) -> bool { 240 | self.t.is_none() && self.f.is_none() 241 | } 242 | 243 | #[inline] 244 | fn insert(&mut self, key: bool, value: V) -> Option { 245 | if key { 246 | self.t.replace(value) 247 | } else { 248 | self.f.replace(value) 249 | } 250 | } 251 | 252 | #[inline] 253 | fn contains_key(&self, key: bool) -> bool { 254 | if key { 255 | self.t.is_some() 256 | } else { 257 | self.f.is_some() 258 | } 259 | } 260 | 261 | #[inline] 262 | fn get(&self, key: bool) -> Option<&V> { 263 | if key { 264 | self.t.as_ref() 265 | } else { 266 | self.f.as_ref() 267 | } 268 | } 269 | 270 | #[inline] 271 | fn get_mut(&mut self, key: bool) -> Option<&mut V> { 272 | if key { 273 | self.t.as_mut() 274 | } else { 275 | self.f.as_mut() 276 | } 277 | } 278 | 279 | #[inline] 280 | fn remove(&mut self, key: bool) -> Option { 281 | if key { 282 | self.t.take() 283 | } else { 284 | self.f.take() 285 | } 286 | } 287 | 288 | #[inline] 289 | fn retain(&mut self, mut func: F) 290 | where 291 | F: FnMut(bool, &mut V) -> bool, 292 | { 293 | if let Some(t) = self.t.as_mut() { 294 | if !func(true, t) { 295 | self.t = None; 296 | } 297 | } 298 | if let Some(f) = self.f.as_mut() { 299 | if !func(false, f) { 300 | self.f = None; 301 | } 302 | } 303 | } 304 | 305 | #[inline] 306 | fn clear(&mut self) { 307 | self.t = None; 308 | self.f = None; 309 | } 310 | 311 | #[inline] 312 | fn iter(&self) -> Self::Iter<'_> { 313 | let map: fn(_) -> _ = |v| (true, v); 314 | let a = self.t.iter().map(map); 315 | let map: fn(_) -> _ = |v| (false, v); 316 | let b = self.f.iter().map(map); 317 | a.chain(b) 318 | } 319 | 320 | #[inline] 321 | fn keys(&self) -> Self::Keys<'_> { 322 | Keys { 323 | bits: if self.t.is_some() { TRUE_BIT } else { 0 } 324 | | if self.f.is_some() { FALSE_BIT } else { 0 }, 325 | } 326 | } 327 | 328 | #[inline] 329 | fn values(&self) -> Self::Values<'_> { 330 | self.t.iter().chain(self.f.iter()) 331 | } 332 | 333 | #[inline] 334 | fn iter_mut(&mut self) -> Self::IterMut<'_> { 335 | let map: fn(_) -> _ = |v| (true, v); 336 | let a = self.t.iter_mut().map(map); 337 | let map: fn(_) -> _ = |v| (false, v); 338 | let b = self.f.iter_mut().map(map); 339 | a.chain(b) 340 | } 341 | 342 | #[inline] 343 | fn values_mut(&mut self) -> Self::ValuesMut<'_> { 344 | self.t.iter_mut().chain(self.f.iter_mut()) 345 | } 346 | 347 | #[inline] 348 | fn into_iter(self) -> Self::IntoIter { 349 | let map: fn(_) -> _ = |v| (true, v); 350 | let a = self.t.into_iter().map(map); 351 | let map: fn(_) -> _ = |v| (false, v); 352 | let b = self.f.into_iter().map(map); 353 | a.chain(b) 354 | } 355 | 356 | #[inline] 357 | fn entry(&mut self, key: bool) -> Entry<'_, Self, bool, V> { 358 | if key { 359 | match OptionBucket::new(&mut self.t) { 360 | OptionBucket::Some(inner) => Entry::Occupied(Occupied { key, inner }), 361 | OptionBucket::None(inner) => Entry::Vacant(Vacant { key, inner }), 362 | } 363 | } else { 364 | match OptionBucket::new(&mut self.f) { 365 | OptionBucket::Some(inner) => Entry::Occupied(Occupied { key, inner }), 366 | OptionBucket::None(inner) => Entry::Vacant(Vacant { key, inner }), 367 | } 368 | } 369 | } 370 | } 371 | -------------------------------------------------------------------------------- /src/map/storage/hashbrown.rs: -------------------------------------------------------------------------------- 1 | use core::hash::Hash; 2 | use core::iter; 3 | 4 | use crate::map::{Entry, MapStorage, OccupiedEntry, VacantEntry}; 5 | 6 | type S = ::hashbrown::hash_map::DefaultHashBuilder; 7 | type Occupied<'a, K, V> = ::hashbrown::hash_map::OccupiedEntry<'a, K, V, S>; 8 | type Vacant<'a, K, V> = ::hashbrown::hash_map::VacantEntry<'a, K, V, S>; 9 | type HashMapEntry<'a, K, V> = ::hashbrown::hash_map::Entry<'a, K, V, S>; 10 | 11 | /// [`MapStorage`] for dynamic types, using [`hashbrown::HashMap`]. 12 | /// 13 | /// This allows for dynamic types such as `&'static str` or `u32` to be used as 14 | /// a [`Key`][crate::Key]. 15 | /// 16 | /// # Examples 17 | /// 18 | /// ``` 19 | /// use fixed_map::{Key, Map}; 20 | /// 21 | /// #[derive(Clone, Copy, Key)] 22 | /// enum MyKey { 23 | /// First(u32), 24 | /// Second, 25 | /// } 26 | /// 27 | /// let mut map = Map::new(); 28 | /// map.insert(MyKey::First(1), 10); 29 | /// assert_eq!(map.get(MyKey::First(1)).copied(), Some(10)); 30 | /// assert_eq!(map.get(MyKey::First(2)), None); 31 | /// assert_eq!(map.get(MyKey::Second), None); 32 | /// ``` 33 | #[repr(transparent)] 34 | pub struct HashbrownMapStorage { 35 | inner: ::hashbrown::HashMap, 36 | } 37 | 38 | impl Clone for HashbrownMapStorage 39 | where 40 | K: Clone, 41 | V: Clone, 42 | { 43 | #[inline] 44 | fn clone(&self) -> Self { 45 | Self { 46 | inner: self.inner.clone(), 47 | } 48 | } 49 | } 50 | 51 | impl PartialEq for HashbrownMapStorage 52 | where 53 | K: Eq + Hash, 54 | V: PartialEq, 55 | { 56 | #[inline] 57 | fn eq(&self, other: &Self) -> bool { 58 | self.inner.eq(&other.inner) 59 | } 60 | } 61 | 62 | impl Eq for HashbrownMapStorage 63 | where 64 | K: Eq + Hash, 65 | V: Eq, 66 | { 67 | } 68 | 69 | impl<'a, K, V> OccupiedEntry<'a, K, V> for Occupied<'a, K, V> 70 | where 71 | K: Copy, 72 | { 73 | #[inline] 74 | fn key(&self) -> K { 75 | *self.key() 76 | } 77 | 78 | #[inline] 79 | fn get(&self) -> &V { 80 | self.get() 81 | } 82 | 83 | #[inline] 84 | fn get_mut(&mut self) -> &mut V { 85 | self.get_mut() 86 | } 87 | 88 | #[inline] 89 | fn into_mut(self) -> &'a mut V { 90 | self.into_mut() 91 | } 92 | 93 | #[inline] 94 | fn insert(&mut self, value: V) -> V { 95 | self.insert(value) 96 | } 97 | 98 | #[inline] 99 | fn remove(self) -> V { 100 | self.remove() 101 | } 102 | } 103 | 104 | impl<'a, K, V> VacantEntry<'a, K, V> for Vacant<'a, K, V> 105 | where 106 | K: Copy + Hash, 107 | { 108 | #[inline] 109 | fn key(&self) -> K { 110 | *self.key() 111 | } 112 | 113 | #[inline] 114 | fn insert(self, value: V) -> &'a mut V { 115 | self.insert(value) 116 | } 117 | } 118 | 119 | impl MapStorage for HashbrownMapStorage 120 | where 121 | K: Copy + Eq + Hash, 122 | { 123 | type Iter<'this> 124 | = iter::Map< 125 | ::hashbrown::hash_map::Iter<'this, K, V>, 126 | fn((&'this K, &'this V)) -> (K, &'this V), 127 | > 128 | where 129 | K: 'this, 130 | V: 'this; 131 | type Keys<'this> 132 | = iter::Copied<::hashbrown::hash_map::Keys<'this, K, V>> 133 | where 134 | K: 'this, 135 | V: 'this; 136 | type Values<'this> 137 | = ::hashbrown::hash_map::Values<'this, K, V> 138 | where 139 | K: 'this, 140 | V: 'this; 141 | type IterMut<'this> 142 | = iter::Map< 143 | ::hashbrown::hash_map::IterMut<'this, K, V>, 144 | fn((&'this K, &'this mut V)) -> (K, &'this mut V), 145 | > 146 | where 147 | K: 'this, 148 | V: 'this; 149 | type ValuesMut<'this> 150 | = ::hashbrown::hash_map::ValuesMut<'this, K, V> 151 | where 152 | K: 'this, 153 | V: 'this; 154 | type IntoIter = ::hashbrown::hash_map::IntoIter; 155 | type Occupied<'this> 156 | = Occupied<'this, K, V> 157 | where 158 | K: 'this, 159 | V: 'this; 160 | type Vacant<'this> 161 | = Vacant<'this, K, V> 162 | where 163 | K: 'this, 164 | V: 'this; 165 | 166 | #[inline] 167 | fn empty() -> Self { 168 | Self { 169 | inner: ::hashbrown::HashMap::new(), 170 | } 171 | } 172 | 173 | #[inline] 174 | fn len(&self) -> usize { 175 | self.inner.len() 176 | } 177 | 178 | #[inline] 179 | fn is_empty(&self) -> bool { 180 | self.inner.is_empty() 181 | } 182 | 183 | #[inline] 184 | fn insert(&mut self, key: K, value: V) -> Option { 185 | self.inner.insert(key, value) 186 | } 187 | 188 | #[inline] 189 | fn contains_key(&self, key: K) -> bool { 190 | self.inner.contains_key(&key) 191 | } 192 | 193 | #[inline] 194 | fn get(&self, key: K) -> Option<&V> { 195 | self.inner.get(&key) 196 | } 197 | 198 | #[inline] 199 | fn get_mut(&mut self, key: K) -> Option<&mut V> { 200 | self.inner.get_mut(&key) 201 | } 202 | 203 | #[inline] 204 | fn remove(&mut self, key: K) -> Option { 205 | self.inner.remove(&key) 206 | } 207 | 208 | #[inline] 209 | fn retain(&mut self, mut func: F) 210 | where 211 | F: FnMut(K, &mut V) -> bool, 212 | { 213 | self.inner.retain(|&k, v| func(k, v)); 214 | } 215 | 216 | #[inline] 217 | fn clear(&mut self) { 218 | self.inner.clear(); 219 | } 220 | 221 | #[inline] 222 | fn iter(&self) -> Self::Iter<'_> { 223 | let map: fn(_) -> _ = |(k, v): (&K, &V)| (*k, v); 224 | self.inner.iter().map(map) 225 | } 226 | 227 | #[inline] 228 | fn keys(&self) -> Self::Keys<'_> { 229 | self.inner.keys().copied() 230 | } 231 | 232 | #[inline] 233 | fn values(&self) -> Self::Values<'_> { 234 | self.inner.values() 235 | } 236 | 237 | #[inline] 238 | fn iter_mut(&mut self) -> Self::IterMut<'_> { 239 | let map: fn(_) -> _ = |(k, v): (&K, &mut V)| (*k, v); 240 | self.inner.iter_mut().map(map) 241 | } 242 | 243 | #[inline] 244 | fn values_mut(&mut self) -> Self::ValuesMut<'_> { 245 | self.inner.values_mut() 246 | } 247 | 248 | #[inline] 249 | fn into_iter(self) -> Self::IntoIter { 250 | self.inner.into_iter() 251 | } 252 | 253 | #[inline] 254 | fn entry(&mut self, key: K) -> Entry<'_, Self, K, V> { 255 | match self.inner.entry(key) { 256 | HashMapEntry::Occupied(entry) => Entry::Occupied(entry), 257 | HashMapEntry::Vacant(entry) => Entry::Vacant(entry), 258 | } 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /src/map/storage/option.rs: -------------------------------------------------------------------------------- 1 | use core::iter; 2 | use core::option; 3 | 4 | use crate::map::{Entry, MapStorage, OccupiedEntry, VacantEntry}; 5 | use crate::option_bucket::{NoneBucket, OptionBucket, SomeBucket}; 6 | use crate::Key; 7 | 8 | type Iter<'a, K, V> = iter::Chain< 9 | iter::Map< 10 | <::MapStorage as MapStorage>::Iter<'a>, 11 | fn((K, &'a V)) -> (Option, &'a V), 12 | >, 13 | iter::Map, fn(&'a V) -> (Option, &'a V)>, 14 | >; 15 | type Keys<'a, K, V> = iter::Chain< 16 | iter::Map<<::MapStorage as MapStorage>::Keys<'a>, fn(K) -> Option>, 17 | option::IntoIter>, 18 | >; 19 | type Values<'a, K, V> = 20 | iter::Chain<<::MapStorage as MapStorage>::Values<'a>, option::Iter<'a, V>>; 21 | type IterMut<'a, K, V> = iter::Chain< 22 | iter::Map< 23 | <::MapStorage as MapStorage>::IterMut<'a>, 24 | fn((K, &'a mut V)) -> (Option, &'a mut V), 25 | >, 26 | iter::Map, fn(&'a mut V) -> (Option, &'a mut V)>, 27 | >; 28 | type ValuesMut<'a, K, V> = iter::Chain< 29 | <::MapStorage as MapStorage>::ValuesMut<'a>, 30 | option::IterMut<'a, V>, 31 | >; 32 | type IntoIter = iter::Chain< 33 | iter::Map< 34 | <::MapStorage as MapStorage>::IntoIter, 35 | fn((K, V)) -> (Option, V), 36 | >, 37 | iter::Map, fn(V) -> (Option, V)>, 38 | >; 39 | 40 | /// [`MapStorage`] for [`Option`] types. 41 | /// 42 | /// # Examples 43 | /// 44 | /// ``` 45 | /// use fixed_map::{Key, Map}; 46 | /// 47 | /// #[derive(Debug, Clone, Copy, PartialEq, Key)] 48 | /// enum Part { 49 | /// A, 50 | /// B, 51 | /// } 52 | /// 53 | /// #[derive(Debug, Clone, Copy, PartialEq, Key)] 54 | /// enum MyKey { 55 | /// First(Option), 56 | /// Second, 57 | /// } 58 | /// 59 | /// let mut a = Map::new(); 60 | /// a.insert(MyKey::First(None), 1); 61 | /// a.insert(MyKey::First(Some(Part::A)), 2); 62 | /// 63 | /// assert_eq!(a.get(MyKey::First(Some(Part::A))), Some(&2)); 64 | /// assert_eq!(a.get(MyKey::First(Some(Part::B))), None); 65 | /// assert_eq!(a.get(MyKey::First(None)), Some(&1)); 66 | /// assert_eq!(a.get(MyKey::Second), None); 67 | /// 68 | /// assert!(a.iter().eq([(MyKey::First(Some(Part::A)), &2), (MyKey::First(None), &1)])); 69 | /// assert!(a.values().copied().eq([2, 1])); 70 | /// assert!(a.keys().eq([MyKey::First(Some(Part::A)), MyKey::First(None)])); 71 | /// ``` 72 | pub struct OptionMapStorage 73 | where 74 | K: Key, 75 | { 76 | some: K::MapStorage, 77 | none: Option, 78 | } 79 | 80 | impl Clone for OptionMapStorage 81 | where 82 | K: Key, 83 | V: Clone, 84 | K::MapStorage: Clone, 85 | { 86 | #[inline] 87 | fn clone(&self) -> Self { 88 | Self { 89 | some: self.some.clone(), 90 | none: self.none.clone(), 91 | } 92 | } 93 | } 94 | 95 | impl Copy for OptionMapStorage 96 | where 97 | K: Key, 98 | V: Copy, 99 | K::MapStorage: Copy, 100 | { 101 | } 102 | 103 | impl PartialEq for OptionMapStorage 104 | where 105 | K: Key, 106 | K::MapStorage: PartialEq, 107 | V: PartialEq, 108 | { 109 | #[inline] 110 | fn eq(&self, other: &Self) -> bool { 111 | self.none == other.none && self.some == other.some 112 | } 113 | } 114 | 115 | impl Eq for OptionMapStorage 116 | where 117 | K: Key, 118 | K::MapStorage: Eq, 119 | V: Eq, 120 | { 121 | } 122 | 123 | pub enum Vacant<'a, K: 'a, V> 124 | where 125 | K: Key, 126 | { 127 | None(NoneBucket<'a, V>), 128 | Some( as MapStorage>::Vacant<'a>), 129 | } 130 | 131 | pub enum Occupied<'a, K: 'a, V> 132 | where 133 | K: Key, 134 | { 135 | None(SomeBucket<'a, V>), 136 | Some( as MapStorage>::Occupied<'a>), 137 | } 138 | 139 | impl<'a, K, V> VacantEntry<'a, Option, V> for Vacant<'a, K, V> 140 | where 141 | K: Key, 142 | { 143 | #[inline] 144 | fn key(&self) -> Option { 145 | match self { 146 | Vacant::None(_) => None, 147 | Vacant::Some(entry) => Some(entry.key()), 148 | } 149 | } 150 | 151 | #[inline] 152 | fn insert(self, value: V) -> &'a mut V { 153 | match self { 154 | Vacant::None(entry) => entry.insert(value), 155 | Vacant::Some(entry) => entry.insert(value), 156 | } 157 | } 158 | } 159 | 160 | impl<'a, K, V> OccupiedEntry<'a, Option, V> for Occupied<'a, K, V> 161 | where 162 | K: Key, 163 | { 164 | #[inline] 165 | fn key(&self) -> Option { 166 | match self { 167 | Occupied::None(_) => None, 168 | Occupied::Some(entry) => Some(entry.key()), 169 | } 170 | } 171 | 172 | #[inline] 173 | fn get(&self) -> &V { 174 | match self { 175 | Occupied::None(entry) => entry.as_ref(), 176 | Occupied::Some(entry) => entry.get(), 177 | } 178 | } 179 | 180 | #[inline] 181 | fn get_mut(&mut self) -> &mut V { 182 | match self { 183 | Occupied::None(entry) => entry.as_mut(), 184 | Occupied::Some(entry) => entry.get_mut(), 185 | } 186 | } 187 | 188 | #[inline] 189 | fn into_mut(self) -> &'a mut V { 190 | match self { 191 | Occupied::None(entry) => entry.into_mut(), 192 | Occupied::Some(entry) => entry.into_mut(), 193 | } 194 | } 195 | 196 | #[inline] 197 | fn insert(&mut self, value: V) -> V { 198 | match self { 199 | Occupied::None(entry) => entry.replace(value), 200 | Occupied::Some(entry) => entry.insert(value), 201 | } 202 | } 203 | 204 | #[inline] 205 | fn remove(self) -> V { 206 | match self { 207 | Occupied::None(entry) => entry.take(), 208 | Occupied::Some(entry) => entry.remove(), 209 | } 210 | } 211 | } 212 | 213 | impl MapStorage, V> for OptionMapStorage 214 | where 215 | K: Key, 216 | { 217 | type Iter<'this> 218 | = Iter<'this, K, V> 219 | where 220 | K: 'this, 221 | V: 'this; 222 | type Keys<'this> 223 | = Keys<'this, K, V> 224 | where 225 | K: 'this, 226 | V: 'this; 227 | type Values<'this> 228 | = Values<'this, K, V> 229 | where 230 | K: 'this, 231 | V: 'this; 232 | type IterMut<'this> 233 | = IterMut<'this, K, V> 234 | where 235 | K: 'this, 236 | V: 'this; 237 | type ValuesMut<'this> 238 | = ValuesMut<'this, K, V> 239 | where 240 | K: 'this, 241 | V: 'this; 242 | type IntoIter = IntoIter; 243 | type Occupied<'this> 244 | = Occupied<'this, K, V> 245 | where 246 | K: 'this, 247 | V: 'this; 248 | type Vacant<'this> 249 | = Vacant<'this, K, V> 250 | where 251 | K: 'this, 252 | V: 'this; 253 | 254 | #[inline] 255 | fn empty() -> Self { 256 | Self { 257 | some: K::MapStorage::empty(), 258 | none: Option::default(), 259 | } 260 | } 261 | 262 | #[inline] 263 | fn len(&self) -> usize { 264 | self.some.len() + usize::from(self.none.is_some()) 265 | } 266 | 267 | #[inline] 268 | fn is_empty(&self) -> bool { 269 | self.some.is_empty() && self.none.is_none() 270 | } 271 | 272 | #[inline] 273 | fn insert(&mut self, key: Option, value: V) -> Option { 274 | match key { 275 | Some(key) => self.some.insert(key, value), 276 | None => self.none.replace(value), 277 | } 278 | } 279 | 280 | #[inline] 281 | fn contains_key(&self, key: Option) -> bool { 282 | match key { 283 | Some(key) => self.some.contains_key(key), 284 | None => self.none.is_some(), 285 | } 286 | } 287 | 288 | #[inline] 289 | fn get(&self, key: Option) -> Option<&V> { 290 | match key { 291 | Some(key) => self.some.get(key), 292 | None => self.none.as_ref(), 293 | } 294 | } 295 | 296 | #[inline] 297 | fn get_mut(&mut self, key: Option) -> Option<&mut V> { 298 | match key { 299 | Some(key) => self.some.get_mut(key), 300 | None => self.none.as_mut(), 301 | } 302 | } 303 | 304 | #[inline] 305 | fn remove(&mut self, key: Option) -> Option { 306 | match key { 307 | Some(key) => self.some.remove(key), 308 | None => self.none.take(), 309 | } 310 | } 311 | 312 | #[inline] 313 | fn retain(&mut self, mut func: F) 314 | where 315 | F: FnMut(Option, &mut V) -> bool, 316 | { 317 | self.some.retain(|k, v| func(Some(k), v)); 318 | if let Some(none) = self.none.as_mut() { 319 | if !func(None, none) { 320 | self.none = None; 321 | } 322 | } 323 | } 324 | 325 | #[inline] 326 | fn clear(&mut self) { 327 | self.some.clear(); 328 | self.none = None; 329 | } 330 | 331 | #[inline] 332 | fn iter(&self) -> Self::Iter<'_> { 333 | let map: fn(_) -> _ = |(k, b)| (Some(k), b); 334 | let a = self.some.iter().map(map); 335 | let map: fn(_) -> _ = |v| (None, v); 336 | let b = self.none.iter().map(map); 337 | a.chain(b) 338 | } 339 | 340 | #[inline] 341 | fn keys(&self) -> Self::Keys<'_> { 342 | let map: fn(_) -> _ = |k| Some(k); 343 | self.some 344 | .keys() 345 | .map(map) 346 | .chain(self.none.is_some().then_some(None::)) 347 | } 348 | 349 | #[inline] 350 | fn values(&self) -> Self::Values<'_> { 351 | self.some.values().chain(self.none.iter()) 352 | } 353 | 354 | #[inline] 355 | fn iter_mut(&mut self) -> Self::IterMut<'_> { 356 | let map: fn(_) -> _ = |(k, b)| (Some(k), b); 357 | let a = self.some.iter_mut().map(map); 358 | let map: fn(_) -> _ = |v| (None, v); 359 | let b = self.none.iter_mut().map(map); 360 | a.chain(b) 361 | } 362 | 363 | #[inline] 364 | fn values_mut(&mut self) -> Self::ValuesMut<'_> { 365 | self.some.values_mut().chain(self.none.iter_mut()) 366 | } 367 | 368 | #[inline] 369 | fn into_iter(self) -> Self::IntoIter { 370 | let map: fn(_) -> _ = |(k, b)| (Some(k), b); 371 | let a = self.some.into_iter().map(map); 372 | let map: fn(_) -> _ = |v| (None, v); 373 | let b = self.none.into_iter().map(map); 374 | a.chain(b) 375 | } 376 | 377 | #[inline] 378 | fn entry(&mut self, key: Option) -> Entry<'_, Self, Option, V> { 379 | match key { 380 | Some(key) => match self.some.entry(key) { 381 | Entry::Occupied(entry) => Entry::Occupied(Occupied::Some(entry)), 382 | Entry::Vacant(entry) => Entry::Vacant(Vacant::Some(entry)), 383 | }, 384 | None => match OptionBucket::new(&mut self.none) { 385 | OptionBucket::Some(some) => Entry::Occupied(Occupied::None(some)), 386 | OptionBucket::None(none) => Entry::Vacant(Vacant::None(none)), 387 | }, 388 | } 389 | } 390 | } 391 | -------------------------------------------------------------------------------- /src/map/storage/singleton.rs: -------------------------------------------------------------------------------- 1 | use crate::map::{Entry, MapStorage}; 2 | use crate::option_bucket::{NoneBucket, OptionBucket, SomeBucket}; 3 | 4 | /// [`MapStorage`] type that can only inhabit a single value (like `()`). 5 | #[repr(transparent)] 6 | #[derive(Clone, Copy)] 7 | pub struct SingletonMapStorage { 8 | inner: Option, 9 | } 10 | 11 | impl PartialEq for SingletonMapStorage 12 | where 13 | V: PartialEq, 14 | { 15 | #[inline] 16 | fn eq(&self, other: &Self) -> bool { 17 | self.inner == other.inner 18 | } 19 | } 20 | 21 | impl Eq for SingletonMapStorage where V: Eq {} 22 | 23 | impl MapStorage for SingletonMapStorage 24 | where 25 | K: Default, 26 | { 27 | type Iter<'this> 28 | = core::option::IntoIter<(K, &'this V)> 29 | where 30 | V: 'this; 31 | type Keys<'this> 32 | = core::option::IntoIter 33 | where 34 | V: 'this; 35 | type Values<'this> 36 | = core::option::Iter<'this, V> 37 | where 38 | V: 'this; 39 | type IterMut<'this> 40 | = core::option::IntoIter<(K, &'this mut V)> 41 | where 42 | V: 'this; 43 | type ValuesMut<'this> 44 | = core::option::IterMut<'this, V> 45 | where 46 | V: 'this; 47 | type IntoIter = core::option::IntoIter<(K, V)>; 48 | type Occupied<'this> 49 | = SomeBucket<'this, V> 50 | where 51 | V: 'this; 52 | type Vacant<'this> 53 | = NoneBucket<'this, V> 54 | where 55 | V: 'this; 56 | 57 | #[inline] 58 | fn empty() -> Self { 59 | Self { 60 | inner: Option::default(), 61 | } 62 | } 63 | 64 | #[inline] 65 | fn len(&self) -> usize { 66 | usize::from(self.inner.is_some()) 67 | } 68 | 69 | #[inline] 70 | fn is_empty(&self) -> bool { 71 | self.inner.is_none() 72 | } 73 | 74 | #[inline] 75 | fn insert(&mut self, _: K, value: V) -> Option { 76 | self.inner.replace(value) 77 | } 78 | 79 | #[inline] 80 | fn contains_key(&self, _: K) -> bool { 81 | self.inner.is_some() 82 | } 83 | 84 | #[inline] 85 | fn get(&self, _: K) -> Option<&V> { 86 | self.inner.as_ref() 87 | } 88 | 89 | #[inline] 90 | fn get_mut(&mut self, _: K) -> Option<&mut V> { 91 | self.inner.as_mut() 92 | } 93 | 94 | #[inline] 95 | fn remove(&mut self, _: K) -> Option { 96 | self.inner.take() 97 | } 98 | 99 | #[inline] 100 | fn retain(&mut self, mut func: F) 101 | where 102 | F: FnMut(K, &mut V) -> bool, 103 | { 104 | if let Some(val) = self.inner.as_mut() { 105 | if !func(K::default(), val) { 106 | self.inner = None; 107 | } 108 | } 109 | } 110 | 111 | #[inline] 112 | fn clear(&mut self) { 113 | self.inner = None; 114 | } 115 | 116 | #[inline] 117 | fn iter(&self) -> Self::Iter<'_> { 118 | self.inner.as_ref().map(|v| (K::default(), v)).into_iter() 119 | } 120 | 121 | #[inline] 122 | fn keys(&self) -> Self::Keys<'_> { 123 | Some(K::default()).into_iter() 124 | } 125 | 126 | #[inline] 127 | fn values(&self) -> Self::Values<'_> { 128 | self.inner.iter() 129 | } 130 | 131 | #[inline] 132 | fn iter_mut(&mut self) -> Self::IterMut<'_> { 133 | self.inner.as_mut().map(|v| (K::default(), v)).into_iter() 134 | } 135 | 136 | #[inline] 137 | fn values_mut(&mut self) -> Self::ValuesMut<'_> { 138 | self.inner.iter_mut() 139 | } 140 | 141 | #[inline] 142 | fn into_iter(self) -> Self::IntoIter { 143 | self.inner.map(|v| (K::default(), v)).into_iter() 144 | } 145 | 146 | #[inline] 147 | fn entry(&mut self, _key: K) -> Entry<'_, Self, K, V> { 148 | match OptionBucket::new(&mut self.inner) { 149 | OptionBucket::Some(some) => Entry::Occupied(some), 150 | OptionBucket::None(none) => Entry::Vacant(none), 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/option_bucket.rs: -------------------------------------------------------------------------------- 1 | //! # PRIVATE API 2 | //! 3 | //! This API is private, for use only in the `derive(Key)` macro. 4 | //! Usage for other purposes is not supported, and this API will 5 | //! not abide by Semver stability guarantees. 6 | //! 7 | //! If you find that this API would be useful outside its 8 | //! application in `fixed-map`, let us know. 9 | //! We can factor it into its own crate. 10 | //! 11 | //! # Option Buckets 12 | //! 13 | //! Utility for working with [`Option`s][Option] 14 | //! in cases where we want mutable access to the value within 15 | //! and the [`Option`] itself (but not at the same time). 16 | //! 17 | //! Provides three types: 18 | //! - [`SomeBucket`] allows accessing the value 19 | //! inside an [`Option`] known to be [`Some`] without `unwrap` 20 | //! - [`NoneBucket`] allows optimally inserting a value 21 | //! into an [`Option`] known to be [`None`] 22 | //! - [`OptionBucket`], an enum over the previous two, 23 | //! easily constructed from any `&mut Option` 24 | //! 25 | //! # Examples 26 | //! 27 | //! Safely implement [`Option::get_or_insert`] 28 | //! ``` 29 | //! use fixed_map::option_bucket::OptionBucket; 30 | //! 31 | //! fn get_or_insert(this: &mut Option, value: T) -> &mut T { 32 | //! match OptionBucket::new(this) { 33 | //! OptionBucket::Some(some) => some.into_mut(), 34 | //! OptionBucket::None(none) => none.insert(value), 35 | //! } 36 | //! } 37 | //! 38 | //! let mut x = None; 39 | //! assert_eq!(get_or_insert(&mut x, 12), &12); 40 | //! ``` 41 | //! 42 | //! Safely implement entry API for [`Option`] 43 | //! ``` 44 | //! use fixed_map::option_bucket::*; 45 | //! 46 | //! struct OccupiedEntry<'a, T> { 47 | //! inner: SomeBucket<'a, T> 48 | //! } 49 | //! 50 | //! struct VacantEntry<'a, T> { 51 | //! inner: NoneBucket<'a, T>, 52 | //! } 53 | //! 54 | //! enum Entry<'a, T> { 55 | //! Vacant(VacantEntry<'a, T>), 56 | //! Occupied(OccupiedEntry<'a, T>), 57 | //! } 58 | //! 59 | //! impl<'a, T> VacantEntry<'a, T> { 60 | //! fn insert(self, value: T) -> &'a mut T { 61 | //! self.inner.insert(value) 62 | //! } 63 | //! } 64 | //! 65 | //! impl<'a, T> OccupiedEntry<'a, T> { 66 | //! fn get(&self) -> &T { 67 | //! self.inner.as_ref() 68 | //! } 69 | //! fn get_mut(&mut self) -> &mut T { 70 | //! self.inner.as_mut() 71 | //! } 72 | //! fn into_mut(self) -> &'a mut T { 73 | //! self.inner.into_mut() 74 | //! } 75 | //! fn insert(&mut self, value: T) -> T { 76 | //! self.inner.replace(value) 77 | //! } 78 | //! fn remove(self) -> T { 79 | //! self.inner.take() 80 | //! } 81 | //! } 82 | //! 83 | //! fn option_entry(this: &mut Option) -> Entry<'_, T> { 84 | //! match OptionBucket::new(this) { 85 | //! OptionBucket::Some(inner) => Entry::Occupied(OccupiedEntry { inner }), 86 | //! OptionBucket::None(inner) => Entry::Vacant(VacantEntry { inner }), 87 | //! } 88 | //! } 89 | //! ``` 90 | 91 | #![allow(unsafe_code)] 92 | // `clippy::pedantic` exceptions 93 | #![allow(clippy::should_implement_trait, clippy::must_use_candidate)] 94 | 95 | use core::mem; 96 | 97 | use crate::map::{OccupiedEntry, VacantEntry}; 98 | 99 | #[cfg(test)] 100 | mod tests; 101 | 102 | /// Abstraction for an [`&mut Option`][Option] that's known to be [`Some`]. 103 | /// 104 | /// # Size 105 | /// 106 | /// `SomeOption` is the size of two pointers, making it 107 | /// twice the size of `&mut Option`. One points to the 108 | /// value inside, and the other points to the `Option` itself. 109 | pub struct SomeBucket<'a, T> { 110 | outer: &'a mut Option, 111 | } 112 | 113 | impl<'a, T> SomeBucket<'a, T> { 114 | /// Creates a new [`SomeBucket`], without checking that 115 | /// the input [`Option`] is `Some`. 116 | /// 117 | /// It's recommended to use [`SomeBucket::new`] or 118 | /// [`OptionBucket::new`] instead. 119 | /// 120 | /// # Safety 121 | /// 122 | /// Caller must guarantee that `opt` is NOT `None`. 123 | #[inline] 124 | pub unsafe fn new_unchecked(opt: &'a mut Option) -> Self { 125 | debug_assert!( 126 | opt.is_some(), 127 | "Undefined Behavior: `None` value passed to `SomeBucket::new_unchecked`." 128 | ); 129 | 130 | SomeBucket { outer: opt } 131 | } 132 | 133 | /// Creates a new [`SomeBucket`]. Returns `Some(SomeBucket)` 134 | /// if `opt` is [`Some`], otherwise returns `None`. 135 | /// 136 | /// For an unchecked version, see [`SomeBucket::new_unchecked`]. 137 | #[inline] 138 | pub fn new(opt: &'a mut Option) -> Option { 139 | if opt.is_some() { 140 | // SAFETY: If conditional ensures that `opt` is `Some` 141 | unsafe { Some(Self::new_unchecked(opt)) } 142 | } else { 143 | None 144 | } 145 | } 146 | 147 | /// Converts from `&Option::Some` to `&T`. 148 | /// 149 | /// # Examples 150 | /// 151 | /// ``` 152 | /// # use fixed_map::option_bucket::SomeBucket; 153 | /// 154 | /// let mut text: Option = Some("Hello, world!".to_string()); 155 | /// let some = SomeBucket::new(&mut text).unwrap(); 156 | /// 157 | /// let hello: &str = &some.as_ref()[..5]; 158 | /// let length: usize = some.as_ref().len(); 159 | /// assert_eq!(hello, "Hello"); 160 | /// assert_eq!(length, 13); 161 | /// ``` 162 | #[inline] 163 | pub fn as_ref(&self) -> &T { 164 | // SAFETY: `outer` is guaranteed to be `Some` 165 | // by the invariants of `new_unchecked` 166 | unsafe { self.outer.as_ref().unwrap_unchecked() } 167 | } 168 | 169 | /// Converts from `&mut Option::Some` to `&mut T`, 170 | /// with the lifetime of this `SomeBucket`. 171 | /// 172 | /// # Examples 173 | /// 174 | /// ``` 175 | /// # use fixed_map::option_bucket::SomeBucket; 176 | /// 177 | /// let mut text: Option = Some("Hello, world!".to_string()); 178 | /// let mut some = SomeBucket::new(&mut text).unwrap(); 179 | /// 180 | /// some.as_mut().push_str(" Happy to be here."); 181 | /// assert_eq!(some.as_ref(), "Hello, world! Happy to be here."); 182 | /// ``` 183 | #[inline] 184 | pub fn as_mut(&mut self) -> &mut T { 185 | // SAFETY: `outer` is guaranteed to be `Some` 186 | // by the invariants of `new_unchecked` 187 | unsafe { self.outer.as_mut().unwrap_unchecked() } 188 | } 189 | 190 | /// Converts from `&mut Option::Some` to `&mut T`, 191 | /// with the lifetime of the original reference, 192 | /// consuming this `SomeBucket`. 193 | /// 194 | /// # Examples 195 | /// 196 | /// ``` 197 | /// # use fixed_map::option_bucket::SomeBucket; 198 | /// 199 | /// let mut text: Option = Some("Hello, world!".to_string()); 200 | /// let some = SomeBucket::new(&mut text).unwrap(); 201 | /// 202 | /// some.into_mut().push_str(" Happy to be here."); 203 | /// assert_eq!(&text.unwrap(), "Hello, world! Happy to be here."); 204 | /// ``` 205 | /// 206 | /// ```compile_fail 207 | /// # use fixed_map::option_bucket::SomeBucket; 208 | /// 209 | /// let mut text: Option = Some("Hello, world!".to_string()); 210 | /// let some = SomeBucket::new(&mut text).unwrap(); 211 | /// 212 | /// some.into_mut().push_str(" Happy to be here."); 213 | /// // can not longer use `some` 214 | /// some.as_ref(); 215 | /// ``` 216 | #[inline] 217 | pub fn into_mut(self) -> &'a mut T { 218 | // SAFETY: `outer` is guaranteed to be `Some` 219 | // by the invariants of `new_unchecked` 220 | unsafe { self.outer.as_mut().unwrap_unchecked() } 221 | } 222 | 223 | /// Sets the value in the `Option::Some`, and returns 224 | /// the old value. 225 | /// 226 | /// # Examples 227 | /// 228 | /// ``` 229 | /// # use fixed_map::option_bucket::SomeBucket; 230 | /// 231 | /// let mut x = Some(2); 232 | /// let mut some = SomeBucket::new(&mut x).unwrap(); 233 | /// 234 | /// let old = some.replace(5); 235 | /// assert_eq!(old, 2); 236 | /// assert_eq!(x, Some(5)); 237 | /// ``` 238 | #[inline] 239 | pub fn replace(&mut self, value: T) -> T { 240 | mem::replace(self.as_mut(), value) 241 | } 242 | 243 | /// Takes the value out of the option, leaving a `None` in its place, 244 | /// and consuming this `SomeBucket`. 245 | /// 246 | /// ``` 247 | /// # use fixed_map::option_bucket::SomeBucket; 248 | /// 249 | /// let mut x = Some(vec![1, 2]); 250 | /// let some = SomeBucket::new(&mut x).unwrap(); 251 | /// 252 | /// let y = some.take(); 253 | /// assert_eq!(x, None); 254 | /// assert_eq!(y, vec![1, 2]); 255 | /// ``` 256 | #[inline] 257 | pub fn take(self) -> T { 258 | // SAFETY: `outer` is guaranteed to be `Some` 259 | // by the invariants of `new_unchecked` 260 | unsafe { self.outer.take().unwrap_unchecked() } 261 | } 262 | } 263 | 264 | impl<'a, K, V> OccupiedEntry<'a, K, V> for SomeBucket<'a, V> 265 | where 266 | K: Default, 267 | { 268 | #[inline] 269 | fn key(&self) -> K { 270 | K::default() 271 | } 272 | 273 | #[inline] 274 | fn get(&self) -> &V { 275 | SomeBucket::as_ref(self) 276 | } 277 | 278 | #[inline] 279 | fn get_mut(&mut self) -> &mut V { 280 | SomeBucket::as_mut(self) 281 | } 282 | 283 | #[inline] 284 | fn into_mut(self) -> &'a mut V { 285 | SomeBucket::into_mut(self) 286 | } 287 | 288 | #[inline] 289 | fn insert(&mut self, value: V) -> V { 290 | SomeBucket::replace(self, value) 291 | } 292 | 293 | #[inline] 294 | fn remove(self) -> V { 295 | SomeBucket::take(self) 296 | } 297 | } 298 | 299 | /// Abstraction for an [`&mut Option`][Option] that's known to be `None`. 300 | /// 301 | /// # Size 302 | /// 303 | /// `NoneBucket` is the same size as `&mut Option` 304 | pub struct NoneBucket<'a, T> { 305 | outer: &'a mut Option, 306 | } 307 | 308 | impl<'a, T> NoneBucket<'a, T> { 309 | /// Creates a new [`NoneBucket`], without checking that 310 | /// the input [`Option`] is `None`. 311 | /// 312 | /// It's recommended to use [`NoneBucket::new`] or 313 | /// [`OptionBucket::new`] instead. 314 | /// 315 | /// # Safety 316 | /// 317 | /// Caller must guarantee that `opt` is NOT [`Some`]. 318 | #[inline] 319 | pub unsafe fn new_unchecked(opt: &'a mut Option) -> Self { 320 | debug_assert!( 321 | opt.is_none(), 322 | "Undefined Behavior: `Some` value passed to `NoneBucket::new_unchecked`." 323 | ); 324 | 325 | NoneBucket { outer: opt } 326 | } 327 | 328 | /// Creates a new [`NoneBucket`]. Returns `Some(NoneBucket)` 329 | /// if `opt` is [`None`], otherwise returns `None`. 330 | /// 331 | /// For an unchecked version, see [`NoneBucket::new_unchecked`]. 332 | #[inline] 333 | pub fn new(opt: &'a mut Option) -> Option { 334 | if opt.is_none() { 335 | // SAFETY: if conditional ensures that `opt` is `None` 336 | unsafe { Some(Self::new_unchecked(opt)) } 337 | } else { 338 | None 339 | } 340 | } 341 | 342 | /// Inserts value into the option, then returns a mutable reference to it. 343 | /// 344 | /// This is practically identical to [`Option::insert`], but avoids 345 | /// operations handling [`drop`]ping the old value 346 | /// (since we know there was no old value). 347 | /// ``` 348 | /// # use fixed_map::option_bucket::NoneBucket; 349 | /// 350 | /// let mut opt = None; 351 | /// let mut none = NoneBucket::new(&mut opt).unwrap(); 352 | /// let val = none.insert(1); 353 | /// assert_eq!(*val, 1); 354 | /// *val = 3; 355 | /// assert_eq!(opt.unwrap(), 3); 356 | /// ``` 357 | #[inline] 358 | pub fn insert(self, value: T) -> &'a mut T { 359 | // SAFETY: `outer` is `None`, so there is no old value to `drop` 360 | unsafe { 361 | let outer: *mut Option = self.outer; 362 | outer.write(Some(value)); 363 | } 364 | 365 | // SAFETY: the code above just filled the option 366 | unsafe { self.outer.as_mut().unwrap_unchecked() } 367 | } 368 | } 369 | 370 | impl<'a, K, V> VacantEntry<'a, K, V> for NoneBucket<'a, V> 371 | where 372 | K: Default, 373 | { 374 | #[inline] 375 | fn key(&self) -> K { 376 | K::default() 377 | } 378 | 379 | #[inline] 380 | fn insert(self, value: V) -> &'a mut V { 381 | NoneBucket::insert(self, value) 382 | } 383 | } 384 | 385 | /// Recommended entry for getting a [`SomeBucket`] or 386 | /// [`NoneBucket`]. Infallibly convertible from any 387 | /// [`&mut Option`][Option]. 388 | pub enum OptionBucket<'a, T> { 389 | /// An option known to be `Some`. 390 | Some(SomeBucket<'a, T>), 391 | /// An option known to be `None`. 392 | None(NoneBucket<'a, T>), 393 | } 394 | 395 | impl<'a, T> OptionBucket<'a, T> { 396 | /// Create an `OptionBucket` from an `&mut Option`. 397 | /// 398 | /// # Examples 399 | /// 400 | /// ``` 401 | /// use fixed_map::option_bucket::OptionBucket; 402 | /// 403 | /// let mut none: Option = None; 404 | /// let none_bucket = OptionBucket::new(&mut none); 405 | /// assert!(matches!(none_bucket, OptionBucket::None(_))); 406 | /// 407 | /// let mut some: Option = Some(12); 408 | /// let some_bucket = OptionBucket::new(&mut some); 409 | /// assert!(matches!(some_bucket, OptionBucket::Some(_))); 410 | /// ``` 411 | #[inline] 412 | pub fn new(opt: &'a mut Option) -> Self { 413 | if opt.is_some() { 414 | // SAFETY: if conditional ensures that `opt` is `Some` 415 | unsafe { OptionBucket::Some(SomeBucket::new_unchecked(opt)) } 416 | } else { 417 | // SAFETY: if conditional ensures that `opt` is `None` 418 | unsafe { OptionBucket::None(NoneBucket::new_unchecked(opt)) } 419 | } 420 | } 421 | } 422 | -------------------------------------------------------------------------------- /src/option_bucket/tests.rs: -------------------------------------------------------------------------------- 1 | use super::{NoneBucket, OptionBucket, SomeBucket}; 2 | 3 | struct OccupiedEntry<'a, T> { 4 | inner: SomeBucket<'a, T>, 5 | } 6 | 7 | struct VacantEntry<'a, T> { 8 | inner: NoneBucket<'a, T>, 9 | } 10 | 11 | enum Entry<'a, T> { 12 | Vacant(VacantEntry<'a, T>), 13 | Occupied(OccupiedEntry<'a, T>), 14 | } 15 | 16 | impl<'a, T> VacantEntry<'a, T> { 17 | fn insert(self, value: T) -> &'a mut T { 18 | self.inner.insert(value) 19 | } 20 | } 21 | 22 | impl<'a, T> OccupiedEntry<'a, T> { 23 | fn get(&self) -> &T { 24 | self.inner.as_ref() 25 | } 26 | 27 | fn get_mut(&mut self) -> &mut T { 28 | self.inner.as_mut() 29 | } 30 | 31 | fn into_mut(self) -> &'a mut T { 32 | self.inner.into_mut() 33 | } 34 | 35 | fn insert(&mut self, value: T) -> T { 36 | self.inner.replace(value) 37 | } 38 | 39 | fn remove(self) -> T { 40 | self.inner.take() 41 | } 42 | } 43 | 44 | impl<'a, T> Entry<'a, T> { 45 | fn or_insert(self, default: T) -> &'a mut T { 46 | match self { 47 | Entry::Occupied(entry) => entry.into_mut(), 48 | Entry::Vacant(entry) => entry.insert(default), 49 | } 50 | } 51 | 52 | fn or_insert_with T>(self, default: F) -> &'a mut T { 53 | match self { 54 | Entry::Occupied(entry) => entry.into_mut(), 55 | Entry::Vacant(entry) => entry.insert(default()), 56 | } 57 | } 58 | 59 | fn and_modify(self, f: F) -> Self { 60 | match self { 61 | Entry::Occupied(mut entry) => { 62 | f(entry.get_mut()); 63 | Entry::Occupied(entry) 64 | } 65 | Entry::Vacant(entry) => Entry::Vacant(entry), 66 | } 67 | } 68 | 69 | fn or_default(self) -> &'a mut T 70 | where 71 | T: Default, 72 | { 73 | match self { 74 | Entry::Occupied(entry) => entry.into_mut(), 75 | Entry::Vacant(entry) => entry.insert(Default::default()), 76 | } 77 | } 78 | } 79 | 80 | trait OptionEntry { 81 | type Entry<'this> 82 | where 83 | Self: 'this; 84 | 85 | fn entry(&mut self) -> Self::Entry<'_>; 86 | } 87 | 88 | impl OptionEntry for Option { 89 | type Entry<'this> 90 | = Entry<'this, T> 91 | where 92 | T: 'this; 93 | 94 | fn entry(&mut self) -> Self::Entry<'_> { 95 | match OptionBucket::new(self) { 96 | OptionBucket::Some(inner) => Entry::Occupied(OccupiedEntry { inner }), 97 | OptionBucket::None(inner) => Entry::Vacant(VacantEntry { inner }), 98 | } 99 | } 100 | } 101 | 102 | #[test] 103 | fn test() { 104 | let mut even: Option = None; 105 | 106 | for n in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] { 107 | if n % 2 == 0 { 108 | even.entry().and_modify(|x| *x += 1).or_insert(1); 109 | } 110 | } 111 | 112 | match even.entry() { 113 | Entry::Occupied(mut entry) => { 114 | assert_eq!(entry.get(), &5); 115 | assert_eq!(entry.insert(-3), 5); 116 | assert_eq!(entry.remove(), -3); 117 | } 118 | Entry::Vacant(_) => unreachable!(), 119 | } 120 | assert!(even.is_none()); 121 | 122 | let day_hours = 24; 123 | 124 | let mut x = None; 125 | x.entry().or_insert_with(|| day_hours * 60 * 60 * 1000); 126 | assert_eq!(x, Some(86_400_000)); 127 | 128 | let mut y: Option = None; 129 | y.entry().or_default(); 130 | assert_eq!(y, Some(0)); 131 | } 132 | -------------------------------------------------------------------------------- /src/raw.rs: -------------------------------------------------------------------------------- 1 | //! Raw access to underlying storage. 2 | //! 3 | //! This can be useful to implement more efficient serialization, since it might 4 | //! provide access to smaller primitive values. 5 | 6 | /// Trait implemented for storage which can be easily converted to and from a 7 | /// raw value. 8 | /// 9 | /// This is implemented for [`SetStorage`] when the `#[key(bitset)]` attribute 10 | /// is present. 11 | /// 12 | /// [`SetStorage`]: crate::set::SetStorage 13 | pub trait RawStorage: Sized { 14 | /// The backing raw value. 15 | type Value; 16 | 17 | /// Get the raw value of the storage. 18 | fn as_raw(&self) -> Self::Value; 19 | 20 | /// Build storage from raw storage. 21 | fn from_raw(raw: Self::Value) -> Self; 22 | } 23 | -------------------------------------------------------------------------------- /src/set/intersection.rs: -------------------------------------------------------------------------------- 1 | //! Module that defines the [`Intersection`] for [`Set`]. 2 | 3 | use core::fmt; 4 | 5 | use super::{Iter, Key, Set}; 6 | 7 | /// A lazy iterator producing elements in the intersection of `Set`s. 8 | /// 9 | /// This `struct` is created by the [`intersection`] method on [`Set`]. See its 10 | /// documentation for more. 11 | /// 12 | /// [`intersection`]: Set::intersection 13 | /// 14 | /// # Examples 15 | /// 16 | /// ``` 17 | /// use fixed_map::{Key, Set}; 18 | /// 19 | /// #[derive(Clone, Copy, Key, Debug)] 20 | /// enum K { 21 | /// One, 22 | /// Two, 23 | /// Three, 24 | /// } 25 | /// 26 | /// let a = Set::from([K::One]); 27 | /// let b = Set::from([K::One, K::Two, K::Two]); 28 | /// 29 | /// let intersection = a.intersection(&b).collect::>(); 30 | /// assert_eq!(intersection, Set::from([K::One])); 31 | /// ``` 32 | #[must_use = "this returns the intersection as an iterator, \ 33 | without modifying either input set"] 34 | pub struct Intersection<'a, T: 'a + Key> { 35 | // iterator of the first set 36 | pub(super) iter: Iter<'a, T>, 37 | // the second set 38 | pub(super) other: &'a Set, 39 | } 40 | 41 | impl Clone for Intersection<'_, T> { 42 | #[inline] 43 | fn clone(&self) -> Self { 44 | Intersection { 45 | iter: self.iter.clone(), 46 | ..*self 47 | } 48 | } 49 | } 50 | 51 | impl Iterator for Intersection<'_, T> 52 | where 53 | T: Key, 54 | { 55 | type Item = T; 56 | 57 | #[inline] 58 | fn next(&mut self) -> Option { 59 | loop { 60 | let elt = self.iter.next()?; 61 | 62 | if self.other.contains(elt) { 63 | return Some(elt); 64 | } 65 | } 66 | } 67 | 68 | #[inline] 69 | fn size_hint(&self) -> (usize, Option) { 70 | let (_, upper) = self.iter.size_hint(); 71 | (0, upper) 72 | } 73 | 74 | #[inline] 75 | fn fold(self, init: B, mut f: F) -> B 76 | where 77 | Self: Sized, 78 | F: FnMut(B, Self::Item) -> B, 79 | { 80 | self.iter.fold(init, |acc, elt| { 81 | if self.other.contains(elt) { 82 | f(acc, elt) 83 | } else { 84 | acc 85 | } 86 | }) 87 | } 88 | } 89 | 90 | impl fmt::Debug for Intersection<'_, T> 91 | where 92 | T: fmt::Debug + Key, 93 | { 94 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 95 | f.debug_list().entries(self.clone()).finish() 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/set/storage.rs: -------------------------------------------------------------------------------- 1 | //! Module that defines the [`SetStorage`] trait. 2 | 3 | mod singleton; 4 | pub use self::singleton::SingletonSetStorage; 5 | 6 | mod boolean; 7 | pub use self::boolean::BooleanSetStorage; 8 | 9 | #[cfg(feature = "hashbrown")] 10 | mod hashbrown; 11 | #[cfg(feature = "hashbrown")] 12 | pub use self::hashbrown::HashbrownSetStorage; 13 | 14 | mod option; 15 | pub use self::option::OptionSetStorage; 16 | 17 | /// The trait defining how storage works for [`Set`][crate::Set]. 18 | /// 19 | /// # Type Arguments 20 | /// 21 | /// - `T` is the key being stored. 22 | pub trait SetStorage: Sized { 23 | /// Immutable iterator over storage. 24 | type Iter<'this>: Iterator + Clone 25 | where 26 | Self: 'this; 27 | 28 | /// Owning iterator over the storage. 29 | type IntoIter: Iterator; 30 | 31 | /// Construct empty storage. 32 | fn empty() -> Self; 33 | 34 | /// Get the length of storage. 35 | fn len(&self) -> usize; 36 | 37 | /// Check if storage is empty. 38 | fn is_empty(&self) -> bool; 39 | 40 | /// This is the storage abstraction for [`Set::insert`][crate::Set::insert]. 41 | fn insert(&mut self, value: T) -> bool; 42 | 43 | /// This is the storage abstraction for [`Set::contains`][crate::Set::contains]. 44 | fn contains(&self, value: T) -> bool; 45 | 46 | /// This is the storage abstraction for [`Set::remove`][crate::Set::remove]. 47 | fn remove(&mut self, value: T) -> bool; 48 | 49 | /// This is the storage abstraction for [`Set::retain`][crate::Set::retain]. 50 | fn retain(&mut self, f: F) 51 | where 52 | F: FnMut(T) -> bool; 53 | 54 | /// This is the storage abstraction for [`Set::clear`][crate::Set::clear]. 55 | fn clear(&mut self); 56 | 57 | /// This is the storage abstraction for [`Set::iter`][crate::Set::iter]. 58 | fn iter(&self) -> Self::Iter<'_>; 59 | 60 | /// This is the storage abstraction for [`Set::into_iter`][crate::Set::into_iter]. 61 | fn into_iter(self) -> Self::IntoIter; 62 | } 63 | -------------------------------------------------------------------------------- /src/set/storage/boolean.rs: -------------------------------------------------------------------------------- 1 | // Iterators are confusing if they impl `Copy`. 2 | #![allow(missing_copy_implementations)] 3 | 4 | use core::mem; 5 | 6 | use crate::set::SetStorage; 7 | 8 | const TRUE_BIT: u8 = 0b10; 9 | const FALSE_BIT: u8 = 0b01; 10 | 11 | /// [`SetStorage`] for [`bool`] types. 12 | /// 13 | /// # Examples 14 | /// 15 | /// ``` 16 | /// use fixed_map::{Key, Set}; 17 | /// 18 | /// #[derive(Debug, Clone, Copy, PartialEq, Key)] 19 | /// enum MyKey { 20 | /// First(bool), 21 | /// Second, 22 | /// } 23 | /// 24 | /// let mut a = Set::new(); 25 | /// a.insert(MyKey::First(false)); 26 | /// 27 | /// assert!(!a.contains(MyKey::First(true))); 28 | /// assert!(a.contains(MyKey::First(false))); 29 | /// assert!(!a.contains(MyKey::Second)); 30 | /// 31 | /// assert!(a.iter().eq([MyKey::First(false)])); 32 | /// ``` 33 | /// 34 | /// Iterator over boolean set: 35 | /// 36 | /// ``` 37 | /// use fixed_map::{Key, Set}; 38 | /// 39 | /// #[derive(Debug, Clone, Copy, PartialEq, Key)] 40 | /// enum MyKey { 41 | /// Bool(bool), 42 | /// Other, 43 | /// } 44 | /// 45 | /// let mut a = Set::new(); 46 | /// a.insert(MyKey::Bool(true)); 47 | /// a.insert(MyKey::Bool(false)); 48 | /// 49 | /// assert!(a.iter().eq([MyKey::Bool(true), MyKey::Bool(false)])); 50 | /// assert_eq!(a.iter().rev().collect::>(), vec![MyKey::Bool(false), MyKey::Bool(true)]); 51 | /// ``` 52 | #[derive(Clone, Copy, PartialEq, Eq)] 53 | pub struct BooleanSetStorage { 54 | bits: u8, 55 | } 56 | 57 | /// See [`BooleanSetStorage::iter`]. 58 | pub struct Iter { 59 | bits: u8, 60 | } 61 | 62 | impl Clone for Iter { 63 | #[inline] 64 | fn clone(&self) -> Iter { 65 | Iter { bits: self.bits } 66 | } 67 | } 68 | 69 | impl Iterator for Iter { 70 | type Item = bool; 71 | 72 | #[inline] 73 | fn next(&mut self) -> Option { 74 | if self.bits & TRUE_BIT != 0 { 75 | self.bits &= !TRUE_BIT; 76 | return Some(true); 77 | } 78 | 79 | if self.bits & FALSE_BIT != 0 { 80 | self.bits &= !FALSE_BIT; 81 | return Some(false); 82 | } 83 | 84 | None 85 | } 86 | 87 | #[inline] 88 | fn size_hint(&self) -> (usize, Option) { 89 | let len = self.bits.count_ones() as usize; 90 | (len, Some(len)) 91 | } 92 | } 93 | 94 | impl DoubleEndedIterator for Iter { 95 | #[inline] 96 | fn next_back(&mut self) -> Option { 97 | if self.bits & FALSE_BIT != 0 { 98 | self.bits &= !FALSE_BIT; 99 | return Some(false); 100 | } 101 | 102 | if self.bits & TRUE_BIT != 0 { 103 | self.bits &= !TRUE_BIT; 104 | return Some(true); 105 | } 106 | 107 | None 108 | } 109 | } 110 | 111 | impl ExactSizeIterator for Iter { 112 | #[inline] 113 | fn len(&self) -> usize { 114 | self.bits.count_ones() as usize 115 | } 116 | } 117 | 118 | impl SetStorage for BooleanSetStorage { 119 | type Iter<'this> = Iter; 120 | type IntoIter = Iter; 121 | 122 | #[inline] 123 | fn empty() -> Self { 124 | Self { bits: 0 } 125 | } 126 | 127 | #[inline] 128 | fn len(&self) -> usize { 129 | usize::from(self.bits & TRUE_BIT != 0) 130 | .saturating_add(usize::from(self.bits & FALSE_BIT != 0)) 131 | } 132 | 133 | #[inline] 134 | fn is_empty(&self) -> bool { 135 | self.bits == 0 136 | } 137 | 138 | #[inline] 139 | fn insert(&mut self, value: bool) -> bool { 140 | let update = self.bits | to_bits(value); 141 | test(mem::replace(&mut self.bits, update), value) 142 | } 143 | 144 | #[inline] 145 | fn contains(&self, value: bool) -> bool { 146 | test(self.bits, value) 147 | } 148 | 149 | #[inline] 150 | fn remove(&mut self, value: bool) -> bool { 151 | let value = to_bits(value); 152 | let update = self.bits & !value; 153 | mem::replace(&mut self.bits, update) != 0 154 | } 155 | 156 | #[inline] 157 | fn retain(&mut self, mut f: F) 158 | where 159 | F: FnMut(bool) -> bool, 160 | { 161 | if test(self.bits, true) && !f(true) { 162 | self.bits &= !TRUE_BIT; 163 | } 164 | 165 | if test(self.bits, false) && !f(false) { 166 | self.bits &= !FALSE_BIT; 167 | } 168 | } 169 | 170 | #[inline] 171 | fn clear(&mut self) { 172 | self.bits = 0; 173 | } 174 | 175 | #[inline] 176 | fn iter(&self) -> Self::Iter<'_> { 177 | Iter { bits: self.bits } 178 | } 179 | 180 | #[inline] 181 | fn into_iter(self) -> Self::IntoIter { 182 | Iter { bits: self.bits } 183 | } 184 | } 185 | 186 | #[inline] 187 | const fn test(bits: u8, value: bool) -> bool { 188 | bits & to_bits(value) != 0 189 | } 190 | 191 | #[inline] 192 | const fn to_bits(value: bool) -> u8 { 193 | if value { 194 | TRUE_BIT 195 | } else { 196 | FALSE_BIT 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /src/set/storage/hashbrown.rs: -------------------------------------------------------------------------------- 1 | use core::hash::Hash; 2 | use core::iter; 3 | 4 | use crate::set::SetStorage; 5 | 6 | /// [`SetStorage`] for dynamically stored types, using [`hashbrown::HashSet`]. 7 | /// 8 | /// This allows for dynamic types such as `&'static str` or `u32` to be used as 9 | /// a [`Key`][crate::Key]. 10 | /// 11 | /// # Examples 12 | /// 13 | /// ``` 14 | /// use fixed_map::{Key, Set}; 15 | /// 16 | /// #[derive(Clone, Copy, Key)] 17 | /// enum MyKey { 18 | /// First(u32), 19 | /// Second, 20 | /// } 21 | /// 22 | /// let mut map = Set::new(); 23 | /// map.insert(MyKey::First(1)); 24 | /// assert_eq!(map.contains(MyKey::First(1)), true); 25 | /// assert_eq!(map.contains(MyKey::First(2)), false); 26 | /// assert_eq!(map.contains(MyKey::Second), false); 27 | /// ``` 28 | #[repr(transparent)] 29 | pub struct HashbrownSetStorage { 30 | inner: ::hashbrown::HashSet, 31 | } 32 | 33 | impl Clone for HashbrownSetStorage 34 | where 35 | T: Clone, 36 | { 37 | #[inline] 38 | fn clone(&self) -> Self { 39 | HashbrownSetStorage { 40 | inner: self.inner.clone(), 41 | } 42 | } 43 | } 44 | 45 | impl PartialEq for HashbrownSetStorage 46 | where 47 | T: Eq + Hash, 48 | { 49 | #[inline] 50 | fn eq(&self, other: &Self) -> bool { 51 | self.inner.eq(&other.inner) 52 | } 53 | } 54 | 55 | impl Eq for HashbrownSetStorage where T: Eq + Hash {} 56 | 57 | impl SetStorage for HashbrownSetStorage 58 | where 59 | T: Copy + Eq + Hash, 60 | { 61 | type Iter<'this> 62 | = iter::Copied<::hashbrown::hash_set::Iter<'this, T>> 63 | where 64 | T: 'this; 65 | type IntoIter = ::hashbrown::hash_set::IntoIter; 66 | 67 | #[inline] 68 | fn empty() -> Self { 69 | Self { 70 | inner: ::hashbrown::HashSet::new(), 71 | } 72 | } 73 | 74 | #[inline] 75 | fn len(&self) -> usize { 76 | self.inner.len() 77 | } 78 | 79 | #[inline] 80 | fn is_empty(&self) -> bool { 81 | self.inner.is_empty() 82 | } 83 | 84 | #[inline] 85 | fn insert(&mut self, value: T) -> bool { 86 | self.inner.insert(value) 87 | } 88 | 89 | #[inline] 90 | fn contains(&self, value: T) -> bool { 91 | self.inner.contains(&value) 92 | } 93 | 94 | #[inline] 95 | fn remove(&mut self, value: T) -> bool { 96 | self.inner.remove(&value) 97 | } 98 | 99 | #[inline] 100 | fn retain(&mut self, mut func: F) 101 | where 102 | F: FnMut(T) -> bool, 103 | { 104 | self.inner.retain(|&value| func(value)); 105 | } 106 | 107 | #[inline] 108 | fn clear(&mut self) { 109 | self.inner.clear(); 110 | } 111 | 112 | #[inline] 113 | fn iter(&self) -> Self::Iter<'_> { 114 | self.inner.iter().copied() 115 | } 116 | 117 | #[inline] 118 | fn into_iter(self) -> Self::IntoIter { 119 | self.inner.into_iter() 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/set/storage/option.rs: -------------------------------------------------------------------------------- 1 | use core::iter; 2 | use core::mem; 3 | use core::option; 4 | 5 | use crate::set::SetStorage; 6 | use crate::Key; 7 | 8 | type Iter<'a, T> = iter::Chain< 9 | iter::Map<<::SetStorage as SetStorage>::Iter<'a>, fn(T) -> Option>, 10 | option::IntoIter>, 11 | >; 12 | type IntoIter = iter::Chain< 13 | iter::Map<<::SetStorage as SetStorage>::IntoIter, fn(T) -> Option>, 14 | option::IntoIter>, 15 | >; 16 | 17 | /// [`SetStorage`] for [`Option`] types. 18 | /// 19 | /// # Examples 20 | /// 21 | /// ``` 22 | /// use fixed_map::{Key, Map}; 23 | /// 24 | /// #[derive(Debug, Clone, Copy, PartialEq, Key)] 25 | /// enum Part { 26 | /// A, 27 | /// B, 28 | /// } 29 | /// 30 | /// #[derive(Debug, Clone, Copy, PartialEq, Key)] 31 | /// enum MyKey { 32 | /// First(Option), 33 | /// Second, 34 | /// } 35 | /// 36 | /// let mut a = Map::new(); 37 | /// a.insert(MyKey::First(None), 1); 38 | /// a.insert(MyKey::First(Some(Part::A)), 2); 39 | /// 40 | /// assert_eq!(a.get(MyKey::First(Some(Part::A))), Some(&2)); 41 | /// assert_eq!(a.get(MyKey::First(Some(Part::B))), None); 42 | /// assert_eq!(a.get(MyKey::First(None)), Some(&1)); 43 | /// assert_eq!(a.get(MyKey::Second), None); 44 | /// 45 | /// assert!(a.iter().eq([(MyKey::First(Some(Part::A)), &2), (MyKey::First(None), &1)])); 46 | /// assert!(a.values().copied().eq([2, 1])); 47 | /// assert!(a.keys().eq([MyKey::First(Some(Part::A)), MyKey::First(None)])); 48 | /// ``` 49 | pub struct OptionSetStorage 50 | where 51 | T: Key, 52 | { 53 | some: T::SetStorage, 54 | none: bool, 55 | } 56 | 57 | impl Clone for OptionSetStorage 58 | where 59 | T: Key, 60 | T::SetStorage: Clone, 61 | { 62 | #[inline] 63 | fn clone(&self) -> Self { 64 | Self { 65 | some: self.some.clone(), 66 | none: self.none, 67 | } 68 | } 69 | } 70 | 71 | impl Copy for OptionSetStorage 72 | where 73 | T: Key, 74 | T::SetStorage: Copy, 75 | { 76 | } 77 | 78 | impl PartialEq for OptionSetStorage 79 | where 80 | T: Key, 81 | T::SetStorage: PartialEq, 82 | { 83 | #[inline] 84 | fn eq(&self, other: &Self) -> bool { 85 | self.none == other.none && self.some == other.some 86 | } 87 | } 88 | 89 | impl Eq for OptionSetStorage 90 | where 91 | T: Key, 92 | T::SetStorage: Eq, 93 | { 94 | } 95 | 96 | impl SetStorage> for OptionSetStorage 97 | where 98 | T: Key, 99 | { 100 | type Iter<'this> 101 | = Iter<'this, T> 102 | where 103 | T: 'this; 104 | type IntoIter = IntoIter; 105 | 106 | #[inline] 107 | fn empty() -> Self { 108 | Self { 109 | some: T::SetStorage::empty(), 110 | none: false, 111 | } 112 | } 113 | 114 | #[inline] 115 | fn len(&self) -> usize { 116 | self.some.len() + usize::from(self.none) 117 | } 118 | 119 | #[inline] 120 | fn is_empty(&self) -> bool { 121 | self.some.is_empty() && self.none 122 | } 123 | 124 | #[inline] 125 | fn insert(&mut self, value: Option) -> bool { 126 | match value { 127 | Some(value) => self.some.insert(value), 128 | None => mem::replace(&mut self.none, true), 129 | } 130 | } 131 | 132 | #[inline] 133 | fn contains(&self, value: Option) -> bool { 134 | match value { 135 | Some(key) => self.some.contains(key), 136 | None => self.none, 137 | } 138 | } 139 | 140 | #[inline] 141 | fn remove(&mut self, key: Option) -> bool { 142 | match key { 143 | Some(key) => self.some.remove(key), 144 | None => mem::replace(&mut self.none, false), 145 | } 146 | } 147 | 148 | #[inline] 149 | fn retain(&mut self, mut func: F) 150 | where 151 | F: FnMut(Option) -> bool, 152 | { 153 | self.some.retain(|value| func(Some(value))); 154 | 155 | if self.none { 156 | self.none = func(None); 157 | } 158 | } 159 | 160 | #[inline] 161 | fn clear(&mut self) { 162 | self.some.clear(); 163 | self.none = false; 164 | } 165 | 166 | #[inline] 167 | fn iter(&self) -> Self::Iter<'_> { 168 | let map: fn(_) -> _ = Some; 169 | self.some 170 | .iter() 171 | .map(map) 172 | .chain(self.none.then_some(None::)) 173 | } 174 | 175 | #[inline] 176 | fn into_iter(self) -> Self::IntoIter { 177 | let map: fn(_) -> _ = Some; 178 | self.some 179 | .into_iter() 180 | .map(map) 181 | .chain(self.none.then_some(None::)) 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /src/set/storage/singleton.rs: -------------------------------------------------------------------------------- 1 | use core::mem; 2 | 3 | use crate::set::SetStorage; 4 | 5 | /// [`SetStorage`] types that can only inhabit a single value (like `()`). 6 | #[repr(transparent)] 7 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 8 | pub struct SingletonSetStorage { 9 | is_set: bool, 10 | } 11 | 12 | impl SetStorage for SingletonSetStorage 13 | where 14 | T: Default + Clone, 15 | { 16 | type Iter<'this> = core::option::IntoIter; 17 | type IntoIter = core::option::IntoIter; 18 | 19 | #[inline] 20 | fn empty() -> Self { 21 | Self { is_set: false } 22 | } 23 | 24 | #[inline] 25 | fn len(&self) -> usize { 26 | usize::from(self.is_set) 27 | } 28 | 29 | #[inline] 30 | fn is_empty(&self) -> bool { 31 | !self.is_set 32 | } 33 | 34 | #[inline] 35 | fn insert(&mut self, _: T) -> bool { 36 | !mem::replace(&mut self.is_set, true) 37 | } 38 | 39 | #[inline] 40 | fn contains(&self, _: T) -> bool { 41 | self.is_set 42 | } 43 | 44 | #[inline] 45 | fn remove(&mut self, _: T) -> bool { 46 | mem::replace(&mut self.is_set, false) 47 | } 48 | 49 | #[inline] 50 | fn retain(&mut self, mut func: F) 51 | where 52 | F: FnMut(T) -> bool, 53 | { 54 | self.is_set = func(T::default()); 55 | } 56 | 57 | #[inline] 58 | fn clear(&mut self) { 59 | self.is_set = false; 60 | } 61 | 62 | #[inline] 63 | fn iter(&self) -> Self::Iter<'_> { 64 | self.is_set.then_some(T::default()).into_iter() 65 | } 66 | 67 | #[inline] 68 | fn into_iter(self) -> Self::IntoIter { 69 | self.is_set.then_some(T::default()).into_iter() 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /tests/empty.rs: -------------------------------------------------------------------------------- 1 | use fixed_map::{Key, Map}; 2 | 3 | #[derive(Debug, Clone, Copy, Key)] 4 | enum MyKey {} 5 | 6 | #[test] 7 | fn empty() { 8 | let _ = Map::::new(); 9 | } 10 | -------------------------------------------------------------------------------- /tests/entry.rs: -------------------------------------------------------------------------------- 1 | use fixed_map::{Key, Map}; 2 | 3 | #[derive(Clone, Copy, Key)] 4 | enum Part { 5 | One, 6 | Two, 7 | } 8 | 9 | #[test] 10 | fn simple() { 11 | let mut map: Map = Map::new(); 12 | 13 | assert_eq!(map.entry(Part::Two).or_default(), &0); 14 | assert_eq!( 15 | map.entry(Part::One).and_modify(|x| *x += 1).or_insert(12), 16 | &12 17 | ); 18 | assert_eq!( 19 | map.entry(Part::One).and_modify(|x| *x += 1).or_insert(12), 20 | &13 21 | ); 22 | } 23 | 24 | #[test] 25 | fn other() { 26 | use fixed_map::{Key, Map}; 27 | 28 | #[derive(Clone, Copy, Key)] 29 | enum MyKey { 30 | Even, 31 | Odd, 32 | } 33 | 34 | let mut map: Map = Map::new(); 35 | 36 | for n in [3, 45, 3, 23, 2, 10, 59, 11, 51, 70] { 37 | map.entry(if n % 2 == 0 { MyKey::Even } else { MyKey::Odd }) 38 | .and_modify(|x| *x += 1) 39 | .or_insert(1); 40 | } 41 | 42 | assert_eq!(map.get(MyKey::Even), Some(&3)); 43 | assert_eq!(map.get(MyKey::Odd), Some(&7)); 44 | } 45 | 46 | #[test] 47 | fn composite() { 48 | use fixed_map::{Key, Map}; 49 | 50 | #[derive(Clone, Copy, Key)] 51 | enum MyKey { 52 | First(bool), 53 | Second, 54 | } 55 | 56 | let mut map: Map> = Map::new(); 57 | 58 | map.entry(MyKey::First(true)).or_default().push(1); 59 | map.entry(MyKey::Second) 60 | .or_insert_with(|| vec![2; 8]) 61 | .truncate(4); 62 | 63 | assert_eq!(map.get(MyKey::First(true)), Some(&vec![1])); 64 | assert_eq!(map.get(MyKey::Second), Some(&vec![2; 4])); 65 | } 66 | 67 | #[cfg(feature = "hashbrown")] 68 | #[test] 69 | fn compound() { 70 | #[derive(Clone, Copy, Key)] 71 | enum MyKey { 72 | Simple, 73 | Composite(Part), 74 | String(&'static str), 75 | Number(u32), 76 | Singleton(()), 77 | } 78 | 79 | let mut map: Map = Map::new(); 80 | 81 | map.insert(MyKey::Composite(Part::One), 1); 82 | assert_eq!(map.entry(MyKey::Composite(Part::Two)).or_default(), &0); 83 | assert_eq!( 84 | map.entry(MyKey::Composite(Part::One)) 85 | .and_modify(|x| *x += 1) 86 | .or_insert(12), 87 | &2 88 | ); 89 | } 90 | -------------------------------------------------------------------------------- /tests/map_feature.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "hashbrown")] 2 | 3 | use fixed_map::{Key, Map}; 4 | 5 | #[derive(Clone, Copy, Key)] 6 | enum Part { 7 | One, 8 | Two, 9 | } 10 | 11 | #[derive(Clone, Copy, Key)] 12 | enum MyKey { 13 | Simple, 14 | Composite(Part), 15 | String(&'static str), 16 | Number(u32), 17 | Singleton(()), 18 | } 19 | 20 | #[test] 21 | fn map_feature() { 22 | let mut map = Map::new(); 23 | 24 | map.insert(MyKey::Simple, 1); 25 | map.insert(MyKey::Composite(Part::One), 2); 26 | map.insert(MyKey::String("foo"), 3); 27 | map.insert(MyKey::Number(1), 4); 28 | map.insert(MyKey::Singleton(()), 5); 29 | 30 | assert_eq!(map.get(MyKey::Simple), Some(&1)); 31 | assert_eq!(map.get(MyKey::Composite(Part::One)), Some(&2)); 32 | assert_eq!(map.get(MyKey::Composite(Part::Two)), None); 33 | assert_eq!(map.get(MyKey::String("foo")), Some(&3)); 34 | assert_eq!(map.get(MyKey::String("bar")), None); 35 | assert_eq!(map.get(MyKey::Number(1)), Some(&4)); 36 | assert_eq!(map.get(MyKey::Number(2)), None); 37 | assert_eq!(map.get(MyKey::Singleton(())), Some(&5)); 38 | } 39 | --------------------------------------------------------------------------------