# Thunderation 🌩️

[![Documentation](https://docs.rs/thunderation/badge.svg)](https://docs.rs/thunderation)
[![Crates.io](https://img.shields.io/crates/v/thunderation.svg)](https://crates.io/crates/thunderation)
[![License](https://img.shields.io/crates/l/thunderation.svg)](https://codeberg.org/BillyDM/thunderation/src/branch/main/LICENSE-MIT)
[![NO AI](https://raw.githubusercontent.com/nuxy/no-ai-badge/master/badge.svg)](https://github.com/nuxy/no-ai-badge)

Thunderation is a generational arena forked from
[Thunderdome](https://crates.io/crates/thunderdome). It adds a few
improvements like unique key type identifiers, improved methods, and the removal
of all unsafe code.

It provides constant time insertion, lookup, and removal via small (8 byte) keys
returned from `Arena` or via slot indices. Thunderation's key type is still 8
bytes when put inside of an `Option<Key>` thanks to Rust's `NonZero*` types. One
limitation of this key type is that arenas can only hold up to `u32::MAX`
elements.

This data structure is backed by a `Vec` and is implemented using zero unsafe
code.

# Why use this over [slotmap](https://crates.io/crates/slotmap)?

The main reason is when you need to get and set values by their slot index
in addition to generational keys. If you do not need this, consider using
slotmap instead.

# Basic Examples

```rust
use thunderation::{Arena, Key};

// Define a unique key type identifier. This prevents keys from
// being used in Arena's they don't belong to.
pub struct MyKey;

// Create an arena with the given key type and the storage type.
let mut arena = Arena::<MyKey, &'static str>::new();

let foo = arena.insert("Foo");
let bar = arena.insert("Bar");

assert_eq!(arena[foo], "Foo");
assert_eq!(arena[bar], "Bar");

// Methods to get/insert items by slot index are also available.
let (key, value) = arena.get_by_slot(foo.slot()).unwrap();
assert_eq!(key, foo);
assert_eq!(value, &"Foo");

arena[bar] = "Replaced";
assert_eq!(arena[bar], "Replaced");

let foo_value = arena.remove(foo);
assert_eq!(foo_value, Some("Foo"));

// The slot previously used by foo will be reused for baz
let baz = arena.insert("Baz");
assert_eq!(arena[baz], "Baz");

// foo is no longer a valid key
assert_eq!(arena.get(foo), None);
```

# Comparison With Similar Crates

| Feature                      | Thunderation | Thunderdome | generational-arena | typed-generational-arena | slotmap | slab |
|------------------------------|--------------|-------------|--------------------|--------------------------|---------|------|
| Generational¹                | Yes          | Yes         | Yes                | Yes                      | Yes     | No   |
| `size_of::<Key>()`           | 8            | 8           | 16                 | varies                   | 8       | 8    |
| `size_of::<Option<Key>>()`   | 8            | 8           | 24                 | varies                   | 8       | 16   |
| Max elements                 | 2³²          | 2³²         | 2⁶⁴                | 2⁶⁴                      | 2³²     | 2⁶⁴  |
| Non-`Copy` values            | Yes          | Yes         | Yes                | Yes                      | Yes     | Yes  |
| `no_std` support             | Yes          | Yes         | Yes                | Yes                      | Yes     | Yes  |
| Uniquely typed keys          | Yes          | No          | No                 | Yes                      | Yes     | No   |
| Get/set values by slot index | Yes          | Yes         | No                 | No                       | No      | Yes  |
| Zero unsafe used             | Yes          | No          | Yes                | Yes                      | No      | No   |
| Serde support                | No           | No          | Yes                | Yes                      | Yes     | No   |

> 1. Generational indices help solve the [ABA
> Problem](https://en.wikipedia.org/wiki/ABA_problem), which can cause dangling
> keys to mistakenly access newly-inserted data.

# Crate Features
* `std` (default): Use the standard library. Disable to make this crate `no-std` compatible.

## License

Licensed under either of

 * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
 * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)

at your option.
