call callback with reference to field - rust

Consider such code:
trait OnUpdate {
fn on_update(&mut self, x: &i32);
}
struct Foo {
field: i32,
cbs: Vec<Box<OnUpdate>>,
}
impl Foo {
fn subscribe(&mut self, cb: Box<OnUpdate>) {
self.cbs.push(cb);
}
fn set_x(&mut self, v: i32) {
self.field = v;
//variant 1
//self.call_callbacks(|v| v.on_update(&self.field));
//variant 2
let f_ref = &self.field;
for item in &mut self.cbs {
item.on_update(f_ref);
}
}
fn call_callbacks<CB: FnMut(&mut Box<OnUpdate>)>(&mut self, mut cb: CB) {
for item in &mut self.cbs {
cb(item);
}
}
}
If I comment variant 2 and uncomment variant 1,
it doesn't compiles, because of I need &Foo and &mut Foo at the same time.
But I really need function in this place, because of I need the same
code to call callbacks in several places.
So do I need macros here to call callbacks, or may be another solution?
Side notes: in real code I use big structure instead of i32,
so I can not copy it. Also I have several methods in OnUpdate,
so I need FnMut in call_callbacks.

An important rule of Rust's borrow checker is, mutable access is exclusive access.
In variant 2, this rule is upheld because the reference to self.field and to mut self.cbs never really overlap. The for loop implicitly invokes into_iter on &mut Vec, which returns a std::slice::IterMut object that references the vector, but not the rest of Foo. In other words, the for loop does not really contain a mutable borrow of self.
In variant 1, there is a call_callbacks which does retain a mutable borrow of self, which means it cannot receive (directly on indirectly) another borrow of self. In other words, at the same time:
It accepts a mutable reference to self, which allows it to modify all its fields, including self.field.
It accepts a closure that also refers to self, because it uses the expression self.field.
Letting this compile would allow call_callbacks to mutate self.field without the closure being aware of it. In case of an integer it might not sound like a big deal, but for other data this would lead to bugs that Rust's borrow checker is explicitly designed to prevent. For example, Rust relies on these properties to prevent unsafe iteration over mutating containers or data races in multi-threaded programs.
In your case it is straightforward to avoid the above situation. set_x is in control both of the contents of the closure and of the mutation to self.field. It could be restated to pass a temporary variable to the closure, and then update self.field, like this:
impl Foo {
fn subscribe(&mut self, cb: Box<OnUpdate>) {
self.cbs.push(cb);
}
fn set_x(&mut self, v: i32) {
self.call_callbacks(|cb| cb.on_update(&v));
self.field = v;
}
fn call_callbacks<OP>(&mut self, mut operation: OP)
where OP: FnMut(&mut OnUpdate)
{
for cb in self.cbs.iter_mut() {
operation(&mut **cb);
}
}
}
Rust has no problem with this code, and effect is the same.
As an exercise, it is possible to write a version of call_callbacks that works like variant 2. In that case, it needs to accept an iterator into the cbs Vec, much like the for loop does, and it must not accept &self at all:
fn set_x(&mut self, v: i32) {
self.field = v;
let fref = &self.field;
Foo::call_callbacks(&mut self.cbs.iter_mut(),
|cb| cb.on_update(fref));
}
fn call_callbacks<OP>(it: &mut Iterator<Item=&mut Box<OnUpdate>>,
mut operation: OP)
where OP: FnMut(&mut OnUpdate)
{
for cb in it {
operation(&mut **cb);
}
}

Related

Lifetime parameters in a trait

I'm having difficulties understanding lifetime parameters in the following code snippet.
struct C {
data: Vec<u32>,
cols: usize
}
trait M<'s> {
fn get(&'s self, r: usize, c: usize) -> u32;
fn get_mut(&'s mut self, r: usize, c: usize) -> &'s mut u32;
}
impl<'s> M<'s> for C {
fn get(&'s self, r: usize, c: usize) -> u32 {
return self.data[self.cols*r+c];
}
fn get_mut(&'s mut self, r: usize, c: usize) -> &'s mut u32 {
return &mut self.data[self.cols*r+c];
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create() -> C {
let data = vec![0u32,1u32,2u32,3u32,4u32,5u32];
return C{data, cols: 3};
}
fn select<'s, 'r: 's>(data: &'r mut dyn M<'s>) {
let mut _val: u32 = 0;
for r in 0..2 {
for c in 0..3 {
_val += *data.get_mut(r,c);
}
}
}
#[test]
fn test_select() {
let mut data = create();
select(&mut data);
}
}
The code snippet does not compile, because it complains that *data is borrowed multiple times in the function fn select<'s, 'r: 's>(data: &'r mut dyn M<'s>) {} when calling get_mut (once in every loop iteration). Even safeguarding the questionable line with curly braces (and thus creating a new context) does not help. My expectation (in both cases) would be, that the mutable borrow of &mut data should end right after the execution of that line.
On the other hand, when I remove all lifetime parameters, everything works as expected.
Can anyone explain what's the difference between the two versions (with and without explicit lifetimes)?
I've also tried to find information about additional lifetime parameters for traits, in particular specifying their meaning, but I have found none. So I assume, that they are just a declaration of the used labels inside the trait. But if that is so, then I would assume that leaving out the lifetime parameters completely and applying the eliding rules would lead to the same result.
There are two things to consider. The first is when you use a generic lifetime for a function, that lifetime must be larger than the life of the function call simply by construction. And the second is since the lifetime self is tied to the lifetime parameter of the trait, when you call .get_mut(), data is borrowed for the lifetime of 's. Combining those two principles, data is borrowed for longer than the function call so you can't call it again (its already mutably borrowed).
On the other hand, when I remove all lifetime parameters, everything works as expected. Can anyone explain what's the difference between the two versions (with and without explicit lifetimes)?
Without a generic lifetime on M, the methods will behave as if defined as so:
impl M for C {
fn get<'a>(&'a self, r: usize, c: usize) -> u32 {
return self.data[self.cols * r + c];
}
fn get_mut<'a>(&'a mut self, r: usize, c: usize) -> &'a mut u32 {
return &mut self.data[self.cols * r + c];
}
}
Thus there is no lifetime associated with the trait; the lifetimes given and returned from the function are generic only to those method calls. And since the compiler can choose a new lifetime 'a for each call and it will always pick the shorted lifetime to satisfy its usage, you can then call data.get_mut() multiple times without worry. And I'll be honest, having the lifetime on the trait didn't make much sense with the original code; as mentioned, the code works with all lifetime annotations removed: playground.

update struct using a value from the struct itself gives: "cannot borrow `*self` as mutable because it is also borrowed as immutable"

I am trying to create a struct that modifies its current_value by appending some "constant" string first_step which is defined when the struct is first created.
code
fn main() {
let mut adder = Adder {
current_value: "init".to_string(),
first_step: ", first".to_string(),
};
adder.do_something()
}
struct Adder {
current_value: String,
first_step: String,
}
impl Adder {
fn add(&mut self, value: &String) {
self.current_value = format!("{}{}", self.current_value, value);
}
fn do_something(&mut self) {
// cannot borrow `*self` as mutable because it is also borrowed as immutable
// mutable borrow occurs here rustc(E0502)
// main.rs(24, 18): immutable borrow occurs here
// main.rs(24, 14): immutable borrow later used by call
self.add(&self.first_step);
}
}
playground
I think the errors are quite clear (the self in self.add is borrowed as mutable because the signature of add has &mut self, but then the value to be appended also comes from self, but this time borrowed as immutable, and we cannot borrow self both mutable and immutable).
But I don't know how to fix this, creating a data structure that can update itself with some "constant" values that are defined when the structure itself is created. In the actual "real life" case I have a struct that contains both a file and file_header: String, and I want to have a method that writes the file_header into the file.
Rust does allow for borrowing parts of a struct separately, but when you call a function/method that takes &mut Self, that always borrows the entire struct — the body of the function is never used as additional information. So, a solution to problems like where you want to mutate part of your structure using information from another part is to rewrite your function signature so that it does have the necessary information.
impl Adder {
/// Algorithm implementation; takes all components explicitly.
/// Is not a method.
fn add_impl(current_value: &mut String, add_value: &str) {
current_value.push_str(add_value);
}
/// Method for external use — less flexible, but simple.
pub fn add(&mut self, value: &str) {
Self::add_impl(&mut self.current_value, value);
}
fn do_something(&mut self) {
Self::add_impl(&mut self.current_value, &self.first_step);
}
}
Your description “…a data structure that can update itself with some "constant" values that are defined when the structure itself is created…” suggests that you might have a more complicated situation than this simple example. If you have more than one mutable field that needs updating (or even if you really want to use method syntax), you can make another struct that contains the right subset of fields — then the methods like do_something can call ordinary &mut self methods on the inner struct.
struct FancyAdder {
first_step: String,
data: AdderData,
}
struct AdderData {
current_value: String,
...
}
impl FancyAdder {
fn do_something(&mut self) {
// This borrows `self.data` mutably and `self.first_step` immutably.
// No overlap.
self.data.add(&self.first_step);
}
}
impl AdderData {
fn add(&mut self, value: &str) {
self.current_value.push_str(value);
}
}

Convert Arc<RwLock> to &mut

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 :)

Can you control borrowing a struct vs borrowing a field?

I'm working on a program involving a struct along these lines:
struct App {
data: Vec<u8>,
overlay: Vec<(usize, Vec<u8>)>,
sink: Sink,
}
In brief the data field holds some bytes and overlay is a series of byte sequences to be inserted at specific indices. The Sink type is unimportant except that it has a function like:
impl Sink {
fn process<'a>(&mut self, input: Vec<&'a [u8]>) {
// ...
}
}
I've implemented an iterator to merge the information from data and overlay for consumption by Sink.
struct MergeIter<'a, 'b> {
data: &'a Vec<u8>,
overlay: &'b Vec<(usize, Vec<u8>)>,
// iterator state etc.
}
impl<'a, 'b> Iterator for MergeIter<'a, 'b> {
type Item = &'a [u8];
// ...
}
This is I think a slight lie, because the lifetime of each &[u8] returned by the iterator isn't always that of the original data. The data inserted from overlay has a different lifetime, but I don't see how I can annotate this more accurately. Anyway, the borrow checker doesn't seem to mind - the following approach works:
fn merge<'a, 'b>(data: &'a Vec<u8>, overlay: &'b Vec<(usize, Vec<u8>)>, start: usize) -> Vec<&'a [u8]> {
MergeIter::new(data, overlay, start).collect()
}
impl App {
fn process(&mut self) {
let merged = merge(&self.data, &self.overlay, 0);
// inspect contents of 'merged'
self.sink.process(merged);
}
}
I end up using this merge function all over the place, but always against the same data/overlay. So I figure I'll add an App::merge function for convenience, and here's where the problem begins:
impl App {
fn merge<'a>(&'a self, start: usize) -> Vec<&'a [u8]> {
MergeIter::new(&self.data, &self.overlay, start).collect()
}
fn process(&mut self) {
let merged = self.merge(0);
// inspect contents of 'merged'
self.sink.process(merged);
}
}
App::process now fails to pass the borrow checker - it refuses to allow the mutable borrow of self.sink while self is borrowed.
I've wrestled with this for some time, and if I've understood correctly the problem isn't with process but with this signature:
fn merge<'a>(&'a self, start: usize) -> Vec<&'a [u8]> {
Here I've essentially told the borrow checker that the references returned in the vector are equivalent to the self borrow.
Even though I feel like I've now understood the problem, I still feel like my hands are tied. Leaving the lifetime annotations out doesn't help (because the compiler does the equivalent?), and with only the two references involved there's no way I can see to tell rust that the output reference has a lifetime bound to something else.
I also tried this:
fn merge<'a, 'b>(&'b self, start: usize) -> Vec<&'a [u8]> {
let data: &'a Vec<u8> = &self.data;
MergeIter::new(&self.data, &self.overlay, start).collect()
}
but the compiler complains about the let statement ("unable to infer appropriate lifetime due to conflicting requirements" -- I also find it infuriating that the compiler doesn't explain said requirements).
Is it possible to achieve this? The Rust Reference is kind of light on lifetime annotations and associated syntax.
rustc 1.0.0-nightly (706be5ba1 2015-02-05 23:14:28 +0000)
As long as the method merge takes &self, you cannot accomplish what you desire: it borrows all of each of its arguments and this cannot be altered.
The solution is to change it so that it doesn’t take self, but instead takes the individual fields you wish to be borrowed:
impl App {
...
fn merge(data: &Vec<u8>, overlay: &Vec<(usize, Vec<u8>)>, start: usize) -> Vec<&[u8]> {
MergeIter::new(data, overlay, start).collect()
}
fn process(&mut self) {
let merged = Self::merge(&self.data, &self.overlay, 0);
... // inspect contents of 'merged'
self.sink.process(merged);
}
}
Yes, you've guessed correctly - the error happens because when you have merge method accept &self, the compiler can't know at its call site that it uses only some fields - merge signature only tells it that the data it returns is somehow derived from self, but it doesn't tell how - and so the compiler assumes the "worst" case and prevents you from accessing other fields self has.
I'm afraid there is no way to fix this at the moment, and I'm not sure there ever will be any. However, you can use macros to shorten merge invocations:
macro_rules! merge {
($this:ident, $start:expr) => {
MergeIter::new(&$this.data, &$this.overlay, $start).collect()
}
}
fn process(&mut self) {
let merged = merge!(self, 0);
// inspect contents of 'merged'
self.sink.process(merged);
}

Unable to hold/pass reference of parent to the composition object

In C++ it would something like struct A is composed of struct B and some function of B takes a pointer to the parent object A. So function of A calling that function of B will simply pass the this pointer to it. I'm trying this in Rust but failing to get it to work - this is what I want to achieve:
struct A<Type: T> {
composition: Type,
value: usize,
}
impl<Type> A<Type> where Type: T {
fn new(obj: Type) -> A<Type> {
A {
composition: obj,
value: 999,
}
}
fn f(&mut self) {
println!("Value: {:?}", self.value);
}
fn call(&mut self) {
self.composition.f(&mut self);
}
}
trait T {
fn f(&mut self, &mut A<Self>);
}
struct B {
value: usize,
}
impl B {
fn new() -> B {
B { value: 0, }
}
}
impl T for B {
fn f(&mut self, parent: &mut A<B>) {
println!("B::f");
parent.f();
}
}
fn main() {
let objA = A::new(B::new());
// I want call sequence -> A::call() -> B::f() -> A::f()
objA.call();
}
Note that i require mutability in all the functions although in example above it might seem that &mut self in most function parameters don't make much sense. How do it do this in Rust?
This cannot work because you're violating mutable aliasing requirements - you're trying to mutably borrow A and its substructure at the same time:
self.composition.f(self);
// roughtly equivalent to:
let c = &mut self.composition; // borrow substructure
c.f(self /* borrow self */);
(I've removed explicit &mut self because it is incorrect (as it gives you &mut &mut A<...>, but it does not change the whole picture at all.)
This is a natural error in Rust framework. Suppose that f implementation on this particular composition X rewrites composition field on the passed object:
impl T for X {
fn f(&mut self, a: &mut A<X>) {
a.composition = create_x_somehow();
}
}
And suddenly the object this method is called on is destroyed, and self is invalidated!
Naturally, the compiler prevents you from doing this even if you know that you don't modify composition, because such kind of knowledge cannot be encoded statically (especially given that this is a trait method which can be implemented by anyone having access to your trait).
You have essentially two choices in such situations:
reformulate the problem so it does not require such architecture anymore, or
use special language/library constructs to work around such static checks.
The second point is about using such things as Cell/RefCell (they are safe, i.e. don't require unsafe blocks, but they can panic at runtime - probably these can work in your case) or, if nothing else helps, dropping to raw pointers and unsafe code. But, frankly, the first option usually is better: if you design your code based on ownership semantics and aliasing rules enforced by the compiler, almost always the resulting architecture would be of much better quality.

Resources