indexmap-nostd-0.4.0/.cargo_vcs_info.json0000644000000001360000000000100137670ustar { "git": { "sha1": "6359475b30abacab3e9e0df6f948bc0507a17106" }, "path_in_vcs": "" }indexmap-nostd-0.4.0/.github/workflows/ci.yml000064400000000000000000000057341046102023000173030ustar 00000000000000name: Rust - Continuous Integration on: push: branches: [ main ] pull_request: branches: [ main ] jobs: check: name: Check runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true - uses: actions-rs/cargo@v1 with: command: check build: name: Build (no_std) runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable target: wasm32-unknown-unknown override: true - name: Add extra targets # Workaround for https://github.com/actions-rs/toolchain/issues/165 run: | rustup target add thumbv7em-none-eabi - uses: actions-rs/cargo@v1 with: command: build args: --no-default-features --target thumbv7em-none-eabi --lib - uses: actions-rs/cargo@v1 with: command: build args: --no-default-features --target wasm32-unknown-unknown test: name: Test strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true - uses: actions-rs/cargo@v1 with: command: test fmt: name: Formatting runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: nightly override: true components: rustfmt - uses: actions-rs/cargo@v1 with: command: fmt doc: name: Documentation runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true components: rust-docs, rust-src - uses: actions-rs/cargo@v1 env: RUSTDOCFLAGS: '-D warnings' with: command: doc args: --no-deps --document-private-items clippy: name: Clippy runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true components: clippy - uses: actions-rs/cargo@v1 with: command: clippy args: -- -D warnings audit: name: Audit runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true - uses: actions-rs/cargo@v1 with: command: audit args: --deny warnings indexmap-nostd-0.4.0/.gitignore000064400000000000000000000000241046102023000145430ustar 00000000000000/target /Cargo.lock indexmap-nostd-0.4.0/CHANGELOG.md000064400000000000000000000022261046102023000143720ustar 00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Version 0.4.0 ### Added - Added `IndexMap::get_key_value` method. - Added `IndexMap::get_full` method. - Added `IndexMap::get_index_of` method. - Added `IndexMap::{get_index, get_index_mut}` methods. - Added `IndexMap::insert_full` method. - Added `IndexSet::get_full` method. - Added `IndexSet::get_index_of` method. - Added `IndexSet::get_index` method. - Added `IndexSet::insert_full` method. - Added `Index` and `IndexMut` impls to `IndexMap`. - Added `Index` impl to `IndexSet`. ## Version 0.3.0 ### Added - Support for `serde` (de)serialization using the `serde` crate feature. - This also includes sequence based (de)serialization as is also supported in the original `indexmap` crate via `serde_seq` submodule. ## Version 0.2.0 ### Added - `Index{Map,Set}::with_capacity` constructor API. - `Index{Map,Set}::reserve` API. ## Version 0.1.0 Initial release of the crate. indexmap-nostd-0.4.0/Cargo.toml0000644000000021700000000000100117650ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "indexmap-nostd" version = "0.4.0" authors = ["Robin Freyler "] description = "A no_std compatible implementation of the indexmap crate" documentation = "https:///docs.rs/indexmap-nostd" readme = "README.md" keywords = [ "hashmap", "no_std", ] categories = [ "data-structures", "no-std", ] license = "Apache-2.0" repository = "https://github.com/robbepop/indexmap-nostd" resolver = "2" [package.metadata.docs.rs] features = ["serde"] [dependencies.serde] version = "1.0" optional = true default-features = false [dev-dependencies.serde_derive] version = "1.0" [features] default = ["std"] std = [] indexmap-nostd-0.4.0/Cargo.toml.orig000064400000000000000000000012001046102023000154370ustar 00000000000000[package] name = "indexmap-nostd" version = "0.4.0" edition = "2021" authors = ["Robin Freyler "] license = "Apache-2.0" readme = "README.md" repository = "https://github.com/robbepop/indexmap-nostd" documentation = "https:///docs.rs/indexmap-nostd" description = "A no_std compatible implementation of the indexmap crate" keywords = ["hashmap", "no_std"] categories = ["data-structures", "no-std"] [dependencies] serde = { version = "1.0", optional = true, default-features = false } [dev-dependencies] serde_derive = "1.0" [features] default = ["std"] std = [] [package.metadata.docs.rs] features = ["serde"] indexmap-nostd-0.4.0/LICENSE000064400000000000000000000277231046102023000135770ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --- LLVM Exceptions to the Apache 2.0 License ---- As an exception, if, as a result of your compiling your source code, portions of this Software are embedded into an Object form of such source code, you may redistribute such embedded portions in such Object form without complying with the conditions of Sections 4(a), 4(b) and 4(d) of the License. In addition, if you combine or link compiled forms of this Software with software that is licensed under the GPLv2 ("Combined Software") and if a court of competent jurisdiction determines that the patent provision (Section 3), the indemnity provision (Section 9) or other Section of the License conflicts with the conditions of the GPLv2, you may retroactively and prospectively choose to deem waived or otherwise exclude such Section(s) of the License, but only in their entirety and only with respect to the Combined Software. indexmap-nostd-0.4.0/README.md000064400000000000000000000033701046102023000140410ustar 00000000000000# `indexmap-nostd` A `no_std` compatible [`indexmap` crate] (re)implementation. **Note:** The [`indexmap` crate] already supports to be compiled in `no_std` environments and it uses [`hashbrown` crate]'s `HashMap` under the hood which still requires some sort of randomized initialization. However, some embedded platforms simply cannot provide ways to randomly seed hash maps and similar data structures making code that depends on it susceptible to users (or attackers) that control inputs to those hash maps. Therefore `indexmap-nostd` is a (re)implementation of the [`indexmap` crate] that replaces the internal use of `HashMap` with `BTreeMap`. ## Advantages This crate and its data structures can be used in any embedded `no_std` environment without the need to provide random seeds for `HashMap` initialization. ## Disadvantages - The current implementation of `indexmap-nostd` focuses on being easy to maintain simple code which trades off efficiency compared to the original [`indexmap` crate]. An example of performance regression is that now inserted keys are duplicated. - Due to the above point some methods now require additional where bounds. For example `IndexMap::insert` now requires `K: Clone`. - We are primarily interested in getting this `no_std` compatible implementation to be working for the [`wasmparser` crate]. This means that we primarily provide a subset of the features and API of the original [`indexmap` crate] and might not be interested in adding features that we do not need for this use case that are also hard to implement or maintain. [`indexmap` crate]: https://www.crates.io/crates/indexmap [`wasmparser` crate]: https://www.crates.io/crates/wasmparser-nostd [`hashbrown` crate]: https://www.crates.io/crates/hashbrown indexmap-nostd-0.4.0/src/lib.rs000064400000000000000000000041441046102023000144650ustar 00000000000000//! ### Disclaimer //! //! This is a reimplementation of the [`indexmap` crate] and meant //! to be a drop-in replacement for its [`indexmap::IndexMap`] and //! [`indexmap::IndexSet`] types in embedded `no_std` environments that cannot //! afford to use hash tables that require random seed initialization in order //! to _not_ be attackable by users controlling their inputs. //! //! This crate was originally and primarily conceived as building block for //! a similar [`wasmparser-nostd` crate] fork for embedded `no_std` environments. //! Therefore this crate currently only supports a subset of the features of //! the original [`indexmap` crate] that are required by the //! [`wasmparser-nostd` crate] initiative. //! //! ### Types //! //! [`IndexMap`] is a hash table where the iteration order of the key-value //! pairs is independent of the hash values of the keys. //! //! [`IndexSet`] is a corresponding hash set using the same implementation and //! with similar properties. //! //! [`wasmparser-nostd` crate]: https://crates.io/crates/wasmparser-nostd //! [`indexmap::IndexMap`]: https://docs.rs/indexmap/latest/indexmap/map/struct.IndexMap.html //! [`indexmap::IndexSet`]: https://docs.rs/indexmap/latest/indexmap/set/struct.IndexSet.html //! [`indexmap` crate]: https://crates.io/crates/indexmap //! [`IndexMap`]: map/struct.IndexMap.html //! [`IndexSet`]: set/struct.IndexSet.html //! //! ### Feature Highlights //! //! [`IndexMap`] and [`IndexSet`] are mostly drop-in compatible with the //! standard library's `HashMap` and `HashSet`. #![cfg_attr(not(feature = "std"), no_std)] #[cfg(feature = "std")] extern crate std as alloc; #[cfg(not(feature = "std"))] extern crate alloc; pub mod map; pub mod set; #[cfg(feature = "serde")] mod serde; #[cfg(feature = "serde")] pub mod serde_seq; pub use self::map::IndexMap; pub use self::set::IndexSet; /// A slot index referencing a slot in an [`IndexMap`]. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] struct SlotIndex(usize); impl SlotIndex { /// Returns the raw `usize` index of the [`SlotIndex`]. pub fn index(self) -> usize { self.0 } } indexmap-nostd-0.4.0/src/map.rs000064400000000000000000000566411046102023000145050ustar 00000000000000//! An ordered map based on a B-Tree that keeps insertion order of elements. use super::SlotIndex; use alloc::collections::{btree_map, BTreeMap}; use alloc::vec::IntoIter as VecIntoIter; use alloc::vec::Vec; use core::borrow::Borrow; use core::fmt; use core::iter::FusedIterator; use core::mem::replace; use core::ops::{Index, IndexMut}; use core::slice::Iter as SliceIter; use core::slice::IterMut as SliceIterMut; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] struct Slot { /// The key of the [`Slot`]. key: K, /// The value of the [`Slot`]. value: V, } impl Slot { /// Creates a new [`Slot`] from the given `key` and `value`. pub fn new(key: K, value: V) -> Self { Self { key, value } } /// Returns the [`Slot`] as a pair of references to its `key` and `value`. pub fn as_pair(&self) -> (&K, &V) { (&self.key, &self.value) } /// Returns the [`Slot`] as a pair of references to its `key` and `value`. pub fn as_pair_mut(&mut self) -> (&K, &mut V) { (&self.key, &mut self.value) } /// Converts the [`Slot`] into a pair of its `key` and `value`. pub fn into_pair(self) -> (K, V) { (self.key, self.value) } /// Returns a shared reference to the value of the [`Slot`]. pub fn value(&self) -> &V { &self.value } /// Returns an exclusive reference to the value of the [`Slot`]. pub fn value_mut(&mut self) -> &mut V { &mut self.value } } /// A b-tree map where the iteration order of the key-value /// pairs is independent of the ordering of the keys. /// /// The interface is closely compatible with the [`indexmap` crate] /// and a subset of the features that is relevant for the /// [`wasmparser-nostd` crate]. /// /// # Differences to original `IndexMap` /// /// Since the goal of this crate was to maintain a simple /// `no_std` compatible fork of the [`indexmap` crate] there are some /// downsides and differences. /// /// - Some operations such as `IndexMap::insert` now require `K: Clone`. /// - It is to be expected that this fork performs worse than the original /// [`indexmap` crate] implementation. /// - The implementation is based on `BTreeMap` internally instead of /// `HashMap` which has the effect that methods no longer require `K: Hash` /// but `K: Ord` instead. /// /// [`indexmap` crate]: https://crates.io/crates/indexmap /// [`wasmparser-nostd` crate]: https://crates.io/crates/wasmparser-nostd #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct IndexMap { /// A mapping from keys to slot indices. key2slot: BTreeMap, /// A vector holding all slots of key value pairs. slots: Vec>, } impl Default for IndexMap { fn default() -> Self { Self::new() } } impl IndexMap { /// Makes a new, empty [`IndexMap`]. /// /// Does not allocate anything on its own. pub fn new() -> Self { Self { key2slot: BTreeMap::new(), slots: Vec::new(), } } /// Constructs a new, empty [`IndexMap`] with at least the specified capacity. /// /// Does not allocate if `capacity` is zero. pub fn with_capacity(capacity: usize) -> Self { Self { key2slot: BTreeMap::new(), slots: Vec::with_capacity(capacity), } } /// Reserve capacity for at least `additional` more key-value pairs. pub fn reserve(&mut self, additional: usize) { self.slots.reserve(additional); } /// Returns the number of elements in the map. pub fn len(&self) -> usize { self.slots.len() } /// Returns `true` if the map contains no elements. pub fn is_empty(&self) -> bool { self.len() != 0 } /// Returns true if the map contains a value for the specified key. /// /// The key may be any borrowed form of the map’s key type, /// but the ordering on the borrowed form must match the ordering on the key type. pub fn contains_key(&self, key: &Q) -> bool where K: Borrow + Ord, Q: Ord, { self.key2slot.contains_key(key) } /// Inserts a key-value pair into the map. /// /// If the map did not have this key present, `None` is returned. /// /// If the map did have this key present, the value is updated, and the old /// value is returned. The key is not updated, though; this matters for /// types that can be `==` without being identical. pub fn insert(&mut self, key: K, value: V) -> Option where K: Ord + Clone, { self.insert_full(key, value) .map(|(_index, old_value)| old_value) } /// Inserts a key-value pair into the map. /// /// Returns the unique index to the key-value pair alongside the previous value. /// /// If the map did not have this key present, `None` is returned. /// /// If the map did have this key present, the value is updated, and the old /// value is returned. The key is not updated, though; this matters for /// types that can be `==` without being identical. pub fn insert_full(&mut self, key: K, value: V) -> Option<(usize, V)> where K: Ord + Clone, { match self.key2slot.entry(key.clone()) { btree_map::Entry::Vacant(entry) => { let new_slot = self.slots.len(); entry.insert(SlotIndex(new_slot)); self.slots.push(Slot::new(key, value)); None } btree_map::Entry::Occupied(entry) => { let index = entry.get().index(); let new_slot = Slot::new(key, value); let old_slot = replace(&mut self.slots[index], new_slot); Some((index, old_slot.value)) } } } /// Gets the given key’s corresponding entry in the map for in-place manipulation. pub fn entry(&mut self, key: K) -> Entry where K: Ord + Clone, { match self.key2slot.entry(key) { btree_map::Entry::Vacant(entry) => Entry::Vacant(VacantEntry { vacant: entry, slots: &mut self.slots, }), btree_map::Entry::Occupied(entry) => Entry::Occupied(OccupiedEntry { occupied: entry, slots: &mut self.slots, }), } } /// Returns a reference to the value corresponding to the key. /// /// The key may be any borrowed form of the map’s key type, /// but the ordering on the borrowed form must match the ordering on the key type. pub fn get(&self, key: &Q) -> Option<&V> where K: Borrow + Ord, Q: Ord, { self.key2slot .get(key) .map(|slot| &self.slots[slot.index()].value) } /// Returns the key-value pair corresponding to the supplied key. /// /// The supplied key may be any borrowed form of the map's key type, /// but the ordering on the borrowed form *must* match the ordering /// on the key type. pub fn get_key_value(&self, key: &Q) -> Option<(&K, &V)> where K: Borrow + Ord, Q: Ord, { self.key2slot .get_key_value(key) .map(|(key, slot)| (key, &self.slots[slot.index()].value)) } /// Returns the key-value pair corresponding to the supplied key /// as well as the unique index of the returned key-value pair. /// /// The supplied key may be any borrowed form of the map's key type, /// but the ordering on the borrowed form *must* match the ordering /// on the key type. pub fn get_full(&self, key: &Q) -> Option<(usize, &K, &V)> where K: Borrow + Ord, Q: Ord, { self.key2slot.get_key_value(key).map(|(key, slot)| { let index = slot.index(); let value = &self.slots[index].value; (index, key, value) }) } /// Returns the unique index corresponding to the supplied key. /// /// The supplied key may be any borrowed form of the map's key type, /// but the ordering on the borrowed form *must* match the ordering /// on the key type. pub fn get_index_of(&self, key: &Q) -> Option where K: Borrow + Ord, Q: Ord, { self.key2slot.get(key).copied().map(SlotIndex::index) } /// Returns a shared reference to the key-value pair at the given index. pub fn get_index(&self, index: usize) -> Option<(&K, &V)> { self.slots.get(index).map(Slot::as_pair) } /// Returns an exclusive reference to the key-value pair at the given index. pub fn get_index_mut(&mut self, index: usize) -> Option<(&K, &mut V)> { self.slots.get_mut(index).map(Slot::as_pair_mut) } /// Gets an iterator over the entries of the map, sorted by key. pub fn iter(&self) -> Iter { Iter { iter: self.slots.iter(), } } /// Gets a mutable iterator over the entries of the map, sorted by key. pub fn iter_mut(&mut self) -> IterMut { IterMut { iter: self.slots.iter_mut(), } } /// Gets an iterator over the values of the map, in order by key. pub fn values(&self) -> Values { Values { iter: self.slots.iter(), } } /// Gets a mutable iterator over the values of the map, in order by key. pub fn values_mut(&mut self) -> ValuesMut { ValuesMut { iter: self.slots.iter_mut(), } } /// Clears the map, removing all elements. pub fn clear(&mut self) { self.key2slot.clear(); self.slots.clear(); } } impl<'a, K, Q, V> Index<&'a Q> for IndexMap where K: Borrow + Ord, Q: Ord, { type Output = V; fn index(&self, key: &'a Q) -> &Self::Output { self.get(key).expect("no entry found for key") } } impl Index for IndexMap { type Output = V; fn index(&self, index: usize) -> &Self::Output { let (_key, value) = self .get_index(index) .expect("IndexMap: index out of bounds"); value } } impl IndexMut for IndexMap { fn index_mut(&mut self, index: usize) -> &mut Self::Output { let (_key, value) = self .get_index_mut(index) .expect("IndexMap: index out of bounds"); value } } impl<'a, K, V> Extend<(&'a K, &'a V)> for IndexMap where K: Ord + Copy, V: Copy, { fn extend(&mut self, iter: T) where T: IntoIterator, { self.extend(iter.into_iter().map(|(key, value)| (*key, *value))) } } impl Extend<(K, V)> for IndexMap where K: Ord + Clone, { fn extend(&mut self, iter: T) where T: IntoIterator, { iter.into_iter().for_each(move |(k, v)| { self.insert(k, v); }); } } impl FromIterator<(K, V)> for IndexMap where K: Ord + Clone, { fn from_iter(iter: T) -> Self where T: IntoIterator, { let mut map = IndexMap::new(); map.extend(iter); map } } impl From<[(K, V); N]> for IndexMap where K: Ord + Clone, { fn from(items: [(K, V); N]) -> Self { items.into_iter().collect() } } impl<'a, K, V> IntoIterator for &'a IndexMap { type Item = (&'a K, &'a V); type IntoIter = Iter<'a, K, V>; fn into_iter(self) -> Self::IntoIter { self.iter() } } impl<'a, K, V> IntoIterator for &'a mut IndexMap { type Item = (&'a K, &'a mut V); type IntoIter = IterMut<'a, K, V>; fn into_iter(self) -> Self::IntoIter { self.iter_mut() } } impl IntoIterator for IndexMap { type Item = (K, V); type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { IntoIter { iter: self.slots.into_iter(), } } } /// An iterator over the entries of an [`IndexMap`]. /// /// This `struct` is created by the [`iter`] method on [`IndexMap`]. See its /// documentation for more. /// /// [`iter`]: IndexMap::iter #[derive(Debug, Clone)] pub struct Iter<'a, K, V> { iter: SliceIter<'a, Slot>, } impl<'a, K, V> Iterator for Iter<'a, K, V> { type Item = (&'a K, &'a V); fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } fn count(self) -> usize { self.iter.count() } fn next(&mut self) -> Option { self.iter.next().map(Slot::as_pair) } } impl<'a, K, V> DoubleEndedIterator for Iter<'a, K, V> { fn next_back(&mut self) -> Option { self.iter.next_back().map(Slot::as_pair) } } impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> { fn len(&self) -> usize { self.iter.len() } } impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} /// A mutable iterator over the entries of an [`IndexMap`]. /// /// This `struct` is created by the [`iter_mut`] method on [`IndexMap`]. See its /// documentation for more. /// /// [`iter_mut`]: IndexMap::iter_mut #[derive(Debug)] pub struct IterMut<'a, K, V> { iter: SliceIterMut<'a, Slot>, } impl<'a, K, V> Iterator for IterMut<'a, K, V> { type Item = (&'a K, &'a mut V); fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } fn count(self) -> usize { self.iter.count() } fn next(&mut self) -> Option { self.iter.next().map(Slot::as_pair_mut) } } impl<'a, K, V> DoubleEndedIterator for IterMut<'a, K, V> { fn next_back(&mut self) -> Option { self.iter.next_back().map(Slot::as_pair_mut) } } impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> { fn len(&self) -> usize { self.iter.len() } } impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} /// An owning iterator over the entries of a [`IndexMap`]. /// /// This `struct` is created by the [`into_iter`] method on [`IndexMap`] /// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter /// [`IntoIterator`]: core::iter::IntoIterator #[derive(Debug)] pub struct IntoIter { iter: VecIntoIter>, } impl Iterator for IntoIter { type Item = (K, V); fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } fn count(self) -> usize { self.iter.count() } fn next(&mut self) -> Option { self.iter.next().map(Slot::into_pair) } } impl DoubleEndedIterator for IntoIter { fn next_back(&mut self) -> Option { self.iter.next_back().map(Slot::into_pair) } } impl ExactSizeIterator for IntoIter { fn len(&self) -> usize { self.iter.len() } } impl FusedIterator for IntoIter {} /// An iterator over the values of an [`IndexMap`]. /// /// This `struct` is created by the [`values`] method on [`IndexMap`]. See its /// documentation for more. /// /// [`values`]: IndexMap::values #[derive(Debug, Clone)] pub struct Values<'a, K, V> { iter: SliceIter<'a, Slot>, } impl<'a, K, V> Iterator for Values<'a, K, V> { type Item = &'a V; fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } fn count(self) -> usize { self.iter.count() } fn next(&mut self) -> Option { self.iter.next().map(Slot::value) } } impl<'a, K, V> DoubleEndedIterator for Values<'a, K, V> { fn next_back(&mut self) -> Option { self.iter.next_back().map(Slot::value) } } impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { fn len(&self) -> usize { self.iter.len() } } impl<'a, K, V> FusedIterator for Values<'a, K, V> {} /// An iterator over the values of an [`IndexMap`]. /// /// This `struct` is created by the [`values`] method on [`IndexMap`]. See its /// documentation for more. /// /// [`values`]: IndexMap::values #[derive(Debug)] pub struct ValuesMut<'a, K, V> { iter: SliceIterMut<'a, Slot>, } impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { type Item = &'a mut V; fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } fn count(self) -> usize { self.iter.count() } fn next(&mut self) -> Option { self.iter.next().map(Slot::value_mut) } } impl<'a, K, V> DoubleEndedIterator for ValuesMut<'a, K, V> { fn next_back(&mut self) -> Option { self.iter.next_back().map(Slot::value_mut) } } impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { fn len(&self) -> usize { self.iter.len() } } impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} /// A view into a single entry in a map, which may either be vacant or occupied. /// /// This `enum` is constructed from the [`entry`] method on [`IndexMap`]. /// /// [`entry`]: IndexMap::entry pub enum Entry<'a, K, V> { /// A vacant entry. Vacant(VacantEntry<'a, K, V>), /// An occupied entry. Occupied(OccupiedEntry<'a, K, V>), } impl<'a, K: Ord, V> Entry<'a, K, V> { /// Ensures a value is in the entry by inserting the default if empty, /// and returns a mutable reference to the value in the entry. pub fn or_insert(self, default: V) -> &'a mut V where K: Clone, { match self { Self::Occupied(entry) => entry.into_mut(), Self::Vacant(entry) => entry.insert(default), } } /// Ensures a value is in the entry by inserting the result /// of the default function if empty, /// and returns a mutable reference to the value in the entry. pub fn or_insert_with V>(self, default: F) -> &'a mut V where K: Clone, { match self { Self::Occupied(entry) => entry.into_mut(), Self::Vacant(entry) => entry.insert(default()), } } /// Ensures a value is in the entry by inserting, /// if empty, the result of the default function. /// /// This method allows for generating key-derived values for /// insertion by providing the default function a reference /// to the key that was moved during the `.entry(key)` method call. /// /// The reference to the moved key is provided /// so that cloning or copying the key is /// unnecessary, unlike with `.or_insert_with(|| ... )`. pub fn or_insert_with_key V>(self, default: F) -> &'a mut V where K: Clone, { match self { Self::Occupied(entry) => entry.into_mut(), Self::Vacant(entry) => { let value = default(entry.key()); entry.insert(value) } } } /// Returns a reference to this entry’s key. pub fn key(&self) -> &K { match *self { Self::Occupied(ref entry) => entry.key(), Self::Vacant(ref entry) => entry.key(), } } /// Provides in-place mutable access to an occupied entry /// before any potential inserts into the map. pub fn and_modify(self, f: F) -> Self where F: FnOnce(&mut V), { match self { Self::Occupied(mut entry) => { f(entry.get_mut()); Self::Occupied(entry) } Self::Vacant(entry) => Self::Vacant(entry), } } } impl<'a, K, V> Entry<'a, K, V> where K: Ord + Clone, V: Default, { /// Ensures a value is in the entry by inserting the default value if empty, /// and returns a mutable reference to the value in the entry. pub fn or_default(self) -> &'a mut V { match self { Self::Occupied(entry) => entry.into_mut(), Self::Vacant(entry) => entry.insert(Default::default()), } } } impl<'a, K, V> fmt::Debug for Entry<'a, K, V> where K: fmt::Debug + Ord, V: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Entry::Vacant(entry) => entry.fmt(f), Entry::Occupied(entry) => entry.fmt(f), } } } /// A view into a vacant entry in an [`IndexMap`]. It is part of the [`Entry`] `enum`. pub struct VacantEntry<'a, K, V> { /// The underlying vacant entry. vacant: btree_map::VacantEntry<'a, K, SlotIndex>, /// The vector that stores all slots. slots: &'a mut Vec>, } impl<'a, K, V> VacantEntry<'a, K, V> where K: Ord, { /// Gets a reference to the key that would be used when inserting a value through the VacantEntry. pub fn key(&self) -> &K { self.vacant.key() } /// Take ownership of the key. pub fn into_key(self) -> K { self.vacant.into_key() } /// Sets the value of the entry with the `VacantEntry`’s key, /// and returns a mutable reference to it. pub fn insert(self, value: V) -> &'a mut V where K: Clone, { let index = self.slots.len(); let key = self.vacant.key().clone(); self.vacant.insert(SlotIndex(index)); self.slots.push(Slot::new(key, value)); &mut self.slots[index].value } } impl<'a, K, V> fmt::Debug for VacantEntry<'a, K, V> where K: fmt::Debug + Ord, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("VacantEntry") .field("key", self.key()) .finish() } } /// A view into an occupied entry in a [`IndexMap`]. It is part of the [`Entry`] `enum`. pub struct OccupiedEntry<'a, K, V> { /// The underlying occupied entry. occupied: btree_map::OccupiedEntry<'a, K, SlotIndex>, /// The vector that stores all slots. slots: &'a mut Vec>, } impl<'a, K, V> OccupiedEntry<'a, K, V> where K: Ord, { /// Gets a reference to the key in the entry. pub fn key(&self) -> &K { self.occupied.key() } /// Gets a reference to the value in the entry. pub fn get(&self) -> &V { let index = self.occupied.get().index(); &self.slots[index].value } /// Gets a mutable reference to the value in the entry. /// /// If you need a reference to the `OccupiedEntry` that may outlive the /// destruction of the `Entry` value, see [`into_mut`]. /// /// [`into_mut`]: OccupiedEntry::into_mut pub fn get_mut(&mut self) -> &mut V { let index = self.occupied.get().index(); &mut self.slots[index].value } /// Converts the entry into a mutable reference to its value. /// /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. /// /// [`get_mut`]: OccupiedEntry::get_mut pub fn into_mut(self) -> &'a mut V { let index = self.occupied.get().index(); &mut self.slots[index].value } /// Sets the value of the entry with the `OccupiedEntry`’s key, /// and returns the entry’s old value. pub fn insert(&mut self, value: V) -> V where K: Clone, { let index = self.occupied.get().index(); let key = self.key().clone(); let new_slot = Slot::new(key, value); let old_slot = replace(&mut self.slots[index], new_slot); old_slot.value } } impl<'a, K, V> fmt::Debug for OccupiedEntry<'a, K, V> where K: fmt::Debug + Ord, V: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedEntry") .field("key", self.key()) .field("value", self.get()) .finish() } } indexmap-nostd-0.4.0/src/serde.rs000064400000000000000000000065641046102023000150310ustar 00000000000000use crate::IndexMap; use core::fmt::{self, Formatter}; use core::marker::PhantomData; use serde::de::value::{MapDeserializer, SeqDeserializer}; use serde::de::{ Deserialize, Deserializer, Error, IntoDeserializer, MapAccess, SeqAccess, Visitor, }; use serde::ser::{Serialize, Serializer}; /// Requires crate feature `"serde"` impl Serialize for IndexMap where K: Serialize + Ord, V: Serialize, { fn serialize(&self, serializer: T) -> Result where T: Serializer, { serializer.collect_map(self) } } struct IndexMapVisitor(PhantomData<(K, V)>); impl<'de, K, V> Visitor<'de> for IndexMapVisitor where K: Deserialize<'de> + Ord + Clone, V: Deserialize<'de>, { type Value = IndexMap; fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { write!(formatter, "a map") } fn visit_map(self, mut map: A) -> Result where A: MapAccess<'de>, { let mut values = IndexMap::with_capacity(map.size_hint().unwrap_or(0)); while let Some((key, value)) = map.next_entry()? { values.insert(key, value); } Ok(values) } } /// Requires crate feature `"serde"` impl<'de, K, V> Deserialize<'de> for IndexMap where K: Deserialize<'de> + Ord + Clone, V: Deserialize<'de>, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_map(IndexMapVisitor(PhantomData)) } } impl<'de, K, V, E> IntoDeserializer<'de, E> for IndexMap where K: IntoDeserializer<'de, E> + Ord, V: IntoDeserializer<'de, E>, E: Error, { type Deserializer = MapDeserializer<'de, ::IntoIter, E>; fn into_deserializer(self) -> Self::Deserializer { MapDeserializer::new(self.into_iter()) } } use crate::IndexSet; /// Requires crate feature `"serde"` impl Serialize for IndexSet where T: Serialize + Ord, { fn serialize(&self, serializer: Se) -> Result where Se: Serializer, { serializer.collect_seq(self) } } struct IndexSetVisitor(PhantomData); impl<'de, T> Visitor<'de> for IndexSetVisitor where T: Deserialize<'de> + Ord + Clone, { type Value = IndexSet; fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { write!(formatter, "a set") } fn visit_seq(self, mut seq: A) -> Result where A: SeqAccess<'de>, { let mut values = IndexSet::with_capacity(seq.size_hint().unwrap_or(0)); while let Some(value) = seq.next_element()? { values.insert(value); } Ok(values) } } /// Requires crate feature `"serde"` impl<'de, T> Deserialize<'de> for IndexSet where T: Deserialize<'de> + Ord + Clone, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_seq(IndexSetVisitor(PhantomData)) } } impl<'de, T, E> IntoDeserializer<'de, E> for IndexSet where T: IntoDeserializer<'de, E> + Ord, E: Error, { type Deserializer = SeqDeserializer<::IntoIter, E>; fn into_deserializer(self) -> Self::Deserializer { SeqDeserializer::new(self.into_iter()) } } indexmap-nostd-0.4.0/src/serde_seq.rs000064400000000000000000000057241046102023000156760ustar 00000000000000//! Functions to serialize and deserialize an [`IndexMap`] as an ordered sequence. //! //! The default `serde` implementation serializes `IndexMap` as a normal map, //! but there is no guarantee that serialization formats will preserve the order //! of the key-value pairs. This module serializes `IndexMap` as a sequence of //! `(key, value)` elements instead, in order. //! //! This module may be used in a field attribute for derived implementations: //! //! ``` //! # use indexmap_nostd::IndexMap; //! # use serde_derive::{Deserialize, Serialize}; //! #[derive(Deserialize, Serialize)] //! struct Data { //! #[serde(with = "indexmap_nostd::serde_seq")] //! map: IndexMap, //! // ... //! } //! ``` //! //! Requires crate feature `"serde"`. use crate::IndexMap; use core::fmt::{self, Formatter}; use core::marker::PhantomData; use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; use serde::ser::{Serialize, Serializer}; /// Serializes an [`IndexMap`] as an ordered sequence. /// /// This function may be used in a field attribute for deriving `Serialize`: /// /// ``` /// # use indexmap_nostd::IndexMap; /// # use serde_derive::Serialize; /// #[derive(Serialize)] /// struct Data { /// #[serde(serialize_with = "indexmap_nostd::serde_seq::serialize")] /// map: IndexMap, /// // ... /// } /// ``` /// /// Requires crate feature `"serde"`. pub fn serialize(map: &IndexMap, serializer: T) -> Result where K: Serialize + Ord, V: Serialize, T: Serializer, { serializer.collect_seq(map) } /// Visitor to deserialize a *sequenced* [`IndexMap`]. struct SeqVisitor(PhantomData<(K, V)>); impl<'de, K, V> Visitor<'de> for SeqVisitor where K: Deserialize<'de> + Ord + Clone, V: Deserialize<'de>, { type Value = IndexMap; fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { write!(formatter, "a sequenced map") } fn visit_seq(self, mut seq: A) -> Result where A: SeqAccess<'de>, { let capacity = seq.size_hint().unwrap_or(0); let mut map = IndexMap::with_capacity(capacity); while let Some((key, value)) = seq.next_element()? { map.insert(key, value); } Ok(map) } } /// Deserializes an [`IndexMap`] from an ordered sequence. /// /// This function may be used in a field attribute for deriving `Deserialize`: /// /// ``` /// # use indexmap_nostd::IndexMap; /// # use serde_derive::Deserialize; /// #[derive(Deserialize)] /// struct Data { /// #[serde(deserialize_with = "indexmap_nostd::serde_seq::deserialize")] /// map: IndexMap, /// // ... /// } /// ``` /// /// Requires crate feature `"serde"`. pub fn deserialize<'de, D, K, V>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, K: Deserialize<'de> + Ord + Clone, V: Deserialize<'de>, { deserializer.deserialize_seq(SeqVisitor(PhantomData)) } indexmap-nostd-0.4.0/src/set.rs000064400000000000000000000246431046102023000145200ustar 00000000000000//! An ordered set based on a B-Tree that keeps insertion order of elements. use super::SlotIndex; use alloc::collections::{btree_map, BTreeMap}; use alloc::vec::IntoIter as VecIntoIter; use alloc::vec::Vec; use core::borrow::Borrow; use core::iter::FusedIterator; use core::ops::Index; use core::slice::Iter as SliceIter; /// A b-tree set where the iteration order of the values /// is independent of the ordering of the values. /// /// The interface is closely compatible with the [`indexmap` crate] /// and a subset of the features that is relevant for the /// [`wasmparser-nostd` crate]. /// /// # Differences to original `IndexSet` /// /// Since the goal of this crate was to maintain a simple /// `no_std` compatible fork of the [`indexmap` crate] there are some /// downsides and differences. /// /// - Some operations such as `IndexSet::insert` now require `K: Clone`. /// - It is to be expected that this fork performs worse than the original /// [`indexmap` crate] implementation. /// - The implementation is based on `BTreeMap` internally instead of /// `HashMap` which has the effect that methods no longer require `K: Hash` /// but `K: Ord` instead. /// /// [`indexmap` crate]: https://crates.io/crates/indexmap /// [`wasmparser-nostd` crate]: https://crates.io/crates/wasmparser-nostd #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct IndexSet { /// A mapping from keys to slot indices. key2slot: BTreeMap, /// A vector holding all keys. slots: Vec, } impl Default for IndexSet { fn default() -> Self { Self::new() } } impl IndexSet { /// Makes a new, empty `IndexSet`. /// /// Does not allocate anything on its own. pub fn new() -> Self { Self { key2slot: BTreeMap::new(), slots: Vec::new(), } } /// Constructs a new, empty [`IndexSet`] with at least the specified capacity. /// /// Does not allocate if `capacity` is zero. pub fn with_capacity(capacity: usize) -> Self { Self { key2slot: BTreeMap::new(), slots: Vec::with_capacity(capacity), } } /// Reserve capacity for at least `additional` more values. pub fn reserve(&mut self, additional: usize) { self.slots.reserve(additional); } /// Returns the number of elements in the set. pub fn len(&self) -> usize { self.slots.len() } /// Returns `true` if the set contains no elements. pub fn is_empty(&self) -> bool { self.len() != 0 } /// Returns `true` if `self` has no elements in common with `other`. /// This is equivalent to checking for an empty intersection. pub fn is_disjoint(&self, other: &Self) -> bool where T: Ord, { self.iter().all(|value| !other.contains(value)) && other.iter().all(|value| !self.contains(value)) } /// Returns `true` if the set is a subset of another, /// i.e., `other` contains at least all the elements in `self`. pub fn is_subset(&self, other: &Self) -> bool where T: Ord, { self.iter().all(|value| other.contains(value)) } /// Returns `true` if the set is a superset of another, /// i.e., `self` contains at least all the elements in `other`. pub fn is_superset(&self, other: &Self) -> bool where T: Ord, { other.is_subset(self) } /// Returns `true` if the set contains an element equal to the value. /// /// The value may be any borrowed form of the set's element type, /// but the ordering on the borrowed form *must* match the /// ordering on the element type. pub fn contains(&self, key: &Q) -> bool where T: Borrow + Ord, Q: Ord, { self.key2slot.contains_key(key) } /// Returns a reference to the element in the set, if any, that is equal to /// the value. /// /// The value may be any borrowed form of the set's element type, /// but the ordering on the borrowed form *must* match the /// ordering on the element type. pub fn get(&self, value: &Q) -> Option<&T> where T: Borrow + Ord, Q: Ord, { self.key2slot .get(value) .map(|index| &self.slots[index.index()]) } /// Returns the index-value pair corresponding to the supplied value. /// /// The supplied key may be any borrowed form of the map's key type, /// but the ordering on the borrowed form *must* match the ordering /// on the key type. pub fn get_full(&self, key: &Q) -> Option<(usize, &T)> where T: Borrow + Ord, Q: Ord, { self.key2slot .get_key_value(key) .map(|(key, slot)| (slot.index(), key)) } /// Returns the unique index corresponding to the supplied value. /// /// The supplied key may be any borrowed form of the map's key type, /// but the ordering on the borrowed form *must* match the ordering /// on the key type. pub fn get_index_of(&self, key: &Q) -> Option where T: Borrow + Ord, Q: Ord, { self.key2slot.get(key).copied().map(SlotIndex::index) } /// Returns a shared reference to the value at the given index. pub fn get_index(&self, index: usize) -> Option<&T> { self.slots.get(index) } /// Adds a value to the set. /// /// Returns whether the value was newly inserted. That is: /// /// - If the set did not previously contain an equal value, `true` is /// returned. /// - If the set already contained an equal value, `false` is returned, and /// the entry is not updated. pub fn insert(&mut self, value: T) -> bool where T: Ord + Clone, { let (_index, inserted) = self.insert_full(value); inserted } /// Adds a value to the set. /// /// Returns the unique index to the value as well as a `bool` flag telling /// whether the value was newly inserted. That is: /// /// - If the set did not previously contain an equal value, `true` is /// returned. /// - If the set already contained an equal value, `false` is returned, and /// the entry is not updated. pub fn insert_full(&mut self, value: T) -> (usize, bool) where T: Ord + Clone, { match self.key2slot.entry(value.clone()) { btree_map::Entry::Vacant(entry) => { let index = self.slots.len(); entry.insert(SlotIndex(index)); self.slots.push(value); (index, true) } btree_map::Entry::Occupied(entry) => { let index = entry.get().index(); self.slots[index] = value; (index, false) } } } /// Gets an iterator that visits the elements in the [`IndexSet`] /// in the order in which they have been inserted into the set unless /// there have been removals. pub fn iter(&self) -> Iter { Iter { iter: self.slots.iter(), } } /// Clears the set, removing all elements. pub fn clear(&mut self) { self.key2slot.clear(); self.slots.clear(); } } impl Index for IndexSet { type Output = T; fn index(&self, index: usize) -> &Self::Output { self.get_index(index) .expect("IndexSet: index out of bounds") } } impl<'a, T> Extend<&'a T> for IndexSet where T: Ord + Copy, { #[allow(clippy::map_clone)] // lifetime issue: seems to be a clippy bug fn extend(&mut self, iter: I) where I: IntoIterator, { self.extend(iter.into_iter().map(|value| *value)) } } impl Extend for IndexSet where T: Ord + Clone, { fn extend(&mut self, iter: I) where I: IntoIterator, { iter.into_iter().for_each(move |value| { self.insert(value); }); } } impl FromIterator for IndexSet where T: Ord + Clone, { fn from_iter(iter: I) -> Self where I: IntoIterator, { let mut set = IndexSet::new(); set.extend(iter); set } } impl From<[T; N]> for IndexSet where T: Ord + Clone, { fn from(items: [T; N]) -> Self { items.into_iter().collect() } } impl<'a, T> IntoIterator for &'a IndexSet { type Item = &'a T; type IntoIter = Iter<'a, T>; fn into_iter(self) -> Self::IntoIter { self.iter() } } impl IntoIterator for IndexSet { type Item = T; type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { IntoIter { iter: self.slots.into_iter(), } } } /// An iterator over the items of a [`IndexSet`]. /// /// This `struct` is created by the [`iter`] method on [`IndexSet`]. /// /// [`iter`]: IndexSet::iter #[derive(Debug, Clone)] pub struct Iter<'a, T> { iter: SliceIter<'a, T>, } impl<'a, T> Iterator for Iter<'a, T> { type Item = &'a T; fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } fn count(self) -> usize { self.iter.count() } fn next(&mut self) -> Option { self.iter.next() } } impl<'a, T> DoubleEndedIterator for Iter<'a, T> { fn next_back(&mut self) -> Option { self.iter.next_back() } } impl<'a, T> ExactSizeIterator for Iter<'a, T> { fn len(&self) -> usize { self.iter.len() } } impl<'a, T> FusedIterator for Iter<'a, T> {} /// An owning iterator over the items of a [`IndexSet`]. /// /// This `struct` is created by the [`into_iter`] method on [`IndexSet`] /// (provided by the [`IntoIterator`] trait). /// /// [`into_iter`]: IntoIterator::into_iter /// [`IntoIterator`]: core::iter::IntoIterator #[derive(Debug)] pub struct IntoIter { iter: VecIntoIter, } impl Iterator for IntoIter { type Item = T; fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } fn count(self) -> usize { self.iter.count() } fn next(&mut self) -> Option { self.iter.next() } } impl DoubleEndedIterator for IntoIter { fn next_back(&mut self) -> Option { self.iter.next_back() } } impl ExactSizeIterator for IntoIter { fn len(&self) -> usize { self.iter.len() } } impl FusedIterator for IntoIter {}