Hello everyone,
I've looked through discussions on forum regarding challenges on mutable borrowing more than once, but none of them seems to have the same type of issue (or maybe i just missed it) as i am facing now.
The code is as follows:
use concread::bptree::{BptreeMap, BptreeMapWriteTxn};
fn main(){
let tree = BptreeMap::<i64, i64>::new();
let mut txn = tree.write();
let _ = wrapper(
&mut txn,
&BptreeMapWriteTxn::<i64, i64>::first_key_value,
);
drop(txn);
}
fn wrapper<'a, 'b, KeyFn>(
txn: &'a mut BptreeMapWriteTxn<'b, i64, i64>,
kvn_fn: &KeyFn,
)
where
KeyFn: Fn(&'a BptreeMapWriteTxn<'b, i64, i64>) -> Option<(&'a i64, &'a i64)>,
{
just_a_call(txn);
just_a_call(txn);
// This introduces the problems with more than once borrowing on the next
// call to just_a_call(..).
call_with_cb(txn, kvn_fn);
just_a_call(txn);
}
fn just_a_call<'a, 'b>(
_txn: &'a mut BptreeMapWriteTxn<'b, i64, i64>,
){}
fn call_with_cb<'a, 'b, KeyFn>(
txn: &'a mut BptreeMapWriteTxn<'b, i64, i64>,
kvn_fn: &KeyFn,
)
where
KeyFn: Fn(&'a BptreeMapWriteTxn<'b, i64, i64>) -> Option<(&'a i64, &'a i64)>,
{
kvn_fn(txn);
}
The error i get:
error[E0499]: cannot borrow `*txn` as mutable more than once at a time
--> src/main.rs:31:17
|
19 | fn wrapper<'a, 'b, KeyFn>(
| -- lifetime `'a` defined here
...
29 | call_with_cb(txn, kvn_fn);
| -------------------------
| | |
| | first mutable borrow occurs here
| argument requires that `*txn` is borrowed for `'a`
30 |
31 | just_a_call(txn);
| ^^^ second mutable borrow occurs here
Maybe i am defining lifetimes for callback function incorrectly, but no matter of what i have tried, i can not get this to work. Have spent few hours already and it seems to be going nowhere.
The goal for the code is to allow to define key/value search function as generic, so i could use first_key_value or last_key_value, or similar. The KeyFn
is used only inside the scope of called function body, called function does not return references, so i kind of don't understand the compilers complaints that multiple borrows have occurred; to me the call to call_with_cb
seems the same as call to just_a_call
function.
Have i defined callback the wrong way? Or the problem is caused due to wrong lifetime definitions?
My motivation to use generics in this situation is to reuse some code and maybe even allow more optimizations for compiler to do, because instead of having if
statement within call_with_cb body to decide which function/method to call, a generics could compile code for each code path from the call site where the callback is already known.
Unfortunately i could not reproduce same/similar error scenario with std BTreeMap, since it has a bit different API, no transactions.