playground link
I'm having trouble trouble understanding why this code can't compile:
struct Ctx<'a> {
n: u64,
phantom: std::marker::PhantomData<&'a u8>,
}
fn process<'a, 'b: 'a>(ctx: &'b mut Ctx<'a>) {
ctx.n += 1;
}
fn main() {
let mut ctx = Ctx { n: 0, phantom: std::marker::PhantomData };
let ref_ctx = &mut ctx;
process(ref_ctx);
process(ref_ctx);
}
The code is silly, but the error is the same as on the "real" code:
Compiling playground v0.0.1 (/playground)
error[E0499]: cannot borrow `*ref_ctx` as mutable more than once at a time
--> src/main.rs:14:13
|
13 | process(ref_ctx);
| ------- first mutable borrow occurs here
14 | process(ref_ctx);
| ^^^^^^^
| |
| second mutable borrow occurs here
| first borrow later used here
For more information about this error, try `rustc --explain E0499`.
error: could not compile `playground` due to previous error
If change the process signature to
fn process(ctx: &mut Ctx<'a>) {
Then it compiles, but I need the lifetimes annotations because in practice Ctx contains references that needs to be annotated. I feel like the problem is 'b: 'a because is could be telling that the borrow MUST outlive the references in Ctx, but it feels weird that just calling a function that returns nothing would extend the borrow,
That feels like a beginner's question, but it definitely has me stumped.
edit:
The code above is minimal because I wanted to avoid explaining the whole context (pun intended), but it might be necessary to find a practical solution. Sorry, that's going to be a bit long.
The real Ctx is here, it's struct that wraps a few Varnish C pointers and gets passed to plugins so they can read it and possibly change it, notably manipulating HTTP objects.
An important part of Ctx is the WS contained in it. It's a workspace that can return non-overlapping slices of writable data that will be deleted automatically once a task has been completed. For the compiler, the best we can tell it is "any slice allocated in the WS will survive for as long as the Ctx wil live".
WS can be used in two ways:
either directly by a plugin to request a slice it'll fill in
or by the boilerplate that's currently python-generated to convert Varnish types into C types. Typically, the plugin returns a String and the boilerplate will allocate a WS slice and copy the data for storage. And example of generated code looks like this:
// the C-matching function that needs to exist for the plugin frame work to pick it up
unsafe extern "C" fn vmod_c_unset_hdr(vrt_ctx: * mut varnish_sys::vrt_ctx, arg1: varnish_sys::VCL_STRING) {
// create the rust Ctx from the pointer
let mut _ctx = Ctx::new(vrt_ctx);
// call the plugin function
match vmod::unset_hdr(
&mut _ctx,
&*arg1.into_rust()
).into_result() { // make sure we have a Result by wrapping lone values
Err(ref e) => { _ctx.fail(e); }, // yell if we didn't got and Err
Ok(v) => v.into_vcl(&mut _ctx.ws), // convert the Ok value into a C type, possibly by copying it into the workspace
}
}
Now, so far, the code at the commit I shared works (hurray), but I get into trouble when I try to implement WS_ReserveAll and WS_Release: basically, grab all the free space you can, write what you need, and then tell Varnish how much you used so the rest is reclaimed and can be used by future calls.
Of course, you can only WS_ReserveAll() once before you need to WS_Release so that felt like a perfect job for Rust.
I though I'd create a new type ReservedBuf, by adding this to the code:
impl<'a> struct WS<'a> {
// some lines omitted
pub fn reserve(&'a mut self) -> ReservedBuf<'a> {
let wsp = unsafe { self.raw.as_mut().unwrap() };
assert_eq!(wsp.magic, varnish_sys::WS_MAGIC);
unsafe {
let sz = varnish_sys::WS_ReserveAll(wsp) as usize;
let buf = from_raw_parts_mut(wsp.f as *mut u8, sz as usize);
ReservedBuf {
buf,
wsp: self.raw,
b: wsp.f as *const u8,
len: 0,
}
}
}
}
pub struct ReservedBuf<'a> {
pub buf: &'a mut [u8],
wsp: *mut varnish_sys::ws,
b: *const u8,
len: usize,
}
impl<'a> ReservedBuf<'a> {
pub fn seal(mut self, sz: usize) -> &'a [u8] {
unsafe {
self.len = std::cmp::min(sz, self.buf.as_ptr().add(sz).offset_from(self.b) as usize);
from_raw_parts_mut(self.buf.as_mut_ptr(), self.len)
}
}
}
impl<'a> Drop for ReservedBuf<'a> {
fn drop(&mut self) {
unsafe {
let wsp = self.wsp.as_mut().unwrap();
assert_eq!(wsp.magic, varnish_sys::WS_MAGIC);
varnish_sys::WS_Release(wsp, self.len as u32);
}
}
}
And it appears to work well enough in the limited tests I ran. My plugin function can be this for example:
pub fn ws_reserve<'a, 'b: 'a>(ctx: &'b mut Ctx<'a>, s: &str) -> Result<varnish_sys::VCL_STRING, String> {
let mut rbuf = ctx.ws.reserve();
let s_buf = s.as_bytes();
let vcl_string = rbuf.buf.as_ptr() as *const i8;
rbuf.buf.write(s_buf);
rbuf.buf.write(b" ");
rbuf.buf.write(s_buf);
rbuf.buf.write(b" ");
rbuf.buf.write(s_buf);
rbuf.buf.write(b"\0");
rbuf.seal(0);
Ok(vcl_string)
}
but I need the lifetime annotations, otherwise I get:
--> src/vmod.rs:21:27
|
20 | pub fn ws_reserve(ctx: &mut Ctx, s: &str) -> Result<varnish_sys::VCL_STRING, String> {
| --------
| |
| these two types are declared with different lifetimes...
21 | let mut rbuf = ctx.ws.reserve();
| ^^^^^^^ ...but data from `ctx` flows into `ctx` here
but with the lifetime annotations, the generated-code calling ws_reserve complains:
unsafe extern "C" fn vmod_c_ws_reserve(vrt_ctx: * mut varnish_sys::vrt_ctx, arg1: varnish_sys::VCL_STRING) -> varnish_sys::VCL_STRING {
let mut _ctx = Ctx::new(vrt_ctx);
match vmod::ws_reserve(
&mut _ctx,
&*arg1.into_rust()
).into_result() {
Err(ref e) => { _ctx.fail(e); ptr::null() },
Ok(v) => v.into_vcl(&mut _ctx.ws),
}
}
error[E0499]: cannot borrow `_ctx` as mutable more than once at a time
--> /home/gquintard/project/varnish-rs/vmod_test/target/debug/build/vmod_example-7ff3d57b642f2bfa/out/generated.rs:69:29
|
66 | &mut _ctx,
| --------- first mutable borrow occurs here
...
69 | Err(ref e) => { _ctx.fail(e); ptr::null() },
| ^^^^
| |
| second mutable borrow occurs here
| first borrow later used here
error[E0499]: cannot borrow `_ctx.ws` as mutable more than once at a time
--> /home/gquintard/project/varnish-rs/vmod_test/target/debug/build/vmod_example-7ff3d57b642f2bfa/out/generated.rs:70:33
|
66 | &mut _ctx,
| --------- first mutable borrow occurs here
...
70 | Ok(v) => v.into_vcl(&mut _ctx.ws),
| ^^^^^^^^^^^^
| |
| second mutable borrow occurs here
| first borrow later used here
For more information about this error, try `rustc --explain E0499`.
error: could not compile `vmod_example` due to 2 previous errors
I guess I sort of understand the compiler qualms about the issues, and I might have painted myself into a corner, but I don't see how to solve this.
When we take a closer look at your code we see you write this:
fn process<'a, 'b: 'a>(ctx: &'b mut Ctx<'a>) {
This 'b: 'a reads as 'b outlives 'a. So you're basically writing a method which borrows ctx longer than what ctx is holding internally with 'a.
With that knowledge it seems very logical why this won't work.
let mut ctx = Ctx { n: 0, phantom: std::marker::PhantomData };
let ref_ctx = &mut ctx;
process(ref_ctx); // Borrow ref_ctx for at least the lifetime of `Ctx::<'a>`
process(ref_ctx); // Can't borrow it again since `'a` has not expired yet
What you're trying to do is probably this:
fn process<'a: 'b, 'b>(ctx: &'b mut Ctx<'a>) {
Borrow ctx for the lifetime 'b which is less long than 'a
If that's the case you can just write this:
fn process<'a>(ctx: &mut Ctx<'a>) {
Or even this:
fn process(ctx: &mut Ctx) {
If this isn't what you're trying to do I hope it still makes sense that using the constraint 'b: 'a creates an impossible borrow.
Related
This question already has an answer here:
Why is there a borrow of a moved value when calling a method that takes self by value with an argument that also calls a method?
(1 answer)
Closed last year.
The below rust code has compilation error.
struct Builder;
impl Builder {
pub fn add(&mut self, id: i32) -> i32 {
id + 1
}
}
fn main() {
let mut b = Builder;
b.add(b.add(10));
}
error[E0499]: cannot borrow `b` as mutable more than once at a time
--> examples/mutable_borrow_at_a_time.rs:10:11
|
10 | b.add(b.add(10));
| - --- ^ second mutable borrow occurs here
| | |
| | first borrow later used by call
| first mutable borrow occurs here
Unlike the question Cannot borrow `x` as mutable more than once at a time, add does not return any reference at all.
Unlike the question Borrow errors for multiple borrows, the return type is i32 which has 'static lifetime.
While the following code can be compiled without errors.
struct Builder;
impl Builder {
pub fn add(&mut self, id: i32) -> i32 {
id + 1
}
}
fn main() {
let mut b = Builder;
let x = b.add(10);
b.add(x);
}
Anyway it is cumbersome to create a dummy variable x every time for a compound expression.
First there will be a mutable borrow on the outer b.add(...) and then there will be an attempt to make a second mutable borrow on the inner b.add(). That is wonderfully explained & visualized by the compiler in the error message that you pasted:
| b.add(b.add(10));
| - --- ^ second mutable borrow occurs here
| | |
| | first borrow later used by call
| first mutable borrow occurs here
This limitation might be removed at some point, but for now, that's how it works.
And for your specific example, as Jmb mentioned, you don't need mut at all, so this will work just fine:
struct Builder;
impl Builder {
pub fn add(&self, id: i32) -> i32 {
id + 1
}
}
fn main() {
let b = Builder;
b.add(b.add(10));
}
It looks like you are attempting to use the builder pattern.
The difficulty stands in passing a &mut on the builder from call to call.
Each step in the chain should rather consume the previous state of the builder and emit a new state (like add() here).
Finally, the last step (build()) consumes the builder for the last time and emits instead the value we intended to build.
You might be worried about the performance cost of these multiple move/consume operations (instead of altering through a &mut), but when enabling optimizations, the compiler is able to look through these calls and can decide to do everything in place: a function only containing Builder::new().add(10).add(20).build() produces mov eax, 30 ret.
struct Builder {
id: i32,
}
impl Builder {
pub fn new() -> Self {
Builder { id: 0 }
}
pub fn add(
mut self,
incr: i32,
) -> Self {
self.id += incr;
self
}
pub fn build(self) -> i32 {
self.id
}
}
fn main() {
let id = Builder::new().add(10).add(20).build();
println!("id={:?}", id);
}
Stripped down to the bare essentials, my problematic code looks as follows:
pub struct Item;
impl Item {
/// Partial copy. Not the same as simple assignment.
pub fn copy_from(&mut self, _other: &Item) {
}
}
pub struct Container {
items: Vec<Item>,
}
impl Container {
pub fn copy_from(&mut self, self_idx: usize, other: &Container, other_idx: usize) {
self.items[self_idx].copy_from(&other.items[other_idx]);
}
}
fn main() {
let mut container = Container { items: vec![Item, Item] };
container.copy_from(0, &container, 1);
}
This is of course rejected by the borrow checker:
error[E0502]: cannot borrow `container` as mutable because it is also borrowed as immutable
--> src/main.rs:21:5
|
21 | container.copy_from(0, &container, 1);
| ^^^^^^^^^^---------^^^^----------^^^^
| | | |
| | | immutable borrow occurs here
| | immutable borrow later used by call
| mutable borrow occurs here
For more information about this error, try `rustc --explain E0502`.
I understand why that happens, but I don't have a good solution.
I've considered adding a dedicated copy_from_self function that callers need to use in cases where self == other:
pub fn copy_from_self(&mut self, to_idx: usize, from_idx: usize) {
if to_idx != from_idx {
unsafe {
let from_item: *const Item = &self.items[from_idx];
self.items[to_idx].copy_from(&*from_item);
}
}
}
But this is un-ergonomic, bloats the API surface, and needs unsafe code inside.
Note that in reality, the internal items data structure is not a simple Vec, so any approach specific to Vec or slice will not work.
Is there an elegant, idiomatic solution to this problem?
If I understand the comments on the question correctly, a general solution seems to be impossible, so this answer is necessarily specific to my actual situation.
As mentioned, the actual data structure is not a Vec. If it were a Vec, we could use split_at_mut to at least implement copy_from_self safely.
But as it happens, my actual data structure is backed by a Vec, so I was able to add a helper function:
/// Returns a pair of mutable references to different items. Useful if you need to pass
/// a reference to one item to a function that takes `&mut self` on another item.
/// Panics if `a == b`.
fn get_mut_2(&mut self, a: usize, b: usize) -> (&mut T, &mut T) {
assert!(a != b);
if a < b {
let (first, second) = self.items.split_at_mut(b);
(&mut first[a], &mut second[0])
} else if a > b {
let (first, second) = self.items.split_at_mut(a);
(&mut second[0], &mut first[b])
} else {
panic!("cannot call get_mut_2 with the same index {} == {}", a, b);
}
}
Now we can implement copy_from_self without unsafe code:
pub fn copy_from_self(&mut self, to_idx: usize, from_idx: usize) {
let (to, from) = self.items.get_mut_2(to_idx, from_idx);
to.unwrap().copy_from(from.unwrap());
}
tl;dr given pub fn func(&'a mut self), why is self considered "mutably borrowed" after func has run?
Given the following minimal viable example (playground)
pub struct Struct1<'a> {
var: &'a u8,
}
impl<'a> Struct1<'a> {
pub fn new() -> Struct1<'a> {
return Struct1 {
var: &33,
}
}
pub fn func(&'a mut self) -> () {
()
}
}
fn main() {
let mut s1 = Struct1::new();
s1.func(); // point 1
// point 2
s1.func(); // point 3
}
results in compiler error
error[E0499]: cannot borrow `s1` as mutable more than once at a time
--> src/test12-borrow-mut-struct-twice-okay.rs:20:5
|
18 | s1.func(); // point 1
| -- first mutable borrow occurs here
19 | // point 2
20 | s1.func(); // point 3
| ^^
| |
| second mutable borrow occurs here
| first borrow later used here
However, at // point 2 the s1 appears to me to not be anymore borrowed. The func is done running. What could be still be borrowing self within func!? It appears func at //point 1 has relinquished control of s1.
What is still borrowing s1 at // point 3 ?
Similar questions:
borrow-errors-for-multiple-borrows
returning-a-reference-from-a-hashmap-or-vec-causes-a-borrow-to-last-beyond-the-s
mysterious-borrow-scope-extension
cannot-borrow-variable-when-borrower-scope-ends
why-does-this-mutable-borrow-live-beyond-its-scope)
mutable-borrow-seems-to-outlive-its-scope
What is still borrowing s1 at // point 3 ?
You're telling the compiler that it's still borrowed, so it's trusting you: while the compiler verifies that your lifetimes are not too short, it doesn't really care if they're so long they make things unusable.
When you write &'a mut self, the 'a is the one declared on the impl block, and thus the one defined on the struct. &'a mut self literally desugars to:
self: &'a mut Struct1<'a>
so once you've called func() the rust compiler goes "well this is borrowed for 'a which is the lifetime associated with s1 which is 'static, so this is mutably borrowed forever, good day", and thus you get "locked out" of the structure.
In fact you can see this aliasing by trying to explicitly declare an 'a on func:
pub fn func<'a>(&'a mut self) -> () {
()
}
error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope
--> src/main.rs:11:17
|
5 | impl<'a> Struct1<'a> {
| -- first declared here
...
11 | pub fn func<'a>(&'a mut self) -> () {
| ^^ lifetime `'a` already in scope
error: aborting due to previous error
So rust is telling you in no uncertain term that within the block 'a always refers to the lifetime declared on the impl block.
The solution is to just remove the 'a, that's the wrong lifetime entirely:
pub fn func(&mut self) -> () {
()
}
In that case rustc will automatically introduce a lifetime, and since the function is not actually borrowing anything that lifetime will only extend to the function call.
This code is an inefficient way of producing a unique set of items from an iterator. To accomplish this, I am attempting to use a Vec to keep track of values I've seen. I believe that this Vec needs to be owned by the innermost closure:
fn main() {
let mut seen = vec![];
let items = vec![vec![1i32, 2], vec![3], vec![1]];
let a: Vec<_> = items
.iter()
.flat_map(move |inner_numbers| {
inner_numbers.iter().filter_map(move |&number| {
if !seen.contains(&number) {
seen.push(number);
Some(number)
} else {
None
}
})
})
.collect();
println!("{:?}", a);
}
However, compilation fails with:
error[E0507]: cannot move out of captured outer variable in an `FnMut` closure
--> src/main.rs:8:45
|
2 | let mut seen = vec![];
| -------- captured outer variable
...
8 | inner_numbers.iter().filter_map(move |&number| {
| ^^^^^^^^^^^^^^ cannot move out of captured outer variable in an `FnMut` closure
This is a little surprising, but isn't a bug.
flat_map takes a FnMut as it needs to call the closure multiple times. The code with move on the inner closure fails because that closure is created multiple times, once for each inner_numbers. If I write the closures in explicit form (i.e. a struct that stores the captures and an implementation of one of the closure traits) your code looks (a bit) like
struct OuterClosure {
seen: Vec<i32>
}
struct InnerClosure {
seen: Vec<i32>
}
impl FnMut(&Vec<i32>) -> iter::FilterMap<..., InnerClosure> for OuterClosure {
fn call_mut(&mut self, (inner_numbers,): &Vec<i32>) -> iter::FilterMap<..., InnerClosure> {
let inner = InnerClosure {
seen: self.seen // uh oh! a move out of a &mut pointer
};
inner_numbers.iter().filter_map(inner)
}
}
impl FnMut(&i32) -> Option<i32> for InnerClosure { ... }
Which makes the illegality clearer: attempting to move out of the &mut OuterClosure variable.
Theoretically, just capturing a mutable reference is sufficient, since the seen is only being modified (not moved) inside the closure. However things are too lazy for this to work...
error: lifetime of `seen` is too short to guarantee its contents can be safely reborrowed
--> src/main.rs:9:45
|
9 | inner_numbers.iter().filter_map(|&number| {
| ^^^^^^^^^
|
note: `seen` would have to be valid for the method call at 7:20...
--> src/main.rs:7:21
|
7 | let a: Vec<_> = items.iter()
| _____________________^
8 | | .flat_map(|inner_numbers| {
9 | | inner_numbers.iter().filter_map(|&number| {
10| | if !seen.contains(&number) {
... |
17| | })
18| | .collect();
| |__________________^
note: ...but `seen` is only valid for the lifetime as defined on the body at 8:34
--> src/main.rs:8:35
|
8 | .flat_map(|inner_numbers| {
| ___________________________________^
9 | | inner_numbers.iter().filter_map(|&number| {
10| | if !seen.contains(&number) {
11| | seen.push(number);
... |
16| | })
17| | })
| |_________^
Removing the moves makes the closure captures work like
struct OuterClosure<'a> {
seen: &'a mut Vec<i32>
}
struct InnerClosure<'a> {
seen: &'a mut Vec<i32>
}
impl<'a> FnMut(&Vec<i32>) -> iter::FilterMap<..., InnerClosure<??>> for OuterClosure<'a> {
fn call_mut<'b>(&'b mut self, inner_numbers: &Vec<i32>) -> iter::FilterMap<..., InnerClosure<??>> {
let inner = InnerClosure {
seen: &mut *self.seen // can't move out, so must be a reborrow
};
inner_numbers.iter().filter_map(inner)
}
}
impl<'a> FnMut(&i32) -> Option<i32> for InnerClosure<'a> { ... }
(I've named the &mut self lifetime in this one, for pedagogical purposes.)
This case is definitely more subtle. The FilterMap iterator stores the closure internally, meaning any references in the closure value (that is, any references it captures) have to be valid as long as the FilterMap values are being thrown around, and, for &mut references, any references have to be careful to be non-aliased.
The compiler can't be sure flat_map won't, e.g. store all the returned iterators in a Vec<FilterMap<...>> which would result in a pile of aliased &muts... very bad! I think this specific use of flat_map happens to be safe, but I'm not sure it is in general, and there's certainly functions with the same style of signature as flat_map (e.g. map) would definitely be unsafe. (In fact, replacing flat_map with map in the code gives the Vec situation I just described.)
For the error message: self is effectively (ignoring the struct wrapper) &'b mut (&'a mut Vec<i32>) where 'b is the lifetime of &mut self reference and 'a is the lifetime of the reference in the struct. Moving the inner &mut out is illegal: can't move an affine type like &mut out of a reference (it would work with &Vec<i32>, though), so the only choice is to reborrow. A reborrow is going through the outer reference and so cannot outlive it, that is, the &mut *self.seen reborrow is a &'b mut Vec<i32>, not a &'a mut Vec<i32>.
This makes the inner closure have type InnerClosure<'b>, and hence the call_mut method is trying to return a FilterMap<..., InnerClosure<'b>>. Unfortunately, the FnMut trait defines call_mut as just
pub trait FnMut<Args>: FnOnce<Args> {
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}
In particular, there's no connection between the lifetime of the self reference itself and the returned value, and so it is illegal to try to return InnerClosure<'b> which has that link. This is why the compiler is complaining that the lifetime is too short to be able to reborrow.
This is extremely similar to the Iterator::next method, and the code here is failing for basically the same reason that one cannot have an iterator over references into memory that the iterator itself owns. (I imagine a "streaming iterator" (iterators with a link between &mut self and the return value in next) library would be able to provide a flat_map that works with the code nearly written: would need "closure" traits with a similar link.)
Work-arounds include:
the RefCell suggested by Renato Zannon, which allows seen to be borrowed as a shared &. The desugared closure code is basically the same other than changing the &mut Vec<i32> to &Vec<i32>. This change means "reborrow" of the &'b mut &'a RefCell<Vec<i32>> can just be a copy of the &'a ... out of the &mut. It's a literal copy, so the lifetime is retained.
avoiding the laziness of iterators, to avoid returning the inner closure, specifically.collect::<Vec<_>>()ing inside the loop to run through the whole filter_map before returning.
fn main() {
let mut seen = vec![];
let items = vec![vec![1i32, 2], vec![3], vec![1]];
let a: Vec<_> = items
.iter()
.flat_map(|inner_numbers| {
inner_numbers
.iter()
.filter_map(|&number| if !seen.contains(&number) {
seen.push(number);
Some(number)
} else {
None
})
.collect::<Vec<_>>()
.into_iter()
})
.collect();
println!("{:?}", a);
}
I imagine the RefCell version is more efficient.
It seems that the borrow checker is getting confused at the nested closures + mutable borrow. It might be worth filing an issue. Edit: See huon's answer for why this isn't a bug.
As a workaround, it's possible to resort to RefCell here:
use std::cell::RefCell;
fn main() {
let seen = vec![];
let items = vec![vec![1i32, 2], vec![3], vec![1]];
let seen_cell = RefCell::new(seen);
let a: Vec<_> = items
.iter()
.flat_map(|inner_numbers| {
inner_numbers.iter().filter_map(|&number| {
let mut borrowed = seen_cell.borrow_mut();
if !borrowed.contains(&number) {
borrowed.push(number);
Some(number)
} else {
None
}
})
})
.collect();
println!("{:?}", a);
}
I came across this question after I ran into a similar issue, using flat_map and filter_map. I solved it by moving the filter_map outside the flat_map closure.
Using your example:
let a: Vec<_> = items
.iter()
.flat_map(|inner_numbers| inner_numbers.iter())
.filter_map(move |&number| {
if !seen.contains(&number) {
seen.push(number);
Some(number)
} else {
None
}
})
.collect();
While coding along to get used to Rust, I stumbled upon a compiler error. I want to understand why I get the error and what to do about it:
cannot infer an appropriate lifetime for lifetime parameter in generic
type due to conflicting requirements
I've been looking at a lot of questions covering similar errors, but most seem related to cyclic dependencies and I don't think this is what's going on here.
This is my attempt at a MWE, which still might be further reducible:
Playground link (slightly different error message)
pub struct InnerMut<T> {
state: u32,
stored_fn: fn(&mut T, u32),
}
impl<T> InnerMut<T> {
pub fn new(stored_fn: fn(&mut T, u32)) -> InnerMut<T> {
return InnerMut {
state: std::u32::MAX,
stored_fn,
};
}
pub fn mutate(&mut self, data: &mut T) {
(self.stored_fn)(data, self.state);
self.state -= 1;
}
}
pub struct StoreFnMut<F>
where
F: FnMut(&mut [u8]),
{
mutable_closure: F,
}
impl<F> StoreFnMut<F>
where
F: FnMut(&mut [u8]),
{
pub fn new(mutable_closure: F) -> StoreFnMut<F> {
StoreFnMut { mutable_closure }
}
fn run_closure_on_mutable_borrow(&mut self) {
let mut buf = vec![0; 100];
(self.mutable_closure)(&mut buf[..]);
}
}
fn foo(borrow: &mut &mut [u8], val: u32) {
borrow[0] = (val & 0xff) as u8;
}
fn main() {
let mut capturing_closure;
let mut store_fn_mut;
let mut inner_mut;
inner_mut = InnerMut::new(foo);
capturing_closure = move |mut borrow: &mut [u8]| {
inner_mut.mutate(&mut borrow);
};
store_fn_mut = StoreFnMut::new(capturing_closure);
store_fn_mut.run_closure_on_mutable_borrow();
}
I get this helpful looking yet confusing error message when compiling with Rust 1.24.1:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in generic type due to conflicting requirements
--> src/main.rs:48:31
|
48 | inner_mut = InnerMut::new(foo);
| ^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 49:25...
--> src/main.rs:49:25
|
49 | capturing_closure = move |mut borrow: &mut [u8]| {
| _________________________^
50 | | inner_mut.mutate(&mut borrow);
51 | | };
| |_____^
note: ...so that expression is assignable (expected &mut &mut [u8], found &mut &mut [u8])
--> src/main.rs:50:26
|
50 | inner_mut.mutate(&mut borrow);
| ^^^^^^^^^^^
note: but, the lifetime must be valid for the block suffix following statement 2 at 46:5...
--> src/main.rs:46:5
|
46 | / let mut inner_mut;
47 | |
48 | | inner_mut = InnerMut::new(foo);
49 | | capturing_closure = move |mut borrow: &mut [u8]| {
... |
53 | | store_fn_mut.run_closure_on_mutable_borrow();
54 | | }
| |_^
note: ...so that variable is valid at time of its declaration
--> src/main.rs:46:9
|
46 | let mut inner_mut;
| ^^^^^^^^^^^^^
I can't possibly think of use case for &mut &mut _.
If you change foo to
fn foo(borrow: &mut [u8], val: u32);
Then you get another error:
error[E0277]: the trait bound `[u8]: std::marker::Sized` is not satisfied
--> src/main.rs:46:25
|
46 | let mut inner_mut = InnerMut::new(foo);
| ^^^^^^^^^^^^^ `[u8]` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[u8]`
note: required by `<InnerMut<T>>::new`
Well, nothing requires T to be Sized in this code as it's only used in references, so let's add the constraint T: ?Sized:
pub struct InnerMut<T: ?Sized> {
state: u32,
stored_fn: fn(&mut T, u32),
}
impl<T: ?Sized> InnerMut<T> {
// …
}
And this works.
What you are experiencing is that the compiler cannot prove that you are not storing a reference to &mut borrow inside mutate() into your InnerMut instance. This would be problematic as for all it knows the parameter to your closure lives shorter than the closure itself. But InnerMut was moved to the closure and must live longer than borrow.
Basically Rust prevents closure arguments from escaping the closure because it does not know how to infer lifetimes then.
Consider this minimal example:
struct Test<T> {
field: fn(T),
}
impl<T> Test<T> {
fn foo(&self, _val: T) {}
}
fn calc(_: &mut i32) {}
fn main() {
let test: Test<&mut i32> = Test { field: calc };
let _ = move |y: i32| {
test.foo(&mut y);
};
}
It is written in a way so that the compiler understands it better so we can understand the error:
error[E0597]: `y` does not live long enough
--> src/main.rs:15:23
|
15 | test.foo(&mut y);
| ^ borrowed value does not live long enough
16 | };
| - `y` dropped here while still borrowed
17 | }
| - borrowed value needs to live until here
But I do not even have fields of that type in my struct
One key principle of Rust is that your function signature is the barrier for error reporting. The function itself is checked against the signature and the callers are checked against the signature. That prevents reporting confusing errors about function bodies to the caller of functions (who did not even write them).
For all that Rust knows, your T is inferred as &mut u[8] and your mutate() captures a mutable self. That is suspicious. Better prevent that potential escape of closure variables.
But slightly changing the code makes it work
Rejecting all programs that are incorrect and accepting all programs that are correct is not decidable. Therefore Rust errs on the side of caution and rejects correct programs. Therefore some slight changes can make it possible for Rust to accept the program even if the program was correct before.
What does this mean for my code?
I really do not know the compiler well enough to answer this question. My guess is that by changing T to [u8] and the absence of explicit lifetimes from the InnerMut type the compiler can prove that your closure variables are not escaping.