Shuffling object vectors around

I guess this is a trivial one but I have no idea how to make it work. So I wanna save space and thus not make any extra copies of anything if I do not need to. I wanna switch the content of two vectors in my object through a private method. The example below i am showing is an oversimplification of a more complicated example where shift is not as simple as here but a more complicated arithmetic shuffle (here I am just rewriting vectors):

Example:

struct Obj {
    a: Vec<u8>,
    b: Vec<u8>,
}

impl Obj {
    pub fn new(aa: Vec<u8>, bb: Vec<u8>) -> Self {
        Obj { a: aa, b: bb }
    }
    
    fn swtch(&mut self, v_a: &mut Vec<u8>, v_b: &mut Vec<u8>) {
        let mut x = 0;
        let tmp = v_b.clone();
        for i in v_a.into_iter() {
            v_b[x] = *i;
            x = x + 1;
        }
        x = 0;
        for i in tmp.into_iter() {
            v_a[x] = i;
            x = x + 1;
        }
    }

    pub fn xcng(&mut self, key: &str) -> &mut Self {
        match key {
            "ab" => self.swtch(&mut self.a, &mut self.b),
            "ba" => self.swtch(&mut self.b, &mut self.a),
            _ => {}
        };

        self
    }
}

fn main() {
    let a = b"abcdefgh".to_vec();
    let b = b"ijklmn".to_vec();

    let obj = Obj::new(a, b);

    obj.xcng("ba").xcng("ab").xcng("bb");

    println!("{:?} {:?}", obj.a, obj.b);
}

my primary goal is to be able to apply xcng() function as many times I want on obj -> obj.xcng("ba").xcng("ab").xcng("ba")....;

However as you can see :blush:

 Compiling playground v0.0.1 (/playground)
error[E0499]: cannot borrow `*self` as mutable more than once at a time
  --> src/main.rs:28:21
   |
28 |             "ab" => self.swtch(&mut self.a, &mut self.b),
   |                     ^^^^^-----^-----------^^^^^^^^^^^^^^
   |                     |    |     |
   |                     |    |     first mutable borrow occurs here
   |                     |    first borrow later used by call
   |                     second mutable borrow occurs here

error[E0499]: cannot borrow `self.a` as mutable more than once at a time

I am doing something I am not supposed to :slight_smile:

can anyone help in solving this conundrum ?

thnx

You can use std::mem::swap(&mut self.a, &mut self.b) to swap the vectors content and avoid manual implementation. Then your fn swtch only needs the &mut self parameter, you don't need to pass in mutable references to self's own a and b vectors.

1 Like

Rust has a limitation that when you have &mut self this is exclusive borrow of all of self (all content together, recursively), which means such method can't take as argument any reference to anything from self.

The workaround is to make it a "static" method that doesn't take self, but only references to fields it needs.

In some cases it's also possible to take &self (shared borrow that allows other shared borrows from self) and use interior mutability (Mutex, etc.)

3 Likes

Considering &mut is more about exclusivity, it would have been interesting if they made it &excl instead. Otherwise, it gives the impression that &mut means that the owner thereof is the only borrow that can possibly be editing an object at once, even though it is possible to safely mutate two or more inner objects concurrently if there is no intersection between the edited items and no changes to alignment.

1 Like

This is actually known as the mutpocalypse that happened before 1.0. Further reading: Baby Steps

3 Likes

So I wanna save space and thus not make any extra copies of anything if I do not need to. I wanna switch the content of two vectors in my object through a private method.

As a way of avoiding unnecessary copies one way to minimise copying would be to store references in your object instead of the vector themselves.

#[derive(Debug)]
struct Obj<'a> {
  a: &'a [u8],
  b: &'a [u8],
}

impl<'a> Obj<'a> {
  pub fn new(a: &'a [u8], b: &'a [u8]) -> Self {
      Obj { a, b }
  }
  
  fn switch(self) -> Self {
    Obj {
      a: self.b,
      b: self.a,
    }
  }
}

fn main() {
  let (a, b) = (b"abcdefgh".to_vec(), b"ijklmn".to_vec());
  let obj1 = Obj::new(&a, &b);
  dbg!(&obj1);
  let obj2 = obj1.switch().switch().switch();
  dbg!(&obj2);
}

We need to bring back the #mutpocalypse. Death never dies

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.