Idiomatic way to transition &mut enum with moved values

I have a unique reference to an enum that looks like this:

enum MaybeInit {
    Uninit(Obj1)
    Init(Obj2)
}

where Obj1 and Obj2 are two non-Clone, non-Default objects with have conversion functions into each other that move their original values, e.g. for Obj1 the method signature looks essentially like fn (self) -> Obj2.

I have a single instance of this MaybeInit enum, and at different points in time during the lifespan of my app I want to transition it back and forth between the Uninit and Init variants, and I'm pretty sure I need to do this through a &mut. Ideally, I want to define methods on the enum looking like this:

impl MaybeInit {
    fn get_or_init(&mut self) -> &mut Obj2 {...}
    fn uninit(&mut self) {...}
}

What is the most idiomatic way of writing the above two functions?

I'm stuck since I can't see a way of moving directly from one variant into the other. I could introduce a third, in-between variant and then use mem::swap to move the contained objects out, perform the conversion, then set the enum to its final value. However, it feels like this pollutes my state machine.

In case it matters: my conversion functions are actually async and return Results.

The problem in general is panic safety. Suppose that the initialization process panics, and that panic is caught, so the MaybeInit still exists and is accessible — what state is it in?

There are a couple of crates that offer tools to do this, take_mut and replace_with, but they both take the approach of forcing an abort instead of unwind — and don't support async at all. I'm not sure if there's any way this could be supported with async, but I haven't thought very hard about it.

You will probably find it most practical to add a third variant. The third variant can be thought of as an accurate representation of the state “async process is busy converting Uninit to Init or vice versa”.

2 Likes

FWIW, there is

to do this, and I'd say it's a common pattern in Rust. It does have tradeoffs / caveats for when the new value never gets to be written (c.f., their docs)

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.