I am simulating a n body problem. I am writing equations as general so that they could be called on any struct types which implements certain traits.
But there is a problem with mutable references to the struct fields. I am stuck with this problem for a about 15 days now. I tried different designs but couldn't figure it out. I am close, I need your help to complete it.
I want to get a mutable and a immutable reference of different struct fields in a equation. Code is at
FYI I can't clone the vector, it is huge size. I have many other functions which takes references of the struct,
so I can't write functions which will give mutable reference to specific types. Please give your answers keeping this as note.
This type of design is not going to work well in Rust, as you've noticed. Fundamentally, there's no way to indicate on a method signature that only a subset of the struct is borrowed. Instead of exposing a bunch of getters, you may want to consider making Base a bit richer - give it methods that actually perform the semantic work, and the underlying impl can then borrow its own individual fields as it sees fit. Or change the location where the fields are stored - instead of being all on 1 trait/type, use several different types that make borrowing scenarios a bit easier.
But, if you really want a "view" of the struct's fields like this, you can essentially ask for the underlying type to deconstruct itself and present you with all the mutable borrows via another type: play example
Unlikely, but depends on what and how you're doing things. The BasePartsMut struct is 96 bytes in size on 64bit - if you copy it around too much and the compiler isn't able to optimize around it, you may pay some cost. But it's hard to speculate. My hunch is it shouldn't be an issue.
Edit: I should mention that you can slim BasePartsMut down to 48 bytes by returning &mut Vec<f32>s instead of slices. But I used slices because that gives your implementations more freedom for how they store the floats - anything that can be deref'd to a slice will work, not just Vec. But thought I'd clarify this.
For the example you pasted, turning body_force and spring_force into methods encapsulates all the details, and allows the underlying type to borrow its own fields freely: play
The gist is instead of asking a trait for its state piece-by-piece (i.e. getX, getY, getZ, ...), you just tell it to do something at a higher level (compute body force, compute/apply spring force, etc).
Alternative you can store positions, velocities and accelerations i separate structs. This allows you to update one property while keeping the others constant.
// Perhaps use a vector class from a library here
struct Vector {
pub x: f32,
pub y: f32,
}
fn main() {
let mut masses = vec![ 1.0, 2.0];
let mut positions = vec![ Vector {x:1.0, y: 2.0 }, Vector {x:3.0, y: 4.0 }];
let mut velocities = vec![ Vector {x:1.0, y: 2.0 }, Vector {x:3.0, y: 4.0 }];
let mut accellerations = vec![ Vector {x:1.0, y: 2.0 }, Vector {x:3.0, y: 4.0 }];
update_accellerations(&masses, &positions, &mut accellerations);
update_velocities(&accellerations, &mut velocities);
update_positions(&velocities, &mut positions);
}
You’ll need split_at_mut here or use raw pointers + unsafe code.
The split is needed to convince the compiler that src and dst are different references - it doesn’t know that src_id and dst_id are different. So if you split and index into the two halves, that it understands.
But, if you don’t want to do split gymnastics then you can use unsafe code and put some assertions that src_id != dst_id and it’ll be safe in the end.
This really begs for generic associated types (GAT) but try this in the meantime.
This will likely lead to borrow/lifetime issues, however, due to using &'a mut self in the trait methods. But, you might get lucky and sidestep it.
As mentioned upthread, you should also consider providing higher level methods, rather than exposing the "parts" to the caller. In general, the more confined you can keep the borrows, the better off you'll be.
I added the combine() as a demo of how you'd make use of the returned parts generically. As it stands, there's no unified trait that allows you to generically retrieve the bits from a given Parts associated type - each implementation of GetMut can return a different type, as you have with FooMut and BarMut.
You can try to unify them by putting the accessors on the Parts trait, like so. But this goes back to exposing internals, and sooner or later, you'll run into borrowck problems I suspect.
Hi @vitalyd. I am extending program, need some help.
In this play I am implementing an equation (Which manipulates the destination struct attributes which is acted up on by source struct).
For a general case there is a situation where destination it self could become source and should be considered as a source for the equation. In that case I have to mutably borrow such a struct twice. I don't know how to do that ( I think I should use RC, but not sure ).
Another way of implementing such an equation is two write two functions where, If same struct is repeated twice, we adapt the function for a self influence case, and write another function where other structs influence the destination. (This is just repeating your self ). I implemented it here Play.
Is there a way, where I can combine both the cases and use a single equation?
You can't mutably borrow a struct if it's also borrowed immutably or mutably - there's no way to do that. A RefCell (likely what you're thinking of, rather than Rc) allows dynamic borrowing, but it'll still be enforcing the same rule: immutable XOR mutable borrows. If you were to try doing this with RefCell, the code would compile but you'd get a runtime panic.
This is probably the approach I'd look into myself. It also seems to yield more straightforward and self-evident code. Are there a bunch of such functions that you'd need to write? If so, maybe a macro can assist in generating them, or perhaps some helper functions can be created that encapsulate some parts of the two function variants.
@vitalyd the function I implement inside it is huge, for example
Code has self implemetation and Code has other source implementation. And there is more physic equations, similar to this.
How can we make it general, thank you.