2 releases
0.1.1 | Sep 3, 2023 |
---|---|
0.1.0 | Aug 30, 2023 |
#877 in Procedural macros
13KB
150 lines
Enum with data to HashMap
This crate provides a way to transform an enum with associated data into a hashmap. This idea came to me as I was working on my UI library.
I wanted to implement styling in a very flexible way. Essentially, every style property is optional unless it's defined. This would have been extremely annoying to implement with a struct as all properties would have had to be an Option. Instead, I just simply create my enum with associated data and transform it into a map. I can later easily access each value with an iterator and manipulate it however I want.
[dependencies]
enum2map = "0.1"
Examples
The way to use the crate is very simple. Define an enum with associated data and derive Enum2Map.
#[derive(Debug, PartialEq, Eq, Clone, Enum2Map)]
pub enum TestValue {
Padding(usize),
Margin(String),
}
Then you can use generic getters and setters or the getter and setter for each property with the new enum that was generated.
pub enum TestValueKey {
Padding,
Margin,
}
let mut map = TestValueMap::new();
map.get(TestValueKey::Margin);
map.get(TestValueKey::Padding);
map.get_or_default(TestValueKey::Padding);
map.get_or_default(TestValueKey::Padding);
map.set(TestValue::Padding(10));
map.set(TestValue::Margin("string test".to_string()));
As well as the getters and setters for each value in your enum:
map.set_padding(50);
map.set_margin("another test".to_string());
map.get_padding();
map.get_margin();
How it works
The derive will first generate the keys from the enum provided:
pub enum TestValueKey {
Padding,
Margin,
}
It will then generate a struct with the generic getters and setters you saw in the examples. It will also generate a getter and setter for each value in your enum. The API was written to follow the HashMap API as closely as I could.
pub struct TestValueMap {
pub values: std::collections::HashMap<TestValueKey, TestValue>,
}
impl TestValueMap {
pub fn new() -> Self {
Self {
values: std::collections::HashMap::new(),
}
}
pub fn insert(&mut self, value: TestValue) -> Option<TestValue> {
match value {
TestValue::Padding(val) => {
self.values.insert(TestValueKey::Padding, TestValue::Padding(val))
}
TestValue::Margin(val) => {
self.values.insert(TestValueKey::Margin, TestValue::Margin(val))
}
}
}
pub fn get(&self, key: TestValueKey) -> Option<&TestValue> {
self.values.get(&key)
}
pub fn get_or_default(&self, key: TestValueKey) -> TestValue {
match self.values.get(&key) {
Some(value) => value.clone(),
None => {
match key {
TestValueKey::Padding => TestValue::Padding(Default::default()),
TestValueKey::Margin => TestValue::Margin(Default::default()),
}
}
}
}
pub fn set(&mut self, value: TestValue) -> Option<TestValue> {
match value {
TestValue::Padding(val) => {
self.values.insert(TestValueKey::Padding, TestValue::Padding(val))
}
TestValue::Margin(val) => {
self.values.insert(TestValueKey::Margin, TestValue::Margin(val))
}
}
}
pub fn get_padding(&self) -> usize {
match self.values.get(&TestValueKey::Padding) {
Some(TestValue::Padding(value)) => value.clone(),
None => Default::default(),
_ => {
::core::panicking::panic_fmt(
format_args!(
"Unexpected condition: Didn\'t find type {0} for {1}",
"usize",
"Padding",
),
);
}
}
}
pub fn get_margin(&self) -> String {
match self.values.get(&TestValueKey::Margin) {
Some(TestValue::Margin(value)) => value.clone(),
None => Default::default(),
_ => {
::core::panicking::panic_fmt(
format_args!(
"Unexpected condition: Didn\'t find type {0} for {1}",
"String",
"Margin",
),
);
}
}
}
pub fn set_padding(&mut self, val: usize) -> Option<usize> {
if let Some(TestValue::Padding(old_value))
= self.values.insert(TestValueKey::Padding, TestValue::Padding(val))
{
return Some(old_value);
}
None
}
pub fn set_margin(&mut self, val: String) -> Option<String> {
if let Some(TestValue::Margin(old_value))
= self.values.insert(TestValueKey::Margin, TestValue::Margin(val))
{
return Some(old_value);
}
None
}
}
Future Work
- Better error handling.
- Handle cases where the enum has no associated data.
- Better documentation.
Dependencies
~1.5MB
~36K SLoC