enum_convert 0.2.0

A Rust procedural macro library for deriving automatic conversions between enum variants
Documentation
# enum_convert

Crate to derive [From](https://doc.rust-lang.org/core/convert/trait.From.html) implementations between enums.

## Features

- **EnumFrom**: Derive `From<Source> for AnnotatedEnum`
- **EnumInto**: Derive `From<AnnotatedEnum> for Target`
- Support for multiple source/target enums
- Flexible variant name mapping (one-to-many, many-to-one)
- Field-level mapping for named struct variants
- Automatic type conversion for fields via `.into()`

## Usage

### EnumFrom - Convert from source enums to annotated target enum

```rust
use enum_convert::EnumFrom;

enum Source {
    Unit,
    Tuple(i32, String),
    Struct { x: i32, y: i32 },
}

#[derive(EnumFrom)]
#[enum_from(Source)]
enum Target {
    #[enum_from]  // Maps from Source::Unit
    Unit,
    #[enum_from]  // Maps from Source::Tuple with type conversion
    Tuple(i64, String),
    #[enum_from]  // Maps from Source::Struct with type conversion
    Struct { x: f64, y: f64 },
    Extra,  // This variant has no mapping
}

// Usage
let source = Source::Tuple(42, "hello".to_string());
let target: Target = source.into();
```

### EnumInto - Convert from annotated source enum to target enums

ℹ️ While the macro is named `EnumInto`, it still implements `From<AnnotatedEnum> for TargetEnum` and thus has an indirect implementation of `Into` as [recommended by the docs](https://doc.rust-lang.org/core/convert/trait.Into.html).
This is similar to `derive_more`'s [Into](https://docs.rs/derive_more/latest/derive_more/derive.Into.html).

```rust
use enum_convert::EnumInto;

#[derive(EnumInto)]
#[enum_into(Target)]
enum Source {
    Unit,  // Maps to Target::Unit
    #[enum_into(Target::Different)]  // Maps to Target::Different
    Variant(i32),
}

enum Target {
    Unit,
    Different(i64),
    Extra,
}

// Usage
let source = Source::Variant(42);
let target: Target = source.into();
```

### Advanced Features

#### Multiple source/target enums

```rust
use enum_convert::EnumFrom;

enum FirstSource {
    Unit,
    Data(String),
}

enum SecondSource {
    Empty,
}

#[derive(EnumFrom)]
#[enum_from(FirstSource, SecondSource)]
enum Target {
    #[enum_from(FirstSource, SecondSource::Empty)]
    Unit,
    #[enum_from(FirstSource)]
    Data(String),
}
```

#### Field mapping

```rust
use enum_convert::EnumFrom;

enum Source {
    Tuple(String, u8),
    Record {
        name: String,
        value: i32,
    },
    Point(i32, i32),
}

#[derive(EnumFrom)]
#[enum_from(Source)]
enum Target {
    #[enum_from]
    Tuple(
        // We effectively re-order fields
        #[enum_from(Source::Tuple.1)] u8,
        #[enum_from(Source::Tuple.0)] String,
    ),
    #[enum_from]
    Record {
        #[enum_from(Source::Record.name)]  // Maps Source::Record.name to Target::Record.title
        title: String,
        value: i32,
    },
    #[enum_from]
    Point {
        #[enum_from(Source::Point.0)]
        x: i64,
        #[enum_from(Source::Point.1)]
        y: i64,
    },
}
```

## Related and similar crates

### derive_more

This crate has some similarities with [derive_more](https://docs.rs/derive_more/latest/derive_more/index.html)'s `From` and `Into` derive macros.

The difference is that with `derive_more` the conversion is field → variant (`From`) and variant → field (`Into`); with this crate it is variant ↔ variant.

```rust
#[derive(derive_more::From, enum_convert::EnumFrom)]
#[enum_from(OtherEnum)]
enum MyEnum {
    #[enum_from]
    Variant1(i32),
}

enum OtherEnum {
    Variant1(i32),
}
```
```rust compile_fail
// `derive_more::From` get expanded to
impl From<i32> for MyEnum {
    fn from(value: i32) -> MyEnum {
        MyEnum::Variant1(value)
    }
}

// `enum_convert::EnumFrom` get expanded to
impl From<OtherEnum> for MyEnum {
    fn from(value: OtherEnum) -> MyEnum {
        match value {
            OtherEnum::Variant1(i) => MyEnum::Variant1(i),
        }
    }
}
```

### enum_to_enum

This crate is very similar to [enum_to_enum](https://docs.rs/enum_to_enum/latest/enum_to_enum/).

At the time of writing (`enum_to_enum` in version 0.1.0) the differences are:
- `enum_convert` does not support [many-to-one conversion with try_into logic ]https://docs.rs/enum_to_enum/latest/enum_to_enum/derive.FromEnum.html#many-to-one-conversion.
- `enum_convert` does not support [effectful conversion]https://docs.rs/enum_to_enum/latest/enum_to_enum/derive.FromEnum.html#effectful-conversion.
- `enum_to_enum` does not support `EnumInto`.
- `enum_to_enum` does not support having variants in the target for which there is no mapping from source.
- `enum_to_enum` does not support fields mapping.

For the common features, here is a comparison of how they are expressed in both crates:

```rust
enum SourceA {
    Unit,
    Tuple(i32, String),
    Struct { x: i32, y: i32 },
}

enum SourceB {
    Unit,
    NoField,
    Tuple(i32, String),
    Struct { x: i32, y: i32 },
}

#[derive(enum_to_enum::FromEnum)]
#[from_enum(SourceA, SourceB)]
enum TargetEnumToEnum {
    #[from_case(SourceB = NoField, Unit)]
    Unit,

    Tuple(i64, String),

    Struct { x: f64, y: f64 },
}

#[derive(enum_convert::EnumFrom)]
#[enum_from(SourceA, SourceB)]
enum TargetEnumConvert {
    #[enum_from(SourceA, SourceB::Unit, SourceB::NoField)]
    Unit,

    #[enum_from(SourceA, SourceB)]
    Tuple(i64, String),

    #[enum_from(SourceA, SourceB)]
    Struct { x: f64, y: f64 },
}
```

### subenum

The [subenum](https://docs.rs/subenum/latest/subenum/) crate allows to implement easily subset of enums with conversion between parent and child.

However, there are cases where it is not desirable or possible to use `subenum`.
For example:
- You don't want to declare the child enum in the same module or crate as the parent enum.
- There already is a child enum coming from another crate and you want to convert from that child enum to your own parent enum.