Call field's function and pass &self in Rust - rust

I have a MainStruct which owns an instance of HelperStruct. I want to make a method that calls helper's method. But the helper's method really needs (immutable) access to MainStruct
struct MainStruct {
helper: HelperStruct,
}
impl MainStruct {
pub fn call_helper(&mut self, args) {
// &mut self because the_method changes inner state of HelperStruct
self.helper.the_method(self, args)
}
}
impl HelperStruct {
pub fn the_method(&mut self, owner: &MainStruct, args) {
owner.other_method();
}
}
With this setup, I'm getting
error[E0502]: cannot borrow `self.helper` as mutable because it is also borrowed as immutable
214 | self.helper.the_method(self, args)
| ^^^^^^^^^^^^----------^----^^^^^^^^^^^^^^^^^^^^^^
| | | |
| | | immutable borrow occurs here
| | immutable borrow later used by call
| mutable borrow occurs here
It is crucial that the MainStruct remains the primary interface for interaction with the functionality (so having Helper own Main isn't an option).
How should I restructure my code (or maybe use smart pointers?) so that I can interact with the owner from the inside of Helper?
Also, it is guaranteed that the_method() will only be called inside an instance of MainStruct.
Actual context:
The MainStruct is the Field of my game. The HelperStruct is the class that takes care of pathing, A* mostly. A* has a number of large arrays that store its state. After an A* pass only some of them need to be reinitialized (or otherwise cleaned).
I end up calling A* a lot of times, so I want to avoid fully reinitializing it for every pass. So I store it in Field, and only call reset() after a pass.
To path plan properly, A* needs to look at the Field (obstacles, etc). While the A* is going, it of course changes some of its own fields, so the_method, being actually
pub fn full_pathing(&mut self, field: &Field, source: (i32, i32), destination: (i32, i32))
needs to have a &mut self

You can make the_method an associated function, and have it only receive a &mut MainStruct. It will have to access itself through that reference:
struct MainStruct {
helper: HelperStruct,
}
impl MainStruct {
pub fn call_helper(&mut self, args) {
HelperStruct::the_method(self, args)
}
}
impl HelperStruct {
pub fn the_method(main: &mut MainStruct, args) {
main.other_method();
//Access helper like this:
main.helper.whatever();
}
}
Alternatively, if your two structs are so intertwined, you could combine them into a single struct.

You need to convince Rust that, whatever HelperStruct is doing with MainStruct, it's not going to try to also access itself through MainStruct, since that constitutes an immutable reference to something that you also have a mutable reference to.
Depending on the complexity and needs of HelperStruct, one option would be to swap a dummy HelperStruct value into MainStruct and then call the function on the (now-isolated) HelperStruct.
use std::mem::swap;
struct MainStruct {
helper: HelperStruct,
}
impl MainStruct {
pub fn call_helper(&mut self, args) {
let mut helper_struct = HelperStruct::default(); // Some dummy value
swap(&mut helper_struct, &mut self.helper);
helper_struct.the_method(self, args);
swap(&mut helper_struct, &mut self.helper);
}
}
This way, HelperStruct.the_method has immutable access to all of MainStruct except itself, which has been temporarily shimmed out. After we're done, we swap the values back and there's no harm done.

Passing self to the_method borrows helper immutably, but the method call itself also borrows it mutably. If you change the signature to
pub fn the_method(&self, owner: &MainStruct, args)
it should work. If you need the_method to take a mutable reference to self you'll need to think of restructuring your code.

Related

Can this kind of pattern be implemented in Rust?

I am writing a tool that generates Rust code, and I've come up with the following pattern that is being generated:
pub fn my_template() {
let mut o = HtmlGenerator::new();
o.paragraph(&mut || {
o.emphasis(&mut || {
o.normal_text("hello");
});
});
}
The paragraph and emphasis methods have the type:
fn paragraph(&mut self, cnt: &mut impl FnMut());
I get the following error:
|
197 | o.paragraph(&mut || {
| ^ --------- -- first mutable borrow occurs here
| | |
| _________| first borrow later used by call
| |
198 | | o.normal_text("hello");
| | - first borrow occurs due to use of `o` in closure
199 | | });
| |__________^ second mutable borrow occurs here
Apparently I cannot borrow the mutable reference twice. It needs to be mutable because some of the generator functions might change the state of the HtmlGenerator, which is why I use methods in the first place.
Can this pattern be implemented in Rust? Am I trying to create nonsense?
The pattern cannot be implemented with exactly the provided signatures of paragraph() and other methods. But it's possible to get the same effect with just minor changes to either the closure signature or the method signatures.
The simplest and cleanest solution would be to pass the HtmlGenerator to the closures:
struct HtmlGenerator {
data: String,
}
impl HtmlGenerator {
fn new() -> HtmlGenerator {
HtmlGenerator {
data: "".to_string(),
}
}
fn paragraph(&mut self, inside: impl FnOnce(&mut HtmlGenerator)) {
self.data.push_str("<p>");
inside(self);
self.data.push_str("</p>");
}
fn normal_text(&mut self, text: &str) {
self.data.push_str(text);
}
fn into_data(self) -> String {
self.data
}
}
Playground
An alternative is to leave the closure signature as-is, but use interior mutability to make methods like paragraph() accept &self, at a very tiny run-time cost. For example:
struct HtmlGenerator {
data: RefCell<String>,
}
impl HtmlGenerator {
fn new() -> HtmlGenerator {
HtmlGenerator {
data: RefCell::new("".to_string()),
}
}
fn paragraph(&self, inside: impl FnOnce()) {
self.data.borrow_mut().push_str("<p>");
inside();
self.data.borrow_mut().push_str("</p>");
}
fn normal_text(&self, text: &str) {
self.data.borrow_mut().push_str(text);
}
fn into_data(self) -> String {
self.data.into_inner()
}
}
Playground
It may appear wrong to modify the data from an "immutable" method, but &self just means that the data is safe to share. self.data.borrow_mut() will panic if the borrow is already active, but that can't happen in the above code because the borrow is released as soon as the underlying data is modified. If we were to hold on to the guard returned by borrow_mut() and invoke the closure with the guard object live, the inner borrow_mut() in normal_text() invoked by the closure would panic.
In both approaches the trait bound for the closures can be the most permissive FnOnce, as the methods only invoke them once.
My question now is whether this pattern can even be ipmlemented in rust or whether I'm trying to create nonsense here?
It can't work like this, because the closure closes over the generator in order to implement the inner call, so the closure and the caller's borrow will necessarily overlap, which can not work.
What can work is for the generator methods to pass in the generator instance to the closures they call:
pub fn my_template() {
let mut o = HtmlGenerator::new();
o.paragraph(|o: &mut HtmlGenerator| {
o.emphasis(|o: &mut HtmlGenerator| {
o.normal_text("hello");
});
});
or something like that.
I also think you're probably better off passing the callable by value:
fn paragraph(&mut self, mut cnt: impl FnMut());

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);
}
}

call callback with reference to field

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);
}
}

Calling a Stack-Allocated Closure Stored in a Struct in Rust

I am storing a closure in a struct like this:
#[derive(Clone)]
struct S<'a> {
func: &'a FnOnce() -> u32
}
fn main() {
let s = S { func: &|| 0 };
let val = (s.func)();
println!("{}", val);
}
When I compile, s.func cannot be moved to execute itself. I understand why it cannot be moved (namely that it's only a reference and that its size is not known at compile time), but don't know why it's being moved at all -- is it just because closures are implemented via traits?
Here's the error message:
error[E0161]: cannot move a value of type std::ops::FnOnce() -> u32:
the size of std::ops::FnOnce() -> u32 cannot be statically determined
--> main.rs:8:15
|
8 | let val = (s.func)();
| ^^^^^^^^
error[E0507]: cannot move out of borrowed content
--> main.rs:8:15
|
8 | let val = (s.func)();
| ^^^^^^^^ cannot move out of borrowed content
error: aborting due to 2 previous errors
Is this only way the solve this to store the closure on the heap (via Box<FnOnce() -> u32>)? And why does calling a closure move it? Presumably calling it doesn't mutate the function itself.
The closure is being moved because FnOnce::call_once takes self by value. This contract enforces the guarantee that the function will not be called more than once.
If you will indeed be calling the closure at most once, and you want to use the FnOnce trait, then your struct needs to take ownership of that closure (and you will need to make your struct generic on the closure type). Note that calling the closure will move the closure out of your struct, thereby invalidating the whole struct; you may work around that by wrapping the FnOnce in an Option and take-ing the closure out of the Option before calling it.
If you might be calling the closure more than once, you don't want to take ownership of the closure, or you don't want to make your struct generic on the closure type, then you should use either Fn or FnMut instead. Fn::call takes self by reference and FnMut::call_mut takes self by mutable reference. Since both accept references, you can use trait objects with them.
As explained by Francis, declaring a closure FnOnce tells Rust that you accept the broadest class of closures, including those that exhaust the objects they capture. That such closures are invoked only once is ensured by the compiler by destroying the closure object itself (by moving it into its own call method) when invoked.
It is possible to use FnOnce and still not have S generic on the closure, but it requires some work to set things up so that the closure can't be possibly invoked more than once:
the closure must be stored in an Option, so its contents can be "stolen" and the Option replaced with None (this part ensures that the closure won't be called twice);
invent a trait that knows how to steal the closure from the option and invoke it (or do something else if the closure was already stolen);
store a reference to the trait object in S - this enables the same S type works on different closures without being generic on closure type.
The result looks like this:
trait Callable {
fn call_once_safe(&mut self, default: u32) -> u32;
}
impl<F: FnOnce() -> u32> Callable for Option<F> {
fn call_once_safe(&mut self, default: u32) -> u32 {
if let Some(func) = self.take() {
func()
} else {
default
}
}
}
struct S<'a> {
func: &'a mut Callable
}
impl<'a> S<'a> {
pub fn invoke(&mut self) -> u32 {
self.func.call_once_safe(1)
}
}
fn main() {
let mut s = S { func: &mut Some(|| 0) };
let val1 = s.invoke();
let val2 = s.invoke();
println!("{} {}", val1, val2);
}
The only place that knows details about the closure is the implementation of Callable for the particular Option<F>, generated for each closure and referenced by the vtable of the &mut Callable fat pointer created when initializing the func in S.

Aquire &'a T from Option<T<'a>>

I'm afraid this may be very basic but I haven't been able to figure it out on my own. I have this map:
subscriptions_map: HashMap<SubscriptionKey, Subscription<'a>>
and this vector:
subscriptions: Vec<&'a Subscription<'a>>,
I want to insert a value into the HashMap and a reference to the same item into the vector. I've tried to do it like this:
let subs: &'a Subscription = &self.subscriptions_map.insert(id, item).unwrap();
self.subscriptions.push(subs);
But it gets this error:
error: borrowed value does not live long enough
let subs: &'a Subscription = &self.subscriptions_map.insert(id, item).unwrap();
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: reference must be valid for the lifetime 'a as defined on the block at 40:70...
pub fn add_subscription(&'a mut self, mut item: Subscription<'a>) {
let id = item.get_id();
let _lock = self.lock.lock().unwrap();
let subs: &'a Subscription = &self.subscriptions_map.insert(id, item).unwrap();
...
note: ...but borrowed value is only valid for the block suffix following statement 2 at 45:87
let subs: &'a Subscription = &self.subscriptions_map.insert(id, item).unwrap();
self.subscriptions.push(subs);
}
error: aborting due to previous error
I guess my question boils down to: If I have an Option<T<'a>>, how can I get a &'a T?
HashMap.insert() returns the old value for the given key, not the value you just passed. That's not what you want!
After you've inserted an item into the HashMap, you must call HashMap.get() to retrieve a pointer to the value. As HashMap.insert() takes ownership of both the key and the value, we need to pass a clone of id to insert() so we can use the original id for the get() call. (If the type of id is Copy, you may omit the call to clone() and let the compiler copy the value.)
use std::collections::HashMap;
#[derive(Eq, PartialEq, Hash, Clone)]
struct SubscriptionKey;
struct Subscription<'a>(&'a ());
struct Foo<'a> {
subscriptions_map: HashMap<SubscriptionKey, Subscription<'a>>,
subscriptions: Vec<&'a Subscription<'a>>,
}
impl<'a> Foo<'a> {
fn add(&'a mut self, id: SubscriptionKey, item: Subscription<'a>) {
self.subscriptions_map.insert(id.clone(), item);
let subs = self.subscriptions_map.get(&id).unwrap();
self.subscriptions.push(subs);
}
}
fn main() {
let subscription_data = &();
let mut f = Foo {
subscriptions_map: HashMap::new(),
subscriptions: Vec::new(),
};
f.add(SubscriptionKey, Subscription(subscription_data));
}
This works fine, but it falls apart if we try to add another subscription. If we do this:
fn main() {
let subscription_data = &();
let subscription_data2 = &();
let mut f = Foo {
subscriptions_map: HashMap::new(),
subscriptions: Vec::new(),
};
f.add(SubscriptionKey, Subscription(subscription_data));
f.add(SubscriptionKey, Subscription(subscription_data2));
}
the compiler gives the following messages:
<anon>:30:5: 30:6 error: cannot borrow `f` as mutable more than once at a time [E0499]
<anon>:30 f.add(SubscriptionKey, Subscription(subscription_data2));
^
<anon>:30:5: 30:6 help: see the detailed explanation for E0499
<anon>:29:5: 29:6 note: previous borrow of `f` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `f` until the borrow ends
<anon>:29 f.add(SubscriptionKey, Subscription(subscription_data));
^
<anon>:31:2: 31:2 note: previous borrow ends here
<anon>:20 fn main() {
...
<anon>:31 }
^
What's going on? Why does the mutable borrow persist after the first call to Foo::add?
The problem comes from the definition of the subscriptions field. It's defined as a Vec<&'a Subscription<'a>>. Satisfying the 'a in Subscription<'a> is easy, since we receive the object with the correct lifetime in add. Satisfying the 'a in &'a ... is harder, since the Subscription<'a> value doesn't have a fixed address until we insert it into subscriptions_map (in my example, a Subscription<'a> is moved from a local variable in main() to a parameter in Foo::add() to inside self.subscriptions_map).
In order to satisfy the outer 'a, Foo::add() must define its self parameter as &'a mut self. If we defined it as &mut self, we couldn't be sure that the references we get out of subscriptions_map would live long enough (their lifetime could be shorter than 'a).
However, by inserting a &'a Subscription<'a> inside of a Foo<'a>, we are effectively locking down the Foo for further modifications, since we are now storing a borrow from self.subscriptions_map in self.subscriptions. Consider what would happen if we inserted another item in subscriptions_map: how can we be sure that the HashMap won't move its items around in memory? If the HashMap does move our item, the pointer in self.subscriptions wouldn't be updated automatically and would be dangling.
Now, suppose that we have this buggy remove() method:
impl<'a> Foo<'a> {
fn remove(&mut self, id: &SubscriptionKey) {
self.subscriptions_map.remove(id);
}
}
This method compiles fine. However, if we tried to call this on a Foo on which we called add() earlier, then self.subscriptions would contain a dangling reference to an item that used to be in self.subscriptions_map.
So the reason why the mutable borrow persists after calling add() is that, since the 'a in Foo<'a> is equal to the lifetime of the Foo<'a> itself, the compiler sees that the object borrows from itself. As you know, we can't have a mutable borrow and another borrow (mutable or not) active at the same time, so Rust prevents us from taking a mutable borrow on f while f itself retains an active borrow. In fact, since we used a method that takes self by mutable reference, Rust assumes that Foo<'a> stores a mutable reference, even though that's not the case, since Rust only looks at the signatures to determine borrows (this is to ensure that changing a private field from &'a T to &'a mut T doesn't cause borrow checking failures to you and, if you're developing a library, to your users). Since the type of an object never changes, the Foo<'a> is locked for the rest of its lifetime.
Now, what can you do? Clearly, you can't usefully have a Vec<&'a Subscription<'a>> in your struct. HashMap provides a values() iterator, but it enumerates the values in an unspecified order, so it won't help you if you want to enumerate the values in the order in which they were added. Instead of using borrowed pointers, you could use Rc:
use std::collections::HashMap;
use std::rc::Rc;
#[derive(Eq, PartialEq, Hash)]
struct SubscriptionKey;
struct Subscription<'a>(&'a ());
struct Foo<'a> {
subscriptions_map: HashMap<SubscriptionKey, Rc<Subscription<'a>>>,
subscriptions: Vec<Rc<Subscription<'a>>>,
}
impl<'a> Foo<'a> {
fn add(&mut self, id: SubscriptionKey, item: Subscription<'a>) {
let item = Rc::new(item);
self.subscriptions_map.insert(id, item.clone());
self.subscriptions.push(item);
}
}
fn main() {
let subscription_data = &();
let mut f = Foo {
subscriptions_map: HashMap::new(),
subscriptions: Vec::new(),
};
f.add(SubscriptionKey, Subscription(subscription_data));
}

Resources