2 unstable releases
0.1.0 | Mar 27, 2023 |
---|---|
0.0.0 | Mar 27, 2023 |
#1996 in Data structures
9KB
[2]: https://github.com/Robbepop/enum-ref/actions/workflows/rust.yml [4]: https://docs.rs/enum-ref [6]: https://crates.io/crates/enum-ref
Continuous Integration | Documentation | Crates.io |
---|---|---|
[][2] | [][4] | [][6] |
#[derive(EnumRef)]
and #[derive(EnumMut)]
This crate provides the #[derive(EnumRef)]
and #[derive(EnumMut)]
proc. macros
that generate reference wrappers for Rust enum
types.
Deriving EnumRef
or EnumMut
will also implement the respective trait which
allows to access and instantiate the generated reference wrappers.
Motivation
The generated reference types are a bit different from default references to Rust enum
instances
in that only the enum
data is a reference while the enum
discriminant remains inline.
When there is a need for having enum
reference wrappers this crate is especially useful
for when a user has enum
types with a big number of variants that would make it labor
intense to maintain a mirroring between original enum
type and reference wrapper.
This might even yield a performance improvement if users mostly are interested in
querying the enum
discriminant. However, performance is not the primary use case
of this crate.
My personal motivation for this crate is to allow for more space efficient enum
encodings.
Usually enum
instances are encoded with an aligned discriminant and all variants share the
same size_of
with the biggest enum
variant.
This has the downside that the default Rust enum
encoding potentially wastes a lot of space.
When trying to encode Rust enum
instances space-efficiently we still want to access the encoded
enum
instances, however we cannot use normal references to them since those references assume
the aligned enum
encoding which won't be the case.
This is where our new reference wrapper types come into play since we can use them for our new
encoding.
Usage
Below we demonstrate how to use the proc. macros provided by this crate.
#[derive(EnumRef, EnumMut)]
#[repr(u8)] // Rust requires this for `B = 42`
enum Test {
A,
B = 42,
C(i32),
D(i32, i64),
E { a: i32 },
F { a: i32, b: i64 },
}
// Access and name the generated `enum` reference wrapper types as follows:
type TestRef<'a> = <Test as EnumRef>::Ref<'a>;
type TestMut<'a> = <Test as EnumMut>::Mut<'a>;
// Creates reference wrappers of `enum` instances as follows:
let test = Test::C(42);
let test_ref: TestRef = <Test as EnumRef>::as_ref(&test);
match (&test, test_ref) {
(Test::C(a0), TestRef::C(a1)) => assert_eq!(a0, a1),
_ => panic!("something wen't wrong ..."),
}
Generated Code
The above #[derive(EnumRef)]
for example will generate roughly the following Rust code:
const _: () = {
#[derive(::core::fmt::Debug)]
#[repr(u8)]
pub enum TestRef<'__enum_ref_lt> {
A,
B = 42,
C(&'__enum_ref_lt i32),
D(&'__enum_ref_lt i32, &'__enum_ref_lt i64),
E {
a: &'__enum_ref_lt i32,
},
F {
a: &'__enum_ref_lt i32,
b: &'__enum_ref_lt i64,
},
}
impl ::enum_ref::EnumRef for Test {
type Ref<'__enum_ref_lt> where Self: '__enum_ref_lt =
TestRef<'__enum_ref_lt> where Self: '__enum_ref_lt;
fn as_ref(&self) -> <Self as ::enum_ref::EnumRef>::Ref<'_> {
type __enum_ref_EnumRef_Ref<'__enum_ref_lt> =
<Test as ::enum_ref::EnumRef>::Ref<'__enum_ref_lt>;
match self {
Self::A => __enum_ref_EnumRef_Ref::A,
Self::B => __enum_ref_EnumRef_Ref::B,
Self::C(_0) => __enum_ref_EnumRef_Ref::C(_0),
Self::D(_0, _1) => __enum_ref_EnumRef_Ref::D(_0, _1),
Self::E { a } => __enum_ref_EnumRef_Ref::E { a },
Self::F { a, b } => __enum_ref_EnumRef_Ref::F { a, b },
}
}
}
};
Dependencies
~235–680KB
~16K SLoC