wasmi_collections-1.0.9/.cargo_vcs_info.json0000644000000001601046102023000146000ustar { "git": { "sha1": "61ba65e6563d8b2f5b699b018349d3330b28b9f3" }, "path_in_vcs": "crates/collections" }wasmi_collections-1.0.9/Cargo.lock0000644000000046741046102023000125710ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "foldhash" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "hashbrown" version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" dependencies = [ "foldhash", ] [[package]] name = "proc-macro2" version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] [[package]] name = "serde" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", ] [[package]] name = "serde_core" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "string-interner" version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23de088478b31c349c9ba67816fa55d9355232d63c3afea8bf513e31f0f1d2c0" dependencies = [ "hashbrown", "serde", ] [[package]] name = "syn" version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "wasmi_collections" version = "1.0.9" dependencies = [ "hashbrown", "string-interner", ] wasmi_collections-1.0.9/Cargo.toml0000644000000032051046102023000126010ustar # 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" rust-version = "1.86" name = "wasmi_collections" version = "1.0.9" authors = ["Robin Freyler "] build = false exclude = ["tests"] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Specialized data structures for the Wasmi interpreter" documentation = "https://docs.rs/wasmi_collections/" readme = "README.md" keywords = [ "wasm", "webassembly", "interpreter", "vm", ] categories = [ "wasm", "no-std", "virtualization", ] license = "MIT/Apache-2.0" repository = "https://github.com/wasmi-labs/wasmi" [package.metadata.cargo-udeps.ignore] normal = ["string-interner"] [features] default = ["std"] hash-collections = [ "dep:hashbrown", "dep:string-interner", ] prefer-btree-collections = [] std = ["string-interner?/std"] [lib] name = "wasmi_collections" path = "src/lib.rs" [dependencies.hashbrown] version = "0.15.1" features = [ "default-hasher", "inline-more", ] optional = true default-features = false [dependencies.string-interner] version = "0.19" features = [ "inline-more", "backends", ] optional = true default-features = false wasmi_collections-1.0.9/Cargo.toml.orig000064400000000000000000000036101046102023000162400ustar 00000000000000[package] name = "wasmi_collections" version.workspace = true rust-version.workspace = true documentation = "https://docs.rs/wasmi_collections/" description = "Specialized data structures for the Wasmi interpreter" authors.workspace = true repository.workspace = true edition.workspace = true readme.workspace = true license.workspace = true keywords.workspace = true categories.workspace = true exclude.workspace = true [dependencies] hashbrown = { version = "0.15.1", default-features = false, optional = true, features = ["default-hasher", "inline-more"] } string-interner = { version = "0.19", default-features = false, optional = true, features = ["inline-more", "backends"] } [features] default = ["std"] std = ["string-interner?/std"] # Hash collections usage: # # - Enable `hash-collections` to make use of hash-based collections in `wasmi_collections`. # - Enable `prefer-btree-collections` to still use btree-based collections even when # the `hash-collections` crate feature is enabled. # # Note: # # - Not enabling `hash-collections` allows `wasmi_collections` to drop lots of # hash-based dependencies and thus decrease compilation times significantly. # - Btree-based collections can be useful for environments without a random source. # # Which collections will be used: # # `hash-collections` | `prefer-btree-collections` | usage # ------------------ | -------------------------- | ------------------- # false | false | btree # true | false | hash # false | true | btree # true | true | btree # hash-collections = [ 'dep:hashbrown', 'dep:string-interner', ] prefer-btree-collections = [] [package.metadata.cargo-udeps.ignore] normal = [ # Needed to suppress weird `udep` warnings. Maybe a `cargo-udep` bug? "string-interner" ] wasmi_collections-1.0.9/README.md000064400000000000000000000247611046102023000146420ustar 00000000000000 | Continuous Integration | Test Coverage | Documentation | Crates.io | |:----------------------:|:--------------------:|:----------------:|:--------------------:| | [![ci][1]][2] | [![codecov][3]][4] | [![docs][5]][6] | [![crates][7]][8] | [1]: https://github.com/wasmi-labs/wasmi/actions/workflows/rust.yml/badge.svg [2]: https://github.com/wasmi-labs/wasmi/actions/workflows/rust.yml [3]: https://codecov.io/gh/wasmi-labs/wasmi/branch/main/badge.svg [4]: https://codecov.io/gh/wasmi-labs/wasmi/branch/main [5]: https://docs.rs/wasmi/badge.svg [6]: https://docs.rs/wasmi [7]: https://img.shields.io/crates/v/wasmi.svg [8]: https://crates.io/crates/wasmi [license-mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg [license-apache-badge]: https://img.shields.io/badge/license-APACHE-orange.svg # Wasmi - WebAssembly (Wasm) Interpreter

Wasmi is an efficient and lightweight WebAssembly interpreter with a focus on constrained and embedded systems. ## Distinct Features - Simple, correct and deterministic execution of WebAssembly. - Efficient and cross-platform WebAssembly runtime for [`no_std` embedded environments](https://doc.rust-lang.org/stable/rustc/platform-support.html). - Compiler/JIT bomb resisting translation. - Loosely mirrors the [Wasmtime API](https://docs.rs/wasmtime/) to act as drop-in replacement. - 100% WebAssembly spec testsuite compliance. - Built-in support for fuel metering. - Supports the official [Wasm C-API](https://github.com/WebAssembly/wasm-c-api). ## Security Audits Wasmi is suitable for safety critical use cases and has been audited twice. | Wasmi Version(s) | Auditor | Contractor | Report | |--:|:--|:--|:--| | `0.36.0`-`0.38.0` | [Runtime Verification Inc.] | [Stellar Development Foundation] | [PDF](./resources/audit-2024-11-27.pdf) | | `0.31.0` | [SRLabs] | [Parity Technologies] | [PDF](./resources/audit-2023-12-20.pdf) | [Wasmtime]: https://github.com/bytecodealliance/wasmtime [SRLabs]: https://www.srlabs.de/ [Runtime Verification Inc.]: https://runtimeverification.com/ [Stellar Development Foundation]: https://stellar.org/foundation [Parity Technologies]: https://www.parity.io/ ## Docs - 📖 [Usage Guide](./docs/usage.md): learn how to use the [Wasmi API](https://crates.io/crates/wasmi) properly. - 🛠️ [Development Guide](./docs/developement.md): learn how to develop for Wasmi. - ✨ [Crate Features](https://docs.rs/wasmi/latest/wasmi/#crate-features): learn about `wasmi` crate features. ## WebAssembly Features | | WebAssembly Proposal | | | | WebAssembly Proposal | | |:-:|:--|:--|:-:|:--|:--|:--| | ✅ | [`mutable-global`] | ≥ `0.14.0` | | ✅ | [`custom-page-sizes`] | [≥ `0.41.0`][(#1197)] | | ✅ | [`saturating-float-to-int`] | ≥ `0.14.0` | | ✅ | [`memory64`] | [≥ `0.41.0`][(#1357)] | | ✅ | [`sign-extension`] | ≥ `0.14.0` | | ✅ | [`wide-arithmetic`] | [≥ `0.42.0`][(#1369)] | | ✅ | [`multi-value`] | ≥ `0.14.0` | | ✅ | [`simd`] | [≥ `0.43.0`][(#1364)] | | ✅ | [`bulk-memory`] | [≥ `0.24.0`][(#628)] | | ✅ | [`relaxed-simd`] | [≥ `0.44.0`][(#1443)] | | ✅ | [`reference-types`] | [≥ `0.24.0`][(#635)] | | 📅 | [`function-references`] | [Tracking Issue][(#774)] | | ✅ | [`tail-calls`] | [≥ `0.28.0`][(#683)] | | 📅 | [`gc`] | [Tracking Issue][(#775)] | | ✅ | [`extended-const`] | [≥ `0.29.0`][(#707)] | | 📅 | [`threads`] | [Tracking Issue][(#777)] | | ✅ | [`multi-memory`] | [≥ `0.37.0`][(#1191)] | | 📅 | [`exception-handling`] | [Tracking Issue][(#1037)] | | | Embeddings | | |:-:|:--|:--| | ✅ | [WASI] | WASI (`wasip1`) support via the [`wasmi_wasi` crate]. | | ✅ | [C-API] | Official Wasm C-API support via the [`wasmi_c_api_impl` crate]. | [`mutable-global`]: https://github.com/WebAssembly/mutable-global [`saturating-float-to-int`]: https://github.com/WebAssembly/nontrapping-float-to-int-conversions [`sign-extension`]: https://github.com/WebAssembly/sign-extension-ops [`multi-value`]: https://github.com/WebAssembly/multi-value [`reference-types`]: https://github.com/WebAssembly/reference-types [`bulk-memory`]: https://github.com/WebAssembly/bulk-memory-operations [`simd` ]: https://github.com/webassembly/simd [`tail-calls`]: https://github.com/WebAssembly/tail-call [`extended-const`]: https://github.com/WebAssembly/extended-const [`function-references`]: https://github.com/WebAssembly/function-references [`gc`]: https://github.com/WebAssembly/gc [`multi-memory`]: https://github.com/WebAssembly/multi-memory [`threads`]: https://github.com/WebAssembly/threads [`relaxed-simd`]: https://github.com/WebAssembly/relaxed-simd [`exception-handling`]: https://github.com/WebAssembly/exception-handling [`custom-page-sizes`]: https://github.com/WebAssembly/custom-page-sizes [`memory64`]: https://github.com/WebAssembly/memory64 [`wide-arithmetic`]: https://github.com/WebAssembly/wide-arithmetic [WASI]: https://github.com/WebAssembly/WASI [C-API]: https://github.com/WebAssembly/wasm-c-api [`wasmi_wasi` crate]: ./crates/wasi [`wasmi_c_api_impl` crate]: ./crates/c_api [(#363)]: https://github.com/wasmi-labs/wasmi/issues/363 [(#364)]: https://github.com/wasmi-labs/wasmi/issues/364 [(#496)]: https://github.com/wasmi-labs/wasmi/issues/496 [(#628)]: https://github.com/wasmi-labs/wasmi/pull/628 [(#635)]: https://github.com/wasmi-labs/wasmi/pull/635 [(#638)]: https://github.com/wasmi-labs/wasmi/pull/638 [(#683)]: https://github.com/wasmi-labs/wasmi/pull/683 [(#707)]: https://github.com/wasmi-labs/wasmi/pull/707 [(#774)]: https://github.com/wasmi-labs/wasmi/pull/774 [(#775)]: https://github.com/wasmi-labs/wasmi/pull/775 [(#776)]: https://github.com/wasmi-labs/wasmi/pull/776 [(#777)]: https://github.com/wasmi-labs/wasmi/pull/777 [(#1037)]: https://github.com/wasmi-labs/wasmi/issues/1137 [(#1197)]: https://github.com/wasmi-labs/wasmi/issues/1197 [(#1191)]: https://github.com/wasmi-labs/wasmi/issues/1191 [(#1357)]: https://github.com/wasmi-labs/wasmi/issues/1357 [(#1364)]: https://github.com/wasmi-labs/wasmi/issues/1364 [(#1369)]: https://github.com/wasmi-labs/wasmi/issues/1369 [(#1443)]: https://github.com/wasmi-labs/wasmi/pull/1443 ## Used by If you want your project on this list [please inform me](mailto:robin.freyler@gmail.com) about you project and how Wasmi is used. Stellar Soroban   Wasmer   Firefly Zero   Typst   Orbitinghail   Smoldot   Munal OS   icu4x   Ayaka   Project Oak   ## Sponsors Special thanks to the past and present sponsors of the Wasmi project.
Sponsoring since Oct. 2024
Sponsored until Oct. 2024
## License Licensed under either of * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) * MIT license ([LICENSE-MIT](LICENSE-MIT) or ) at your option. ## Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. wasmi_collections-1.0.9/src/arena/component_vec.rs000064400000000000000000000146231046102023000204410ustar 00000000000000use crate::arena::ArenaIndex; use alloc::vec::Vec; use core::{ fmt::{self, Debug}, marker::PhantomData, ops::{Index, IndexMut}, }; /// Stores components for entities backed by a [`Vec`]. pub struct ComponentVec { components: Vec>, marker: PhantomData Idx>, } /// [`ComponentVec`] does not store `Idx` therefore it is `Send` without its bound. unsafe impl Send for ComponentVec where T: Send {} /// [`ComponentVec`] does not store `Idx` therefore it is `Sync` without its bound. unsafe impl Sync for ComponentVec where T: Sync {} impl Debug for ComponentVec where T: Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ComponentVec") .field("components", &DebugComponents(&self.components)) .finish() } } struct DebugComponents<'a, T>(&'a [Option]); impl Debug for DebugComponents<'_, T> where T: Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut map = f.debug_map(); let components = self .0 .iter() .enumerate() .filter_map(|(n, component)| component.as_ref().map(|c| (n, c))); for (idx, component) in components { map.entry(&idx, component); } map.finish() } } impl Default for ComponentVec { #[inline] fn default() -> Self { Self::new() } } impl PartialEq for ComponentVec where T: PartialEq, { #[inline] fn eq(&self, other: &Self) -> bool { self.components.eq(&other.components) } } impl Eq for ComponentVec where T: Eq {} impl ComponentVec { /// Creates a new empty [`ComponentVec`]. #[inline] pub fn new() -> Self { Self { components: Vec::new(), marker: PhantomData, } } /// Clears all components from the [`ComponentVec`]. #[inline] pub fn clear(&mut self) { self.components.clear(); } } impl ComponentVec where Idx: ArenaIndex, { /// Sets the `component` for the entity at `index`. /// /// Returns the old component of the same entity if any. pub fn set(&mut self, index: Idx, component: T) -> Option { let index = index.into_usize(); if index >= self.components.len() { // The underlying vector does not have enough capacity // and is required to be enlarged. self.components.resize_with(index + 1, || None); } self.components[index].replace(component) } /// Unsets the component for the entity at `index` and returns it if any. #[inline] pub fn unset(&mut self, index: Idx) -> Option { self.components .get_mut(index.into_usize()) .and_then(Option::take) } /// Returns a shared reference to the component at the `index` if any. /// /// Returns `None` if no component is stored under the `index`. #[inline] pub fn get(&self, index: Idx) -> Option<&T> { self.components .get(index.into_usize()) .and_then(Option::as_ref) } /// Returns an exclusive reference to the component at the `index` if any. /// /// Returns `None` if no component is stored under the `index`. #[inline] pub fn get_mut(&mut self, index: Idx) -> Option<&mut T> { self.components .get_mut(index.into_usize()) .and_then(Option::as_mut) } } impl Index for ComponentVec where Idx: ArenaIndex, { type Output = T; #[inline] fn index(&self, index: Idx) -> &Self::Output { self.get(index) .unwrap_or_else(|| panic!("missing component at index: {}", index.into_usize())) } } impl IndexMut for ComponentVec where Idx: ArenaIndex, { #[inline] fn index_mut(&mut self, index: Idx) -> &mut Self::Output { self.get_mut(index) .unwrap_or_else(|| panic!("missing component at index: {}", index.into_usize())) } } #[cfg(test)] mod tests { use super::*; use std::{format, string::String}; /// Add `n` components and perform checks along the way. fn add_components(vec: &mut ComponentVec, n: usize) { for i in 0..n { let mut str = format!("{i}"); assert!(vec.get(i).is_none()); assert!(vec.get_mut(i).is_none()); assert!(vec.set(i, str.clone()).is_none()); assert_eq!(vec.get(i), Some(&str)); assert_eq!(vec.get_mut(i), Some(&mut str)); assert_eq!(&vec[i], &str); assert_eq!(&mut vec[i], &mut str); } } #[test] fn it_works() { let mut vec = >::new(); let n = 10; add_components(&mut vec, n); // Remove components in reverse order for fun. // Check if components have been removed properly. for i in (0..n).rev() { let str = format!("{i}"); assert_eq!(vec.unset(i), Some(str)); assert!(vec.get(i).is_none()); assert!(vec.get_mut(i).is_none()); } } #[test] fn clear_works() { let mut vec = >::new(); let n = 10; add_components(&mut vec, n); // Clear component vec and check if components have been removed properly. vec.clear(); for i in 0..n { assert!(vec.get(i).is_none()); assert!(vec.get_mut(i).is_none()); } } #[test] fn debug_works() { let mut vec = >::new(); add_components(&mut vec, 4); { let debug_str = format!("{vec:?}"); let expected_str = "\ ComponentVec { components: {0: \"0\", 1: \"1\", 2: \"2\", 3: \"3\"} }\ "; assert_eq!(debug_str, expected_str); } { let debug_str = format!("{vec:#?}"); let expected_str = "\ ComponentVec {\n \ components: {\n \ 0: \"0\",\n \ 1: \"1\",\n \ 2: \"2\",\n \ 3: \"3\",\n \ },\n}\ "; assert_eq!(debug_str, expected_str); } } } wasmi_collections-1.0.9/src/arena/dedup.rs000064400000000000000000000101341046102023000166740ustar 00000000000000use super::{Arena, ArenaIndex, Iter, IterMut}; use crate::{map, Map}; use core::{ hash::Hash, ops::{Index, IndexMut}, }; /// A deduplicating arena allocator with a given index and entity type. /// /// For performance reasons the arena cannot deallocate single entities. #[derive(Debug)] pub struct DedupArena { entity2idx: Map, entities: Arena, } impl Default for DedupArena { #[inline] fn default() -> Self { Self::new() } } impl PartialEq for DedupArena where T: PartialEq, { #[inline] fn eq(&self, other: &Self) -> bool { self.entities.eq(&other.entities) } } impl Eq for DedupArena where T: Eq {} impl DedupArena { /// Creates a new empty deduplicating entity arena. #[inline] pub fn new() -> Self { Self { entity2idx: Map::new(), entities: Arena::new(), } } /// Returns the allocated number of entities. #[inline] pub fn len(&self) -> usize { self.entities.len() } /// Returns `true` if the [`Arena`] has not yet allocated entities. #[inline] pub fn is_empty(&self) -> bool { self.len() == 0 } /// Clears all entities from the arena. #[inline] pub fn clear(&mut self) { self.entity2idx.clear(); self.entities.clear(); } /// Returns an iterator over the shared reference of the [`Arena`] entities. #[inline] pub fn iter(&self) -> Iter<'_, Idx, T> { self.entities.iter() } /// Returns an iterator over the exclusive reference of the [`Arena`] entities. #[inline] pub fn iter_mut(&mut self) -> IterMut<'_, Idx, T> { self.entities.iter_mut() } } impl DedupArena where Idx: ArenaIndex, T: Hash + Ord + Clone, { /// Allocates a new entity and returns its index. /// /// # Note /// /// Only allocates if the entity does not already exist in the [`DedupArena`]. pub fn alloc(&mut self, entity: T) -> Idx { match self.entity2idx.entry(entity.clone()) { map::Entry::Occupied(entry) => *entry.get(), map::Entry::Vacant(entry) => { let index = self.entities.next_index(); self.entities.alloc(entity); entry.insert(index); index } } } /// Returns a shared reference to the entity at the given index if any. #[inline] pub fn get(&self, index: Idx) -> Option<&T> { self.entities.get(index) } /// Returns an exclusive reference to the entity at the given index if any. #[inline] pub fn get_mut(&mut self, index: Idx) -> Option<&mut T> { self.entities.get_mut(index) } } impl FromIterator for DedupArena where Idx: ArenaIndex, T: Hash + Clone + Ord, { fn from_iter(iter: I) -> Self where I: IntoIterator, { let entities = Arena::from_iter(iter); let entity2idx = entities .iter() .map(|(idx, entity)| (entity.clone(), idx)) .collect::>(); Self { entity2idx, entities, } } } impl<'a, Idx, T> IntoIterator for &'a DedupArena where Idx: ArenaIndex, { type Item = (Idx, &'a T); type IntoIter = Iter<'a, Idx, T>; #[inline] fn into_iter(self) -> Self::IntoIter { self.iter() } } impl<'a, Idx, T> IntoIterator for &'a mut DedupArena where Idx: ArenaIndex, { type Item = (Idx, &'a mut T); type IntoIter = IterMut<'a, Idx, T>; #[inline] fn into_iter(self) -> Self::IntoIter { self.iter_mut() } } impl Index for DedupArena where Idx: ArenaIndex, { type Output = T; #[inline] fn index(&self, index: Idx) -> &Self::Output { &self.entities[index] } } impl IndexMut for DedupArena where Idx: ArenaIndex, { #[inline] fn index_mut(&mut self, index: Idx) -> &mut Self::Output { &mut self.entities[index] } } wasmi_collections-1.0.9/src/arena/guarded.rs000064400000000000000000000016741046102023000172170ustar 00000000000000use crate::arena::ArenaIndex; /// A guarded entity. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct GuardedEntity { guard_idx: GuardIdx, entity_idx: EntityIdx, } impl GuardedEntity { /// Creates a new [`GuardedEntity`]. #[inline] pub fn new(guard_idx: GuardIdx, entity_idx: EntityIdx) -> Self { Self { guard_idx, entity_idx, } } } impl GuardedEntity where GuardIdx: ArenaIndex, EntityIdx: ArenaIndex, { /// Returns the entity index of the [`GuardedEntity`]. /// /// Return `None` if the `guard_index` does not match. #[inline] pub fn entity_index(&self, guard_index: GuardIdx) -> Option { if self.guard_idx.into_usize() != guard_index.into_usize() { return None; } Some(self.entity_idx) } } wasmi_collections-1.0.9/src/arena/mod.rs000064400000000000000000000204551046102023000163610ustar 00000000000000//! Fast arena data structures specialized for usage in the Wasmi interpreter. //! //! They cannot deallocate single allocated entities for extra efficiency. //! These data structures mainly serve as the backbone for an efficient WebAssembly //! store, module, instance and engine implementation. mod component_vec; mod dedup; mod guarded; pub use self::{component_vec::ComponentVec, dedup::DedupArena, guarded::GuardedEntity}; use alloc::vec::Vec; use core::{ iter::Enumerate, marker::PhantomData, ops::{Index, IndexMut, Range}, slice, }; /// Types that can be used as indices for arenas. pub trait ArenaIndex: Copy { /// Converts the [`ArenaIndex`] into the underlying `usize` value. fn into_usize(self) -> usize; /// Converts the `usize` value into the associated [`ArenaIndex`]. fn from_usize(value: usize) -> Self; } /// An arena allocator with a given index and entity type. /// /// For performance reasons the arena cannot deallocate single entities. #[derive(Debug)] pub struct Arena { entities: Vec, marker: PhantomData, } /// [`Arena`] does not store `Idx` therefore it is `Send` without its bound. unsafe impl Send for Arena where T: Send {} /// [`Arena`] does not store `Idx` therefore it is `Sync` without its bound. unsafe impl Sync for Arena where T: Sync {} impl Default for Arena { fn default() -> Self { Self::new() } } impl PartialEq for Arena where T: PartialEq, { fn eq(&self, other: &Self) -> bool { self.entities.eq(&other.entities) } } impl Eq for Arena where T: Eq {} impl Arena { /// Creates a new empty entity [`Arena`]. pub fn new() -> Self { Self { entities: Vec::new(), marker: PhantomData, } } /// Returns the allocated number of entities. #[inline] pub fn len(&self) -> usize { self.entities.len() } /// Returns `true` if the arena has not yet allocated entities. #[inline] pub fn is_empty(&self) -> bool { self.len() == 0 } /// Clears all entities from the arena. #[inline] pub fn clear(&mut self) { self.entities.clear(); } /// Returns an iterator over the shared reference of the arena entities. #[inline] pub fn iter(&self) -> Iter<'_, Idx, T> { Iter { iter: self.entities.iter().enumerate(), marker: PhantomData, } } /// Returns an iterator over the exclusive reference of the arena entities. #[inline] pub fn iter_mut(&mut self) -> IterMut<'_, Idx, T> { IterMut { iter: self.entities.iter_mut().enumerate(), marker: PhantomData, } } } impl Arena where Idx: ArenaIndex, { /// Returns the next entity index. fn next_index(&self) -> Idx { Idx::from_usize(self.entities.len()) } /// Allocates a new entity and returns its index. #[inline] pub fn alloc(&mut self, entity: T) -> Idx { let index = self.next_index(); self.entities.push(entity); index } /// Allocates a new default initialized entity and returns its index. #[inline] pub fn alloc_many(&mut self, amount: usize) -> Range where T: Default, { let start = self.next_index(); self.entities .extend(core::iter::repeat_with(T::default).take(amount)); let end = self.next_index(); Range { start, end } } /// Returns a shared reference to the entity at the given index if any. #[inline] pub fn get(&self, index: Idx) -> Option<&T> { self.entities.get(index.into_usize()) } /// Returns an exclusive reference to the entity at the given index if any. #[inline] pub fn get_mut(&mut self, index: Idx) -> Option<&mut T> { self.entities.get_mut(index.into_usize()) } /// Returns an exclusive reference to the pair of entities at the given indices if any. /// /// Returns `None` if `fst` and `snd` refer to the same entity. /// Returns `None` if either `fst` or `snd` is invalid for this [`Arena`]. #[inline] pub fn get_pair_mut(&mut self, fst: Idx, snd: Idx) -> Option<(&mut T, &mut T)> { let fst_index = fst.into_usize(); let snd_index = snd.into_usize(); if fst_index == snd_index { return None; } if fst_index > snd_index { let (fst, snd) = self.get_pair_mut(snd, fst)?; return Some((snd, fst)); } // At this point we know that fst_index < snd_index. let (fst_set, snd_set) = self.entities.split_at_mut(snd_index); let fst = fst_set.get_mut(fst_index)?; let snd = snd_set.get_mut(0)?; Some((fst, snd)) } } impl FromIterator for Arena { #[inline] fn from_iter(iter: I) -> Self where I: IntoIterator, { Self { entities: Vec::from_iter(iter), marker: PhantomData, } } } impl<'a, Idx, T> IntoIterator for &'a Arena where Idx: ArenaIndex, { type Item = (Idx, &'a T); type IntoIter = Iter<'a, Idx, T>; #[inline] fn into_iter(self) -> Self::IntoIter { self.iter() } } impl<'a, Idx, T> IntoIterator for &'a mut Arena where Idx: ArenaIndex, { type Item = (Idx, &'a mut T); type IntoIter = IterMut<'a, Idx, T>; #[inline] fn into_iter(self) -> Self::IntoIter { self.iter_mut() } } /// An iterator over shared references of arena entities and their indices. #[derive(Debug)] pub struct Iter<'a, Idx, T> { iter: Enumerate>, marker: PhantomData Idx>, } impl<'a, Idx, T> Iterator for Iter<'a, Idx, T> where Idx: ArenaIndex, { type Item = (Idx, &'a T); #[inline] fn next(&mut self) -> Option { self.iter .next() .map(|(idx, entity)| (Idx::from_usize(idx), entity)) } #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } } impl DoubleEndedIterator for Iter<'_, Idx, T> where Idx: ArenaIndex, { #[inline] fn next_back(&mut self) -> Option { self.iter .next() .map(|(idx, entity)| (Idx::from_usize(idx), entity)) } } impl ExactSizeIterator for Iter<'_, Idx, T> where Idx: ArenaIndex, { #[inline] fn len(&self) -> usize { self.iter.len() } } /// An iterator over exclusive references of arena entities and their indices. #[derive(Debug)] pub struct IterMut<'a, Idx, T> { iter: Enumerate>, marker: PhantomData Idx>, } impl<'a, Idx, T> Iterator for IterMut<'a, Idx, T> where Idx: ArenaIndex, { type Item = (Idx, &'a mut T); #[inline] fn next(&mut self) -> Option { self.iter .next() .map(|(idx, entity)| (Idx::from_usize(idx), entity)) } #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } } impl DoubleEndedIterator for IterMut<'_, Idx, T> where Idx: ArenaIndex, { #[inline] fn next_back(&mut self) -> Option { self.iter .next() .map(|(idx, entity)| (Idx::from_usize(idx), entity)) } } impl ExactSizeIterator for IterMut<'_, Idx, T> where Idx: ArenaIndex, { #[inline] fn len(&self) -> usize { self.iter.len() } } impl Arena { /// Panics with an index out of bounds message. fn index_out_of_bounds(len: usize, index: usize) -> ! { panic!("index out of bounds: the len is {len} but the index is {index}") } } impl Index for Arena where Idx: ArenaIndex, { type Output = T; #[inline] fn index(&self, index: Idx) -> &Self::Output { self.get(index) .unwrap_or_else(|| Self::index_out_of_bounds(self.len(), index.into_usize())) } } impl IndexMut for Arena where Idx: ArenaIndex, { #[inline] fn index_mut(&mut self, index: Idx) -> &mut Self::Output { let len = self.len(); self.get_mut(index) .unwrap_or_else(|| Self::index_out_of_bounds(len, index.into_usize())) } } wasmi_collections-1.0.9/src/hash.rs000064400000000000000000000057311046102023000154370ustar 00000000000000//! Utilities for hashmap initialization based on random sources. //! //! Inspired by [`wasmparser`](https://crates.io/crates/wasmparser)'s `collections` module. use core::hash::{BuildHasher, Hasher}; /// Wasmi's hashing state stored per-map. /// /// This is DoS-resistant when the `std` feature is activated and still somewhat /// resistant when it's not active but not as secure. #[derive(Clone, Debug)] pub struct RandomState(RandomStateImpl); impl Default for RandomState { #[inline] fn default() -> RandomState { RandomState(RandomStateImpl::default()) } } impl BuildHasher for RandomState { type Hasher = RandomStateHasher; #[inline] fn build_hasher(&self) -> RandomStateHasher { RandomStateHasher(self.0.build_hasher()) } } /// Wasmi's hasher type used with [`RandomState`]. pub struct RandomStateHasher(::Hasher); impl Hasher for RandomStateHasher { #[inline] fn finish(&self) -> u64 { self.0.finish() } #[inline] fn write(&mut self, bytes: &[u8]) { self.0.write(bytes) } #[inline] fn write_u8(&mut self, i: u8) { self.0.write_u8(i) } #[inline] fn write_u16(&mut self, i: u16) { self.0.write_u16(i) } #[inline] fn write_u32(&mut self, i: u32) { self.0.write_u32(i) } #[inline] fn write_u64(&mut self, i: u64) { self.0.write_u64(i) } #[inline] fn write_u128(&mut self, i: u128) { self.0.write_u128(i) } #[inline] fn write_usize(&mut self, i: usize) { self.0.write_usize(i) } #[inline] fn write_i8(&mut self, i: i8) { self.0.write_i8(i) } #[inline] fn write_i16(&mut self, i: i16) { self.0.write_i16(i) } #[inline] fn write_i32(&mut self, i: i32) { self.0.write_i32(i) } #[inline] fn write_i64(&mut self, i: i64) { self.0.write_i64(i) } #[inline] fn write_i128(&mut self, i: i128) { self.0.write_i128(i) } #[inline] fn write_isize(&mut self, i: isize) { self.0.write_isize(i) } } // When the `std` feature is active reuse the standard library's implementation // of hash state and hasher. #[cfg(feature = "std")] use std::collections::hash_map::RandomState as RandomStateImpl; // When the `std` feature is NOT active then rely on `hashbrown`'s `RandomState` // which relies on ASLR by default for randomness. #[derive(Clone, Debug)] #[cfg(not(feature = "std"))] struct RandomStateImpl { state: hashbrown::DefaultHashBuilder, } #[cfg(not(feature = "std"))] impl Default for RandomStateImpl { fn default() -> Self { Self { state: hashbrown::DefaultHashBuilder::default(), } } } #[cfg(not(feature = "std"))] impl BuildHasher for RandomStateImpl { type Hasher = ::Hasher; #[inline] fn build_hasher(&self) -> Self::Hasher { self.state.build_hasher() } } wasmi_collections-1.0.9/src/head_vec.rs000064400000000000000000000036751046102023000162570ustar 00000000000000use alloc::vec::Vec; use core::mem; /// A [`Vec`]-like data structure with fast access to the last item. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct HeadVec { /// The top (or last) item in the [`HeadVec`]. head: Option, /// The rest of the items in the [`HeadVec`] excluding the last item. rest: Vec, } impl Default for HeadVec { #[inline] fn default() -> Self { Self { head: None, rest: Vec::new(), } } } impl HeadVec { /// Removes all items from the [`HeadVec`]. #[inline] pub fn clear(&mut self) { self.head = None; self.rest.clear(); } /// Returns the number of items stored in the [`HeadVec`]. #[inline] pub fn len(&self) -> usize { match self.head { Some(_) => 1 + self.rest.len(), None => 0, } } /// Returns `true` if the [`HeadVec`] contains no items. #[inline] pub fn is_empty(&self) -> bool { self.len() == 0 } /// Returns a shared reference to the last item in the [`HeadVec`] if any. /// /// Returns `None` if the [`HeadVec`] is empty. #[inline] pub fn last(&self) -> Option<&T> { self.head.as_ref() } /// Returns an exclusive reference to the last item in the [`HeadVec`] if any. /// /// Returns `None` if the [`HeadVec`] is empty. #[inline] pub fn last_mut(&mut self) -> Option<&mut T> { self.head.as_mut() } /// Pushes a new `value` onto the [`HeadVec`]. #[inline] pub fn push(&mut self, value: T) { let prev_head = self.head.replace(value); if let Some(prev_head) = prev_head { self.rest.push(prev_head); } } /// Pops the last `value` from the [`HeadVec`] if any. #[inline] pub fn pop(&mut self) -> Option { let new_top = self.rest.pop(); mem::replace(&mut self.head, new_top) } } wasmi_collections-1.0.9/src/lib.rs000064400000000000000000000034631046102023000152620ustar 00000000000000//! Data structures specialized for usage in the Wasmi interpreter. //! //! All data structures provide an API that can be backed by both [`HashMap`] and [`BTreeMap`]. //! Users can choose which kind of backend to operate on via the `no-hash-maps` crate feature. //! //! # Provided Data Structures //! //! - [`Arena`]: typed arena for fast allocations and accesses //! - [`DedupArena`]: typed arena that also deduplicates, based on either [`HashMap`] or [`BTreeMap`] //! - [`ComponentVec`]: useful to add properties to entities stored in an [`Arena`] or [`DedupArena`] //! - [`Map`]: generic set of values, based on either [`HashMap`] or [`BTreeMap`] //! - [`Set`]: generic key-value mapping, based on either [`HashSet`] or [`BTreeSet`] //! - [`StringInterner`]: stores and deduplicates strings efficiently, based on either [`HashSet`] or [`BTreeSet`] //! //! [`HashSet`]: https://docs.rs/hashbrown/0.15.0/hashbrown/struct.HashSet.html //! [`HashMap`]: https://docs.rs/hashbrown/0.15.0/hashbrown/struct.HashMap.html //! [`BTreeSet`]: std::collections::BTreeSet //! [`BTreeMap`]: std::collections::BTreeMap #![no_std] #![warn( clippy::cast_lossless, clippy::missing_errors_doc, clippy::used_underscore_binding, clippy::redundant_closure_for_method_calls, clippy::type_repetition_in_bounds, clippy::inconsistent_struct_constructor, clippy::default_trait_access, clippy::map_unwrap_or, clippy::items_after_statements )] extern crate alloc; #[cfg(feature = "std")] extern crate std; pub mod arena; #[cfg(feature = "hash-collections")] pub mod hash; mod head_vec; pub mod map; pub mod set; pub mod string_interner; #[cfg(test)] mod tests; #[doc(inline)] pub use self::{ arena::{Arena, ComponentVec, DedupArena}, head_vec::HeadVec, map::Map, set::Set, string_interner::StringInterner, }; wasmi_collections-1.0.9/src/map.rs000064400000000000000000000514241046102023000152710ustar 00000000000000//! Type definitions for a default map. use core::{borrow::Borrow, fmt::Debug, hash::Hash, iter::FusedIterator, ops::Index}; #[cfg(all( feature = "hash-collections", not(feature = "prefer-btree-collections") ))] mod detail { use crate::hash; use hashbrown::hash_map; pub type MapImpl = hash_map::HashMap; pub type EntryImpl<'a, K, V> = hash_map::Entry<'a, K, V, hash::RandomState>; pub type OccupiedEntryImpl<'a, K, V> = hash_map::OccupiedEntry<'a, K, V, hash::RandomState>; pub type VacantEntryImpl<'a, K, V> = hash_map::VacantEntry<'a, K, V, hash::RandomState>; pub type IterImpl<'a, K, V> = hash_map::Iter<'a, K, V>; pub type IterMutImpl<'a, K, V> = hash_map::IterMut<'a, K, V>; pub type IntoIterImpl = hash_map::IntoIter; pub type KeysImpl<'a, K, V> = hash_map::Keys<'a, K, V>; pub type ValuesImpl<'a, K, V> = hash_map::Values<'a, K, V>; pub type ValuesMutImpl<'a, K, V> = hash_map::ValuesMut<'a, K, V>; pub type IntoKeysImpl = hash_map::IntoKeys; pub type IntoValuesImpl = hash_map::IntoValues; } #[cfg(any( not(feature = "hash-collections"), feature = "prefer-btree-collections" ))] mod detail { use alloc::collections::btree_map; pub type MapImpl = btree_map::BTreeMap; pub type EntryImpl<'a, K, V> = btree_map::Entry<'a, K, V>; pub type OccupiedEntryImpl<'a, K, V> = btree_map::OccupiedEntry<'a, K, V>; pub type VacantEntryImpl<'a, K, V> = btree_map::VacantEntry<'a, K, V>; pub type IterImpl<'a, K, V> = btree_map::Iter<'a, K, V>; pub type IterMutImpl<'a, K, V> = btree_map::IterMut<'a, K, V>; pub type IntoIterImpl = btree_map::IntoIter; pub type KeysImpl<'a, K, V> = btree_map::Keys<'a, K, V>; pub type ValuesImpl<'a, K, V> = btree_map::Values<'a, K, V>; pub type ValuesMutImpl<'a, K, V> = btree_map::ValuesMut<'a, K, V>; pub type IntoKeysImpl = btree_map::IntoKeys; pub type IntoValuesImpl = btree_map::IntoValues; } /// A default key-value mapping. /// /// Provides an API compatible with both [`HashMap`] and [`BTreeMap`]. /// /// [`HashMap`]: https://docs.rs/hashbrown/0.15.0/hashbrown/struct.HashMap.html /// [`BTreeMap`]: std::collections::BTreeMap #[derive(Debug, Clone)] pub struct Map { inner: detail::MapImpl, } impl Default for Map { #[inline] fn default() -> Self { Self { inner: detail::MapImpl::default(), } } } impl Map { /// Creates a new empty [`Map`]. #[inline] pub fn new() -> Self { Self::default() } /// Clears the [`Map`], removing all elements. #[inline] pub fn clear(&mut self) { self.inner.clear() } /// Returns the number of elements in the [`Map`]. #[inline] pub fn len(&self) -> usize { self.inner.len() } /// Returns `true` if the [`Map`] contains no elements. #[inline] pub fn is_empty(&self) -> bool { self.inner.is_empty() } /// Returns an iterator that yields the items in the [`Map`]. #[inline] pub fn iter(&self) -> Iter<'_, K, V> { Iter { inner: self.inner.iter(), } } /// Returns a mutable iterator that yields the items in the [`Map`]. #[inline] pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { IterMut { inner: self.inner.iter_mut(), } } /// Returns an iterator that yields the keys in the [`Map`]. #[inline] pub fn keys(&self) -> Keys<'_, K, V> { Keys { inner: self.inner.keys(), } } /// Creates a consuming iterator visiting all the keys in arbitrary order. /// /// The [`Map`] cannot be used after calling this. /// The iterator element type is `K`. #[inline] pub fn into_keys(self) -> IntoKeys { IntoKeys { inner: self.inner.into_keys(), } } /// Returns an iterator that yields the values in the [`Map`]. #[inline] pub fn values(&self) -> Values<'_, K, V> { Values { inner: self.inner.values(), } } /// Creates a consuming iterator visiting all the values in arbitrary order. /// /// The [`Map`] cannot be used after calling this. /// The iterator element type is `V`. #[inline] pub fn into_values(self) -> IntoValues { IntoValues { inner: self.inner.into_values(), } } /// Returns a mutable iterator that yields the values in the [`Map`]. #[inline] pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> { ValuesMut { inner: self.inner.values_mut(), } } } impl Map where K: Hash + Eq + Ord, { /// Reserves capacity for at least `additional` more elements to be inserted in the [`Map`]. #[inline] pub fn reserve(&mut self, additional: usize) { #[cfg(all( feature = "hash-collections", not(feature = "prefer-btree-collections") ))] self.inner.reserve(additional); #[cfg(any( not(feature = "hash-collections"), feature = "prefer-btree-collections" ))] let _ = additional; } /// Returns true if `key` is contains in the [`Map`]. #[inline] pub fn contains_key(&self, key: &Q) -> bool where K: Borrow, Q: ?Sized + Hash + Eq + Ord, { self.inner.contains_key(key) } /// Returns a reference to the value corresponding to the `key`. #[inline] pub fn get(&self, key: &Q) -> Option<&V> where K: Borrow, Q: ?Sized + Hash + Eq + Ord, { self.inner.get(key) } /// 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. #[inline] pub fn get_key_value(&self, key: &Q) -> Option<(&K, &V)> where K: Borrow, Q: ?Sized + Hash + Eq + Ord, { self.inner.get_key_value(key) } /// Returns a mutable reference to the value corresponding to the key. #[inline] pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> where K: Borrow, Q: ?Sized + Hash + Eq + Ord, { self.inner.get_mut(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. #[inline] pub fn insert(&mut self, key: K, value: V) -> Option { self.inner.insert(key, value) } /// Removes a key from the [`Map`], returning the value at the key if the key was previously in the map. #[inline] pub fn remove(&mut self, key: &Q) -> Option where K: Borrow, Q: ?Sized + Hash + Eq + Ord, { self.inner.remove(key) } /// Removes a key from the [`Map`], returning the stored key and value if the key /// was previously in the map. /// /// 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. #[inline] pub fn remove_entry(&mut self, key: &Q) -> Option<(K, V)> where K: Borrow, Q: ?Sized + Hash + Ord, { self.inner.remove_entry(key) } /// Gets the given key's corresponding entry in the [`Map`] for in-place manipulation. #[inline] pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { match self.inner.entry(key) { detail::EntryImpl::Occupied(entry) => Entry::Occupied(OccupiedEntry { inner: entry }), detail::EntryImpl::Vacant(entry) => Entry::Vacant(VacantEntry { inner: entry }), } } /// Retains only the elements specified by the predicate. /// /// In other words, remove all pairs `(k, v)` for which `f(&k, &mut v)` returns `false`. /// The elements are visited in ascending key order. #[inline] pub fn retain(&mut self, f: F) where F: FnMut(&K, &mut V) -> bool, { self.inner.retain(f) } } impl PartialEq for Map where K: Eq + Hash, V: Eq, { #[inline] fn eq(&self, other: &Self) -> bool { self.inner == other.inner } } impl Eq for Map where K: Eq + Hash, V: Eq, { } impl Index<&Q> for Map where K: Borrow + Hash + Eq + Ord, Q: ?Sized + Hash + Eq + Ord, { type Output = V; #[inline] fn index(&self, key: &Q) -> &V { &self.inner[key] } } impl<'a, K, V> Extend<(&'a K, &'a V)> for Map where K: Eq + Hash + Ord + Copy, V: Copy, { #[inline] fn extend>(&mut self, iter: Iter) { self.inner.extend(iter) } } impl Extend<(K, V)> for Map where K: Eq + Hash + Ord, { #[inline] fn extend>(&mut self, iter: Iter) { self.inner.extend(iter) } } /// 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 [`Map`]. #[derive(Debug)] pub enum Entry<'a, K: Ord, V> { /// An occupied entry. Occupied(OccupiedEntry<'a, K, V>), /// A vacant entry. Vacant(VacantEntry<'a, K, V>), } impl<'a, K, V> Entry<'a, K, V> where K: Hash + Ord, { /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. #[inline] pub fn or_insert(self, default: V) -> &'a mut V { 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. #[inline] pub fn or_insert_with V>(self, default: F) -> &'a mut V { 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(|| ... )`. #[inline] pub fn or_insert_with_key V>(self, default: F) -> &'a mut V { 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. #[inline] 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. #[inline] 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: Hash + Ord, 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. #[inline] pub fn or_default(self) -> &'a mut V { match self { Self::Occupied(entry) => entry.into_mut(), Self::Vacant(entry) => entry.insert(Default::default()), } } } /// A view into an occupied entry in a [`Map`]. /// /// It is part of the [`Entry`] enum. pub struct OccupiedEntry<'a, K, V> { inner: detail::OccupiedEntryImpl<'a, K, V>, } impl<'a, K, V> Debug for OccupiedEntry<'a, K, V> where K: Debug + Ord + 'a, V: Debug + 'a, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { self.inner.fmt(f) } } impl<'a, K, V> OccupiedEntry<'a, K, V> where K: Ord + 'a, V: 'a, { /// Gets a reference to the key in the entry. #[inline] pub fn key(&self) -> &K { self.inner.key() } /// Gets a reference to the value in the entry. #[inline] pub fn get(&self) -> &V { self.inner.get() } /// Gets a mutable reference to the value in the entry. #[inline] pub fn get_mut(&mut self) -> &mut V { self.inner.get_mut() } /// Sets the value of the entry with the [`OccupiedEntry`]'s key, and returns the entry's old value. #[inline] pub fn insert(&mut self, value: V) -> V { self.inner.insert(value) } /// Converts the [`OccupiedEntry`] into a mutable reference to the value in the entry /// with a lifetime bound to the map itself. #[inline] pub fn into_mut(self) -> &'a mut V { self.inner.into_mut() } /// Take ownership of the key and value from the [`Map`]. #[inline] pub fn remove_entry(self) -> (K, V) { self.inner.remove_entry() } /// Takes the value of the entry out of the [`Map`], and returns it. #[inline] pub fn remove(self) -> V { self.inner.remove() } } /// A view into a vacant entry in a [`Map`]. /// /// It is part of the [`Entry`] enum. pub struct VacantEntry<'a, K, V> { inner: detail::VacantEntryImpl<'a, K, V>, } impl<'a, K, V> Debug for VacantEntry<'a, K, V> where K: Debug + Ord + 'a, V: Debug + 'a, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { self.inner.fmt(f) } } impl<'a, K, V> VacantEntry<'a, K, V> where K: Ord + 'a, V: 'a, { /// Gets a reference to the key in the entry. #[inline] pub fn key(&self) -> &K { self.inner.key() } /// Take ownership of the key. #[inline] pub fn into_key(self) -> K { self.inner.into_key() } /// Sets the value of the entry with the [`VacantEntry`]'s key, and returns a mutable reference to it. #[inline] pub fn insert(self, value: V) -> &'a mut V where K: Hash, { self.inner.insert(value) } } impl FromIterator<(K, V)> for Map where K: Hash + Eq + Ord, { fn from_iter(iter: I) -> Self where I: IntoIterator, { Self { inner: >::from_iter(iter), } } } impl<'a, K, V> IntoIterator for &'a Map { type Item = (&'a K, &'a V); type IntoIter = Iter<'a, K, V>; #[inline] fn into_iter(self) -> Self::IntoIter { self.iter() } } /// An iterator over the items of a [`Map`]. #[derive(Debug, Clone)] pub struct Iter<'a, K, V> { inner: detail::IterImpl<'a, K, V>, } impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { type Item = (&'a K, &'a V); #[inline] fn next(&mut self) -> Option { self.inner.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: 'a, V: 'a> ExactSizeIterator for Iter<'a, K, V> { #[inline] fn len(&self) -> usize { self.inner.len() } } impl<'a, K: 'a, V: 'a> FusedIterator for Iter<'a, K, V> where detail::IterImpl<'a, K, V>: FusedIterator { } impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut Map { type Item = (&'a K, &'a mut V); type IntoIter = IterMut<'a, K, V>; #[inline] fn into_iter(self) -> Self::IntoIter { self.iter_mut() } } /// An iterator over the mutable items of a [`Map`]. #[derive(Debug)] pub struct IterMut<'a, K, V> { inner: detail::IterMutImpl<'a, K, V>, } impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> { type Item = (&'a K, &'a mut V); #[inline] fn next(&mut self) -> Option { self.inner.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> { #[inline] fn len(&self) -> usize { self.inner.len() } } impl<'a, K: 'a, V: 'a> FusedIterator for IterMut<'a, K, V> where detail::IterMutImpl<'a, K, V>: FusedIterator { } impl IntoIterator for Map { type Item = (K, V); type IntoIter = IntoIter; #[inline] fn into_iter(self) -> Self::IntoIter { IntoIter { inner: self.inner.into_iter(), } } } /// An iterator over the owned items of an [`Map`]. #[derive(Debug)] pub struct IntoIter { inner: detail::IntoIterImpl, } impl Iterator for IntoIter { type Item = (K, V); #[inline] fn next(&mut self) -> Option { self.inner.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl ExactSizeIterator for IntoIter { #[inline] fn len(&self) -> usize { self.inner.len() } } impl FusedIterator for IntoIter where detail::IntoIterImpl: FusedIterator {} /// An iterator over the keys of a [`Map`]. #[derive(Debug, Clone)] pub struct Keys<'a, K, V> { inner: detail::KeysImpl<'a, K, V>, } impl<'a, K: 'a, V> Iterator for Keys<'a, K, V> { type Item = &'a K; #[inline] fn next(&mut self) -> Option { self.inner.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: 'a, V> ExactSizeIterator for Keys<'a, K, V> { #[inline] fn len(&self) -> usize { self.inner.len() } } impl<'a, K: 'a, V> FusedIterator for Keys<'a, K, V> where detail::KeysImpl<'a, K, V>: FusedIterator {} /// An iterator over the values of a [`Map`]. #[derive(Debug, Clone)] pub struct Values<'a, K, V> { inner: detail::ValuesImpl<'a, K, V>, } impl<'a, K, V: 'a> Iterator for Values<'a, K, V> { type Item = &'a V; #[inline] fn next(&mut self) -> Option { self.inner.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K, V: 'a> ExactSizeIterator for Values<'a, K, V> { #[inline] fn len(&self) -> usize { self.inner.len() } } impl<'a, K, V: 'a> FusedIterator for Values<'a, K, V> where detail::ValuesImpl<'a, K, V>: FusedIterator { } /// An mutable iterator over the values of a [`Map`]. #[derive(Debug)] pub struct ValuesMut<'a, K, V> { inner: detail::ValuesMutImpl<'a, K, V>, } impl<'a, K, V: 'a> Iterator for ValuesMut<'a, K, V> { type Item = &'a mut V; #[inline] fn next(&mut self) -> Option { self.inner.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K, V: 'a> ExactSizeIterator for ValuesMut<'a, K, V> { #[inline] fn len(&self) -> usize { self.inner.len() } } impl<'a, K, V: 'a> FusedIterator for ValuesMut<'a, K, V> where detail::ValuesMutImpl<'a, K, V>: FusedIterator { } /// An iterator over the owned keys of a [`Map`]. #[derive(Debug)] pub struct IntoKeys { inner: detail::IntoKeysImpl, } impl Iterator for IntoKeys { type Item = K; #[inline] fn next(&mut self) -> Option { self.inner.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl ExactSizeIterator for IntoKeys { #[inline] fn len(&self) -> usize { self.inner.len() } } impl FusedIterator for IntoKeys where detail::IntoKeysImpl: FusedIterator {} /// An iterator over the owned values of a [`Map`]. #[derive(Debug)] pub struct IntoValues { inner: detail::IntoValuesImpl, } impl Iterator for IntoValues { type Item = V; #[inline] fn next(&mut self) -> Option { self.inner.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl ExactSizeIterator for IntoValues { #[inline] fn len(&self) -> usize { self.inner.len() } } impl FusedIterator for IntoValues where detail::IntoValuesImpl: FusedIterator {} wasmi_collections-1.0.9/src/set.rs000064400000000000000000000365451046102023000153160ustar 00000000000000//! Type definitions for a default set. use core::{ borrow::Borrow, fmt::{self, Debug}, hash::Hash, iter::FusedIterator, ops::{BitAnd, BitOr, BitXor, Sub}, }; #[cfg(all( feature = "hash-collections", not(feature = "prefer-btree-collections") ))] mod detail { use crate::hash; use hashbrown::hash_set; pub type SetImpl = hash_set::HashSet; pub type IterImpl<'a, T> = hash_set::Iter<'a, T>; pub type IntoIterImpl = hash_set::IntoIter; pub type DifferenceImpl<'a, T> = hash_set::Difference<'a, T, hash::RandomState>; pub type IntersectionImpl<'a, T> = hash_set::Intersection<'a, T, hash::RandomState>; pub type SymmetricDifferenceImpl<'a, T> = hash_set::SymmetricDifference<'a, T, hash::RandomState>; pub type UnionImpl<'a, T> = hash_set::Union<'a, T, hash::RandomState>; } #[cfg(any( not(feature = "hash-collections"), feature = "prefer-btree-collections" ))] mod detail { use alloc::collections::btree_set; pub type SetImpl = btree_set::BTreeSet; pub type IterImpl<'a, T> = btree_set::Iter<'a, T>; pub type IntoIterImpl = btree_set::IntoIter; pub type DifferenceImpl<'a, T> = btree_set::Difference<'a, T>; pub type IntersectionImpl<'a, T> = btree_set::Intersection<'a, T>; pub type SymmetricDifferenceImpl<'a, T> = btree_set::SymmetricDifference<'a, T>; pub type UnionImpl<'a, T> = btree_set::Union<'a, T>; } /// A default set of values. /// /// Provides an API compatible with both [`HashSet`] and [`BTreeSet`]. /// /// [`HashSet`]: https://docs.rs/hashbrown/0.15.0/hashbrown/struct.HashSet.html /// [`BTreeSet`]: std::collections::BTreeSet #[derive(Debug, Clone)] pub struct Set { /// The underlying hash-set or btree-set data structure used. inner: detail::SetImpl, } impl Default for Set { #[inline] fn default() -> Self { Self { inner: detail::SetImpl::default(), } } } impl Set { /// Clears the [`Set`], removing all elements. #[inline] pub fn clear(&mut self) { self.inner.clear() } /// Retains only the elements specified by the predicate. /// /// In other words, remove all elements `e` for which `f(&e)` returns `false`. /// The elements are visited in unsorted (and unspecified) order. #[inline] pub fn retain(&mut self, f: F) where T: Ord, F: FnMut(&T) -> bool, { self.inner.retain(f) } /// Returns the number of elements in the [`Set`]. #[inline] pub fn len(&self) -> usize { self.inner.len() } /// Returns `true` if the [`Set`] contains no elements. #[inline] pub fn is_empty(&self) -> bool { self.inner.is_empty() } /// Returns an iterator that yields the items in the [`Set`]. #[inline] pub fn iter(&self) -> Iter<'_, T> { Iter { inner: self.inner.iter(), } } } impl Set where T: Eq + Hash + Ord, { /// Reserves capacity for at least `additional` more elements to be inserted in the [`Set`]. #[inline] pub fn reserve(&mut self, additional: usize) { #[cfg(all( feature = "hash-collections", not(feature = "prefer-btree-collections") ))] self.inner.reserve(additional); #[cfg(any( not(feature = "hash-collections"), feature = "prefer-btree-collections" ))] let _ = additional; } /// Returns true if the [`Set`] contains an element equal to the `value`. #[inline] pub fn contains(&self, value: &Q) -> bool where T: Borrow, Q: ?Sized + Hash + Eq + Ord, { self.inner.contains(value) } /// Returns a reference to the element in the [`Set`], if any, that is equal to the `value`. #[inline] pub fn get(&self, value: &Q) -> Option<&T> where T: Borrow, Q: ?Sized + Hash + Eq + Ord, { self.inner.get(value) } /// Adds `value` to the [`Set`]. /// /// Returns whether the value was newly inserted: /// /// - Returns `true` if the set did not previously contain an equal value. /// - Returns `false` otherwise and the entry is not updated. #[inline] pub fn insert(&mut self, value: T) -> bool { self.inner.insert(value) } /// If the set contains an element equal to the value, removes it from the [`Set`] and drops it. /// /// Returns `true` if such an element was present, otherwise `false`. #[inline] pub fn remove(&mut self, value: &Q) -> bool where T: Borrow, Q: ?Sized + Hash + Eq + Ord, { self.inner.remove(value) } /// Removes and returns 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. #[inline] pub fn take(&mut self, value: &Q) -> Option where T: Borrow, Q: ?Sized + Hash + Ord, { self.inner.take(value) } /// Adds a value to the [`Set`], replacing the existing value, if any, that is equal to the given /// one. Returns the replaced value. #[inline] pub fn replace(&mut self, value: T) -> Option { self.inner.replace(value) } /// Returns `true` if `self` has no elements in common with `other`. /// This is equivalent to checking for an empty intersection. #[inline] pub fn is_disjoint(&self, other: &Self) -> bool { self.inner.is_disjoint(&other.inner) } /// Returns `true` if the [`Set`] is a subset of another, /// i.e., `other` contains at least all the values in `self`. #[inline] pub fn is_subset(&self, other: &Self) -> bool { self.inner.is_subset(&other.inner) } /// Returns `true` if the [`Set`] is a superset of another, /// i.e., `self` contains at least all the values in `other`. #[inline] pub fn is_superset(&self, other: &Self) -> bool { self.inner.is_superset(&other.inner) } /// Visits the values representing the difference, /// i.e., the values that are in `self` but not in `other`. #[inline] pub fn difference<'a>(&'a self, other: &'a Self) -> Difference<'a, T> { Difference { inner: self.inner.difference(&other.inner), } } /// Visits the values representing the symmetric difference, /// i.e., the values that are in `self` or in `other` but not in both. #[inline] pub fn symmetric_difference<'a>(&'a self, other: &'a Self) -> SymmetricDifference<'a, T> { SymmetricDifference { inner: self.inner.symmetric_difference(&other.inner), } } /// Visits the values representing the intersection, /// i.e., the values that are both in `self` and `other`. /// /// When an equal element is present in `self` and `other` /// then the resulting `Intersection` may yield references to /// one or the other. This can be relevant if `T` contains fields which /// are not compared by its `Eq` implementation, and may hold different /// value between the two equal copies of `T` in the two sets. #[inline] pub fn intersection<'a>(&'a self, other: &'a Self) -> Intersection<'a, T> { Intersection { inner: self.inner.intersection(&other.inner), } } /// Visits the values representing the union, /// i.e., all the values in `self` or `other`, without duplicates. #[inline] pub fn union<'a>(&'a self, other: &'a Self) -> Union<'a, T> { Union { inner: self.inner.union(&other.inner), } } } impl PartialEq for Set where T: Eq + Hash, { #[inline] fn eq(&self, other: &Self) -> bool { self.inner == other.inner } } impl Eq for Set where T: Eq + Hash {} impl FromIterator for Set where T: Hash + Eq + Ord, { #[inline] fn from_iter(iter: I) -> Self where I: IntoIterator, { Self { inner: >::from_iter(iter), } } } impl<'a, T> IntoIterator for &'a Set { type Item = &'a T; type IntoIter = Iter<'a, T>; #[inline] fn into_iter(self) -> Self::IntoIter { self.iter() } } impl<'a, T> Extend<&'a T> for Set where T: Hash + Eq + Ord + Copy + 'a, { #[inline] fn extend>(&mut self, iter: Iter) { self.inner.extend(iter) } } impl Extend for Set where T: Hash + Eq + Ord, { #[inline] fn extend>(&mut self, iter: Iter) { self.inner.extend(iter) } } impl<'a, T> BitAnd for &'a Set where T: Eq + Hash + Ord + Clone + 'a, { type Output = Set; #[inline] fn bitand(self, rhs: Self) -> Set { Set { inner: BitAnd::bitand(&self.inner, &rhs.inner), } } } impl<'a, T> BitOr for &'a Set where T: Eq + Hash + Ord + Clone + 'a, { type Output = Set; #[inline] fn bitor(self, rhs: Self) -> Set { Set { inner: BitOr::bitor(&self.inner, &rhs.inner), } } } impl<'a, T> BitXor for &'a Set where T: Eq + Hash + Ord + Clone + 'a, { type Output = Set; #[inline] fn bitxor(self, rhs: Self) -> Set { Set { inner: BitXor::bitxor(&self.inner, &rhs.inner), } } } impl<'a, T> Sub for &'a Set where T: Eq + Hash + Ord + Clone + 'a, { type Output = Set; #[inline] fn sub(self, rhs: Self) -> Set { Set { inner: Sub::sub(&self.inner, &rhs.inner), } } } /// An iterator over the items of a [`Set`]. #[derive(Debug, Clone)] pub struct Iter<'a, T> { inner: detail::IterImpl<'a, T>, } impl<'a, T: 'a> Iterator for Iter<'a, T> { type Item = &'a T; #[inline] fn next(&mut self) -> Option { self.inner.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, T: 'a> ExactSizeIterator for Iter<'a, T> { #[inline] fn len(&self) -> usize { self.inner.len() } } impl<'a, T: 'a> FusedIterator for Iter<'a, T> where detail::IterImpl<'a, T>: FusedIterator {} impl IntoIterator for Set { type Item = T; type IntoIter = IntoIter; #[inline] fn into_iter(self) -> Self::IntoIter { IntoIter { inner: self.inner.into_iter(), } } } /// An iterator over the owned items of an [`Set`]. #[derive(Debug)] pub struct IntoIter { inner: detail::IntoIterImpl, } impl Iterator for IntoIter { type Item = T; #[inline] fn next(&mut self) -> Option { self.inner.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl ExactSizeIterator for IntoIter { #[inline] fn len(&self) -> usize { self.inner.len() } } impl FusedIterator for IntoIter where detail::IntoIterImpl: FusedIterator {} /// A lazy iterator producing elements in the difference of [`Set`]s. /// /// This `struct` is created by the [`difference`] method on [`Set`]. /// See its documentation for more. /// /// [`difference`]: Set::difference pub struct Difference<'a, T: 'a> { inner: detail::DifferenceImpl<'a, T>, } impl Debug for Difference<'_, T> where T: Debug + Hash + Eq, { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.fmt(f) } } impl Clone for Difference<'_, T> { #[inline] fn clone(&self) -> Self { Self { inner: self.inner.clone(), } } } impl<'a, T> Iterator for Difference<'a, T> where T: Hash + Eq + Ord, { type Item = &'a T; #[inline] fn next(&mut self) -> Option { self.inner.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, T> FusedIterator for Difference<'a, T> where T: Hash + Eq + Ord, detail::DifferenceImpl<'a, T>: FusedIterator, { } /// A lazy iterator producing elements in the intersection of [`Set`]s. /// /// This `struct` is created by the [`intersection`] method on [`Set`]. /// See its documentation for more. /// /// [`intersection`]: Set::intersection pub struct Intersection<'a, T: 'a> { inner: detail::IntersectionImpl<'a, T>, } impl Debug for Intersection<'_, T> where T: Debug + Hash + Eq, { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.fmt(f) } } impl Clone for Intersection<'_, T> { #[inline] fn clone(&self) -> Self { Self { inner: self.inner.clone(), } } } impl<'a, T> Iterator for Intersection<'a, T> where T: Hash + Eq + Ord, { type Item = &'a T; #[inline] fn next(&mut self) -> Option { self.inner.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, T> FusedIterator for Intersection<'a, T> where T: Hash + Eq + Ord, detail::IntersectionImpl<'a, T>: FusedIterator, { } /// A lazy iterator producing elements in the symmetric difference of [`Set`]s. /// /// This `struct` is created by the [`symmetric_difference`] method on /// [`Set`]. See its documentation for more. /// /// [`symmetric_difference`]: Set::symmetric_difference pub struct SymmetricDifference<'a, T: 'a> { inner: detail::SymmetricDifferenceImpl<'a, T>, } impl Debug for SymmetricDifference<'_, T> where T: Debug + Hash + Eq, { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.fmt(f) } } impl Clone for SymmetricDifference<'_, T> { #[inline] fn clone(&self) -> Self { Self { inner: self.inner.clone(), } } } impl<'a, T> Iterator for SymmetricDifference<'a, T> where T: Hash + Eq + Ord, { type Item = &'a T; #[inline] fn next(&mut self) -> Option { self.inner.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, T> FusedIterator for SymmetricDifference<'a, T> where T: Hash + Eq + Ord, detail::SymmetricDifferenceImpl<'a, T>: FusedIterator, { } /// A lazy iterator producing elements in the union of [`Set`]s. /// /// This `struct` is created by the [`union`] method on /// [`Set`]. See its documentation for more. /// /// [`union`]: Set::union pub struct Union<'a, T: 'a> { inner: detail::UnionImpl<'a, T>, } impl Debug for Union<'_, T> where T: Debug + Hash + Eq, { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.fmt(f) } } impl Clone for Union<'_, T> { #[inline] fn clone(&self) -> Self { Self { inner: self.inner.clone(), } } } impl<'a, T> Iterator for Union<'a, T> where T: Hash + Eq + Ord, { type Item = &'a T; #[inline] fn next(&mut self) -> Option { self.inner.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, T> FusedIterator for Union<'a, T> where T: Hash + Eq + Ord, detail::UnionImpl<'a, T>: FusedIterator, { } wasmi_collections-1.0.9/src/string_interner/detail.rs000064400000000000000000000133261046102023000211710ustar 00000000000000use super::{GetOrInternWithHint, InternHint, Sym}; use alloc::{ borrow::Borrow, collections::{btree_map::Entry, BTreeMap}, sync::Arc, vec::Vec, }; use core::{cmp::Ordering, mem, ops::Deref}; pub type StringInternerImpl = StringInterner; mod hint { /// Indicates that the calling scope is unlikely to be executed. #[cold] #[inline] pub fn cold() {} } /// A string interner. /// /// Efficiently interns strings and distributes symbols. #[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct StringInterner { string2symbol: BTreeMap, strings: Vec>, } impl GetOrInternWithHint for StringInterner { fn get_or_intern_with_hint(&mut self, string: T, hint: InternHint) -> Sym where T: AsRef, { let string = string.as_ref(); match hint { InternHint::LikelyExists => self.get_or_intern_hint_existing(string), InternHint::LikelyNew | InternHint::None => self.get_or_intern_hint_new(string), } } } impl StringInterner { /// Creates a new empty [`StringInterner`]. #[inline] pub fn new() -> Self { Self::default() } /// Returns the number of interned strings. #[inline] pub fn len(&self) -> usize { self.string2symbol.len() } /// Returns `true` if the [`StringInterner`] is empty. #[inline] pub fn is_empty(&self) -> bool { self.len() == 0 } /// Returns the symbol of the string and interns it if necessary. /// /// # Note /// /// - Optimized for `string` not to be contained in [`StringInterner`] before this operation. /// - Allocates `string` twice on the heap if it already existed prior to this operation. fn get_or_intern_hint_new(&mut self, string: &str) -> Sym { match self.string2symbol.entry(LenOrder(string.into())) { Entry::Vacant(entry) => { let symbol = Sym::from_usize(self.strings.len()); self.strings.push(entry.key().clone().0); entry.insert(symbol); symbol } Entry::Occupied(entry) => { hint::cold(); *entry.get() } } } /// Returns the symbol of the string and interns it if necessary. /// /// # Note /// /// - Optimized for `string` to already be contained in [`StringInterner`] before this operation. /// - Queries the position within `strings2symbol` twice in case `string` already existed. #[inline] fn get_or_intern_hint_existing(&mut self, string: &str) -> Sym { match self.string2symbol.get(<&LenOrderStr>::from(string)) { Some(symbol) => *symbol, None => self.intern(string), } } /// Interns the `string` into the [`StringInterner`]. /// /// # Panics /// /// If the `string` already exists. #[cold] fn intern(&mut self, string: T) -> Sym where T: AsRef, { let string = string.as_ref(); let symbol = Sym::from_usize(self.strings.len()); let rc_string: Arc = Arc::from(string); let old = self .string2symbol .insert(LenOrder(rc_string.clone()), symbol); assert!(old.is_none()); self.strings.push(rc_string); symbol } /// Returns the symbol for the string if interned. #[inline] pub fn get(&self, string: T) -> Option where T: AsRef, { self.string2symbol .get(<&LenOrderStr>::from(string.as_ref())) .copied() } /// Resolves the symbol to the underlying string. #[inline] pub fn resolve(&self, symbol: Sym) -> Option<&str> { self.strings.get(symbol.into_usize()).map(Deref::deref) } } /// An `Arc` that defines its own (more efficient) [`Ord`]. #[derive(Debug, Clone, PartialEq, Eq)] #[repr(transparent)] pub struct LenOrder(Arc); impl Ord for LenOrder { #[inline] fn cmp(&self, other: &Self) -> Ordering { self.as_str().cmp(other.as_str()) } } impl PartialOrd for LenOrder { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl LenOrder { #[inline] pub fn as_str(&self) -> &LenOrderStr { (&*self.0).into() } } /// A `str` that defines its own (more efficient) [`Ord`]. #[derive(Debug, Eq, PartialEq)] #[repr(transparent)] pub struct LenOrderStr(str); impl<'a> From<&'a str> for &'a LenOrderStr { #[inline] fn from(value: &'a str) -> Self { // Safety: This operation is safe because // // - we preserve the lifetime `'a` // - the `LenOrderStr` type is a `str` newtype wrapper and `#[repr(transparent)` unsafe { mem::transmute(value) } } } impl Borrow for LenOrder { #[inline] fn borrow(&self) -> &LenOrderStr { (&*self.0).into() } } impl PartialOrd for LenOrderStr { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for LenOrderStr { #[inline] fn cmp(&self, other: &Self) -> Ordering { let lhs = self.0.as_bytes(); let rhs = other.0.as_bytes(); match lhs.len().cmp(&rhs.len()) { Ordering::Equal => { if lhs.len() < 8 { for (l, r) in lhs.iter().zip(rhs) { match l.cmp(r) { Ordering::Equal => (), ordering => return ordering, } } Ordering::Equal } else { lhs.cmp(rhs) } } ordering => ordering, } } } wasmi_collections-1.0.9/src/string_interner.rs000064400000000000000000000115041046102023000177230ustar 00000000000000//! Data structure to efficiently store and deduplicate strings. #[cfg(all( feature = "hash-collections", not(feature = "prefer-btree-collections") ))] mod detail { use super::{GetOrInternWithHint, Sym}; use crate::hash; use string_interner::{backend::BufferBackend, StringInterner, Symbol}; pub type StringInternerImpl = StringInterner, hash::RandomState>; impl GetOrInternWithHint for StringInternerImpl { #[inline] fn get_or_intern_with_hint(&mut self, string: T, _hint: super::InternHint) -> Sym where T: AsRef, { self.get_or_intern(string) } } impl Symbol for Sym { #[inline] fn try_from_usize(index: usize) -> Option { let Ok(value) = u32::try_from(index) else { return None; }; Some(Self::from_u32(value)) } #[inline] fn to_usize(self) -> usize { self.into_u32() as usize } } } #[cfg(any( not(feature = "hash-collections"), feature = "prefer-btree-collections" ))] mod detail; /// Internment hint to speed-up certain use cases. #[derive(Debug, Copy, Clone)] pub enum InternHint { /// No hint is given to the [`StringInterner`]. None, /// Hint that the string to be interned likely already exists. LikelyExists, /// Hint that the string to be interned likely does not yet exist. LikelyNew, } /// Symbols returned by the [`StringInterner`] to resolve interned strings. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Sym(u32); impl Sym { /// Creates a new [`Sym`] from the `u32` value. pub fn from_u32(value: u32) -> Self { Self(value) } /// Creates a new [`Sym`] from the `usize` value. /// /// # Panics /// /// If the `usize` value is out of bounds for [`Sym`]. pub fn from_usize(value: usize) -> Self { u32::try_from(value).map_or_else(|_| panic!("out of bounds symbol index: {value}"), Self) } /// Returns the `u32` value of the [`Sym`]. pub fn into_u32(self) -> u32 { self.0 } /// Returns the value of the [`Sym`] as `usize`. pub fn into_usize(self) -> usize { self.0 as usize } } /// Efficiently interns and deduplicates strings. #[derive(Debug, Clone, PartialEq, Eq)] pub struct StringInterner { inner: detail::StringInternerImpl, } impl Default for StringInterner { #[inline] fn default() -> Self { Self::new() } } impl StringInterner { /// Creates a new empty [`StringInterner`]. #[inline] pub fn new() -> Self { Self { inner: detail::StringInternerImpl::new(), } } /// Returns the number of strings interned by the [`StringInterner`]. #[inline] pub fn len(&self) -> usize { self.inner.len() } /// Returns `true` if the [`StringInterner`] has no interned strings. #[inline] pub fn is_empty(&self) -> bool { self.inner.is_empty() } /// Returns the symbol for the given string if any. /// /// Can be used to query if a string has already been interned without interning. #[inline] pub fn get(&self, string: T) -> Option where T: AsRef, { self.inner.get(string) } /// Interns the given string. /// /// Returns a symbol for resolution into the original string. /// /// # Panics /// /// If the interner already interns the maximum number of strings possible /// by the chosen symbol type. #[inline] pub fn get_or_intern(&mut self, string: T) -> Sym where T: AsRef, { self.inner.get_or_intern_with_hint(string, InternHint::None) } /// Interns the given string with usage hint. /// /// Returns a symbol for resolution into the original string. /// /// # Panics /// /// If the interner already interns the maximum number of strings possible /// by the chosen symbol type. #[inline] pub fn get_or_intern_with_hint(&mut self, string: T, hint: InternHint) -> Sym where T: AsRef, { self.inner.get_or_intern_with_hint(string, hint) } /// Returns the string for the given symbol if any. #[inline] pub fn resolve(&self, symbol: Sym) -> Option<&str> { self.inner.resolve(symbol) } } /// Extension trait for [`StringInterner`] backends. trait GetOrInternWithHint { /// Interns the given string with usage hint. /// /// Returns a symbol for resolution into the original string. /// /// # Panics /// /// If the interner already interns the maximum number of strings possible /// by the chosen symbol type. fn get_or_intern_with_hint(&mut self, string: T, hint: InternHint) -> Sym where T: AsRef; } wasmi_collections-1.0.9/src/tests.rs000064400000000000000000000120211046102023000156440ustar 00000000000000use super::arena::*; impl ArenaIndex for usize { fn into_usize(self) -> usize { self } fn from_usize(value: usize) -> Self { value } } const TEST_ENTITIES: &[&str] = &["a", "b", "c", "d"]; mod arena { use super::*; fn alloc_arena(entities: &[&'static str]) -> Arena { let mut arena = >::new(); // Check that the given arena is actually empty. assert_eq!(arena.len(), 0); assert!(arena.is_empty()); // Fill arena and check invariants while doing so. for idx in 0..entities.len() { assert!(arena.get(idx).is_none()); } for (n, str) in entities.iter().enumerate() { assert_eq!(arena.alloc(str), n); } // Check state of filled arena. assert_eq!(arena.len(), entities.len()); assert!(!arena.is_empty()); for (n, str) in entities.iter().enumerate() { assert_eq!(arena.get(n), Some(str)); assert_eq!(&arena[n], str); } assert_eq!(arena.get(arena.len()), None); // Return filled arena. arena } #[test] fn alloc_works() { alloc_arena(TEST_ENTITIES); } #[test] fn clear_works() { let mut arena = alloc_arena(TEST_ENTITIES); // Clear the arena and check if all elements are removed. arena.clear(); assert_eq!(arena.len(), 0); assert!(arena.is_empty()); for idx in 0..arena.len() { assert_eq!(arena.get(idx), None); } assert_eq!(arena.get(arena.len()), None); } #[test] fn iter_works() { let arena = alloc_arena(TEST_ENTITIES); assert!(arena.iter().eq(TEST_ENTITIES.iter().enumerate())); } #[test] fn from_iter_works() { let expected = alloc_arena(TEST_ENTITIES); let actual = TEST_ENTITIES.iter().copied().collect::>(); assert_eq!(actual, expected); } #[test] fn duplicates_work() { let mut arena = alloc_arena(TEST_ENTITIES); // Re-inserting the same entities into the filled arena will // result in new and unique indices since the standard arena // type does not deduplicate its entities. let previous_len = arena.len(); for (idx, str) in TEST_ENTITIES.iter().enumerate() { let offset = previous_len + idx; assert_eq!(arena.alloc(str), offset); assert_eq!(arena.get(offset), Some(str)); } // Assert that the arena actually did increase in size since // there is no deduplication of equal entities. assert_eq!(arena.len(), previous_len + TEST_ENTITIES.len()); } } mod dedup_arena { use super::*; fn alloc_dedup_arena(entities: &[&'static str]) -> DedupArena { let mut arena = >::new(); // Check that the given arena is actually empty. assert_eq!(arena.len(), 0); assert!(arena.is_empty()); // Fill arena and check invariants while doing so. for idx in 0..entities.len() { assert!(arena.get(idx).is_none()); } for (n, str) in entities.iter().enumerate() { assert_eq!(arena.alloc(str), n); } // Check state of filled arena. assert_eq!(arena.len(), entities.len()); assert!(!arena.is_empty()); for (n, str) in entities.iter().enumerate() { assert_eq!(arena.get(n), Some(str)); assert_eq!(&arena[n], str); } assert_eq!(arena.get(arena.len()), None); // Return filled arena. arena } #[test] fn alloc_works() { alloc_dedup_arena(TEST_ENTITIES); } #[test] fn clear_works() { let mut arena = alloc_dedup_arena(TEST_ENTITIES); // Clear the arena and check if all elements are removed. arena.clear(); assert_eq!(arena.len(), 0); assert!(arena.is_empty()); for idx in 0..arena.len() { assert_eq!(arena.get(idx), None); } assert_eq!(arena.get(arena.len()), None); } #[test] fn iter_works() { let arena = alloc_dedup_arena(TEST_ENTITIES); assert!(arena.iter().eq(TEST_ENTITIES.iter().enumerate())); } #[test] fn from_iter_works() { let expected = alloc_dedup_arena(TEST_ENTITIES); let actual = TEST_ENTITIES.iter().copied().collect::>(); assert_eq!(actual, expected); } #[test] fn duplicates_work() { let mut arena = alloc_dedup_arena(TEST_ENTITIES); // Re-inserting the same entities into the filled arena will // yield back the same indices as their already allocated entities. for (idx, str) in TEST_ENTITIES.iter().enumerate() { assert_eq!(arena.alloc(str), idx); assert_eq!(arena.get(idx), Some(str)); } // Assert that the deduplicating arena did not increase in size. assert_eq!(arena.len(), TEST_ENTITIES.len()); } }