Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 41 additions & 26 deletions crates/iddqd/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@ Maps where keys are borrowed from values.

This crate consists of several map types, collectively called **ID maps**:

* [`IdOrdMap`](https://docs.rs/iddqd/0.4.6/iddqd/id_ord_map/imp/struct.IdOrdMap.html): A B-Tree based map where keys are borrowed from values.
* [`IdHashMap`](https://docs.rs/iddqd/0.4.6/iddqd/id_hash_map/imp/struct.IdHashMap.html): A hash map where keys are borrowed from values.
* [`BiHashMap`](https://docs.rs/iddqd/0.4.6/iddqd/bi_hash_map/imp/struct.BiHashMap.html): A bijective (1:1) hash map with two keys, borrowed from
* [`IdOrdMap`]: A B-Tree based map where keys are borrowed from values.
* [`IdHashMap`]: A hash map where keys are borrowed from values.
* [`BiHashMap`]: A bijective (1:1) hash map with two keys, borrowed from
values.
* [`TriHashMap`](https://docs.rs/iddqd/0.4.6/iddqd/tri_hash_map/imp/struct.TriHashMap.html): A trijective (1:1:1) hash map with three keys, borrowed
* [`TriHashMap`]: A trijective (1:1:1) hash map with three keys, borrowed
from values.

## Usage

* Pick your ID map type.
* Depending on the ID map type, implement [`IdOrdItem`](https://docs.rs/iddqd/0.4.6/iddqd/id_ord_map/trait_defs/trait.IdOrdItem.html), [`IdHashItem`](https://docs.rs/iddqd/0.4.6/iddqd/id_hash_map/trait_defs/trait.IdHashItem.html),
[`BiHashItem`](https://docs.rs/iddqd/0.4.6/iddqd/bi_hash_map/trait_defs/trait.BiHashItem.html), or [`TriHashItem`](https://docs.rs/iddqd/0.4.6/iddqd/tri_hash_map/trait_defs/trait.TriHashItem.html) for your value type.
* Depending on the ID map type, implement [`IdOrdItem`], [`IdHashItem`],
[`BiHashItem`], or [`TriHashItem`] for your value type.
* Store values in the ID map type.

### Features
Expand All @@ -40,7 +40,7 @@ issues encountered using Rust’s default map types in practice at Oxide.
* There’s no `insert` method; insertion must be through either
`insert_overwrite` or `insert_unique`. You must pick an insertion
behavior.
* For hash maps, the default hasher is [`foldhash`](https://docs.rs/foldhash/0.2.0/foldhash/index.html), which is much faster
* For hash maps, the default hasher is [`foldhash`], which is much faster
than SipHash. However, foldhash does *not provide the same level of HashDoS
resistance* as SipHash. If that is important to you, you can use a different
hasher. (Disable the `default-hasher` feature to require a hash
Expand All @@ -49,19 +49,19 @@ issues encountered using Rust’s default map types in practice at Oxide.

We’ve also sometimes needed to index a set of data by more than one key, or
perhaps map one key to another. For that purpose, this crate provides
[`BiHashMap`](https://docs.rs/iddqd/0.4.6/iddqd/bi_hash_map/imp/struct.BiHashMap.html) and [`TriHashMap`](https://docs.rs/iddqd/0.4.6/iddqd/tri_hash_map/imp/struct.TriHashMap.html).
[`BiHashMap`] and [`TriHashMap`].

* [`BiHashMap`](https://docs.rs/iddqd/0.4.6/iddqd/bi_hash_map/imp/struct.BiHashMap.html) has two keys, and provides a bijection (1:1 relationship)
* [`BiHashMap`] has two keys, and provides a bijection (1:1 relationship)
between the keys.
* [`TriHashMap`](https://docs.rs/iddqd/0.4.6/iddqd/tri_hash_map/imp/struct.TriHashMap.html) has three keys, and provides a trijection (1:1:1
* [`TriHashMap`] has three keys, and provides a trijection (1:1:1
relationship) between the keys.

As a consequence of the general API structure, maps can have arbitrary
non-key data associated with them as well.

### Examples

An example for [`IdOrdMap`](https://docs.rs/iddqd/0.4.6/iddqd/id_ord_map/imp/struct.IdOrdMap.html):
An example for [`IdOrdMap`]:

````rust
use iddqd::{IdOrdItem, IdOrdMap, id_upcast};
Expand Down Expand Up @@ -103,7 +103,7 @@ for user in &users {

Keys don’t have to be borrowed from the value. For smaller `Copy` types,
it’s recommended that you use owned keys. Here’s an example of using
[`IdOrdMap`](https://docs.rs/iddqd/0.4.6/iddqd/id_ord_map/imp/struct.IdOrdMap.html) with a small integer key:
[`IdOrdMap`] with a small integer key:

````rust
struct Record {
Expand All @@ -125,7 +125,7 @@ impl IdOrdItem for Record {
// ...
````

An example for [`IdHashMap`](https://docs.rs/iddqd/0.4.6/iddqd/id_hash_map/imp/struct.IdHashMap.html), showing a complex borrowed key. Here,
An example for [`IdHashMap`], showing a complex borrowed key. Here,
“complex” means that the key is not a reference itself, but a struct that
returns references to more than one field from the value.

Expand Down Expand Up @@ -199,8 +199,8 @@ through the [`Borrow`] trait.
But the [`Borrow`] trait is a bit too restrictive for complex keys such as
`ArtifactKey` above, requiring workarounds such as [dynamic
dispatch](https://github.com/sunshowers-code/borrow-complex-key-example). To
address this, the crates.io ecosystem has standardized on the [`Equivalent`](https://docs.rs/equivalent/1.0.2/equivalent/trait.Equivalent.html)
and [`Comparable`](https://docs.rs/equivalent/1.0.2/equivalent/trait.Comparable.html) traits as generalizations of `Borrow`. The map types in
address this, the crates.io ecosystem has standardized on the [`Equivalent`]
and [`Comparable`] traits as generalizations of `Borrow`. The map types in
this crate require these traits.

For a key type `T::Key<'_>` and a query type `Q`:
Expand All @@ -209,7 +209,7 @@ For a key type `T::Key<'_>` and a query type `Q`:
must hash in the same way as `T::Key<'_>`. Typically, this is done by
ensuring that enum variants and struct fields are in the same
order[^proptest].
* [`IdOrdMap`](https://docs.rs/iddqd/0.4.6/iddqd/id_ord_map/imp/struct.IdOrdMap.html) requires `Q: Comparable<T::Key<'_>>`, which in turn requires
* [`IdOrdMap`] requires `Q: Comparable<T::Key<'_>>`, which in turn requires
`Equivalent<T::Key<'_>>`. (There’s no need for `Q` to implement `Ord` or
`Eq` itself.)

Expand Down Expand Up @@ -245,7 +245,7 @@ let owned_key = OwnedArtifactKey {
assert_eq!(artifacts.get(&owned_key).unwrap().data, b"data1",);
````

There’s a blanket implementation of [`Equivalent`](https://docs.rs/equivalent/1.0.2/equivalent/trait.Equivalent.html) and [`Comparable`](https://docs.rs/equivalent/1.0.2/equivalent/trait.Comparable.html) for
There’s a blanket implementation of [`Equivalent`] and [`Comparable`] for
[`Borrow`], so if your type already implements [`Borrow`], there aren’t any
extra steps to take.

Expand Down Expand Up @@ -277,26 +277,26 @@ tests depend on nextest’s process-per-test model.

## No-std compatibility

Most of this crate is no-std compatible, though [`alloc`](https://doc.rust-lang.org/nightly/alloc/index.html) is required.
Most of this crate is no-std compatible, though [`alloc`] is required.

The [`IdOrdMap`](https://docs.rs/iddqd/0.4.6/iddqd/id_ord_map/imp/struct.IdOrdMap.html) type is not currently no-std compatible due to its use of a
The [`IdOrdMap`] type is not currently no-std compatible due to its use of a
thread-local. This thread-local is just a way to work around a limitation in
std’s `BTreeMap` API, though. Either a custom B-Tree implementation, or a
platform-specific notion of thread locals, would suffice to make
[`IdOrdMap`](https://docs.rs/iddqd/0.4.6/iddqd/id_ord_map/imp/struct.IdOrdMap.html) no-std compatible.
[`IdOrdMap`] no-std compatible.

## Optional features

* `allocator-api2`: Enables support for custom allocators via the
[`allocator_api2`](https://docs.rs/allocator-api2/0.2.21/allocator_api2/index.html) crate. Both global and scoped/arena allocators
[`allocator_api2`] crate. Both global and scoped/arena allocators
(such as `bumpalo`) are supported. Custom allocators are not currently
supported by `IdOrdMap`.
* `daft`: Enables [`daft`](https://docs.rs/daft/0.1.5/daft/index.html) support for all ID map types. *Not enabled by
* `daft`: Enables [`daft`] support for all ID map types. *Not enabled by
default.*
* `default-hasher`: Enables the `DefaultHashBuilder` type. Disable this
feature to require a hash builder type parameter to be passed into
[`IdHashMap`](https://docs.rs/iddqd/0.4.6/iddqd/id_hash_map/imp/struct.IdHashMap.html), [`BiHashMap`](https://docs.rs/iddqd/0.4.6/iddqd/bi_hash_map/imp/struct.BiHashMap.html), and [`TriHashMap`](https://docs.rs/iddqd/0.4.6/iddqd/tri_hash_map/imp/struct.TriHashMap.html). *Enabled by default.*
* `proptest`: Enables [`proptest`](https://docs.rs/proptest/1.7.0/proptest/index.html) support for all ID map types, providing
[`IdHashMap`], [`BiHashMap`], and [`TriHashMap`]. *Enabled by default.*
* `proptest`: Enables [`proptest`] support for all ID map types, providing
[`Arbitrary`] implementations and strategies for property-based testing.
*Not enabled by default.*
* `schemars08`: Enables [`schemars`] support for all ID map types,
Expand Down Expand Up @@ -335,8 +335,23 @@ The name `iddqd` is a reference to [a cheat
code](https://doomwiki.org/wiki/Doom_cheat_codes) in the classic video game
*Doom*. It has `id` in the name, and is short and memorable.

[`Borrow`]: https://doc.rust-lang.org/nightly/core/borrow/trait.Borrow.html
[`Arbitrary`]: https://docs.rs/proptest/1.7.0/proptest/arbitrary/traits/trait.Arbitrary.html
[`IdOrdMap`]: https://docs.rs/iddqd/0.4.6/iddqd/id_ord_map/imp/struct.IdOrdMap.html "struct iddqd::id_ord_map::imp::IdOrdMap"
[`IdHashMap`]: https://docs.rs/iddqd/0.4.6/iddqd/id_hash_map/imp/struct.IdHashMap.html "struct iddqd::id_hash_map::imp::IdHashMap"
[`BiHashMap`]: https://docs.rs/iddqd/0.4.6/iddqd/bi_hash_map/imp/struct.BiHashMap.html "struct iddqd::bi_hash_map::imp::BiHashMap"
[`TriHashMap`]: https://docs.rs/iddqd/0.4.6/iddqd/tri_hash_map/imp/struct.TriHashMap.html "struct iddqd::tri_hash_map::imp::TriHashMap"
[`IdOrdItem`]: https://docs.rs/iddqd/0.4.6/iddqd/id_ord_map/trait_defs/trait.IdOrdItem.html "trait iddqd::id_ord_map::trait_defs::IdOrdItem"
[`IdHashItem`]: https://docs.rs/iddqd/0.4.6/iddqd/id_hash_map/trait_defs/trait.IdHashItem.html "trait iddqd::id_hash_map::trait_defs::IdHashItem"
[`BiHashItem`]: https://docs.rs/iddqd/0.4.6/iddqd/bi_hash_map/trait_defs/trait.BiHashItem.html "trait iddqd::bi_hash_map::trait_defs::BiHashItem"
[`TriHashItem`]: https://docs.rs/iddqd/0.4.6/iddqd/tri_hash_map/trait_defs/trait.TriHashItem.html "trait iddqd::tri_hash_map::trait_defs::TriHashItem"
[`foldhash`]: https://docs.rs/foldhash/0.2.0/foldhash/index.html "module foldhash"
[`Borrow`]: https://doc.rust-lang.org/nightly/core/borrow/trait.Borrow.html "trait core::borrow::Borrow"
[`Equivalent`]: https://docs.rs/equivalent/1.0.2/equivalent/trait.Equivalent.html "trait equivalent::Equivalent"
[`Comparable`]: https://docs.rs/equivalent/1.0.2/equivalent/trait.Comparable.html "trait equivalent::Comparable"
[`alloc`]: https://doc.rust-lang.org/nightly/alloc/index.html "module alloc"
[`allocator_api2`]: https://docs.rs/allocator-api2/0.2.21/allocator_api2/index.html "module allocator_api2"
[`daft`]: https://docs.rs/daft/0.1.5/daft/index.html "module daft"
[`proptest`]: https://docs.rs/proptest/1.7.0/proptest/index.html "module proptest"
[`Arbitrary`]: https://docs.rs/proptest/1.7.0/proptest/arbitrary/traits/trait.Arbitrary.html "trait proptest::arbitrary::traits::Arbitrary"
[`schemars`]: https://crates.io/crates/schemars
[automatic replacement]: https://github.com/oxidecomputer/iddqd/blob/main/crates/iddqd-extended-examples/examples/typify-types.rs
[`typify`]: https://crates.io/crates/typify
Expand Down
Loading