axhash-dashmap 0.1.1

Concurrent DashMap and DashSet powered by dashmap (multi-shard RwLock) and fueled by axhash (AES-NI accelerated hashing).
Documentation
# axhash-dashmap

Concurrent [`DashMap`] and [`DashSet`] collections for Rust.

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

[![Crates.io](https://img.shields.io/crates/v/axhash-dashmap.svg)](https://crates.io/crates/axhash-dashmap)
[![Docs.rs](https://docs.rs/axhash-dashmap/badge.svg)](https://docs.rs/axhash-dashmap)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](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

| Crate | Description |
|---|---|
| `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);
```

| Need | Use |
|---|---|
| `::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.
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

```rust
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`

```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`

| Goal | Call |
|---|---|
| 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`

| Goal | Call |
|---|---|
| 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);
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`.

```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

| Flag | Default | Effect |
|---|:---:|---|
| `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