When I wrote the following code, some confusing compile errors occurred. Can anyone tell me how to deal with it?
Code:
Stage::Graduated(vision) => {
if vision.show_panel {
let mut tree = vec![];
for _ in vision.images.iter() {
tree.push(iced_native::widget::tree::Tree::empty());
}
let mut current_tree;
let mut points = iced_native::overlay::Group::new();
for (index, _i) in vision.images.iter().enumerate() {
current_tree = &mut tree[index];
let pinpoint = crate::button_from_svg();
let floating_element = FloatingElementOverlay::new(
&mut current_tree,
pinpoint,
&Anchor::SouthEast,
&Offset { x: 0.0, y: 0.0 },
);
points = points.push(floating_element.overlay(Point { x: 0.0, y: 0.0 }));
}
return column![points].into();
} else {
return column![].into();
}
}
Errors:
PS D:\graduate> cargo run
Compiling graduate v0.1.0 (C:\Users\amazi\graduate)
error[E0506]: cannot assign to `current_tree` because it is borrowed
--> src\main.rs:1172:33
|
1172 | ... current_tree = &mut tree[index];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `current_tree` is assigned to here but it was already borrowed
...
1180 | ... &mut current_tree,
| ----------------- `current_tree` is borrowed here
...
1185 | ... points = points.push(overlay.overlay(Point { x: 0.0, y: 0.0 }));
| ------ borrow later used here
error[E0499]: cannot borrow `tree` as mutable more than once at a time
--> src\main.rs:1172:53
|
1172 | current_tree = &mut tree[index];
| ^^^^ `tree` was mutably borrowed here in the previous iteration of the loop
...
1206 | } else {
| - first borrow might be used here, when `points` is dropped and runs the destructor for type `Group<'_, Message, iced_graphics::renderer::Renderer<iced_wgpu::backend::Backend, Theme>>`
Some errors have detailed explanations: E0499, E0506.
For more information about an error, try `rustc --explain E0499`.
error: could not compile `graduate` due to 2 previous errors
I believe that the issue is current_tree = &mut tree[index] borrowing all of tree every loop iteration. This wouldn't normally be a problem, but in this case you're storing the result in points which lives beyond the end of the loop. So current_tree from the second loop iteration exists at the same time as current_tree from the first, which is disallowed.
To make this work, you need to split a single borrow of tree into separate borrows of the individual elements, which you can do with tree.iter_mut():
(untested)
for (current_tree, _i) in std::iter::zip(tree.iter_mut(), vision.images.iter()) {
// ...
}
That isn't enough, because returning points would be a UAF when tree is dropped.
I don't actually know how the FloatingElementOverlay struct is intended to be used. But the docs indicate that this is an internal implementation detail. The example uses FloatingElement.
When I then tried to use your code in a similar way, another error appeared. I wonder why it violated Rust's borrow rule while the previous snippet didn't.
I would really appreciate it if you can help me understand them as well.
Code:
fn overlay<'b>(
&'b mut self,
state: &'b mut Tree,
layout: Layout<'_>,
renderer: &Renderer,
) -> Option<overlay::Element<'b, Message, Renderer>> {
let bounds = layout.bounds();
let position = Point::new(0.0, 0.0);
let res = (self.element)();
let mut group = iced_native::overlay::Group::new();
let mut empty_state = vec![];
for _ in res.iter() {
empty_state.push(iced_native::widget::tree::Tree::empty());
}
for (i, cur) in std::iter::zip(res.into_iter(), empty_state.iter_mut()) {
group = group.push(
FloatingElementOverlay::new(cur, i, &self.anchor, &self.offset)
.overlay(position),
);
}
Some(group.into())
}
The Error:
error[E0515]: cannot return value referencing local variable `empty_state`
--> src\floatingelement.rs:222:13
|
216 | for (i, cur) in std::iter::zip(res.into_iter(), empty_state.iter_mut()) {
| ---------------------- `empty_state` is borrowed here
...
222 | Some(group.into())
| ^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function