Rust lifetimes: can't re-borrow mutable field inside a method - rust

I'm trying to write a data structure ScopedSet that mutably borrows a HashSet, adding an element to it, and then removes that element when the ScopedSet is dropped:
let mut s = HashSet::new();
if let Some(mut s) = ScopedSet::new_with(&mut s, 1) {
// Do something knowing `s.set` contains `1`
}
// `s` no longer contains `1`
I managed to get a working implementation for this:
use std::collections::HashSet;
use std::cmp::Eq;
use std::hash::Hash;
struct ScopedSet<'s, T: Eq + Hash> {
value: T,
set: &'s mut HashSet<T>,
}
impl<'s, T: Eq + Hash> Drop for ScopedSet<'s, T> {
fn drop(&mut self) {
self.set.remove(&self.value);
}
}
impl<'s, T: Clone + Eq + Hash> ScopedSet<'s, T> {
fn new_with(set: &'s mut HashSet<T>, value: T) -> Option<Self> {
if set.insert(value.clone()) {
Some(Self { value, set })
} else {
None
}
}
}
However, trouble arises when I try to do stacked borrows. I can do the following:
if let Some(mut s) = ScopedSet::new_with(&mut s, 1) {
if let Some(mut s) = ScopedSet::new_with(&mut s.set, 2) {
// Do something knowing `s.set` contains both `1` and `2`
}
};
but I would like to have a method on ScopedSet that would allow me to do this:
if let Some(mut s) = ScopedSet::new_with(&mut s, 1) {
if let Some(mut s) = s.with(2) {
// Do something knowing `s.set` contains both `1` and `2`
}
};
I haven't found a way to write ScopedSet::with that's accepted by the borrow checker. For example:
impl<'s, T: Clone + Eq + Hash> ScopedSet<'s, T> {
fn with<'a, 'b>(&'a mut self, value: T) -> Option<ScopedSet<'b, T>>
where
's: 'a,
'a: 'b,
{
if self.set.insert(value.clone()) {
Some(Self {
value,
set: &mut self.set,
})
} else {
None
}
}
}
Here, the rational is that I want to create a ScopedSet containing a borrow &'b mut HashSet<T> which is outlived by the parent ScopedSet borrow (&'a mut self), giving me 'a: 'b. I also know that the parent borrow must be outlived by the data borrow &'s mut HashSet<T>, so we have 's: 'a. Unfortunately, this does not compile:
error: lifetime may not live long enough
--> src/main.rs:35:22
|
26 | impl<'s, T: Clone + Eq + Hash> ScopedSet<'s, T> {
| -- lifetime `'s` defined here
27 | fn with<'a, 'b>(&'a mut self, value: T) -> Option<ScopedSet<'b, T>>
| -- lifetime `'a` defined here
...
35 | set: &mut self.set,
| ^^^^^^^^^^^^^ this usage requires that `'a` must outlive `'s`
|
= help: consider adding the following bound: `'a: 's`
Does anybody have an idea of how I could get ScopedSet::with working?

The problem with your implementation is very simple: you're using Self where you need to use ScopedSet.
This:
Some(Self {
value,
set: &mut self.set,
})
Needs to be this:
Some(ScopedSet {
value,
set: &mut self.set,
})
And it will work.
Self in the context of the implementation is ScopedSet<'s, T>, but you need ScopedSet<'b, T>.

Related

Can a trait's impl specify a lifetime that comes from a method's input argument?

For a type
pub struct Child<'a> {
buf: &'a mut [u8],
}
I can define a trait and implement the trait for the type but with a lifetime that is bound to a calling function's context (not to a local loop context):
pub trait MakeMut<'a> {
fn make_mut(buf: &'a mut [u8]) -> Self;
}
impl<'a> MakeMut<'a> for Child<'a> {
fn make_mut(buf: &'a mut [u8]) -> Self {
Self { buf }
}
}
And first to show a somewhat working example because x is only borrowed within the context of the loop because Child::make_mut is hardcoded in the map1 function:
pub fn map1<F>(mut func: F)
where
F: FnMut(&mut Child),
{
let mut vec = vec![0; 16];
let x = &mut vec;
for i in 0..2 {
let offset = i * 8;
let s = &mut x[offset..];
let mut w = Child::make_mut(s);
func(&mut w);
}
}
But in trying to make map2, a generic version of map1 where the T is bound to the MakeMut trait but with lifetime of the entire function body, this won't compile, for good reasons (the T lifetimes that would be created by T: MakeMut<'a> have the lifetime of map2, not the inner loop):
pub fn map2<'a, F, T>(mut func: F) // lifetime `'a` defined here
where
T: MakeMut<'a>,
F: FnMut(&mut T),
{
let mut vec = vec![0; 16];
let x = &mut vec;
for i in 0..2 {
let offset = i * 8;
let s = &mut x[offset..];
let mut w = T::make_mut(s); // error: argument requires that `*x` is borrowed for `'a`
func(&mut w);
}
}
I want to do something almost like this but of course it doesn't compile either:
pub trait MakeMut {
fn make_mut<'a>(buf: &'a mut [u8]) -> Self;
}
impl<'a> MakeMut for Child<'a> {
fn make_mut(buf: &'a mut [u8]) -> Self { // lifetime mismatch
Self{ buf }
}
}
with the compiler errors:
error[E0308]: method not compatible with trait
--> src/main.rs:45:5
|
45 | fn make_mut(buf: &'a mut [u8]) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected fn pointer `fn(&'a mut [u8]) -> Child<'_>`
found fn pointer `fn(&'a mut [u8]) -> Child<'_>`
note: the lifetime `'a` as defined here...
--> src/main.rs:45:5
|
45 | fn make_mut(buf: &'a mut [u8]) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime `'a` as defined here
--> src/main.rs:44:6
|
44 | impl<'a> MakeMut for Child<'a> {
| ^^
Is there a syntax that allows a trait for a Child<'a> where the 'a is defined by the input argument to the method make_mut? So a generic function could be defined for a trait that returns an instance but where the instance lifetime is not the entire function, but just a shorter lifetime defined by an inner block?
I understand the lifetime is part of the type being returned, but it almost seems like a higher-ranked trait bound (HRTB) would suite this problem except I haven't found a way to specify the lifetime that suites the trait and the method signatures.
Here is a playground link https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=fb28d6da9d89fde645edeb1ca0ae5b21
Your first attempt is close to what you want. For reference:
pub trait MakeMut<'a> {
fn make_mut(buf: &'a mut [u8]) -> Self;
}
impl<'a> MakeMut<'a> for Child<'a> {
fn make_mut(buf: &'a mut [u8]) -> Self {
Self { buf }
}
}
The first problem is the bound on T in map2:
pub fn map2<'a, F, T>(mut func: F)
where
T: MakeMut<'a>,
F: FnMut(&mut T),
This requires the compiler to deduce a single 'a that applies for the whole function. Since lifetime parameters come from outside of the function, the lifetime 'a is necessarily longer than the function invocation, which means anything with lifetime 'a has to outlive the function. Working backwards from the T::make_mut() call, the compiler eventually deduces that x is &'a mut Vec<_> which means vec has to outlive the function invocation, but there's no possible way it can since it's a local.
This can be fixed by using a higher-rank trait bound indicating that T has to implement MakeMut<'a> for any possible lifetime 'a, which is expressed like this:
pub fn map2<F, T>(mut func: F)
where
T: for<'a> MakeMut<'a>,
F: FnMut(&mut T),
With this change, the code compiles.
What you'll then find is that you can't ever actually call map2 with T=Child<'_> because you'll run into the same problem in a different place. The caller must specify a specific lifetime for 'a in Child<'a>, but this disagrees with the HRTB -- you have impl<'a> MakeMut<'a> for Child<'a> but the HRTB wants impl<'a, 'b> MakeMut<'b> for Child<'a>, and that brings back the lifetime problem in that implementation's make_mut.
One way around this is to decouple the implementation of MakeMut from Child, providing a "factory type" that uses associated types. This way, the caller doesn't have to supply any pesky lifetime argument that could cause trouble later.
pub trait MakeMut<'a> {
type Item;
fn make_mut(buf: &'a mut [u8]) -> Self::Item;
}
struct ChildFactory;
impl<'a> MakeMut<'a> for ChildFactory {
type Item = Child<'a>;
fn make_mut(buf: &'a mut [u8]) -> Child<'a> {
Child { buf }
}
}
Then we modify map2 to be aware of the associated type:
pub fn map2<F, T>(mut func: F)
where
T: for<'a> MakeMut<'a>,
F: for<'a, 'b> FnMut(&'b mut <T as MakeMut<'a>>::Item),
whew
Now, finally, we can use map2:
map2::<_, ChildFactory>(|v| {});
(Playground)

How to allow immutable and mutable borrows to coexist in a function with explicit lifetimes?

For context: I'm implementing an Entity, basically a thin wrapper around a heterogenous map, and trying to implement an update method:
struct Entity {
pub id: u64,
data: HashMap<TypeId, Box<dyn Any>>,
}
impl Entity {
pub fn new(id: u64) -> Self {
Entity { id, data: HashMap::new() }
}
pub fn get_atom<T: Any>(&self) -> Option<&T> {
self.data.get(&TypeId::of::<T>())?.downcast_ref()
}
pub fn set_atom<T: Any>(&mut self, value: T) {
self.data.insert(TypeId::of::<T>(), Box::new(value));
}
pub fn update<T: Any, R: Any>(&mut self, f: impl Fn(&T) -> R)
{
if let Some(val) = self.get_atom() {
self.set_atom(f(val));
}
}
}
This works, but gives a warning:
warning: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/entity.rs:71:13
|
70 | if let Some(val) = self.get_atom() {
| --------------- immutable borrow occurs here
71 | self.set_atom(f(val));
| ^^^^^^^^^^^^^^^^---^^
| | |
| | immutable borrow later used here
| mutable borrow occurs here
OK, that's fixable like this, which removes the warning.
pub fn update<T: Any, R: Any>(&mut self, f: impl Fn(&T) -> R)
{
let maybe : Option<R> = self.get_atom().map(f);
if let Some(val) = maybe {
self.set_atom(val);
}
}
The problem I have is when I introduce a trait for abstracting over getting stuff out of the entity (which permits me to abstract over arity: getting a tuple returns a value if each of the components is in the entity):
trait GetComponent<'a, T> {
fn get_component(entity: &'a Entity) -> Option<T>;
}
// sample atom impl
impl <'a> GetComponent<'a, &'a u32> for &'a u32 {
fn get_component(entity: &'a Entity) -> Option<&'a u32> {
entity.get_atom()
}
}
// sample composite impl
impl <'a, A, B> GetComponent<'a, (A, B)> for (A, B) where
A: GetComponent<'a, A>,
B: GetComponent<'a, B>,
{
fn get_component(entity: &'a Entity) -> Option<(A, B)> {
Some((A::get_component(entity)?, B::get_component(entity)?))
}
}
impl Entity {
<in addition to the above>
pub fn get<'a, T: GetComponent<'a, T>>(&'a self) -> Option<T> {
T::get_component(self)
}
pub fn update<'a, T: 'a, R: Any>(&'a mut self, f: impl Fn(&T) -> R)
where &'a T: GetComponent<'a, &'a T>
{
let maybe : Option<R> = self.get().map(f);
if let Some(val) = maybe {
self.set_atom(val);
}
}
}
The trait requires me to be explicit about lifetimes, and everything else I've tried to do so far with the entity seems to be just fine. But this update method gives this compile error (not a warning this time):
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/entity.rs:56:13
|
51 | pub fn update<'a, T: 'a, R: Any>(&'a mut self, f: impl Fn(&T) -> R)
| -- lifetime `'a` defined here
...
54 | let maybe : Option<R> = self.get().map(f);
| ----------
| |
| immutable borrow occurs here
| argument requires that `*self` is borrowed for `'a`
55 | if let Some(val) = maybe {
56 | self.set_atom(val);
| ^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
Now, as far as I can see, there's no reason why I shouldn't be able to immutably borrow for a shorter period, so the immutable borrow "expires" before I do the mutation - just like in the version without explicit lifetimes used prior to the trait.
But I can't for the life of me work out how to make this work.
You can solve this with a higher-rank trait bound (HRTB):
pub fn update<T, R: Any>(&mut self, f: impl Fn(&T) -> R)
where for <'a> &'a T: GetComponent<'a, &'a T>
This says that for any possible lifetime 'a, T must satisfy the given bound. This allows you to specify how the various lifetimes on the type T relate to each other without binding them to a specific lifetime, such as that of &mut self.
(Playground)

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?

How to write trait bound that supports += operation whose right hand is reference in complicated case in Rust [duplicate]

This question already has an answer here:
How to write a trait bound for adding two references of a generic type?
(1 answer)
Closed 2 years ago.
I'd like to write an Add operation supported Vector struct, and write a some trait that uses the Vector struct, so I wrote this.
use std::ops::*;
#[derive(Clone)]
struct Vector<T>(Vec<T>);
impl<'a, T> Add<&'a Vector<T>> for Vector<T>
where
T: AddAssign<&'a T>,
{
type Output = Vector<T>;
fn add(mut self, rhs: &'a Vector<T>) -> Self::Output {
self.0
.iter_mut()
.zip(rhs.0.iter())
.for_each(|(left, right)| {
*left += right;
});
self
}
}
trait SomeOperation<'a ,T>
where
T: AddAssign<&'a T>+Clone + 'a,
{
fn add(u:Vector<T>,v:&'a Vector<T>)->Vector<T>{
let w = u+v;
let x = v.clone()+&w;
x
}
}
But compilation error occurs.
21 | trait SomeOperation<'a ,T>
| -- lifetime `'a` defined here
...
27 | let x = v.clone()+&w;
| ^^
| |
| borrowed value does not live long enough
| requires that `w` is borrowed for `'a`
28 | x
29 | }
| - `w` dropped here while still borrowed
How can I avoid these types of error.
You talk about implementing AddAssign but your code tries to implement Add. Also, I couldn't figure out what SomeOperation was for. I added the Debug trait to the derive line.
use std::ops::*;
#[derive(Clone, Debug)]
struct Vector<T>(Vec<T>);
impl<'a, T> AddAssign<&'a Vector<T>> for Vector<T>
where
T: AddAssign<&'a T>
{
fn add_assign(&mut self, rhs: &'a Vector<T>) {
self.0
.iter_mut()
.zip(rhs.0.iter())
.for_each(|(left, right)| {
*left += right;
});
}
}
impl<'a, 'b, T> Add<& 'b Vector<T>> for & 'a Vector<T>
where
Vector<T>: AddAssign<& 'b Vector<T>>,
T: Clone,
{
type Output = Vector<T>;
fn add(self, other: & 'b Vector<T>) -> Self::Output {
let mut res: Vector<T> = self.clone();
res += other;
res
}
}
fn main() {
let mut v1: Vector<u32> = Vector(vec![1, 2, 3]);
let v2 = Vector(vec![4, 5, 6]);
println!("Add: {:?}", &v1 + &v2);
v1 += &v2;
println!("AddAssign{:?}", v1);
}

Cannot infer a lifetime for a closure returning a boxed trait that contains a reference

I am trying to compile the following code (playground):
trait MockFutureTrait {
type Item;
}
struct MockFuture<T> {
item: T,
}
impl<T> MockFutureTrait for MockFuture<T> {
type Item = T;
}
struct FragMsgReceiver<'a, 'c: 'a> {
recv_dgram: &'a FnMut(&mut [u8])
-> Box<MockFutureTrait<Item = &mut [u8]> + 'c>,
}
fn constrain_handler<F>(f: F) -> F
where
F: FnMut(&mut [u8]) -> Box<MockFutureTrait<Item = &mut [u8]>>,
{
f
}
fn main() {
let mut recv_dgram = constrain_handler(|buf: &mut [u8]| {
Box::new(MockFuture { item: buf }) as Box<MockFutureTrait<Item = &mut [u8]>>
});
let ref_recv_dgram = &mut recv_dgram;
let fmr = FragMsgReceiver {
recv_dgram: ref_recv_dgram,
};
}
And I get the compile error:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:28:37
|
28 | Box::new(MockFuture { item: buf }) as Box<MockFutureTrait<Item = &mut [u8]>>
| ^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 27:44...
--> src/main.rs:27:44
|
27 | let mut recv_dgram = constrain_handler(|buf: &mut [u8]| {
| ____________________________________________^
28 | | Box::new(MockFuture { item: buf }) as Box<MockFutureTrait<Item = &mut [u8]>>
29 | | });
| |_____^
note: ...so that expression is assignable (expected &mut [u8], found &mut [u8])
--> src/main.rs:28:37
|
28 | Box::new(MockFuture { item: buf }) as Box<MockFutureTrait<Item = &mut [u8]>>
| ^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that expression is assignable (expected std::boxed::Box<MockFutureTrait<Item=&mut [u8]> + 'static>, found std::boxed::Box<MockFutureTrait<Item=&mut [u8]>>)
--> src/main.rs:28:9
|
28 | Box::new(MockFuture { item: buf }) as Box<MockFutureTrait<Item = &mut [u8]>>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I tried to add various lifetime hints, but I couldn't get this code to compile.
My previous related questions on SO about this:
Cannot infer a lifetime for a struct containing a reference to a closure: Solving the same problem, when the return value is a simple struct and not a trait.
How can multiple struct fields be generics that use the same higher-kinded lifetime?: About trying to solve this problem without Boxes. The answer suggests that for now I will have to use Box>.
Note that I am using the helper function constrain_handler according to a suggestion I got in question 2; it allows me to overcome a different compilation error.
It appears that you've missed a key takeaway of your previous questions and their duplicates:
Lifetime annotation for closure argument
Cannot infer a lifetime for a struct containing a reference to a closure
How to declare a lifetime for a closure argument
By declaring a type on the closure argument, you stop performing type inference for the arguments. This causes a new implicit lifetime to be generated by the closure, one which does not match your requirements. Just don't declare the type at all.
Next, you need to state that your closure is going to take a reference to some bytes and return a boxed trait object that will return some bytes of the same lifetime and contains a reference of that same lifetime:
struct FragMsgReceiver<'a> {
recv_dgram: &'a for<'b> FnMut(&'b mut [u8])
-> Box<MockFutureTrait<Item = &'b mut [u8]> + 'b>,
}
See Why is Box<Iterator<Item = &Foo> + 'a> needed? for more details about the + 'a syntax.
Then update constrain_handler to match:
struct FragMsgReceiver<'a> {
recv_dgram: &'a for<'b> FnMut(&'b mut [u8])
-> Box<MockFutureTrait<Item = &'b mut [u8]> + 'b>,
}
fn constrain_handler<F>(f: F) -> F
where
F: for<'b> FnMut(&'b mut [u8])
-> Box<MockFutureTrait<Item = &'b mut [u8]> + 'b>,
{
f
}
fn main() {
let mut recv_dgram = constrain_handler(|buf| Box::new(MockFuture { item: buf }));
let fmr = FragMsgReceiver {
recv_dgram: &mut recv_dgram,
};
}
The whole thing can be made simpler if you just take a generic closure directly:
struct FragMsgReceiver<R>
where
R: for<'b> FnMut(&'b mut [u8])
-> Box<MockFutureTrait<Item = &'b mut [u8]> + 'b>,
{
recv_dgram: R,
}
fn main() {
let fmr = FragMsgReceiver {
recv_dgram: |buf| Box::new(MockFuture { item: buf }),
};
}

Resources