rustenumsborrow-checker

Convert enum to another enum in Rust while selectively moving contained values


I have two enums like this:

enum E1 {
  A { val: SomeValue1 },
  B(SomeValue2),
  C(SomeValue3),
}

enum E2 {
  A,
  B(SomeValue2),
  C(SomeValue3),
  D,
  E
}

Here the SomeValueX types don't implement Copy or Clone.

I'm trying to write code that takes E1 as an input and does the following:

  1. Perform some actions on the contained values. If the input is E1::A(val), it needs to take ownership of val.
  2. Convert the input to E2

Currently I'm doing something like this:

fn example(input: E1) -> E2 {
  match input {
    E1::A(val) => { do_something_with_a(val); E2::A },
    E1::B(val) => { do_something_with_b(&val); E2::B(val) },
    E1::C(val) => { do_something_with_c(&val); E2::C(val) },
  }
}

Is there any way to clean this up and potentially split 1. and 2. into separate functions? I didn't succeed in doing it because:

I'm open to changing the enums as needed or using macros.


Solution

  • If you really like it better as two functions, you can change the order of your operations. Do 2 before 1.

    So you'll have one function that deconstructs E1 into E2 plus an optional Option<SomeValue1> as a tuple:

    fn deconstruct_your2(input: E1) -> (E2, Option<SomeValue1>) {
        match input {
            E1::A(val) => (E2::A, Option::Some(val)),
            E1::B(val) => (E2::B(val), Option::None),
            E1::C(val) => (E2::C(val), Option::None),
        }
    }
    

    And then another function that only borrows E2 and consumes the Option<SomeValue1> (taking ownership of SomeValue1):

    fn useInput_your1(input: &E2, input2: Option<Some1>) -> () {
        match input {
            E2::A => do_something_with_a(input2.expect("intput error: you must provide Option::Some(x) input2 in case of A")),
            E2::B(val) => do_something_with_b(val),
            E2::C(val) => do_something_with_c(val),
            _ => {}
        }
    }
    

    Then you can chain them like this:

    fn example(input: E1) -> E2 {
        let (a, b) = deconstruct_your2(input);
        useInput_your1(&a, b);
        return a;
    }