#enums #derive #conversion #convert #from #into

into_variant

Easily convert your types into the corresponding enum variant

4 releases (2 breaking)

0.3.0 May 14, 2022
0.2.0 Apr 7, 2022
0.1.1 Apr 6, 2022
0.1.0 Apr 6, 2022

#2981 in Rust patterns

MIT/Apache

10KB
99 lines

into_variant

Easily convert your types into the corresponding enum variant.

Usage

Commonly in Rust, you'll have enum variants with a single field – such enums let you differentiate between different types of values. For example, you might have a hierarchy of possible app messages:

use into_variant::VariantFrom;

#[derive(VariantFrom)]
enum AppMessage {
    File(FileMessage),
    Editor(EditorMessage),
}

#[derive(VariantFrom)]
enum FileMessage {
    Save(SaveMessage),
    Close(CloseMessage),
}

#[derive(VariantFrom)]
enum EditorMessage {
    Insert(InsertMessage),
    Formatting(FormattingMessage),
}

struct SaveMessage {}
struct CloseMessage {}
struct InsertMessage {}

Normally, if you wanted to construct one of these messages, you'd have to type a long chain of nested enums:

AppMessage::File(FileMessage::Save(SaveMessage {}))
//        ^^^^^^^^^^^^^^^^^^^^^^^^ this bit is redundant, let's infer it automatically!

However, since there is only one way to create an AppMessage with a SaveMessage inside, we can infer the enum variants automatically – that's what this crate is for!

#[test]
fn test_variant_from() {
    assert!(matches!(
        AppMessage::variant_from(SaveMessage {}),
        AppMessage::File(FileMessage::Save(SaveMessage {}))
    ));

    assert!(matches!(
        AppMessage::variant_from(InsertMessage {}),
        AppMessage::Editor(EditorMessage::Insert(InsertMessage {}))
    ));
}

You also get into_variant, which gets even shorter if AppMessage can be inferred too – for example, in function calls:

#[test]
fn test_into_variant() {
    function_that_takes_app_message(SaveMessage {}.into_variant())
}

fn function_that_takes_app_message(_message: AppMessage) {}

Works for arbitrarily deeply nested enums!

#[derive(VariantFrom)]
enum FormattingMessage {
    ClearFormatting(ClearFormattingMessage),
}

struct ClearFormattingMessage {}

#[test]
fn test_deeper_nesting() {
    assert!(matches!(
        AppMessage::variant_from(ClearFormattingMessage {}),
        AppMessage::Editor(EditorMessage::Formatting(
            FormattingMessage::ClearFormatting(ClearFormattingMessage {})
        ))
    ))
}

You can find the full example, along with others, in tests/app_message.rs.

Project Status

I needed this for a thing, so it might get maintained for a while. Suggestions are appreciated, but I can't guarantee I'll address them.

Dependencies

~1.5MB
~33K SLoC