Skip to main content

Crate axhash_dashmap

Crate axhash_dashmap 

Source
Expand description

§axhash-dashmap

Concurrent DashMap and DashSet collections for Rust.

Powered by dashmap (multi-shard RwLock) · Fueled by axhash (AES-NI accelerated hashing)

Crates.io Docs.rs License: MIT


§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

CrateDescription
axhashHigh-performance hashing engine
axhash-mapFast HashMap/HashSet powered by hashbrown
axhash-indexmapOrdered maps with AxHash
axhash-dashmapConcurrent DashMap powered by AxHash
┌─────────────────────────────────────────────────────────────────┐
│                       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.

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.

use axhash_dashmap::AxDashMap;

let map: AxDashMap<&str, u32> = AxDashMap::new();
map.insert("hello", 42);
assert_eq!(*map.get("hello").unwrap(), 42);
NeedUse
::new() / ::with_capacity() / ::with_shard_amount()AxDashMap / AxDashSet
Serde #[derive(Serialize, Deserialize)]DashMap / DashSet
Custom / seeded hasherAxDashMap::with_hasher(AxBuildHasher::with_seed(s))
Raw dashmap accessRawDashMap / RawDashSet

§Installation

[dependencies]
axhash-dashmap = "0.1"

§Optional features

# 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

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.
let total: u32 = scores.iter().map(|r| *r.value()).sum();
assert_eq!(total, 159);

// Bulk mutation without extra allocation.
scores.alter_all(|_, v| v * 2);
assert_eq!(*scores.get("alice").unwrap(), 86);

// Predicate-based removal.
scores.retain(|_, v| *v > 50);

§AxDashSet

use axhash_dashmap::AxDashSet;

let seen: AxDashSet<u64> = AxDashSet::new();
seen.insert(1);
seen.insert(2);
seen.insert(2); // duplicate — silently ignored

assert_eq!(seen.len(), 2);
assert!(seen.contains(&1));

§Concurrent usage with Arc

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

GoalCall
Empty map, default shardsAxDashMap::new()
Pre-allocated mapAxDashMap::with_capacity(n)
Custom shard countAxDashMap::with_shard_amount(shards)
Capacity + shard countAxDashMap::with_capacity_and_shard_amount(n, shards)
Default (zero seed)AxDashMap::default()
Seeded hasherAxDashMap::with_hasher(AxBuildHasher::with_seed(s))
Seeded + capacityAxDashMap::with_capacity_and_hasher(n, AxBuildHasher::with_seed(s))
Seeded + shard countAxDashMap::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

GoalCall
Empty set, default shardsAxDashSet::new()
Pre-allocated setAxDashSet::with_capacity(n)
Default (zero seed)AxDashSet::default()
Seeded hasherAxDashSet::with_hasher(AxBuildHasher::with_seed(s))
Seeded + capacityAxDashSet::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):

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.

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);
map.retain(|_, v| *v > 0);
assert!(!map.contains_key("temp"));

// into_read_only — zero-copy promotion to a read-only view.
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.

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

FlagDefaultEffect
serde❌ offEnables serde::Serialize / Deserialize on DashMap / DashSet.
rayon❌ offEnables rayon parallel iterators on DashMap / DashSet.

§Dependency footprint

axhash-dashmap
├── axhash-core   (AxHasher + AxBuildHasher — AES hash engine)
└── dashmap       (multi-shard RwLock concurrent map, no default features)

§License

MIT — see LICENSE.

Structs§

AxBuildHasher
The AES-NI accelerated hasher. Re-exported so callers don’t need a direct axhash-core dependency.
AxDashMap
AxDashSet
Concurrent hash set backed by dashmap (multi-shard RwLock) with AxHasher (AES-NI accelerated hashing) as the default hasher.
AxHasher
The AES-NI accelerated hasher. Re-exported so callers don’t need a direct axhash-core dependency.
DashOccupiedEntry
DashVacantEntry
RawDashMap
Raw dashmap::DashMap — available without a direct dashmap dep. DashMap is an implementation of a concurrent associative array/hashmap in Rust.
RawDashSet
Raw dashmap::DashSet — available without a direct dashmap dep. DashSet is a thin wrapper around DashMap using () as the value type. It uses methods and types which are more convenient to work with on a set.

Enums§

DashEntry
Dashmap entry types — re-exported for ergonomic match arms.

Type Aliases§

DashMap
Drop-in dashmap::DashMap with AxHasher as the default hasher.
DashSet
Drop-in dashmap::DashSet with AxHasher as the default hasher.