# axhash-dashmap
Concurrent [`DashMap`] and [`DashSet`] collections for Rust.
**Powered by [dashmap]** (multi-shard `RwLock`) · **Fueled by [axhash]** (AES-NI accelerated hashing)
[](https://crates.io/crates/axhash-dashmap)
[](https://docs.rs/axhash-dashmap)
[](LICENSE)
---
## Why axhash-dashmap?
`dashmap::DashMap` defaults to `RandomState` — a secure but slower hasher that
re-seeds on every process start. `axhash-dashmap` swaps the hasher for
**axhash**, which exploits hardware AES instructions (AES-NI on x86-64, AES on
ARMv8) to produce hashes at near-memory-bandwidth speed.
In a sharded concurrent map, **every shard lookup begins with a hash** to
determine which shard to lock. A faster hasher therefore reduces latency at the
point of highest contention.
## Ecosystem
| `axhash` | High-performance hashing engine |
| `axhash-map` | Fast HashMap/HashSet powered by `hashbrown` |
| `axhash-indexmap` | Ordered maps with AxHash |
| `axhash-dashmap` | Concurrent DashMap powered by AxHash |
```text
┌─────────────────────────────────────────────────────────────────┐
│ axhash-dashmap │
│ │
│ Type aliases (Serde-compatible) │
│ DashMap<K, V> DashSet<T> │
│ │
│ Branded newtypes (ergonomic constructors) │
│ AxDashMap<K, V> AxDashSet<T> │
│ │ │ │
│ dashmap::DashMap dashmap::DashSet │
│ ┌──────────┬─── ··· ───┬──────────┐ │
│ │ shard 0 │ shard 1 │ shard N │ ← parking_lot::RwLock │
│ └──────────┴─── ··· ───┴──────────┘ │
│ │ │
│ BuildHasherDefault<AxHasher> │
│ (AES-NI — shard selection + bucket probing) │
└─────────────────────────────────────────────────────────────────┘
```
Key points:
- **Only the hash step changes.** All concurrency guarantees, shard-locking
semantics, and deadlock-safety properties of `dashmap` are fully preserved.
- **Zero overhead.** `AxDashMap` is a `#[inline(always)]` newtype; the compiler
sees through it entirely.
- **AES is detected at runtime.** A portable software fallback is used
automatically on CPUs without AES instructions — you ship one binary.
---
## Two usage modes
### Mode 1 — Type alias (`DashMap` / `DashSet`)
Plain type aliases over `dashmap` with `BuildHasherDefault<AxHasher>` baked in.
Because there is no wrapper struct, **Serde and other `#[derive]`-based crates
work out of the box**.
```rust
use axhash_dashmap::{DashMap, AxHasher};
use core::hash::BuildHasherDefault;
// Serde-compatible — no custom wrapper type in the type hierarchy.
let map: DashMap<&str, u32> =
dashmap::DashMap::with_hasher(BuildHasherDefault::<AxHasher>::default());
map.insert("hello", 42);
```
### Mode 2 — Branded newtype (`AxDashMap` / `AxDashSet`)
A thin newtype wrapper that adds `::new()` / `::with_capacity()` /
`::with_shard_amount()` constructors (`dashmap::DashMap::new()` is only defined
for `RandomState` — not for generic `S`). Every `DashMap` method is accessible
transparently via `Deref`.
```rust
use axhash_dashmap::AxDashMap;
let map: AxDashMap<&str, u32> = AxDashMap::new();
map.insert("hello", 42);
assert_eq!(*map.get("hello").unwrap(), 42);
```
| `::new()` / `::with_capacity()` / `::with_shard_amount()` | `AxDashMap` / `AxDashSet` |
| Serde `#[derive(Serialize, Deserialize)]` | `DashMap` / `DashSet` |
| Custom / seeded hasher | `AxDashMap::with_hasher(AxBuildHasher::with_seed(s))` |
| Raw `dashmap` access | `RawDashMap` / `RawDashSet` |
---
## Installation
```toml
[dependencies]
axhash-dashmap = "0.1"
```
### Optional features
```toml
# Enable serde::Serialize / Deserialize on DashMap / DashSet
axhash-dashmap = { version = "0.1", features = ["serde"] }
# Enable rayon parallel iterators
axhash-dashmap = { version = "0.1", features = ["rayon"] }
```
---
## Quick start
### AxDashMap
```rust
use axhash_dashmap::AxDashMap;
// Create — zero-overhead newtype wrapper.
let scores: AxDashMap<&str, u32> = AxDashMap::new();
scores.insert("alice", 42);
scores.insert("bob", 17);
scores.insert("carol", 99);
// Lookup (returns a Ref guard — no clone needed).
assert_eq!(*scores.get("alice").unwrap(), 42);
// Entry API — increment atomically within a shard lock.
scores.entry("alice").and_modify(|v| *v += 1);
assert_eq!(*scores.get("alice").unwrap(), 43);
// Concurrent iteration.
scores.alter_all(|_, v| v * 2);
assert_eq!(*scores.get("alice").unwrap(), 86);
// Predicate-based removal.
```rust
use std::sync::Arc;
use axhash_dashmap::AxDashMap;
let map: Arc<AxDashMap<u32, u32>> = Arc::new(AxDashMap::with_capacity(10_000));
let handles: Vec<_> = (0..8)
.map(|t| {
let m = Arc::clone(&map);
std::thread::spawn(move || {
for i in 0u32..125 {
m.insert(t * 125 + i, i * i);
}
})
})
.collect();
for h in handles { h.join().unwrap(); }
assert_eq!(map.len(), 1_000);
```
---
## Constructors
### `AxDashMap`
| Empty map, default shards | `AxDashMap::new()` |
| Pre-allocated map | `AxDashMap::with_capacity(n)` |
| Custom shard count | `AxDashMap::with_shard_amount(shards)` |
| Capacity + shard count | `AxDashMap::with_capacity_and_shard_amount(n, shards)` |
| Default (zero seed) | `AxDashMap::default()` |
| Seeded hasher | `AxDashMap::with_hasher(AxBuildHasher::with_seed(s))` |
| Seeded + capacity | `AxDashMap::with_capacity_and_hasher(n, AxBuildHasher::with_seed(s))` |
| Seeded + shard count | `AxDashMap::with_hasher_and_shard_amount(AxBuildHasher::with_seed(s), shards)` |
> **Shard count tip:** `shard_amount` must be a **power of two**.
> Default = logical CPUs × 4, rounded up to the next power of two.
> More shards → less contention under high thread counts.
> Fewer shards → lower memory overhead for small maps.
### `AxDashSet`
| Empty set, default shards | `AxDashSet::new()` |
| Pre-allocated set | `AxDashSet::with_capacity(n)` |
| Default (zero seed) | `AxDashSet::default()` |
| Seeded hasher | `AxDashSet::with_hasher(AxBuildHasher::with_seed(s))` |
| Seeded + capacity | `AxDashSet::with_capacity_and_hasher(n, AxBuildHasher::with_seed(s))` |
---
## Seeded construction
Supply a random seed to harden against hash-flooding attacks when keys come
from untrusted input (e.g. HTTP parameters, user-supplied JSON):
```rust
use axhash_dashmap::{AxDashMap, AxBuildHasher};
// In production: derive seed from OS entropy (rand, getrandom, etc.).
let seed: u64 = 0xdeadbeef_cafebabe;
let map: AxDashMap<String, u32, AxBuildHasher> =
AxDashMap::with_hasher(AxBuildHasher::with_seed(seed));
map.insert("untrusted_key".to_string(), 1);
```
---
## All dashmap methods are available
`AxDashMap` and `AxDashSet` implement `Deref` / `DerefMut` to the underlying
`dashmap::DashMap` / `dashmap::DashSet`, so every method is directly accessible
without extra imports — `entry`, `iter`, `alter`, `alter_all`, `retain`,
`into_read_only`, `shrink_to_fit`, `get_mut`, and more.
```rust
use axhash_dashmap::AxDashMap;
let map: AxDashMap<&str, u32> = AxDashMap::new();
map.insert("hits", 0);
// entry — modify-or-insert within a single shard lock.
map.entry("hits").and_modify(|n| *n += 1);
// retain — predicate-based removal.
map.insert("temp", 0);
let map: AxDashMap<&str, u32> = [("a", 1), ("b", 2)].into_iter().collect();
let ro = map.into_inner().into_read_only();
assert_eq!(*ro.get("a").unwrap(), 1);
```
---
## Interoperability with raw dashmap types
The crate re-exports `RawDashMap` and `RawDashSet` and provides `From`
conversions in both directions so you can cross the boundary without a direct
`dashmap` dependency in your own `Cargo.toml`.
```rust
use core::hash::BuildHasherDefault;
use axhash_dashmap::{AxDashMap, RawDashMap, AxHasher};
// Wrap a raw dashmap.
let raw: RawDashMap<&str, u32, BuildHasherDefault<AxHasher>> =
dashmap::DashMap::with_hasher(BuildHasherDefault::default());
raw.insert("x", 99);
let ax: AxDashMap<&str, u32> = raw.into();
assert_eq!(*ax.get("x").unwrap(), 99);
// Unwrap back to dashmap.
let raw: RawDashMap<&str, u32, BuildHasherDefault<AxHasher>> = ax.into();
assert_eq!(*raw.get("x").unwrap(), 99);
```
---
## Feature flags
| `serde` | ❌ off | Enables `serde::Serialize` / `Deserialize` on `DashMap` / `DashSet`. |
| `rayon` | ❌ off | Enables rayon parallel iterators on `DashMap` / `DashSet`. |
---
## Dependency footprint
```text
axhash-dashmap
├── axhash-core (AxHasher + AxBuildHasher — AES hash engine)
└── dashmap (multi-shard RwLock concurrent map, no default features)
```
---
## License
MIT — see [LICENSE](LICENSE).
[`DashMap`]: https://docs.rs/dashmap/latest/dashmap/struct.DashMap.html
[`DashSet`]: https://docs.rs/dashmap/latest/dashmap/struct.DashSet.html
[dashmap]: https://crates.io/crates/dashmap
[axhash]: https://crates.io/crates/axhash