Comments (7)
I also think this would be really useful. One could use a hashmap but then you'd have to .unwrap()
every time you .get
a value even if you know that every enum variant has a valid value, and being able to make a custom struct for each enum to act as a variant map would have a lot of uses.
I created an initial implementation of a derive macro for this on my own repo here. If you have the following code:
#[derive(EnumMap)]
enum Size {
Small,
Medium,
Large,
}
it expands to:
struct SizeMap<T> {
small: T,
medium: T,
large: T,
}
impl<T> SizeMap<T> {
fn new(small: T, medium: T, large: T) -> SizeMap<T> {
SizeMap { small, medium, large }
}
fn get(&self, variant: Size) -> &T {
match variant {
Size::Small => &self.small,
Size::Medium => &self.medium,
Size::Large => &self.large,
}
}
fn set(&mut self, variant: Size, new_value: T) {
match variant {
Size::Small => self.small = new_value,
Size::Medium => self.medium = new_value,
Size::Large => self.large = new_value,
}
}
}
I'd be happy to turn this into a PR if the owners of this repo would be interesting in having this macro. I also feel that there are questions to be discussed before releasing something like this, e.g.:
- How do we specify what the visibility of the expanded struct could be? It would be useful to allow it to sometimes be
pub
but it can't always bepub
since it may then leak an external type if the original enum is notpub
- Should we have other initializers? Having some other options such as setting the value of all variants with a
Copy
value, or setting the value of all variants with a provided closure would be very useful, I think. - How do we deal with variants that have data (as mentioned above)? Should we even try to accommodate for that? We could perhaps look to the policy of
EnumIter
for this one, since it would run into a similar problem.
If any maintainers would like to help us move forward with getting this merged in by reviewing a PR or answering these questions with their thoughts, that would be really appreciated!
from strum.
That looks great! Would you like access to my version so we can start merging our implementations?
- It should probably be the same as the base enum, as I believe EnumIter does that as well; it would be impossible to use the map without the enum.
- I like both of those; also, a default would be nice
- I think it makes sense to either only support unit variants or only map using the discriminator. I don't want to try to figure out how to make it recursive.
Should we do a blanket iter()
that only applies when EnumIter is also derived?
fn iter(&self) -> Iterator<Item = T> {
Enum::iter().map(|k| (k, self.get(k))
}
from strum.
Oh my god, I feel a bit foolish now - when I pulled up your version last time, github showed me no changes from its parent repo for some reason and I just assumed you hadn't committed your work yet (and thus went on to do a lot of extraneous work on my own repo). I didn't consider just implementing Index
and IndexMut
as well and you've already got visibility all worked out - I wholeheartedly support merging in your code, it seems to be much more complete than mine (once we've figured out the questions above, of course).
from strum.
lol I thought yours seemed more complete. I also don't really know what I'm doing with all these procedural macros. A lot of my stuff is probably cargo cult-ish, since I copied a bunch from EnumIter. I think we should also change it to the named struct fields rather than sized array
from strum.
Hey folks, this sounds like a really useful macro, but I'm worried there's a number of situational concerns that will make it difficult to generalize across a range of needs. Some thoughts:
- To match the other Map apis, it might be valuable for the struct fields to internally be
Option<T>
so that they can be removed and whatnot. - The memory usage of this map scales with the number of variants rather than the number of entries. For sparsely filled maps, that might be unexpected, and there's a performance trade-off there that people might not be aware of.
- Like you said, I think we need a better story about how variants with data will behave.
If we can make some of these trade-offs more configurable, I'd consider including it in strum because it is a cool idea, and it sounds like there's a need :) If not though, it might be better off as its own crate so that people have some flexibility in choosing the implementation they want for this feature.
How does that sound?
from strum.
As for your first two points, that sounds like you'd just have a wrapper around HashMap or BTreeMap. The main point for my application of this one is that there's always a value, so you can safely index into it without thinking about unwrapping.
It might make more sense to call it something other than EnumMap, since it's basically a named array and not a true map. Having said that, it is starting to sound like it doesn't quite fit into strum. On the other hand, it seems way too small to be its own crate.
from strum.
I've updated my repo with some of June's code. Here's a list of important features I have working:
- The derived
MyEnumMap<T>
has a field of typeT
for each variant ofMyEnum
Derive Clone, Default, PartialEq
forMyEnumMap<T>
fn new(#(<fields>,)*) -> Self { ... }
- publically exposed constructor because we don't want topub
the actual struct fieldsIndex<T>
andIndexMut<T>
from strum.
Related Issues (20)
- EnumIter does not work for enums named 'Option'
- [Feature] Macro to Implement PartialEq<str> HOT 1
- strum::Display doesn't work with non-unit non-string variants
- `EnumString` should derive `From<&str>` instead of `TryFrom<&str>` when `#[strum(default)]` is present HOT 1
- to_string and serialize when used together causes unreachable code HOT 2
- `get_bool` and `get_int` in `EnumProperty` are undocumented and always return None
- AsRef<str> and default variants
- EnumDiscriminants: can't infer type HOT 3
- Getting the discriminant from an enum variant HOT 3
- Publish new release. HOT 4
- AsRefStr documentation incorrectly states 'static ref is returned HOT 2
- Publish Git tags HOT 2
- TryFrom<Repr> for enums using FromRepr? HOT 2
- Implement `Iterator` for EnumTable HOT 6
- Customize error message for FromStr
- Documentation for `VariantArray` and `VariantNames` say their `VARIANTS` constants are arrays, but they're actually slices HOT 2
- Support for const_into_str to Enable Static String Conversion in Const Context
- Accessing the EnumTable type through the enum HOT 1
- Error updating to 0.26 - trait bound `std::iter::FusedIterator` is not satisfied HOT 1
- Itertools 0.13.0 and strum derive macro EnumIter break if both are used at the same time HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from strum.