| Continuous Integration | Documentation | Crates.io | |:----------------------:|:----------------:|:--------------------:| | [![ci][1]][2] | [![docs][3]][4] | [![crates][5]][6] | [1]: https://github.com/Robbepop/enum-ref/actions/workflows/rust.yml/badge.svg [2]: https://github.com/Robbepop/enum-ref/actions/workflows/rust.yml [3]: https://docs.rs/enum-ref/badge.svg [4]: https://docs.rs/enum-ref [5]: https://img.shields.io/crates/v/enum-ref.svg [6]: https://crates.io/crates/enum-ref # `#[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. ```rust #[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> = ::Ref<'a>; type TestMut<'a> = ::Mut<'a>; // Creates reference wrappers of `enum` instances as follows: let test = Test::C(42); let test_ref: TestRef = ::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: ```rust 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) -> ::Ref<'_> { type __enum_ref_EnumRef_Ref<'__enum_ref_lt> = ::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 }, } } } }; ```