In a Rust program I have a state and I want to update some bits of it in a loop. The pattern is probably very familiar to experienced Rust programmers, even as a beginner I've encountered this several times. It looks like this:
struct T1 {} // not Copy or Clone
enum PgmState {
State1(T1),
State2(T1),
State3,
}
struct Pgm {
state: PgmState,
}
impl Pgm {
fn loop_(&mut self) {
match self.state { PgmState::State1(ref t1) => {
// update self.state
},
PgmState::State2(ref t1) => {
// update self.state
},
PgmState::State3 => {
// update self.state
}
}
}
}
This obviously doesn't work because match
expression borrows self.state
so I can't update it. In an earlier version my state type was actually Copy
so I could just copy self.state
to stack, inspect it and update self.state
. But recently I lost this trait so I need a different solution now.
To be able to update self.state
without losing any information I think I have to first move it to the stack, and then copy the new form back to self.state
. During this update phase there has to be something in self.state
and I'm not sure what to put there.
Option 1: Use std::mem::uninitialized
. Terrible solution because any panics in this code will cause the program to crash in horrible ways.
Option 2: Add a new variant to PgmState
as a placeholder: enum PgmState { ..., PlaceHolder }
. I don't like this either because now I have to handle this constuctor everywhere else (just to panic!()
).
Option 3: Refactor the code so that the "tag" bit is a new field and other fields in PgmState
are now optional fields, something like:
struct T1 {} // not Copy or Clone
#[derive(Copy, Clone)]
enum PgmState { State1, State2, State3 }
struct Pgm {
state: PgmState,
/// Only avaiable when PgmState is State1 or State2
state_data: Option<T1>,
}
This is still horrible because (1) this means more panics in the rest of the code (because of new invalid but representable states), (2) T1
is still not copy or clone so if I want to update T1 in-place this won't work.
Anyone know any other options? I thinking I'll go with (2) but I don't like introducing panics in every other match
on this state.