Convert Arc<RwLock> to &mut - rust

I am trying to have a value in a trait that can be mutated by means of a reference. The problem is that the String values are very large and may be accessed by many threads, so my solution looks something like this:
trait MyTrait {
fn name<'a>(&'a mut self) -> &'a mut String;
}
struct SimpleImpl {
name: String
}
impl MyTrait for SimpleImpl {
fn name<'a>(&'a mut self) -> &'a mut String {
&mut self.name
}
}
use std::sync::{Arc,RwLock};
struct ParallelImpl {
name: Arc<RwLock<String>>
}
impl MyTrait for ParallelImpl {
fn name<'a>(&'a mut self) -> &'a mut String {
self.name.get_mut().unwrap()
}
}
fn main() {
let mut a = SimpleImpl { name: String::from("simple") };
let mut b = ParallelImpl { name: Arc::new(RwLock::new(String::from("parallel"))) };
a.name().as_mut_str();
b.name().as_mut_str();
}
This fails to compile with
main2.rs:23:9: 23:18 error: cannot borrow immutable borrowed content as mutable
main2.rs:23 self.name.get_mut().unwrap()
Why can't I call get_mut() to unwrap both the Arc and the RwLock?

Have a better look at the interface of RwLock.
get_mut returns a LockResult<&mut T> which is a guard object. The destruction of this guard automatically unlocks the lock.
In order for things to be safe, the &mut T that you get by calling unwrap() on the guard is borrowing from the guard, that is, the lifetime of the result of unwrap() is limited by that of the guard (since after the guard is destroyed, the lock is unlocked).
And here, you are creating a temporary guard and throwing it away immediately, so the lifetime of the reference cannot exceed that of the function...
Congratz to Rust! Yet another data race prevented at compile-time :)

Related

Borrow Checker Not Releasing Immutable Borrow

I'm having a problem in the code below where the borrow checker complains about an immutable borrow in the call to self.entries.push() despite placing all the temporary code inside its own scope.
I have checked other posts with similar problems, but I can't figure out how to adapt the code to my own situation -- I'm still pretty new to Rust. Suggestions?
impl Entry {
pub fn chain(&self, spair: &SigningPair, expires: u16)
-> Result<(Entry, HashMap<&str,CryptoString>), MensagoError> {
// New Entry and HashMap allocated in here to be returned
}
}
pub struct Keycard {
_type: EntryType,
pub entries: Vec<Entry>,
}
impl Keycard {
pub fn get_current(&self) -> Option<&Entry> {
// ...
}
pub fn chain(&mut self, spair: &SigningPair, expires: u16)
-> Result<HashMap<&str,CryptoString>, MensagoError> {
let (newentry, keys) = {
let entry = match self.get_current() {
Some(v) => v,
None => { return Err(MensagoError::ErrEmptyData) }
};
match entry.get_field("Type")?.as_str() {
"Organization" | "User" => (),
_ => { return Err(MensagoError::ErrInvalidKeycard) }
}
entry.chain(spair, expires)?
};
self.entries.push(newentry);
Ok(keys)
}
}
I'm fairly certain that the error is because the returnvalue of chain() is incorrect:
HashMap<&str,CryptoString> should be HashMap<&'static str,CryptoString> or HashMap<String,CryptoString>
The explanation is a little bit longer, though.
Rust borrow checker demands that a value can be:
borrowed immutably by many borrowers or
borrowed mutably by exactly one borrower
no other borrows can exist (mutable or immutable) when a value gets modified
You try to modify the value self.entry at self.entries.push(newentry). Therefore, there must not be any borrows that reference self.entry.
Sadly, a borrow chain exists that borrows self, which indirectly also borrows self.entry at that point in time:
the type of newentry contains a reference, &str. newentry got created in .chain(), where &str has no lifetime annotations and therefore has the same lifetime as entry.
entry is created by self.get_current(), where again, &Entry is a reference with no explicit lifetime annotation and therefore has the same lifetime as self.
Which means through the chain newentry -> entry -> self, the self object is still borrowed while you try to call self.entries.push(). This is exactly what the error message is trying to tell you.
There are several solutions to those problems usually:
Introduce Rc instead of references
.clone() somewhere in between to break the reference chain
make sure that the reference chain actually makes sense in the first place, and if not, introduce lifetimes appropriately
In your case I think it's solution #3, as there is no reason why newentry should borrow entry. The type &str is most likely incorrect and should be &'static str. In my experience, using &str as a key for HashMap doesn't make much sense, it should be either &'static str (= global constant string like "hello") or the owned, mutable version String. Using a temporary reference as a key is quite strange and therefore most likely a beginner error.
The fixed version is:
use std::collections::HashMap;
pub struct Entry;
pub struct SigningPair;
pub struct CryptoString;
pub enum MensagoError {
ErrEmptyData,
ErrInvalidKeycard,
}
pub struct EntryType;
impl Entry {
pub fn chain(
&self,
_: &SigningPair,
_: u16,
) -> Result<(Entry, HashMap<&'static str, CryptoString>), MensagoError> {
todo!()
}
fn get_field(&self, _: &str) -> Result<String, MensagoError> {
todo!()
}
}
pub struct Keycard {
_type: EntryType,
pub entries: Vec<Entry>,
}
impl Keycard {
pub fn get_current(&self) -> Option<&Entry> {
todo!()
}
pub fn chain(
&mut self,
spair: &SigningPair,
expires: u16,
) -> Result<HashMap<&str, CryptoString>, MensagoError> {
let (newentry, keys) = {
let entry = match self.get_current() {
Some(v) => v,
None => return Err(MensagoError::ErrEmptyData),
};
match entry.get_field("Type")?.as_str() {
"Organization" | "User" => (),
_ => return Err(MensagoError::ErrInvalidKeycard),
}
entry.chain(spair, expires)?
};
self.entries.push(newentry);
Ok(keys)
}
}

Why RefCell's `into_inner` requires a move?

I have a situation where I have to move a struct from one object to another through a &mut self. Take a look:
pub struct MyStruct {
//no copy trait
device: Device
}
impl MyStruct {
pub fn finalize(&mut self) {
//error: cannot move since I borrowed
let interface = InterfaceBuilder::new(self.device)
}
}
First of all, why I cannot move something out of a borrowed mutable reference? Borrowed mutables are exclusive, there's no chance another code is looking into it.
Well, to address this problem I changed to
pub struct MyStruct {
//no copy trait
device: RefCell<Device>
}
impl MyStruct {
pub fn finalize(&mut self) {
//error on `self.device`: cannot move out of `self.device` which is behind a mutable reference
let interface = InterfaceBuilder::new(self.device.into_inner())
}
}
I know why the error occurs:
pub fn into_inner(self) -> T
calling into_inner makes self.device move. Why RefCell simply does not have an implementation pub fn into_inner(&mut self) -> T? I don't see a problem.
You cannot move out of a mutable reference because that would leave the original object incomplete.
Consider this code:
struct MyStruct {
s: String
}
fn finalize(f: &mut MyStruct) {
let _x = f.s; //error E0507!
}
fn main() {
let mut my = MyStruct {
s: "hi".into()
};
finalize(&mut my);
println!("{}", my.s); //what should this do?
}
Then, RefCell::into_inner(&mut self) -> T has the same problem. You could call it twice in a row and you would get two T values where before there was only one. And that, for a non Copy type is impossible.
If you want this function to consume the inner value, probably it should consume the outer value too:
fn finalize(f: MyStruct) {
let _x = f.s;
}
If you really want to move a value out of a mutable reference, you must leave something valid in its place. The easiest way is to declare an Option and use take() to steal and replace it with a None:
struct MyStruct {
s: Option<String>
}
fn finalize(f: &mut MyStruct) {
let _x = f.s.take();
}
Naturally, Option::take returns an Option so that if you call it twice, the second time you get None. If you are positive you have a value you can do take().uwnrap().
Alternatively, if your field type is Default you can use std::mem::take that replaces it with a default-created value:
struct MyStruct {
s: Vec<i32>
}
fn finalize(f: &mut MyStruct) {
let _x = std::mem::take(&mut f.s);
}
PS #1: there is Cell::take(&self) -> T, but only if T implements Default. It works just like std::mem::take but with a non-mutable reference.
PS #2: there is also unsafe fn ManuallyDrop::take(slot: &mut ManuallyDrop<T>) -> T, that is intented to be used in advanced drop implementations. But it is unsafe so it should never be your first option: if you call it twice you will get undefined behavior.

How can I tell the compiler to release a borrow in a struct without dropping the entire struct?

I have the following struct which represents a plan for a numeric computation:
pub struct NfftPlan<'a> {
x: Option<&'a [f64]>,
f_hat: Option<&'a [Complex64]>,
// ...
}
It has a set_f_hat method:
pub fn set_f_hat(&mut self, f_hat: &'a [Complex64]) {
self.f_hat = Some(f_hat);
}
and an execute method:
pub fn execute(&self) -> Vec<Complex64>
which uses f_hat immutably.
I want to use this in the following way:
let mut f_hat = vec![1,2,3,4];
let plan = NfftPlan::new()
plan.set_f_hat(&f_hat);
plan.execute();
f_hat[0] = 3; // Change f_hat to a new value
plan.execute(); //New computation
This fails because I cant mutate f_hat while plan still exists.
Is there a way for plan to release the borrow to f_hat which would allow me to mutate the f_hat vector?
Something like this:
releasedata(&self) {
self.f_hat = None
} //Now the compiler forgets that plan would hold an borrow to f_hat
I know that Rust does not allow me to change the vector while a borrow to it exists, in this case via the f_hat reference in the NfftPlan struct.
I would like a way to tell the compiler to drop the reference to the vector in the NfftPlan struct without dropping the entire struct.
Explanation
How can I tell the compiler to release a borrow
You cannot, period. This isn't something you "tell" the compiler, the compiler knows all. You can only completely stop using the reference.
without dropping the entire struct
Dropping doesn't clear the borrow, only the borrow no longer being used does, which may happen from the drop.
f_hat[0] = 3; // Change f_hat to a new value
plan.execute(); //New computation
This is exactly one of the types of code that Rust tries to prevent. It is not obvious at all that plan.execute() should return a different value because some apparently unrelated value has changed.
Solutions
Encode it in the type system
I'd structure my types to reflect how they need to be used, creating throwaway values that can execute only once everything has been combined together. This means that the structure that borrows f_mut is dropped as soon as it's done; note how this removes the Option completely:
fn main() {
let mut f_hat = 42;
let plan = Plan::default();
plan.set_f_hat(&f_hat).execute();
f_hat = 3;
plan.set_f_hat(&f_hat).execute();
}
#[derive(Debug, Default)]
struct Plan<'a> {
x: Option<&'a i32>,
}
impl<'a> Plan<'a> {
fn set_f_hat(&self, f_hat: &'a i32) -> PlanPlus<'a> {
PlanPlus { x: self.x, f_hat }
}
}
#[derive(Debug)]
struct PlanPlus<'a> {
x: Option<&'a i32>,
f_hat: &'a i32,
}
impl<'a> PlanPlus<'a> {
fn execute(&self) {}
}
Use interior mutability and reference counting
use std::{cell::Cell, rc::Rc};
#[derive(Debug, Default)]
struct Plan<'a> {
x: Option<&'a i32>,
f_hat: Option<Rc<Cell<i32>>>,
}
impl<'a> Plan<'a> {
fn set_f_hat(&mut self, f_hat: Rc<Cell<i32>>) {
self.f_hat = Some(f_hat);
}
fn execute(&self) {}
}
fn main() {
let f_hat = Rc::new(Cell::new(42));
let mut plan = Plan::default();
plan.set_f_hat(f_hat.clone());
plan.execute();
f_hat.set(3);
plan.execute();
}
Recognize that the member is mutable
#[derive(Debug, Default)]
struct Plan<'a> {
x: Option<&'a i32>,
f_hat: Option<&'a mut i32>,
}
impl<'a> Plan<'a> {
fn f_hat(&mut self) -> &mut Option<&'a mut i32> {
&mut self.f_hat
}
fn execute(&self) {}
}
fn main() {
let mut f_hat = 42;
let mut plan = Plan::default();
*plan.f_hat() = Some(&mut f_hat);
plan.execute();
**plan.f_hat().as_mut().unwrap() = 3;
plan.execute();
}
See also:
What are the options to end a mutable borrow in Rust?
Drop a immutable borrow to make a mutable borrow
Moved variable still borrowing after calling `drop`?

Returning a mutable reference that is behind an immutable reference, passed to the function

How is returning a mutable reference that is behind an immutable reference, passed as an argument to the function, handled?
struct Foo { i: i32 }
struct Bar<'b> {
f: &'b mut Foo
}
impl<'a: 'b, 'b> Bar<'b> {
fn func(&'a self) -> &'b mut Foo {
self.f
}
}
fn main() {
let mut foo = Foo { i: 1 };
let bar = Bar { f: &mut foo };
bar.func();
}
gives the following error:
error[E0389]: cannot borrow data mutably in a `&` reference
--> src/main.rs:9:14
|
8 | fn func(&'a self) -> &'b mut Foo {
| -------- use `&'a mut self` here to make mutable
9 | self.f
| ^^^^^^ assignment into an immutable reference
I (sort of) understand what the compiler is trying to prevent here. But I am confused with the error message assignment into an immutable reference . What exactly is being assigned into self (or inside ofself.f?) ?
I wrote the following code to simulate this problem and got the same error message, which unlike the above one, I am able to understand. Here's the code:
fn main() {
let mut foo = Foo { i: 1 };
let bar = Bar { f: &mut foo };
let pbar = &bar;
pbar.f.i = 2; // assignment into an immutable reference
}
In the first example, is it trying to move the mutable reference f out of self (since &mut is not a Copy type), treating it as a mutation inside the immutable reference self, hence the error message assignment into an immutable reference?
You can't create a mutable reference from an immutable one. This means that you need to change &self into &mut self:
impl<'a: 'b, 'b> Bar<'b> {
fn func(&'a mut self) -> &'b mut Foo {
self.f
}
}
And now the your variable needs to be mutable so that you can take a mutable reference to it for the method:
let mut bar = Bar { f: &mut foo };
bar.func();
What exactly is being assigned into self (or inside of self.x?) ?
The error message might be a little off. There is no assignment in your code, but you are returning a mutable reference. The only extra thing that a mutable reference would let you do here is to assign self.f or self.f.i.
Definitely this error message can be improved, but it does include a hint to make the &'a self mutable to fix the problem.
Now, your original question:
How is returning a mutable reference that is behind an immutable reference, passed as an argument to the function, handled?
Rust provides a variety of container types for interior mutability, such as Cell and RefCell. These types take the responsibility for ensuring correctness away from the compiler and make it a runtime check. One way of applying a RefCell to your code might be like this:
use std::cell::RefCell;
use std::ops::DerefMut;
struct Foo { i: i32 }
struct Bar<'b> {
// store the data in a RefCell for interior mutability
f: &'b RefCell<Foo>
}
impl<'a: 'b, 'b> Bar<'b> {
// Return a RefMut smart pointer instead of mutable ref, but hide the implementation,
// just exposing it as something that can be mutably dereferenced as a Foo
fn func(&'a self) -> impl DerefMut<Target = Foo> + 'b {
self.f.borrow_mut()
}
}
fn main() {
let foo = RefCell::new(Foo { i: 1 });
let bar = Bar { f: &foo };
let mut f = bar.func();
f.i = 3;
}

How do I return an Iterator over a collection encapsulated by a RefCell/RwLock Ref/Guard using unsafe code?

Multiple questions were already asked regarding this topic:
Returning iterator of a Vec in a RefCell
How do I return an iterator that has a reference to something inside a RefCell?
How can I return an iterator over a locked struct member in Rust?
The answers are more or less: It's not possible (without unsafe).
I tried the unsafe variant myself and want to ask if this way is safe.
The idea is that I wrap the guard in a struct that implements Iterator. Besides the guard, an iterator is stored which will be created from the stored guard:
struct MapIter<'a> {
guard: RwLockReadGuard<'a, HashMap<i32, i32>>,
iter: Iter<'a, i32, i32>,
}
It's created with these lines:
impl<'a> MapIter<'a> {
fn new(map: &'a RwLock<HashMap<i32, i32>>) -> Box<Self> {
// create a `box Self`
// the iterator remains uninitialized.
let mut boxed = Box::new(Self {
guard: map.read().expect("ToDo"),
iter: unsafe { mem::uninitialized() },
});
// create the iterator from `box Self`.
boxed.iter = unsafe {
(*(&boxed.guard as *const RwLockReadGuard<'a, HashMap<i32, i32>>)).iter()
};
boxed
}
}
Now it can implement Iterator:
impl<'a> Iterator for MapIter<'a> {
type Item = (&'a i32, &'a i32);
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
}
Is this code safe?
See this code in action at the playground.
Additionally I get a trivial cast warning
warning: trivial cast: warning: trivial cast: `&std::sync::RwLockReadGuard<'_, std::collections::HashMap<i32, i32>>` as `*const std::sync::RwLockReadGuard<'a, std::collections::HashMap<i32, i32>>`. Cast can be replaced by coercion, this might require type ascription or a temporary variable
|
| unsafe { (*(&boxed.guard as *const RwLockReadGuard<'a, HashMap<i32, i32>>)).iter() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
How to get around this?
No, it's not safe. I can use Container to create a dangling reference in safe code:
let container = Container::new(); // create a container
let r = {
let mut it = container.iter();
it.next() // obtain a reference to part of it
};
container.map.write().unwrap().clear(); // empty the container
println!("{:?}", r); // oh dear.
In the playground this compiles, which isn't good, because r contains references to data that are invalidated when the HashMap is cleared.
Vladimir Matveev's answer to a similar question explains in more detail why this is unsound, and contains the following concise summary:
You cannot do this because it would allow you to circumvent runtime checks for uniqueness violations.

Resources