Swapping structures wrapped in enums

Hello,

I have some structure (actually a vector) wrapped in an enum and I would like to define a method bar(&mut self) that allows me to :

  1. Swap the wrapped vector with another one constructed with the previous one, without creating any copy of anything on the way.
  2. Change the enum pattern of self

Here is an example of what I would like to do, because I admit it seems pretty unclear :

#[derive(Debug)]
enum Foo {
    A(Vec<i32>), // Here is the wrapped structure
    B(Vec<Vec<i32>>)
}
use Foo::{A, B};
    
impl Foo {
    fn bar(&mut self) {
        match self {
            A(vect) => *self = B(vec![*vect]),
            _ => ()
        }
    }
}

fn main() {
    let mut ex: Foo = A(vec![1]);
    ex.bar();
    println!("{:?}", ex);
}

Now, this does not work for me because I'm moving the ownership of *vect to the method bar. Of course I could use a .clone() but my question is whether I can do this without copying my whole vector on another place of the heap or not (that's what cloning does, right ?).

I suppose this may be possible since I can do something similar by returning a value rather than modifying self :

impl Foo {
    fn bar(self) -> Foo {
        match self {
            A(vect) => B(vec![vect]),
            _ => self
        }
    }
}

fn main() {
    let mut ex: Foo = A(vec![1]);
    ex = ex.bar();
    println!("{:?}", ex);
}

Thank you for taking your time to answer my question :slight_smile: I did not find any conversation related to this specific topic but maybe I just did not search well, sorry if so.

    fn bar(&mut self) {
        match self {
            A(vect) => *self = B(vec![core::mem::take(vect)]),
            _ => ()
        }
    }

When the question is "how to move out from behind a mutable reference", the answer is invariably mem::take or mem::replace.

3 Likes

I usually prefer defining a poisoned state whenever I'm doing this with an enum, so that there's no chance for the intermediate taken state to be observed by accident (in panic recovery or similar):

#[derive(Debug)]
enum Foo {
    A(Vec<i32>), // Here is the wrapped structure
    B(Vec<Vec<i32>>),

    /// An error occurred in processing
    Poisoned
}
use Foo::{A, B, Poisoned};
    
impl Foo {
    fn bar(&mut self) {
        *self = match core::mem::replace(self, Poisoned) {
            Poisoned => unreachable!(),
            A(vect) => B(vec![vect]),
            b @ B(..) => b,
        }
    }
}