How to dissociate mutability from lifetime in Rust? - rust

I want to have two types (in my question-fitted examples I will mark them as IdHandler counting IDs, and IdUser using the IDs), where the dependent one of them should not outlive (hence, lifetimes) the dependency, and that's the only requirement. Figured the quickest solution would be using PhantomData<&'...>:
struct IdHandler {
id_counter: u64,
}
struct IdUser<'a> {
_a: PhantomData<&'a IdHandler>,
id: u64,
}
Then, using a mutable reference with a specified lifetime, I made a function in impl IdHandler to create the users:
fn new_id_user<'a>(self: &'a mut IdHandler) -> IdUser<'a> {
let res = IdUser {
_a: PhantomData,
id: self.id_counter,
};
self.id_counter += 1;
res
}
Now, I will make a function that takes in a mutable reference and tries to make a pair of IdUsers:
fn f<'a>(id_handler: &'a mut IdHandler) -> (IdUser<'a>, IdUser<'a>) {
let a1 = id_handler.new_id_user();
let a2 = id_handler.new_id_user();
(a1, a2)
}
And here's an example of how those types and functions may be used:
fn main() {
let mut id_handler = IdHandler { id_counter: 0u64 };
let (a1, a2) = f(&mut id_handler);
assert_eq!(a1.id, 0u64);
assert_eq!(a2.id, 1u64);
assert_eq!(id_handler.id_counter, 2u64);
id_handler.stop(); // fn stop(self) {}
// Ideally here 'a is dead,
// so you can't perform operations on IdUser<'a>
// assert_eq!(a2.id, 1u64);
}
Given the fact that new_id_user(...) only uses the mutability for a moment, and then hopefully "releases" it back (as it is not used any longer than the function call - I do not know the exact rule Rust uses, but it works without _a/'a or when fn f(...) -> ()), I'd expect f(...) to work just fine. However, the compiler has greeted me with following:
error[E0499]: cannot borrow `*id_handler` as mutable more than once at a time
--> src\main.rs:29:14
|
27 | fn f<'a>(id_handler: &'a mut IdHandler) -> (IdUser<'a>, IdUser<'a>) {
| -- lifetime `'a` defined here
28 | let a1 = id_handler.new_id_user();
| ------------------------ first mutable borrow occurs here
29 | let a2 = id_handler.new_id_user();
| ^^^^^^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
30 | (a1, a2)
| -------- returning this value requires that `*id_handler` is borrowed for `'a`
Does anyone know whether there is a solution that I'm missing, or am I doomed to allow IdUsers to outlive the IdHandler?

Unfortunately you cannot. Preserving a value with a lifetime will prevent the mutating the value from which it was derived even if you don't actually keep a reference to it. A common workaround if you want to ensure the lifetimes are bound while still being able to mutate is to use interior mutability (via Cell, RefCell, Mutex, etc).
Here's a working example using Cell:
use std::marker::PhantomData;
use std::cell::Cell;
struct IdHandler {
id_counter: Cell<u64>,
}
impl IdHandler {
fn new_id_user<'a>(self: &'a IdHandler) -> IdUser<'a> {
let res = IdUser {
_a: PhantomData,
id: self.id_counter.get(),
};
self.id_counter.set(self.id_counter.get() + 1);
res
}
}
struct IdUser<'a> {
_a: PhantomData<&'a IdHandler>,
id: u64,
}
fn f<'a>(id_handler: &'a IdHandler) -> (IdUser<'a>, IdUser<'a>) {
let a1 = id_handler.new_id_user();
let a2 = id_handler.new_id_user();
(a1, a2)
}
fn main() {
let mut id_handler = IdHandler { id_counter: Cell::new(0u64) };
let (a1, a2) = f(&mut id_handler);
assert_eq!(a1.id, 0u64);
assert_eq!(a2.id, 1u64);
}

Related

How do I pass a mutable reference to a method on an object that belongs to that reference?

I have a struct instance A that belongs to a struct instance B. I will need to do some processing on this data by calling the parent.
struct A {
val : u8
}
struct B {
data : u8,
a : A
}
impl A {
pub fn process(&mut self, b : &mut B) {
println!("Processing {} - {}", b.data, self.val);
//do stuff with val and data...
}
}
impl B {
pub fn process(&mut self) {
self.a.process(self);
}
}
fn main() {
let mut b = B {
data : 0,
a : A {
val : 3
}
};
b.process();
}
When I try to call b.process(), I'm getting the following failure:
error[E0499]: cannot borrow `self.a` as mutable more than once at a time
--> src/main.rs:47:9
|
47 | self.a.process(self);
| ^^^^^^^-------^----^
| | | |
| | | first mutable borrow occurs here
| | first borrow later used by call
| second mutable borrow occurs here
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:47:24
|
47 | self.a.process(self);
| ---------------^^^^-
| | | |
| | | second mutable borrow occurs here
| | first borrow later used by call
| first mutable borrow occurs here
All of this works fine when mutable references aren't needed.
So my question is, what's the right way to do this when I need this type of relationship between the two structs?
In Rust you can either have a single mutable reference or multiple immutable references, or, put differently: single writer / multiple readers.
let mut a = 0; // Only mutable variables can be written to
let a1 = &a;
let a2 = &a; // Readers can be many
// This is an error:
let a3 = &mut a; // You cannot write to `a` while it is borrowed for reading
print!("{} {} {}", a1, a2, a3)
let mut a = 0;
let a1 = &mut a; // You can have a single writer
// This is an error:
let a2 = &mut a; // But there can be only one
// This is also an error:
let a3 = &a; // You cannot read while `a` can be written to
print!("{} {} {}", a1, a2, a3)
Following this logic we can make some observations on the code
impl A {
// this implies that both self and B can change
pub fn process(&mut self, b: &mut B) {
println!("Processing {} - {}", b.data, self.val);
//do stuff with val and data...
}
pub fn process_changes_a(&mut self, b: &B) {
println!("Processing {} - {}", b.data, self.val);
}
pub fn process_changes_b(&self, b: &mut B) {
println!("Processing {} - {}", b.data, self.val);
}
}
impl B {
pub fn process(&mut self) {
// it's possible to use clones to work around this
// however it's probably better to refactor the logic
// let's see what happens when using clones
let mut tmp_self = self.clone();
let mut tmp_a = self.a.clone();
// this can modify both self.a and tmp_self
self.a.process(&mut tmp_self);
// now self and tmp_self could be different
// does self need to have the value of the &mut B?
// note: this clone is only necessary for
// the other examples to compile
*self = tmp_self.clone();
// or does only self.a need to change?
tmp_a.process(self);
self.a = tmp_a;
// or should the original self.a stay the same?
self.data = tmp_self.data;
}
pub fn process_changes_a(&mut self) {
// you still need a clone of self.a
// otherwise A::process_changes_a could
// modify a through self while reading b.a
let mut tmp_a = self.a.clone();
tmp_a.process_changes_a(self);
self.a = tmp_a;
}
pub fn process_changes_b(&mut self) {
// you still need a clone of self.a
// otherwise A::process_changes_b could
// modify a through b.a while reading self
let tmp_a = self.a.clone();
tmp_a.process_changes_b(self);
}
pub fn process_on_self(&mut self) {
// if you need to modify both self and self.a
// it might be best to have the method directly on B
println!("Processing {} - {}", self.data, self.a.val);
}
}
The problem really comes from the fact that A::process(&mut self, b: &mut B) doesn't know that both self and b.a reference the same value when called from B and expects them to be different. You can make it work by using clones or copies, however it is probably unnecessary.
Personally, I'd probably try to move the logic of process() entirely to B. In your example A depends on B, but also B depends on A. This would make it so that only B depends on A, which makes things simpler.
You can't that's against Rusts aliasing rules, you'd have two mutable references to the A one direct and one indirectly through B. If you really wanted to you could use interior mutability (RefCell, Mutex, ...) but as kaya3 pointed out your suggested implementation seems rather strange even from an OO viewpoint. If it needs a B anyways, I'd just implement it on B diretly without the indirection.

How to find generic bounds for producer that creates objects with trait-lifetime bounds

I have reduced my actual code to this minimal example:
trait Producer<P> where P: Something {
fn produce(&self) -> Box<P>;
}
struct P1 {}
impl Producer<B1> for P1 {
fn produce(&self) -> Box<B1> {
Box::new(B1 {})
}
}
trait Something {}
trait Borrower<'b> {
type B: std::fmt::Display;
fn borrow(&'b self) -> Self::B;
}
struct B1 {}
impl Something for B1 {}
impl<'b> Borrower<'b> for B1 {
type B = Borrowing1<'b>;
fn borrow(&'b self) -> Self::B {
Borrowing1 { _b: &self }
}
}
struct Borrowing1<'b> {
_b: &'b B1,
}
impl<'b> std::fmt::Display for Borrowing1<'b> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Borrowing1")
}
}
fn perform<'b, P, B>(producer: P) where P: Producer<B>, B: Something + Borrower<'b> + 'static {
for _ in 0..1 {
let b = producer.produce();
let s = b.borrow().to_string();
eprintln!("{}", s);
}
}
fn main() {
let p1 = P1 {};
perform(p1);
}
I have a Producer type that creates Something. And that something can implement Borrower<'b>, which introduces a lifetime. Then, I want to restrict a function perform to receive producers that produce Something with the trait Borrower<'b>. However, since I can't prevent introducing a lifetime in perform the function thinks that all produced items must live for the entire function execution. Actually, they are static objects that just implement Borrower<'b>. But I struggle finding the correct bounds.
The error message reflects that:
error[E0597]: `*b` does not live long enough
--> src/main.rs:46:17
|
43 | fn perform<'b, P, B>(producer: P) where P: Producer<B>, B: Something + Borrower<'b> + 'static {
| -- lifetime `'b` defined here
...
46 | let s = b.borrow().to_string();
| ^---------
| |
| borrowed value does not live long enough
| argument requires that `*b` is borrowed for `'b`
47 | eprintln!("{}", s);
48 | }
| - `*b` dropped here while still borrowed
Maybe you can help me with that.
This can be solved using higher-rank trait bounds:
You don't have to pass a lifetime to function here. Instead you need to define a lifetime on the go when borrow() is called. Following should solve the issue:
fn perform<P, B>(producer: P)
where
P: Producer<B>,
for<'b> B: Something + Borrower<'b> + 'static,
{
for _ in 0..1 {
let b = producer.produce();
let u = b.borrow();
let s = u.to_string();
eprintln!("{}", s);
}
}
Playground
Higher-rank trait bounds are explained pretty nicely here: How does for<> syntax differ from a regular lifetime bound?

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 to resolve lifetime error for mutable reference in Rust?

I am not sure why the following code does not compile.
use std::cmp::Ordering;
struct MyItr<'a> {
cur: &'a i32,
}
impl<'a> Ord for MyItr<'a> {
fn cmp(&self, other: &MyItr) -> Ordering {
self.cur.cmp(&other.cur)
}
}
impl<'a> PartialOrd for MyItr<'a> {
fn partial_cmp(&self, other: &MyItr<'a>) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<'a> PartialEq for MyItr<'a> {
fn eq(&self, other: &MyItr) -> bool {
self.cur == other.cur
}
}
impl<'a> Eq for MyItr<'a> {}
fn f0<'a>(t0: &'a mut MyItr<'a>, t1: &'a mut MyItr<'a>, i: &'a i32) {
let t = std::cmp::max(t0, t1);
t.cur = i;
}
fn f1() {
let i0 = 1;
let i1 = 2;
let mut z0 = MyItr { cur: &i0 };
let mut z1 = MyItr { cur: &i1 };
let i2 = 3;
f0(&mut z0, &mut z1, &i2);
}
$ cargo build
Compiling foo v0.1.0 (file:///private/tmp/foo)
error: `z1` does not live long enough
--> lib.rs:40:1
|
39 | f0(&mut z0, &mut z1, &i2);
| -- borrow occurs here
40 | }
| ^ `z1` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
My understanding is the borrowed references to z0 and z1 are backed once the f0 invocation ends. However, The compiler seems to assume the borrowed references are not backed.
$ cargo --version
cargo 0.20.0-nightly (41e490480 2017-05-16)
There are two problems here. The first is that you've over-specified lifetimes, creating a situation the compiler just can't deal with.
fn f0<'a>(t0: &'a mut MyItr<'a>, t1: &'a mut MyItr<'a>, i: &'a i32)
You've told the compiler that all the arguments must be pointers with the same lifetime. The compiler can narrow overlapping lifetimes, but in this case that doesn't help. You've specified that the pointer to the MyItrs has the same lifetime as the thing they point to, and the outer pointers are mutable.
The second problem is that (even after fixing that), what you're trying to do is just outright unsafe and will lead to dangling pointers.
Here's a more minimal example:
struct S<'a> {
ptr: &'a i32,
}
fn f<'b>(t: &'b mut S<'b>, new_ptr: &'b i32) {}
fn main() {
let i0 = 1;
let mut s = S { ptr: &i0 };
let i1 = 2;
f(&mut s, &i1);
}
What is 'b? Well, the compiler can only narrow lifetimes, so usually you'd just take the lifetimes of everything you're trying to pass and pick the shortest one. In this case, that would be the lifetime of i1. So, it has to narrow the lifetime of &s. The lifetime on the pointer to s itself isn't a problem (you can narrow how long you take a borrow for), but narrowing the inner lifetime (the one used for the ptr field) is a problem.
If the compiler narrowed the lifetime of s.ptr, you would then be able to store &i1 in that field. s expects s.ptr to outlive itself, but that will no longer be true: i1 will be destroyed before s is, meaning s.ptr will contain a dangling pointer. And Rust will not allow that to happen.
As a result, Rust can't narrow s's inner 'a lifetime... but if it can't narrow it, then that means 'b must be the full, un-narrowed 'a. But wait, that means that 'b is longer than the lifetime of s itself and i1. And that's impossible.
Hence the failure.
The solution requires two things. First, you need to not over-specify lifetimes. Secondly, you need to ensure that some valid lifetime exists at all; in the case of your original code, that means moving i2 above z0 and z1 so that it outlives them. Like so:
fn f0<'a>(t0: &mut MyItr<'a>, t1: &mut MyItr<'a>, i: &'a i32) {
let t: &mut MyItr<'a> = std::cmp::max(t0, t1);
t.cur = i;
}
fn f1() {
let i0 = 1;
let i1 = 2;
let i2 = 3;
let mut z0 = MyItr { cur: &i0 };
let mut z1 = MyItr { cur: &i1 };
f0(&mut z0, &mut z1, &i2);
}
A rule of thumb: don't just spam a single lifetime everywhere. Only use the same lifetime for things that should be the same.

Calling two member functions that work with different fields at the same time [duplicate]

It seems that if you borrow a reference to a struct field, the whole struct is considered borrowed. I've managed to isolate and example of what I want to do. I just want to get a "read-only" reference to a field in B to obtain some data and then modify another field of B. Is there a idiomatic Rust way to do this?
struct A {
i: i32,
}
struct B {
j: i32,
a: Box<A>,
}
impl B {
fn get<'a>(&'a mut self) -> &'a A {
&*self.a
}
fn set(&mut self, j: i32) {
self.j = j
}
}
fn foo(a: &A) -> i32 {
a.i + 1
}
fn main() {
let a = Box::new(A { i: 47 });
let mut b = B { a: a, j: 1 };
let a_ref = b.get();
b.set(foo(a_ref));
}
error[E0499]: cannot borrow `b` as mutable more than once at a time
--> src/main.rs:27:5
|
26 | let a_ref = b.get();
| - first mutable borrow occurs here
27 | b.set(foo(a_ref));
| ^ second mutable borrow occurs here
28 | }
| - first borrow ends here
It's a feature of the language. From the compiler point of view, there is no way for it to know that it's safe to call your set() function while a is borrowed via get().
Your get() function borrows b mutably, and returns a reference, thus b will remain borrowed until this reference goes out of scope.
You have several way of handling this:
Separate your two fields into two different structs
Move the code which needs to access both attribute inside a method of B
Make your attributes public, you will thus be able to directly get references to them
Compute the new value before setting it, like this:
fn main() {
let a = Box::new(A { i: 47 });
let mut b = B { a: a, j: 1 };
let newval = {
let a_ref = b.get();
foo(a_ref)
};
b.set(newval);
}
Expanding a bit on Levans' answer
Move the code which needs to access both attribute inside a method of B
That might look like this at a first pass:
impl B {
fn do_thing(&mut self) {
self.j = self.a.foo()
}
}
However, this hard-codes the call to foo. You could also accept a closure to allow this to be more flexible:
impl B {
fn update_j_with_a<F>(&mut self, f: F)
where
F: FnOnce(&mut A) -> i32,
{
self.j = f(&mut self.a)
}
}
// ...
b.update_j_with_a(|a| a.foo())
Separate your two fields into two different structs
This is also applicable when you have borrowed two disjoint subsets of attributes. For example:
struct A {
description: String,
name: String,
age: u8,
money: i32,
}
impl A {
fn update_description(&mut self) {
let description = &mut self.description;
*description = self.build_description()
// cannot borrow `*self` as immutable because `self.description` is also borrowed as mutable
}
fn build_description(&self) -> String {
format!(
"{} is {} years old and has {} money",
self.name,
self.age,
self.money
)
}
}
fn main() {}
Can be changed into
struct A {
description: String,
info: Info,
}
struct Info {
name: String,
age: u8,
money: i32,
}
impl A {
fn update_description(&mut self) {
let description = &mut self.description;
*description = self.info.build_description()
}
}
impl Info {
fn build_description(&self) -> String {
format!(
"{} is {} years old and has {} money",
self.name,
self.age,
self.money
)
}
}
fn main() {}
You can combine these two steps (and I'd say that it's better practice) and move the method onto the inner struct.

Resources