variant-builder-macro 0.3.0

This crate gives us the VariantBuider proc macro which can be used to streamline creting an enum from wrapping variants each using the builder pattern.
Documentation
# `variant_builder_macro`

A procedural macro to simplify the creation of builder methods for enum variants, especially when used with the [`derive_builder`](https://crates.io/crates/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 the `derive_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`:

```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.

```rust
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:

```rust
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:

```rust
impl Default for AnimalVenom {
    fn default() -> Self {
        Self::Contact(Default::default())
    }
}
```

---

### Examples

#### Creating Enum Variants with Builders

```rust
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()`:

```rust
let default_contact_venom = AnimalVenom::default();
println!("{:?}", default_contact_venom);
```

You can also explicitly call the default variant builder:

```rust
let default_contact_venom = AnimalVenom::contact(|_builder| {});
println!("{:?}", default_contact_venom);
```

#### Partial Field Initialization

You can initialize only the fields you need:

```rust
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:

```bash
cargo test
```

---

## Limitations

- Each variant must have exactly one unnamed field.
- The field type must implement `Default` and provide a `build` method (e.g., via `derive_builder`).
- Only one variant can be marked with `#[default]`.

---

## License

This crate is licensed under the MIT License. See [LICENSE](./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.