Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace the content of an RwLockWriteGuard

Tags:

rust

Let's assume the following code:

use std::sync::RwLock;

pub struct NotCloneable(u8);

pub struct Foo {
    value: RwLock<Vec<NotCloneable>>,
}

impl Foo {
    // does not work
    pub fn filter_out_values(&self) {
        let mut guard = self.value.write().unwrap();
        *guard = guard.into_iter().filter(|nc| nc.0 != 0).collect();
    }
}
error[E0507]: cannot move out of borrowed content
  --> src/lib.rs:12:18
   |
12 |         *guard = guard.into_iter().filter(|nc| nc.0 != 0).collect();
   |                  ^^^^^ cannot move out of borrowed content

(playground)

How do I make the function filter_out_values work?

like image 673
hellow Avatar asked Nov 10 '18 08:11

hellow


2 Answers

The special circumstance here is, that your T is not Cloneable, therefore you cannot use guard.iter().filter(...).cloned().collect().

I see two options here.

  1. Instead of RwLock<Vec<NotCloneable>> you could use RwLock<Option<Vec<NotCloneable>>> and then use Option::take() to get the value the RwLock was holding and leaving None

  2. You could use std::mem::take(), which is a shortcut for std::mem::replace(v, Default::default()), to get the vec from the guard without triggering the error, because there is no way that you leave the value of the RwLock in an undefined state, where it does not hold any value

use std::sync::RwLock;

pub struct NotCloneable(u8);

pub struct Foo {
    value: RwLock<Vec<NotCloneable>>,
}

impl Foo {
    pub fn filter_out_values(&self) {
        let mut guard = self.value.write().unwrap();
        let vec = std::mem::take(&mut *guard);
        *guard = vec.into_iter().filter(|nc| nc.0 != 0).collect();
    }
}

pub struct Foo1 {
    value: RwLock<Option<Vec<NotCloneable>>>,
}

impl Foo1 {
    pub fn filter_out_values(&self) {
        let mut guard = self.value.write().unwrap();
        let vec = guard.take();
        *guard = Some(vec.unwrap().into_iter().filter(|nc| nc.0 != 0).collect());
    }
}

(playground)

like image 110
3 revs, 2 users 97% Avatar answered Nov 12 '22 12:11

3 revs, 2 users 97%


While the other answer is correct, in this case, I'd recommend you to use Vec::retain():

impl Foo {
    pub fn filter_out_values(&self) {
        let mut guard = self.value.write().unwrap();
        guard.retain(|nc| nc.0 != 0);
    }
}

It will also be faster.

like image 29
Chayim Friedman Avatar answered Nov 12 '22 10:11

Chayim Friedman