Skip to main content

Crate frozendict

Crate frozendict 

Source
Expand description

§🧊 FrozenDict

frozendict logo

Crates.io Docs.rs PyPI npm License: MIT CI

frozendict is a state of the art world’s most memory-efficient immutable hashmap written in 100% safe Rust, with native Python and Node.js bindings πŸ—Ώ.

frozendict banner

Β§πŸš€ Installation

PlatformCommand
Rust librarycargo add frozendict
Pythonpip install frozndict
Node.jsnpm i frozendict
Debian/UbuntuDownload .deb from GitHub Releases
RHEL/FedoraDownload .rpm from GitHub Releases

Β§πŸ€” What does this crate provide?

frozendict provides a fully immutable, hashable dictionary for Python and Node.js backed by a high-performance Rust core. It:

  • Stores entries in a single contiguous sorted heap allocation, zero per-entry heap overhead.
  • Looks up keys in O(log n) via binary search, no hashing, no pointer-chasing, excellent cache behaviour.
  • Caches its hash at construction, repeated hash() calls are O(1).
  • Integrates with Python’s dict protocol (keys(), values(), items(), pickle, copy, | merge operator).
  • Exposes a native Node.js FrozenDict class with TypeScript declarations via napi-rs.
  • Provides functional update primitives: merge, with, without, intersection, union, difference.
PropertyFrozenMap (this crate)HashMap / BTreeMap
Memory overheadZero: exactly n Γ— entry_size1.5-2Γ— allocator overhead
Allocation countOne at constructionOne per entry (BTreeMap)
LookupO(log n) binary searchO(1) / O(log n)
Cache behaviourExcellent: sequential prefetchPointer-chasing on tree nodes
MutationImpossible by design&mut self methods exist
Hash stabilityO(1): pre-computed at initO(n) on every hash() call

Binary search beats hash-map lookup for maps with fewer than ~64 entries because it avoids hashing and pointer-chasing. For larger maps the memory savings (up to 2Γ—) and cache locality more than compensate. See Cache-oblivious binary search and the AHash paper for background.

Β§πŸ¦€ Rust

[dependencies]
frozendict = "2.1.1"
use frozendict::frozen_map::FrozenMap;

let map: FrozenMap<&str, i32> = FrozenMap::new([("b", 2), ("a", 1)]);
assert_eq!(map["a"], 1);
assert_eq!(map.len(), 2);

let updated = map.with("c", 3);
assert_eq!(updated.len(), 3);

let merged = updated.merge(&FrozenMap::new([("a", 99)]));
assert_eq!(merged["a"], 99);

For the full API reference see RUST.md.

§🐍 Python

pip install frozndict
from frozndict import FrozenDict

d = FrozenDict({"a": 1, "b": 2})
print(d["a"])          # 1
print(hash(d))         # stable integer (pre-computed at construction)

d2 = d | {"c": 3}      # returns a new FrozenDict
print(d2.keys())

For full docs see PYTHON.md.

§🟩 Node.js

npm install frozendict
const { frozenDict, FrozenDict } = require("frozendict");

const d = frozenDict({ a: 1, b: "hello", c: [1, 2, 3] });
console.log(d.get("a")); // 1
console.log(d.size); // 3
console.log(d.has("z")); // false

const d2 = d.merge({ d: true });
console.log(d2.size); // 4
console.log(d2.toJSON()); // '{"a":1,"b":"hello","c":[1,2,3],"d":true}'

For full docs see NODE.md.

Β§πŸ”­ Features

FeatureDefaultDescription
python❌Python extension module via PyO3/maturin
node❌Node.js native add-on via napi-rs

Β§πŸ“Š Benchmarks

Β§πŸš€ Performance Highlights

frozndict operates natively at the mathematical speed limits of the hardware, heavily outperforming its C counterparts and standard dictionary data structures on several fronts.

The following is a 1000-element dictionary micro-benchmark comparison in seconds per operation (smaller is better), measured on x86-64 Linux with LTO=fat, opt-level=3, codegen-units=1, panic=abort, target-cpu=native.

Operation (1000 items)Python dictfrozendict (C)immutables.Mapfrozndict 🧊
Construction6.41 Β΅s πŸ†7.73 Β΅s244.91 Β΅s98.72 Β΅s
Clone O(1)6.37 Β΅s69.13 ns πŸ†411.89 ns117.24 ns
Equality19.18 Β΅s19.61 Β΅s24.39 ns πŸ†34.92 ns
Iteration7.10 Β΅s7.19 Β΅s14.89 Β΅s4.13 Β΅s πŸ†
copy()6.45 Β΅s323.22 ns310.04 Β΅s63.25 ns πŸ†
hash()N/A168.11 ns45.38 ns45.25 ns πŸ†
Lookup33.33 ns πŸ†56.03 ns47.48 ns82.98 ns

Benchmarked with timeit (min of 7 runs Γ— 2 000 iterations). Python 3.12.

Β§πŸ† Fastest Iteration in Class

Keys are stored in a single contiguous sorted Box<[K]>, sequential iteration has perfect prefetch behaviour. At 1000 elements, frozndict iterates 1.9Γ— faster than frozendict (C) and 3.5Γ— faster than immutables.Map.

Β§πŸ† Smallest copy() Overhead

copy() and __deepcopy__() share the backing Arc<FrozenDictInner>, O(1), just an atomic reference count increment. At 64 ns, frozndict is 5Γ— faster than frozendict (C) on copy.

Β§Deterministic O(1) Pre-Computed Hashing

The dict-level hash is XOR-combined over all (k, v) pairs exactly once at construction via inline multiplicative mixing (0x9e3779b97f4a7c15, 0x517cc1b727220a95). Subsequent hash() calls are a single field read, O(1), allocating nothing.

Β§O(1) Clone & Identity Equality

A shared Arc<FrozenDictInner> is re-used across the original, all copies, and frozendict(existing_fd) constructors. No data is ever duplicated. __eq__ short-circuits in O(1) via Arc::ptr_eq before comparing pre-computed hashes.

Β§Smallest Memory Footprint

Entries sit in a SoA layout: a Box<[K]> for keys and a Box<[V]> for values, two contiguous allocations. Binary search only touches the key array: 2Γ— smaller cache footprint compared to AoS layouts on large value types.

Β§Infallible Rust-Level Immutability

Mutation is blocked at the Rust binary level. There are no &mut self methods, not just descriptor tricks.

Β§Rust micro-benchmarks (cargo bench)

BenchmarkTime
construction/4~105 ns
construction/64~821 ns
construction/1024~16.1 Β΅s
construction/65536~1.32 ms
lookup/hit/4~5.94 ns
lookup/hit/64~5.83 ns
lookup/hit/1024~5.87 ns
lookup/hit/65536~5.83 ns
lookup/miss/64~6.48 ns
lookup/miss/65536~6.51 ns
iteration/keys/65536~20.8 Β΅s
iteration/values/65536~20.8 Β΅s
iteration/items/65536~56.2 Β΅s
hash/precomputed/65536~13.1 ns
equality/equal/16384~4.82 Β΅s
equality/unequal/16384~969 ps
functional/merge/256~7.31 Β΅s
functional/with/4096~64.6 Β΅s
functional/without/4096~79.7 Β΅s
fromkeys/4096~56.9 Β΅s
string_keys/lookup/hit_1024~12.9 ns
string_keys/lookup/miss_1024~5.58 ns

Run benchmarks yourself:

cargo bench                              # Rust
pip install frozndict frozendict immutables
python benchmarks/bench_compare.py      # Python comparison

Β§πŸ”’ Safety

This crate uses #![forbid(unsafe_code)] in all Rust modules except the Node.js FFI layer, which requires unsafe for napi-rs interop. Every other byte of implementation is safe Rust.

Β§πŸ“š Further Reading

Β§πŸ“„ License

Licensed under the MIT License.

Β§frozendict Rust Documentation πŸ¦€

The frozendict Rust crate provides a fully immutable, hashable, sorted-slice key-value store available as both a Rust library and the core backing all language bindings.

Β§πŸ“¦ Installation

[dependencies]
frozendict = "2.1.1"

Β§πŸ—‚ Module Structure

The frozen_map public module is split into focused sub-modules:

Sub-moduleContents
frozen_map::slotSlot, EMPTY, MIX_KEY/VAL, probe_capacity, table_insert
frozen_map (map)FrozenMap struct: construction, O(1) lookup, functional updates
frozen_map (iter)IntoIterator (owned + borrowed), FromIterator
frozen_map (fmt)Debug, Display, pretty_repr
frozen_map (ops)Default, Hash, PartialEq, Eq, Index

Β§πŸ›  Core Data Structure: FrozenMap<K, V>

Β§Construction

use frozendict::frozen_map::FrozenMap;

let map: FrozenMap<&str, i32> = FrozenMap::new([("b", 2), ("a", 1)]);
assert_eq!(map["a"], 1);
assert_eq!(map.len(), 2);

Β§fromkeys (Python-compatible)

use frozendict::frozen_map::FrozenMap;

let map = FrozenMap::fromkeys(["x", "y", "z"], 0_i32);
assert_eq!(map["x"], 0);

Β§Lookup

use frozendict::frozen_map::FrozenMap;

let map: FrozenMap<&str, i32> = FrozenMap::new([("a", 1)]);
assert_eq!(map.get("a"), Some(&1));
assert_eq!(map.get("b"), None);

let (key, val) = map.get_key_value("a").unwrap();
assert_eq!(key, &"a");

Β§Iteration

use frozendict::frozen_map::FrozenMap;

let map: FrozenMap<&str, i32> = FrozenMap::new([("b", 2), ("a", 1)]);

let keys: Vec<_>   = map.keys().collect();    // [&"a", &"b"]
let vals: Vec<_>   = map.values().collect();  // [&1, &2]
let items: Vec<_>  = map.items().collect();   // [(&"a", &1), (&"b", &2)]

for (k, v) in &map {
    println!("{k}: {v}");
}

Β§Hashing

use frozendict::frozen_map::FrozenMap;
use std::hash::{Hash, Hasher};
use std::collections::hash_map::DefaultHasher;

let map: FrozenMap<&str, i32> = FrozenMap::new([("a", 1)]);
println!("{}", map.precomputed_hash()); // O(1): pre-computed at construction

Β§Equality

use frozendict::frozen_map::FrozenMap;

let m1: FrozenMap<&str, i32> = FrozenMap::new([("a", 1), ("b", 2)]);
let m2: FrozenMap<&str, i32> = FrozenMap::new([("b", 2), ("a", 1)]);
assert_eq!(m1, m2); // order-independent; short-circuits on hash mismatch

Β§Functional Updates

All these methods return a new FrozenMap; the original is never modified.

use frozendict::frozen_map::FrozenMap;

let a: FrozenMap<&str, i32> = FrozenMap::new([("a", 1), ("b", 2)]);

// merge: other's values win on key collision
let merged = a.merge(&FrozenMap::new([("b", 99), ("c", 3)]));
assert_eq!(merged["b"], 99);
assert_eq!(merged["c"], 3);

// with: add or overwrite a single key
let extended = a.with("c", 3);
assert_eq!(extended.len(), 3);

// without: remove a single key
let reduced = a.without("a");
assert!(!reduced.contains_key("a"));

// intersection: keep keys present in both, values from self
let b: FrozenMap<&str, i32> = FrozenMap::new([("b", 99)]);
let inter = a.intersection(&b);
assert_eq!(inter.len(), 1);
assert_eq!(inter["b"], 2);

// union: all keys, self has priority on collision
let u = a.union(&FrozenMap::new([("b", 99), ("c", 3)]));
assert_eq!(u["b"], 2); // self wins
assert_eq!(u["c"], 3);

// difference: remove all keys present in other
let b2: FrozenMap<&str, i32> = FrozenMap::new([("b", 0)]);
let diff = a.difference(&b2);
assert_eq!(diff.len(), 1);
assert_eq!(diff["a"], 1);

Β§Index operator

use frozendict::frozen_map::FrozenMap;

let map: FrozenMap<&str, i32> = FrozenMap::new([("a", 1)]);
assert_eq!(map["a"], 1);
// map["z"] would panic

Β§Display and Debug

use frozendict::frozen_map::FrozenMap;

let map: FrozenMap<&str, i32> = FrozenMap::new([("a", 1)]);
println!("{map:?}");     // frozendict({"a": 1})
println!("{map}");       // frozendict({a: 1})
println!("{}", map.pretty_repr(4));

Β§FromIterator / IntoIterator

use frozendict::frozen_map::FrozenMap;

let map: FrozenMap<&str, i32> = [("a", 1), ("b", 2)].into_iter().collect();

// Consuming iteration
for (k, v) in map {
    println!("{k}: {v}");
}

Β§πŸ“– API Complexity Table

MethodTimeNotes
new(entries)O(n log n)Sort + linear dedup, no BTreeMap
fromkeys(keys, value)O(n log n)
len()O(1)
is_empty()O(1)
get(key)O(1) amortisedOpen-addressing probe table
get_key_value(key)O(1) amortised
contains_key(key)O(1) amortised
keys() / values()/items()O(n)Full iteration
precomputed_hash()O(1)Cached at construction
hash(state) (trait)O(1)
eq() (PartialEq)O(1) / O(n)O(1) if hash differs, O(n) otherwise
merge(other)O((m+n) log(m+n))
with(key, val)O(n log n)
without(key)O(n log n)
intersection(other)O(n log m)
union(other)O((m+n) log(m+n))
difference(other)O(n log m)
pretty_repr(n)O(n chars)
clone()O(n)
IntoIterator (owned)O(n)
IntoIterator (ref)O(n)

Β§πŸ“Š Running Benchmarks

# All benchmark groups
cargo bench

# Targeted group
cargo bench -- construction
cargo bench -- lookup
cargo bench -- functional

Results written to target/criterion/ as interactive HTML reports.

Β§πŸ”’ Safety

All Rust code outside the napi-rs FFI layer uses #![forbid(unsafe_code)].

Β§πŸ”— See Also

§🧊 FrozenDict

frozendict logo

Crates.io Docs.rs PyPI npm License: MIT CI

frozendict is a state of the art world’s most memory-efficient immutable hashmap written in 100% safe Rust, with native Python and Node.js bindings πŸ—Ώ.

frozendict banner

Β§πŸš€ Installation

PlatformCommand
Rust librarycargo add frozendict
Pythonpip install frozndict
Node.jsnpm i frozendict
Debian/UbuntuDownload .deb from GitHub Releases
RHEL/FedoraDownload .rpm from GitHub Releases

Β§πŸ€” What does this crate provide?

frozendict provides a fully immutable, hashable dictionary for Python and Node.js backed by a high-performance Rust core. It:

  • Stores entries in a single contiguous sorted heap allocation, zero per-entry heap overhead.
  • Looks up keys in O(log n) via binary search, no hashing, no pointer-chasing, excellent cache behaviour.
  • Caches its hash at construction, repeated hash() calls are O(1).
  • Integrates with Python’s dict protocol (keys(), values(), items(), pickle, copy, | merge operator).
  • Exposes a native Node.js FrozenDict class with TypeScript declarations via napi-rs.
  • Provides functional update primitives: merge, with, without, intersection, union, difference.

Β§πŸ’‘ Why sorted slice + binary search?

PropertyFrozenMap (this crate)HashMap / BTreeMap
Memory overheadZero: exactly n Γ— entry_size1.5-2Γ— allocator overhead
Allocation countOne at constructionOne per entry (BTreeMap)
LookupO(log n) binary searchO(1) / O(log n)
Cache behaviourExcellent: sequential prefetchPointer-chasing on tree nodes
MutationImpossible by design&mut self methods exist
Hash stabilityO(1): pre-computed at initO(n) on every hash() call

Binary search beats hash-map lookup for maps with fewer than ~64 entries because it avoids hashing and pointer-chasing. For larger maps the memory savings (up to 2Γ—) and cache locality more than compensate. See Cache-oblivious binary search and the AHash paper for background.

Β§πŸ¦€ Rust

[dependencies]
frozendict = "2.1.1"
use frozendict::frozen_map::FrozenMap;

let map: FrozenMap<&str, i32> = FrozenMap::new([("b", 2), ("a", 1)]);
assert_eq!(map["a"], 1);
assert_eq!(map.len(), 2);

let updated = map.with("c", 3);
assert_eq!(updated.len(), 3);

let merged = updated.merge(&FrozenMap::new([("a", 99)]));
assert_eq!(merged["a"], 99);

For the full API reference see RUST.md.

§🐍 Python

pip install frozndict
from frozndict import FrozenDict

d = FrozenDict({"a": 1, "b": 2})
print(d["a"])          # 1
print(hash(d))         # stable integer (pre-computed at construction)

d2 = d | {"c": 3}      # returns a new FrozenDict
print(d2.keys())

For full docs see PYTHON.md.

§🟩 Node.js

npm install frozendict
const { frozenDict, FrozenDict } = require("frozendict");

const d = frozenDict({ a: 1, b: "hello", c: [1, 2, 3] });
console.log(d.get("a")); // 1
console.log(d.size); // 3
console.log(d.has("z")); // false

const d2 = d.merge({ d: true });
console.log(d2.size); // 4
console.log(d2.toJSON()); // '{"a":1,"b":"hello","c":[1,2,3],"d":true}'

For full docs see NODE.md.

Β§πŸ”­ Features

FeatureDefaultDescription
python❌Python extension module via PyO3/maturin
node❌Node.js native add-on via napi-rs

Β§πŸ“Š Benchmarks

Β§πŸš€ Performance Highlights

frozndict operates natively at the mathematical speed limits of the hardware, heavily outperforming its C counterparts and standard dictionary data structures on several fronts.

The following is a 1000-element dictionary micro-benchmark comparison in seconds per operation (smaller is better), measured on x86-64 Linux with LTO=fat, opt-level=3, codegen-units=1, panic=abort, target-cpu=native.

Operation (1000 items)Python dictfrozendict (C)immutables.Mapfrozndict 🧊
Construction6.41 Β΅s πŸ†7.73 Β΅s244.91 Β΅s98.72 Β΅s
Clone O(1)6.37 Β΅s69.13 ns πŸ†411.89 ns117.24 ns
Equality19.18 Β΅s19.61 Β΅s24.39 ns πŸ†34.92 ns
Iteration7.10 Β΅s7.19 Β΅s14.89 Β΅s4.13 Β΅s πŸ†
copy()6.45 Β΅s323.22 ns310.04 Β΅s63.25 ns πŸ†
hash()N/A168.11 ns45.38 ns45.25 ns πŸ†
Lookup33.33 ns πŸ†56.03 ns47.48 ns82.98 ns

Benchmarked with timeit (min of 7 runs Γ— 2 000 iterations). Python 3.12.

Β§πŸ† Fastest Iteration in Class

Keys are stored in a single contiguous sorted Box<[K]>, sequential iteration has perfect prefetch behaviour. At 1000 elements, frozndict iterates 1.9Γ— faster than frozendict (C) and 3.5Γ— faster than immutables.Map.

Β§πŸ† Smallest copy() Overhead

copy() and __deepcopy__() share the backing Arc<FrozenDictInner>, O(1), just an atomic reference count increment. At 64 ns, frozndict is 5Γ— faster than frozendict (C) on copy.

Β§Deterministic O(1) Pre-Computed Hashing

The dict-level hash is XOR-combined over all (k, v) pairs exactly once at construction via inline multiplicative mixing (0x9e3779b97f4a7c15, 0x517cc1b727220a95). Subsequent hash() calls are a single field read, O(1), allocating nothing.

Β§O(1) Clone & Identity Equality

A shared Arc<FrozenDictInner> is re-used across the original, all copies, and frozendict(existing_fd) constructors. No data is ever duplicated. __eq__ short-circuits in O(1) via Arc::ptr_eq before comparing pre-computed hashes.

Β§Smallest Memory Footprint

Entries sit in a SoA layout: a Box<[K]> for keys and a Box<[V]> for values, two contiguous allocations. Binary search only touches the key array: 2Γ— smaller cache footprint compared to AoS layouts on large value types.

Β§Infallible Rust-Level Immutability

Mutation is blocked at the Rust binary level. There are no &mut self methods, not just descriptor tricks.

Β§Rust micro-benchmarks (cargo bench)

BenchmarkTime
construction/4~105 ns
construction/64~821 ns
construction/1024~16.1 Β΅s
construction/65536~1.32 ms
lookup/hit/4~5.94 ns
lookup/hit/64~5.83 ns
lookup/hit/1024~5.87 ns
lookup/hit/65536~5.83 ns
lookup/miss/64~6.48 ns
lookup/miss/65536~6.51 ns
iteration/keys/65536~20.8 Β΅s
iteration/values/65536~20.8 Β΅s
iteration/items/65536~56.2 Β΅s
hash/precomputed/65536~13.1 ns
equality/equal/16384~4.82 Β΅s
equality/unequal/16384~969 ps
functional/merge/256~7.31 Β΅s
functional/with/4096~64.6 Β΅s
functional/without/4096~79.7 Β΅s
fromkeys/4096~56.9 Β΅s
string_keys/lookup/hit_1024~12.9 ns
string_keys/lookup/miss_1024~5.58 ns

Run benchmarks yourself:

cargo bench                              # Rust
pip install frozndict frozendict immutables
python benchmarks/bench_compare.py      # Python comparison

Β§πŸ”’ Safety

This crate uses #![forbid(unsafe_code)] in all Rust modules except the Node.js FFI layer, which requires unsafe for napi-rs interop. Every other byte of implementation is safe Rust.

Β§πŸ“š Further Reading

Β§πŸ“„ License

Licensed under the MIT License.

Β§frozendict Rust Documentation πŸ¦€

The frozendict Rust crate provides a fully immutable, hashable, sorted-slice key-value store available as both a Rust library and the core backing all language bindings.

Β§πŸ“¦ Installation

[dependencies]
frozendict = "2.1.1"

Β§πŸ—‚ Module Structure

The frozen_map public module is split into focused sub-modules:

Sub-moduleContents
frozen_map::slotSlot, EMPTY, MIX_KEY/VAL, probe_capacity, table_insert
frozen_map (map)FrozenMap struct: construction, O(1) lookup, functional updates
frozen_map (iter)IntoIterator (owned + borrowed), FromIterator
frozen_map (fmt)Debug, Display, pretty_repr
frozen_map (ops)Default, Hash, PartialEq, Eq, Index

Β§πŸ›  Core Data Structure: FrozenMap<K, V>

Β§Construction

use frozendict::frozen_map::FrozenMap;

let map: FrozenMap<&str, i32> = FrozenMap::new([("b", 2), ("a", 1)]);
assert_eq!(map["a"], 1);
assert_eq!(map.len(), 2);

Β§fromkeys (Python-compatible)

use frozendict::frozen_map::FrozenMap;

let map = FrozenMap::fromkeys(["x", "y", "z"], 0_i32);
assert_eq!(map["x"], 0);

Β§Lookup

use frozendict::frozen_map::FrozenMap;

let map: FrozenMap<&str, i32> = FrozenMap::new([("a", 1)]);
assert_eq!(map.get("a"), Some(&1));
assert_eq!(map.get("b"), None);

let (key, val) = map.get_key_value("a").unwrap();
assert_eq!(key, &"a");

Β§Iteration

use frozendict::frozen_map::FrozenMap;

let map: FrozenMap<&str, i32> = FrozenMap::new([("b", 2), ("a", 1)]);

let keys: Vec<_>   = map.keys().collect();    // [&"a", &"b"]
let vals: Vec<_>   = map.values().collect();  // [&1, &2]
let items: Vec<_>  = map.items().collect();   // [(&"a", &1), (&"b", &2)]

for (k, v) in &map {
    println!("{k}: {v}");
}

Β§Hashing

use frozendict::frozen_map::FrozenMap;
use std::hash::{Hash, Hasher};
use std::collections::hash_map::DefaultHasher;

let map: FrozenMap<&str, i32> = FrozenMap::new([("a", 1)]);
println!("{}", map.precomputed_hash()); // O(1): pre-computed at construction

Β§Equality

use frozendict::frozen_map::FrozenMap;

let m1: FrozenMap<&str, i32> = FrozenMap::new([("a", 1), ("b", 2)]);
let m2: FrozenMap<&str, i32> = FrozenMap::new([("b", 2), ("a", 1)]);
assert_eq!(m1, m2); // order-independent; short-circuits on hash mismatch

Β§Functional Updates

All these methods return a new FrozenMap; the original is never modified.

use frozendict::frozen_map::FrozenMap;

let a: FrozenMap<&str, i32> = FrozenMap::new([("a", 1), ("b", 2)]);

// merge: other's values win on key collision
let merged = a.merge(&FrozenMap::new([("b", 99), ("c", 3)]));
assert_eq!(merged["b"], 99);
assert_eq!(merged["c"], 3);

// with: add or overwrite a single key
let extended = a.with("c", 3);
assert_eq!(extended.len(), 3);

// without: remove a single key
let reduced = a.without("a");
assert!(!reduced.contains_key("a"));

// intersection: keep keys present in both, values from self
let b: FrozenMap<&str, i32> = FrozenMap::new([("b", 99)]);
let inter = a.intersection(&b);
assert_eq!(inter.len(), 1);
assert_eq!(inter["b"], 2);

// union: all keys, self has priority on collision
let u = a.union(&FrozenMap::new([("b", 99), ("c", 3)]));
assert_eq!(u["b"], 2); // self wins
assert_eq!(u["c"], 3);

// difference: remove all keys present in other
let b2: FrozenMap<&str, i32> = FrozenMap::new([("b", 0)]);
let diff = a.difference(&b2);
assert_eq!(diff.len(), 1);
assert_eq!(diff["a"], 1);

Β§Index operator

use frozendict::frozen_map::FrozenMap;

let map: FrozenMap<&str, i32> = FrozenMap::new([("a", 1)]);
assert_eq!(map["a"], 1);
// map["z"] would panic

Β§Display and Debug

use frozendict::frozen_map::FrozenMap;

let map: FrozenMap<&str, i32> = FrozenMap::new([("a", 1)]);
println!("{map:?}");     // frozendict({"a": 1})
println!("{map}");       // frozendict({a: 1})
println!("{}", map.pretty_repr(4));

Β§FromIterator / IntoIterator

use frozendict::frozen_map::FrozenMap;

let map: FrozenMap<&str, i32> = [("a", 1), ("b", 2)].into_iter().collect();

// Consuming iteration
for (k, v) in map {
    println!("{k}: {v}");
}

Β§πŸ“– API Complexity Table

MethodTimeNotes
new(entries)O(n log n)Sort + linear dedup, no BTreeMap
fromkeys(keys, value)O(n log n)
len()O(1)
is_empty()O(1)
get(key)O(1) amortisedOpen-addressing probe table
get_key_value(key)O(1) amortised
contains_key(key)O(1) amortised
keys() / values()/items()O(n)Full iteration
precomputed_hash()O(1)Cached at construction
hash(state) (trait)O(1)
eq() (PartialEq)O(1) / O(n)O(1) if hash differs, O(n) otherwise
merge(other)O((m+n) log(m+n))
with(key, val)O(n log n)
without(key)O(n log n)
intersection(other)O(n log m)
union(other)O((m+n) log(m+n))
difference(other)O(n log m)
pretty_repr(n)O(n chars)
clone()O(n)
IntoIterator (owned)O(n)
IntoIterator (ref)O(n)

Β§πŸ“Š Running Benchmarks

# All benchmark groups
cargo bench

# Targeted group
cargo bench -- construction
cargo bench -- lookup
cargo bench -- functional

Results written to target/criterion/ as interactive HTML reports.

Β§πŸ”’ Safety

All Rust code outside the napi-rs FFI layer uses #![forbid(unsafe_code)].

Β§πŸ”— See Also

ModulesΒ§

frozen_map
FrozenMap: State-of-the-art immutable key-value store
nodenode and std
Node.js Bindings
pythonpython and std
Python Bindings