`Deref` and `DerefMut` for enums
Opened this issue · 4 comments
Is there a technical reason not to support Deref
and DerefMut
for enum input types? Seems to me like this would work pretty idiomatically so long as the different variants all supported a consistent target.
For example:
#[derive(derive_more::Deref)]
enum MyEnum1<'a> {
Variant1(&'a [u8]),
Variant2(&'a [u8]),
Variant3(&'a [u8]),
}
#[derive(derive_more::Deref)]
#[deref(forward)]
enum MyEnum2<'a> {
Variant1([u8; 4]),
Variant2(Vec<u8>),
}
For the cases you describe I agree it should be possible (at least the first one, the second one might be harder). So no technical reason, just no-one implemented it yet.
+1 for this. My use case could easily be derived:
enum Compression {
Stored(u32),
Zlib(u32),
LZMA1(u32),
}
impl Deref for Compression {
type Target = u32;
fn deref(&self) -> &Self::Target {
match self {
Self::Stored(size) | Self::Zlib(size) | Self::LZMA1(size) => size,
}
}
}
impl DerefMut for Compression {
fn deref_mut(&mut self) -> &mut Self::Target {
match self {
Self::Stored(size) | Self::Zlib(size) | Self::LZMA1(size) => size,
}
}
}
I had a short session where I tried to implement this feature. I came across a few speed bumps which changed my opinion a little.
1. We can only support enums with "unnamed" data fields
We already know one condition is that the data fields across the input enum must be consistent in some way. Additionally, unless I'm missing something, we can't support the "named fields" enum data type. Even if data were consistent, with named fields it's not clear what the Deref::Target
type should be. For example.
enum MyEnum {
Variant1 {
named_field1: u8,
named_field2: bool,
},
Variant2 {
named_field1: u8,
named_field2: bool,
},
}
These variants with named field data are not proper types, so there is no clear type to return in these cases. I guess we could annotate a named field in each variant with #[enabled]
- and this would be the target type / value. My gut feeling is that this would feel a bit too contrived.
So I guess this means that we can only support enums with unnamed fields as data.
2. We can only support unnamed fields with 1 tuple field
Even if we restrict support to enums with unnamed fields style data, there's still an issue if the data contains more than one field. For example:
enum MyEnum {
Variant1(u8, bool),
Variant2(u8, bool),
}
What would the Deref::Target
type be here? It's tempting to try using tuple: type Target = (u8, bool)
however, again because the data in an enum variant is not a proper type, we don't actually have such tuple values to reference and return in our Deref::deref
implementation.
So additionally we would need to restrict support for deriving Deref
to just enums with unnnamed fields data with precicely one unnamed field.
Summary
So overall deriving Deref
/ DerefMut
for enums would have to be restricted to only enums with consistent unnamed field data, each with precisely one unnamed field. My gut feeling now is that implementing this is not worth the trouble due to the lack of generality. I'm keen to hear what other people think, though.
@BenLeadbetter I think you're making this more complicated than necessary. We can use the same approach that we use for structs with multiple fields here: Adding a #[deref]
attribute to the field that you want to create the deref for. It's shown in the documentation in the first example code block (as the third struct):
// You can specify the field you want to derive `Deref` for.
#[derive(Deref)]
struct CoolVec {
cool: bool,
#[deref]
vec: Vec<i32>,
}
So your examples with enums should then look like this, if you want to to create a Deref derive for u8
:
#[derive(Deref)]
enum MyEnum {
Variant1 {
#[deref]
named_field1: u8,
named_field2: bool,
},
Variant2 {
#[deref]
named_field1: u8,
named_field2: bool,
},
}
enum MyEnum {
Variant1(#[deref] u8, bool),
Variant2(#[deref] u8, bool),
}