0
votes

How can the code below be made to compile? It seems perfectly safe, but I can't convince the compiler that it is.

The version matching *self gives the error:

error[E0507]: cannot move out of borrowed content
 --> src/main.rs:8:16
  |
8 |         match (*self, y) {
  |                ^^^^^ cannot move out of borrowed content

The version matching self gives:

error[E0382]: use of moved value: `*self`
  --> src/main.rs:17:26
   |
8  |         match (self, y) {
   |                ---- value moved here
...
17 |                 (*a * b, self)
   |                          ^^^^ value used here after move
   |
   = note: move occurs because `self` has type `&'a mut Foo<'a>`, which does not implement the `Copy` trait
enum Foo<'a> {
    Foo1(Option<&'a mut Foo<'a>>),
    Foo2(i16),
}

impl<'a> Foo<'a> {
    fn bar(&'a mut self, y: i16) -> (i16, &'a mut Foo<'a>) {
        match (self, y) {
            (&mut Foo::Foo1(Some(ref mut a)), b) if (b == 5) => {
                return a.bar(y)
            },

            (&mut Foo::Foo2(ref mut a), b) if (b == 5) => {
                print!("is five");
                *a = (b + 42) as i16;

                (*a * b, self)
            },

            ref mut x => {
                print!("is not five!");
                (y, self)
            }
        }
    }
}

I feel like I would need a match arm such as the following, but it doesn't seem to be valid syntax:

(ref mut f @ Foo::Foo1, b) if (b == 5) => {
    print!("is five");
    f.0 = b + 42;
    (b, f)
} 
error[E0532]: expected unit struct/variant or constant, found tuple variant `Foo::Foo1`
  --> src/main.rs:24:30
   |
24 |                 (ref mut f @ Foo::Foo1, b) if (b == 5) => {
   |                              ^^^^^^^^^ not a unit struct/variant or constant

This is a dumbed down version of a deep_fetch_mut of a toml::Value that I am trying to write. The goal would be to be able to call .deep_fetch_mut(vec!["aaa","bbb","ccc"]), that will return a mutable reference to that value inside the toml::Value.

This question is an extension of How can I pattern match a tuple containing a &mut enum and use the enum in the match arm?

1
Again, returning self seemingly serves no purpose.Shepmaster
But it does, because when calling it with Foo::Foo1(Foo::Foo1(Foo::Foo1(Foo::Foo2(5))), the returned reference is to Foo:Foo2(5), not the original reference passed in. The whole point is to search for that element in the data structure.Ákos Vandra
Adjusting the solution in the other question for the second and third arm, with an early return in the first is not working here: cannot borrow *self as mutable more than once at a timeÁkos Vandra
I believe your question is answered by the answers of Iterating through a recursive structure using mutable references and returning the last valid reference. If you disagree, please edit your question to explain the differences. Otherwise, we can mark this question as already answered.Shepmaster

1 Answers

0
votes

This seems to compile, but it's very ugly. Is there a way to simplify this?

enum Foo<'a> {
    Foo1(Option<&'a mut Foo<'a>>),
    Foo2(i16),
}

impl<'a> Foo<'a> {
    fn bar(&'a mut self, y: i16) -> (i16, &'a mut Foo<'a>) {
        match (&mut *self, y) {
            (Foo::Foo1(Some(ref mut a)), b) if (b == 5) => {
                return a.bar(y)
            },

            (self2, c) => {
                let n = match (&mut *self2 , c) {
                    (Foo::Foo2(ref mut a), b) if (b == 5) => {
                        print!("is five");
                        *a = (b + 42) as i16;

                        *a * b
                    },

                    ref mut x => {
                        print!("is not five!");
                        y
                    }
                };

                return (n, self2)
            }
        }
    }
}