Enum Companion Derive
This crate provides a procedural macro to derive two companion enums for a given struct, along with several helper methods. This is useful for dynamically accessing and updating struct fields.
Basic Usage
Here's a simple example of how to use EnumCompanion:
# use EnumCompanion;
# use EnumCompanionTrait;
// The macro generates two enums: `MyStructField` and `MyStructValue`.
// It also generates `value()` and `update()` methods.
let mut my_struct = MyStruct ;
// Access a field's value
let name_value = my_struct.value;
assert_eq!;
// Update a field's value
my_struct.update;
assert_eq!;
// Get all fields
let fields = fields;
assert_eq!;
The macro generates the following code behind the scenes (without any #[companion] attributes):
Full-Featured Example
EnumCompanion offers several attributes to customize its behavior.
# use EnumCompanion;
# use Uuid;
let mut config = Config ;
// Use the custom function names
let version = config.get_value;
assert_eq!;
// The `session_id` field was skipped
assert_eq!;
// The derived traits can be used
use HashSet;
let mut field_set = new;
field_set.insert;
Converting Values Back
The generated ...Value enum also implements TryFrom<...Value> for each of the underlying types, allowing you to convert a value enum back into its concrete type.
# use EnumCompanion;
# use TryInto;
#
# // fields_fn="get_fields" is only needed here to avoid using the trait from the enum_companion crate (not available here)
#
#
# let my_struct = MyStruct ;
let name_value = my_struct.value;
// Convert the value back into a String
let name: String = name_value.try_into.unwrap;
assert_eq!;
// This would fail to compile if you tried to convert to the wrong type,
// but a runtime check is also possible.
let id_value = my_struct.value;
let id_res: = id_value.try_into;
assert!;
Creating Values from Tuples
You can also create a ...Value enum from a tuple of (...Field, InnerValue), which can be useful for constructing values dynamically.
# use EnumCompanion;
# use TryInto;
#
# // fields_fn="get_fields" is only needed here to avoid using the trait from the enum_companion crate (not available here)
#
#
let name_tuple = ;
let name_value: MyStructValue = name_tuple.try_into.unwrap;
assert_eq!;
// This would fail if the inner value type does not match the field.
let id_tuple_fail = ;
let id_res: = id_tuple_fail.try_into;
assert!;
Available Attributes
On the struct:
#[companion(value_fn = "new_name")]: Changes the name of the value getter function (default:"value").#[companion(update_fn = "new_name")]: Changes the name of the value setter function (default:"update").#[companion(fields_fn = "new_name")]: Changes the name of the fields getter function (default:"fields").#[companion(derive_field(Trait1, Trait2))]: Adds derive macros to the...Fieldenum.#[companion(derive_value(Trait1, Trait2))]: Adds derive macros to the...Valueenum.#[companion(serde_field(attr=value))]: Adds Serde attributes to the...Fieldenum.#[companion(serde_value(attr=value))]: Adds Serde attributes to the...Valueenum.
On fields:
#[companion(rename = "NewName")]: Renames the variant in the companion enums.#[companion(skip)]: Excludes the field from the companion enums.
Trait-based Access
If the default method names (value, update, fields) are not overridden, the macro will also implement the enum_companion::EnumCompanionTrait. This allows for generic programming over any struct that derives EnumCompanion with default settings.
Limits
This crate has those known limitations :
CloneRequirement: Thevalue()method needs to clone the field values. Therefore, all fields in the struct must implement theClonetrait.- Named Structs Only: The macro can only be used on structs with named fields (e.g.,
struct MyStruct { id: u32 }). It does not support tuple structs or unit structs. TryFromwith Generics: Due to Rust's orphan rule,TryFromis not implemented for fields that are generic or contain generic types.