Crate to derive From implementations between enums.
- 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()
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();ℹ️ 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.
This is similar to derive_more's Into.
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();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),
}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,
},
}This crate has some similarities with derive_more'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.
#[derive(derive_more::From, enum_convert::EnumFrom)]
#[enum_from(OtherEnum)]
enum MyEnum {
#[enum_from]
Variant1(i32),
}
enum OtherEnum {
Variant1(i32),
}// `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),
}
}
}This crate is very similar to enum_to_enum.
At the time of writing (enum_to_enum in version 0.1.0) the differences are:
enum_convertdoes not support many-to-one conversion with try_into logic .enum_convertdoes not support effectful conversion.enum_to_enumdoes not supportEnumInto.enum_to_enumdoes not support having variants in the target for which there is no mapping from source.enum_to_enumdoes not support fields mapping.
For the common features, here is a comparison of how they are expressed in both crates:
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 },
}The 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.