2 unstable releases
new 0.2.0 | Dec 6, 2024 |
---|---|
0.1.0 | Dec 6, 2024 |
#22 in #shorthand
143 downloads per month
11KB
69 lines
variant_builder_macro
A procedural macro to simplify the creation of builder methods for enum variants, especially when used with the derive_builder
crate. This macro automates the generation of variant-specific builder methods, enabling concise and flexible creation of enum instances.
Features
- Automated Builder Methods: Automatically generates builder methods for each variant in an enum.
- Integration with
derive_builder
: Works seamlessly with thederive_builder
crate to manage complex field initialization. - Default Variant Support: Automatically implements the
Default
trait for enums with a designated#[default]
variant. - Improved Type Safety: Ensures that only valid builder configurations are allowed.
- Simplified API: Reduces boilerplate by eliminating the need to manually write repetitive constructor methods.
Installation
Add variant_builder_macro
to your Cargo.toml
:
[dependencies]
variant_builder_macro = "0.1"
derive_builder = "0.10" # Required for field builders
Usage
Basic Example
Define an enum and apply the VariantBuilder
macro. Each variant must have a single unnamed field with a type that implements Default
and has a builder (e.g., generated by derive_builder
). Use the #[default]
attribute to specify a default variant.
use variant_builder_macro::VariantBuilder;
use derive_builder::Builder;
#[derive(VariantBuilder, Debug, Clone, PartialEq)]
pub enum AnimalVenom {
#[default]
Contact(ContactVenom),
Injected(InjectedVenom),
Defensive(DefensiveVenom),
Offensive(OffensiveVenom),
}
#[derive(Builder, Debug, Clone, PartialEq, Default)]
#[builder(setter(into))]
pub struct ContactVenom {
potency: String,
activation: String,
}
#[derive(Builder, Debug, Clone, PartialEq, Default)]
#[builder(setter(into))]
pub struct InjectedVenom {
delivery_method: String,
potency: String,
}
#[derive(Builder, Debug, Clone, PartialEq, Default)]
#[builder(setter(into))]
pub struct DefensiveVenom {
deterrence: String,
effectiveness: u32,
}
#[derive(Builder, Debug, Clone, PartialEq, Default)]
#[builder(setter(into))]
pub struct OffensiveVenom {
speed: u32,
potency: String,
}
Generated API
The macro generates builder methods for each variant. For example, for the Contact
variant:
impl AnimalVenom {
pub fn contact<F>(build: F) -> Self
where
F: FnOnce(&mut ContactVenomBuilder),
{
let mut builder = ContactVenomBuilder::default();
build(&mut builder);
Self::Contact(builder.build().expect("Builder failed to construct variant"))
}
}
Additionally, if a #[default]
attribute is specified, the Default
trait is implemented automatically:
impl Default for AnimalVenom {
fn default() -> Self {
Self::Contact(Default::default())
}
}
Examples
Creating Enum Variants with Builders
fn main() {
let contact_venom = AnimalVenom::contact(|builder| {
builder
.potency("High".to_string())
.activation("Immediate".to_string());
});
let injected_venom = AnimalVenom::injected(|builder| {
builder
.delivery_method("Spines".to_string())
.potency("Moderate".to_string());
});
println!("{:?}", contact_venom);
println!("{:?}", injected_venom);
}
Using Default Values
If no fields are modified, the builder uses default values. The default variant is used for Default::default()
:
let default_contact_venom = AnimalVenom::default();
println!("{:?}", default_contact_venom);
You can also explicitly call the default variant builder:
let default_contact_venom = AnimalVenom::contact(|_builder| {});
println!("{:?}", default_contact_venom);
Partial Field Initialization
You can initialize only the fields you need:
let defensive_venom = AnimalVenom::defensive(|builder| {
builder.deterrence("High".to_string());
});
println!("{:?}", defensive_venom);
Testing
This crate includes a comprehensive test suite. Run the tests with:
cargo test
Limitations
- Each variant must have exactly one unnamed field.
- The field type must implement
Default
and provide abuild
method (e.g., viaderive_builder
). - Only one variant can be marked with
#[default]
.
License
This crate is licensed under the MIT License. See LICENSE for details.
Contributions
Contributions are welcome! If you find any issues or have ideas for new features, feel free to open an issue or submit a pull request.
Dependencies
~0.8–1.3MB
~27K SLoC