Replace the content of an RwLockWriteGuard - 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?

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.
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
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)

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.

Related

When is it safe to extend the lifetime of references into Arenas?

I have a struct which uses Arena:
struct Foo<'f> {
a: Arena<u64>, // from the typed-arena crate
v: Vec<&'f u64>,
}
Is it safe to extend the lifetime of a reference into the arena so long as it is bound by the lifetime of the main struct?
impl<'f> Foo<'f> {
pub fn bar(&mut self, n: u64) -> Option<&'f u64> {
if n == 0 {
None
} else {
let n_ref = unsafe { std::mem::transmute(self.a.alloc(n)) };
Some(n_ref)
}
}
}
For more context, see this Reddit comment.
Is it safe to extend the lifetime of a reference into the arena so long as it is bound by the lifetime of the main struct?
The Arena will be dropped along with Foo so, in principle, this would be safe, but it would also be unnecessary because the Arena already lives long enough.
However, this is not what your code is actually doing! The lifetime 'f could be longer that the lifetime of the struct — it can be as long as the shortest-lived reference inside v. For example:
fn main() {
let n = 1u64;
let v = vec![&n];
let bar;
{
let mut foo = Foo { a: Arena::new(), v };
bar = foo.bar(2);
// foo is dropped here, along with the Arena
}
// bar is still useable here because 'f is the full scope of `n`
println!("bar = {:?}", bar); // Some(8021790808186446178) - oops!
}
Trying to pretend that the lifetime is longer than it really is has created an opportunity for Undefined Behaviour in safe code.
A possible fix is to own the Arena outside of the struct and rely on the borrow checker to make sure that it is not dropped while it is still in use:
struct Foo<'f> {
a: &'f Arena<u64>,
v: Vec<&'f u64>,
}
impl<'f> Foo<'f> {
pub bar(&mut self, n: u64) -> Option<&'f u64> {
if n == 0 {
None
} else {
Some(self.a.alloc(n))
}
}
}
fn main() {
let arena = Arena::new();
let n = 1u64;
let v = vec![&n];
let bar;
{
let mut foo = Foo { a: &arena, v };
bar = foo.bar(2);
}
println!("bar = {:?}", bar); // Some(2)
}
Just like your unsafe version, the lifetimes express that the reference to the Arena must be valid for at least as long as the items in the Vec. However, this also enforces that this fact is true! Since there is no unsafe code, you can trust the borrow-checker that this will not trigger UB.

How do I modify the content of a `RefCell<Option<T>>`?

I have an Option<T> that is shared by several structures and that must be mutable. I'm using a RefCell since, as I understand, it is the tool for that job. How do I access (and alter) the content of that Option<T> ?
I tried the following:
use std::cell::RefCell;
#[derive(Debug)]
struct S {
val: i32
}
fn main() {
let rc: RefCell<Option<S>> = RefCell::new(Some(S{val: 0}));
if let Some(ref mut s2) = rc.borrow_mut() {
s2.val += 1;
}
println!("{:?}", rc);
}
But the compiler won't let me do it:
error[E0308]: mismatched types
--> <anon>:10:12
|
10 | if let Some(ref mut s2) = rc.borrow_mut() {
| ^^^^^^^^^^^^^^^^ expected struct `std::cell::RefMut`, found enum `std::option::Option`
|
= note: expected type `std::cell::RefMut<'_, std::option::Option<S>, >`
found type `std::option::Option<_>`
When you borrow_mut the RefCell, you get a RefMut, as the compiler says. To get the value inside it, just use the operator deref_mut:
use std::cell::RefCell;
#[derive(Debug)]
struct S {
val: i32
}
fn main() {
let rc: RefCell<Option<S>> = RefCell::new(Some(S{val: 0}));
if let Some(ref mut s2) = *rc.borrow_mut() { // deref_mut
s2.val += 1;
}
println!("{:?}", rc);
}

How can I update a struct, setting most but not all of the fields to a default value?

I know about the great Rust feature:
Foo {
fieldX: someValue,
..Self::default()
}
I want to use this in a method with &mut self, not touching fields f10 and f11 and setting the others to default:
#[derive(Default)]
struct Foo {
f1: u32,
//...
f10: Vec<u32>,
f11: Vec<u32>,
}
impl Foo {
fn f1(&mut self) {
let new_me = Foo {
f10: self.f10,
..Self::default()
};
*self = new_me;
}
}
but the compiler says:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:12:18
|
12 | f10: self.f10,
| ^^^^ cannot move out of borrowed content
How can I:
Leave signature of f1 as is: &mut self
Not copy any Vec<>, only moving
Not write boring code, like
self.f1 = 0;
self.f2 = 0;
self.f3 = None;
// ...
I'd replace the entire self with the default value, then preserve the interesting fields from the previous value:
use std::mem;
impl Foo {
fn f1(&mut self) {
let old = mem::replace(self, Self::default());
self.f10 = old.f10;
}
}

How to make &mut self from &self?

I want to expose a public function with immutable self which calls a private function with mutable self.
struct Foo {
value: i32,
}
impl Foo {
fn f1(&self) {
self.f2(); // <--- is it possible to make self mutable?
}
fn f2(&mut self) {
self.value = 5;
}
}
fn main() {
let foo = Foo { value: 0 };
foo.f1();
}
When compiling this code I get an error
cannot borrow immutable borrowed content *self as mutable
Is it possible to make self mutable?
EDIT:
After missing that last sentence.. you could get away with wrapping the property in a Cell:
use std::cell::Cell;
struct Foo { value: Cell<i32> }
impl Foo {
fn f1(&self) {
self.f2();
}
fn f2(&self) {
self.value.set(5);
}
}
fn main() {
let foo = Foo { value: Cell::new(0) };
foo.f1();
println!("{:?}", foo.value.get()); // prints 5
}
What you want cannot be done: you cannot convert a non-mutable reference into a mutable one.
But you can get almost that with RefCell:
struct Foo { value: RefCell<i32> }
impl Foo {
fn f1(&self) {
let mutValue = self.value.borrow_mut();
*mutValue = 5;
}
}
I didn't even need the f2 function!

Calling a method on a value inside a mutable Option

I have a mutable Option type and I'm trying to mutate the thing inside the Some but I can't figure out how to do it.
use std::net::TcpStream;
use std::io::Write;
struct Foo {
stream: Option<TcpStream>,
}
impl Foo {
fn send(&mut self) {
self.stream.map(|x| x.write(b"test")).expect("Couldn't write");
}
}
This produces the error:
error[E0596]: cannot borrow immutable argument `x` as mutable
--> src/main.rs:10:29
|
10 | self.stream.map(|x| x.write(b"test")).expect("Couldn't write");
| - ^ cannot borrow mutably
| |
| consider changing this to `mut x`
Can someone try to implement send as an example to help me understand?
As Vladimir Matveev points out, if let is even nicer, and is more idiomatic than iterating over the Option:
#[derive(Debug)]
struct Foo {
stream: Option<i32>,
}
impl Foo {
fn send(&mut self) {
if let Some(ref mut x) = self.stream {
*x += 1;
}
}
}
fn main() {
let mut f = Foo { stream: Some(0) };
println!("{:?}", f);
f.send();
println!("{:?}", f);
}
As of Rust 1.26, match ergonomics allows you to omit some of the keywords:
impl Foo {
fn send(&mut self) {
if let Some(x) = &mut self.stream {
*x += 1;
}
}
}
Before that, I would usually use Option::as_mut:
impl Foo {
fn send(&mut self) {
if let Some(x) = self.stream.as_mut() {
*x += 1;
}
}
}
Other options
As Vladimir Matveev points out (again!), map is usually used to transform data, not for side effects (which I agree with). You could instead use iter_mut (or the shorthand of &mut collection), as I feel that iteration is usually for side effects. I like this because it means our code can avoid having a conditional:
impl Foo {
fn send(&mut self) {
for x in &mut self.stream {
*x += 1;
}
}
}
You can also leverage the IntoIterator implementation for Option:
impl Foo {
fn send(&mut self) {
for x in self.stream.as_mut() {
*x += 1;
}
}
}
As a follow-up to #idupree's variant, it is also possible to use if-let syntax:
struct Foo {
stream: Option<i32>,
}
impl Foo {
fn send(&mut self) {
if let Some(ref mut x) = self.stream {
*x = 0;
}
}
}
I'd also argue that this is more idiomatic than map(), because map() method is intended for transforming an Option, not executing side effects (and assignment is a side effect).
You can match on the Option directly, like the following (showing i32 rather than TcpStream):
struct Foo {
stream: Option<i32>,
}
impl Foo {
fn send(&mut self) {
match self.stream {
Some(ref mut x) => {
*x = 0;
}
None => {}
}
}
}
(Not sure whether that's the most idiomatic way to do it.)

Resources