16 releases (6 stable)
1.5.0 | May 26, 2024 |
---|---|
0.10.0 | Feb 19, 2024 |
0.7.0 | Feb 6, 2023 |
0.4.0 | Dec 30, 2022 |
#237 in Data structures
1,088 downloads per month
32KB
284 lines
EnumMap for Rust
Contribution guide | Apache v2 license
A map of enum variants to values. EnumMap is a fixed-size map, where each variant of the enum is mapped to a value. This implementation of EnumMap uses safe Rust only and is a a zero-cost abstraction over an array (const-sized), where the index of the array corresponds to the position of the variant in the enum.
Because it is a thin wrapper over an array, it is stack-allocated by default. Simply std::boxed::Box
ing it will move it to the heap, at the caller's discretion.
- Indexed by enum variants.
- IndexMut by enum variants.
- Debug if the enum is Debug.
- PartialEq if the value is PartialEq. Same for Eq.
Debug and Eq are optional features. They are enabled by default.
Usage
Please refer to the documentation for a complete list of features and more in-depth documentation.
use enum_collections::{EnumMap, Enumerated, em, em_default, em_option};
#[derive(Enumerated)]
pub enum Letter {
A,
B,
}
// Indexing and mutation
// The SIZE hint is required until [generic_const_expr](https://github.com/rust-lang/rust/issues/76560) are stabilized.
let mut enum_map = EnumMap::<Letter, i32, { Letter::SIZE }>::new_default();
assert_eq!(0, enum_map[Letter::A]);
enum_map[Letter::A] = 42;
assert_eq!(42, enum_map[Letter::A]);
// Construction using macros
// (Key type, Value type, Key=>Value pairs)
let enum_map = em!(Letter, i32, A=>42, B=>24); // All values set explicitly
assert_eq!(42, enum_map[Letter::A]);
assert_eq!(24, enum_map[Letter::B]);
// (Key type, Value type, optional Key=>Value pairs)
let enum_map = em_default!(Letter, i32, A => 42); // Default used for missing values
assert_eq!(42, enum_map[Letter::A]);
assert_eq!(i32::default(), enum_map[Letter::B]);
let enum_map = em_default!(Letter, i32,); // All default
assert_eq!(i32::default(), enum_map[Letter::A]);
assert_eq!(i32::default(), enum_map[Letter::B]);
// EnumMap of optional values `Option<V>`, value type is automatically wrapped in `Option`.
// (Key type, Value type, optional Key=>Value pairs)
let enum_map = em_option!(Letter, i32, A => 42);
assert_eq!(Some(42), enum_map[Letter::A]);
assert_eq!(None, enum_map[Letter::B]);
// Constructor with default values
let enum_map_default = EnumMap::<Letter, i32, { Letter::SIZE }>::new_default();
assert_eq!(0, enum_map_default[Letter::A]);
assert_eq!(0, enum_map_default[Letter::B]);
// Convenience constructor for optional values
let mut enum_map_option = EnumMap::<Letter, Option<i32>, { Letter::SIZE }>::new_option();
assert_eq!(None, enum_map_option[Letter::A]);
assert_eq!(None, enum_map_option[Letter::B]);
enum_map_option[Letter::A] = Some(42);
assert_eq!(Some(42), enum_map_option[Letter::A]);
// Constructor with custom initialization
#[derive(PartialEq, Eq, Debug)]
struct Custom;
let enum_map = EnumMap::<Letter, Custom, { Letter::SIZE }>::new(|| Custom);
assert_eq!(Custom, enum_map[Letter::A]);
assert_eq!(Custom, enum_map[Letter::B]);
// Custom initialization function with enum variant (key) inspection
let enum_map = EnumMap::<Letter, i32, { Letter::SIZE }>::new_inspect(|letter| {
match letter {
Letter::A => 42,
Letter::B => 24,
}
});
assert_eq!(42, enum_map[Letter::A]);
assert_eq!(24, enum_map[Letter::B]);
// Debug
#[derive(Enumerated, Debug)]
pub enum LetterDebugDerived {
A,
B,
}
let enum_map_debug =
EnumMap::<LetterDebugDerived, i32, { LetterDebugDerived::SIZE }>::new(|| 42);
assert_eq!("{A: 42, B: 42}", format!("{:?}", enum_map_debug));
Iterate over enum variants
#[derive(Enumerated, Debug)]
pub enum Letter {
A,
B,
}
Letter::VARIANTS
.iter()
.for_each(|letter| println!("{:?}", letter));
Features
Portions of functionality are feature-flagged, but enabled by default. This is to allow turning this functionality off when not needed, e.g. Debug
and Eq
implementations.
See docs.rs for details.
Benchmarks
Invoke cargo bench
to run benchmarks. While EnumMap
operates in pico-seconds, std::collections::HashMap
in > 10 nanoseconds.
Benchmark results
EnumMap get time: [221.09 ps 221.59 ps 222.21 ps]
Found 10 outliers among 100 measurements (10.00%)
5 (5.00%) high mild
5 (5.00%) high severe
EnumMap insert time: [230.05 ps 233.38 ps 236.25 ps]
Found 2 outliers among 100 measurements (2.00%)
1 (1.00%) high mild
1 (1.00%) high severe
EnumMap new: default time: [852.31 ps 853.28 ps 854.37 ps]
Found 2 outliers among 100 measurements (2.00%)
1 (1.00%) low mild
1 (1.00%) high mild
EnumMap new: Option::None
time: [1.7100 ns 1.7110 ns 1.7120 ns]
Found 2 outliers among 100 measurements (2.00%)
1 (1.00%) high mild
1 (1.00%) high severe
EnumMap new: provider fn
time: [791.17 ps 792.38 ps 793.65 ps]
Found 7 outliers among 100 measurements (7.00%)
1 (1.00%) low mild
4 (4.00%) high mild
2 (2.00%) high severe
EnumMap new: inspecting provider fn
time: [775.03 ps 776.84 ps 778.92 ps]
Found 8 outliers among 100 measurements (8.00%)
4 (4.00%) high mild
4 (4.00%) high severe
std::collections::HashMap get
time: [13.433 ns 13.484 ns 13.543 ns]
Found 8 outliers among 100 measurements (8.00%)
3 (3.00%) high mild
5 (5.00%) high severe
std::collections::HashMap insert
time: [14.094 ns 14.107 ns 14.121 ns]
Found 4 outliers among 100 measurements (4.00%)
1 (1.00%) high mild
3 (3.00%) high severe
Dependencies
~1.5MB
~37K SLoC