What I basically want to implement — a parent, that can spawn a child with reference to self. And if child gets mut — reference also gets mut.
If I create child object from scratch outside of parent — I can have parent in Rc<> and pass to child Rc copy. Which look good for me until I want to have elegant API (pseudo):
let parent = Parent::new();
parent.create_child(id="api test") \\ mut method
let child = parent.create_child(id="first child"); \\ mut method, but non-mut reference
let child2 = parent.create_child(id="second child"); \\ non mut
child2.change_id("second bud") \\ error — mut reference of parent
Since I make an high-level wrap of Cpp FFI to non-object API, I can avoid all the errors and warnings. But I would like to have something like this: when multiple child objects can be spawned by parent without borowing parent as &mut. Is it possible?
If you want Track.name to be semantically settable without taking a &mut to the parent node, you can also consider wrapping only the name field in a RefCell.
However, this gets complicated because you have long lived dynamic borrows being returned from get_name -- if any of those are standing when you call set_name, then borrow_mut will panic!
More complicated options include RefCell<Option<Rc<str>>> (solves Ref problems by returning Rc<str> from get_name) and other reference-counted string types, like the bytes crate bytes::Bytes.
Thank You so much for the both examples! I need a bit of time to experiment with them. But, actually, I have an opposite problem: I do not have a error in place where I would like to see it (Track::set_name(& mut self) should also make ref to track.project mutable).
Or I have (currently) an option to carry &mut Project inside track, which will not allow having multiple immutable tracks in one scope and even have problems with iterations through them.
OK, this code behaves exactly like I want from it. But it not produces errors by rustcheck, which was my original wish. And, what bothers me more — that it makes the mutable behavior implicit, but for the crate I would like to see it explicit...
Later I faced several problems with naive generic implementation. So, I've sketched the situation in one-module test, and found solution, that seems to me quite elegant: generic_mutability_test - Rust
env_logger::init();
let mut root = Root::new();
let window1 = root.make_child();
// Err: cannot borrow `root` as mutable more than once at a time
// let window2 = root.make_child(); // try to uncomment
let w1_id = window1.get_id(); // Drop window1 and finish &mut borrow of Root
debug!("{}", w1_id);
let id2 = root.make_child().get_id();
let _window1 = root.get_child(w1_id).unwrap();
let _window2 = root.get_child(id2).unwrap(); // OK!
// Err: no method named `make_button` found for struct `Window<'_,
// test::Immutable>` in the current scope. The method was found for
// `Window<'a, test::Mutable>`
// _window1.make_button()
let mut window1 = root.get_child_mut(w1_id).unwrap();
let button = window1.make_button();
let b_id = button.get_id();
let mut frame = window1.make_frame();
let fr_b_id = frame.make_button().get_id();
let f_id = frame.get_id();
// Err: cannot borrow `window1` as mutable more than once at a time
// debug!("button text: {}", button.get_text());
// Err: no method named `get_button` found for struct
// `Window<'_, test::Mutable>` in the current scope
// the method was found for - `Window<'a, test::Immutable>`
// let button = window1.get_button(b_id);
let window1 = root.get_child(w1_id).unwrap();
let frame = window1.get_frame(f_id).unwrap();
let w_b = window1.get_button(b_id).unwrap();
let fr_b = frame.get_button(fr_b_id).unwrap();
debug!("is window button clicked: {}", w_b.is_clicked());
debug!("is frame button clicked: {}", fr_b.is_clicked());