Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Post History
Here's the solution I ended up with a while back to traverse the (sub-)tree, starting at the given root component. In short, the model's field, components, is used directly and small unsafe blocks ...
Answer
#3: Post edited
Here's the solution I ended up with a while back to traverse the (sub-)tree, starting at the given root component. In short, the models's field, `components`, is used directly and small `unsafe` blocks are used to push the root's children into the vector-backed queue that's currently being traversed.- While a full working example can be found at [this playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e0e914ae50d38b8b6a481e0bfd5070cc), the minimal/core part of it is below:
- ```rust
- impl Component for Model {
- fn children(&self) -> Vec<&dyn Component> {
- let mut v: Vec<&dyn Component> = self.components
- .iter()
- .map(|c| c.deref())
- .collect();
- let q = &mut v as *mut Vec<&dyn Component>;
- v.iter().for_each(|c| unsafe {
- (*q).append(&mut c.children())
- });
- v
- }
- fn children_mut(&mut self) -> Vec<&mut dyn Component> {
- let mut v: Vec<&mut dyn Component> = self.components
- .iter_mut()
- .map(|c| c.deref_mut())
- .collect();
- let q = &mut v as *mut Vec<&mut dyn Component>;
- unsafe {
- (*q).iter_mut().for_each(|c| {
- (*q).append(&mut c.children_mut())
- })
- }
- v
- }
- }
- ```
- The caveat/con here is that, under the *experimental* "Stacked Borrows" memory model in the *nightly* toolchain, Miri says the above causes UB inside the `Vec` implementation:
- ```text
- error: Undefined Behavior: deallocating while item [SharedReadOnly for <9045>] is strongly protected
- --> /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:776:13
- |
- 776 | alloc.grow(ptr, old_layout, new_layout)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item [SharedReadOnly for <9045>] is strongly protected
- |
- = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
- = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
- = note: BACKTRACE:
- = note: inside `alloc::raw_vec::finish_grow::<std::alloc::Global>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:776:13: 776:52
- = note: inside `alloc::raw_vec::RawVecInner::grow_amortized` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:661:19: 661:93
- = note: inside `alloc::raw_vec::RawVecInner::<A>::reserve::do_reserve_and_handle::<std::alloc::Global>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:554:31: 554:79
- note: inside closure
- ```
- In short, Miri says the `Vec` implementation runs into UB while allocating memory for the vector, likely b/c the `Vec` is being modified while being traversed.
- I've not (yet?) been successful in refactoring the above to remove the `unsafe` blocks. Perhaps some method type signature changes I'm not (currently) aware of would be required.
- If you have specific suggestions, please post them in a comment.
- Here's the solution I ended up with a while back to traverse the (sub-)tree, starting at the given root component. In short, the model's field, `components`, is used directly and small `unsafe` blocks are used to push the root's children into the vector-backed queue that's currently being traversed.
- While a full working example can be found at [this playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e0e914ae50d38b8b6a481e0bfd5070cc), the minimal/core part of it is below:
- ```rust
- impl Component for Model {
- fn children(&self) -> Vec<&dyn Component> {
- let mut v: Vec<&dyn Component> = self.components
- .iter()
- .map(|c| c.deref())
- .collect();
- let q = &mut v as *mut Vec<&dyn Component>;
- v.iter().for_each(|c| unsafe {
- (*q).append(&mut c.children())
- });
- v
- }
- fn children_mut(&mut self) -> Vec<&mut dyn Component> {
- let mut v: Vec<&mut dyn Component> = self.components
- .iter_mut()
- .map(|c| c.deref_mut())
- .collect();
- let q = &mut v as *mut Vec<&mut dyn Component>;
- unsafe {
- (*q).iter_mut().for_each(|c| {
- (*q).append(&mut c.children_mut())
- })
- }
- v
- }
- }
- ```
- The caveat/con here is that, under the *experimental* "Stacked Borrows" memory model in the *nightly* toolchain, Miri says the above causes UB inside the `Vec` implementation:
- ```text
- error: Undefined Behavior: deallocating while item [SharedReadOnly for <9045>] is strongly protected
- --> /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:776:13
- |
- 776 | alloc.grow(ptr, old_layout, new_layout)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item [SharedReadOnly for <9045>] is strongly protected
- |
- = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
- = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
- = note: BACKTRACE:
- = note: inside `alloc::raw_vec::finish_grow::<std::alloc::Global>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:776:13: 776:52
- = note: inside `alloc::raw_vec::RawVecInner::grow_amortized` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:661:19: 661:93
- = note: inside `alloc::raw_vec::RawVecInner::<A>::reserve::do_reserve_and_handle::<std::alloc::Global>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:554:31: 554:79
- note: inside closure
- ```
- In short, Miri says the `Vec` implementation runs into UB while allocating memory for the vector, likely b/c the `Vec` is being modified while being traversed.
- I've not (yet?) been successful in refactoring the above to remove the `unsafe` blocks. Perhaps some method type signature changes I'm not (currently) aware of would be required.
- If you have specific suggestions, please post them in a comment.
#2: Post edited
- Here's the solution I ended up with a while back to traverse the (sub-)tree, starting at the given root component. In short, the models's field, `components`, is used directly and small `unsafe` blocks are used to push the root's children into the vector-backed queue that's currently being traversed.
- While a full working example can be found at [this playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e0e914ae50d38b8b6a481e0bfd5070cc), the minimal/core part of it is below:
- ```rust
- impl Component for Model {
- fn children(&self) -> Vec<&dyn Component> {
- let mut v: Vec<&dyn Component> = self.components
- .iter()
- .map(|c| c.deref())
- .collect();
- let q = &mut v as *mut Vec<&dyn Component>;
- v.iter().for_each(|c| unsafe {
- (*q).append(&mut c.children())
- });
- v
- }
- fn children_mut(&mut self) -> Vec<&mut dyn Component> {
- let mut v: Vec<&mut dyn Component> = self.components
- .iter_mut()
- .map(|c| c.deref_mut())
- .collect();
- let q = &mut v as *mut Vec<&mut dyn Component>;
- unsafe {
- (*q).iter_mut().for_each(|c| {
- (*q).append(&mut c.children_mut())
- })
- }
- v
- }
- }
- ```
The caveat/con here is that, under the *experimental* "Stacked Borrows" memory model in the *nightly* toolchain, Miri says the above causes UB:- ```text
- error: Undefined Behavior: deallocating while item [SharedReadOnly for <9045>] is strongly protected
- --> /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:776:13
- |
- 776 | alloc.grow(ptr, old_layout, new_layout)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item [SharedReadOnly for <9045>] is strongly protected
- |
- = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
- = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
- = note: BACKTRACE:
- = note: inside `alloc::raw_vec::finish_grow::<std::alloc::Global>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:776:13: 776:52
- = note: inside `alloc::raw_vec::RawVecInner::grow_amortized` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:661:19: 661:93
- = note: inside `alloc::raw_vec::RawVecInner::<A>::reserve::do_reserve_and_handle::<std::alloc::Global>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:554:31: 554:79
- note: inside closure
- ```
In short, Miri says the `Vec` implementation runs into UB while allocating memory for the vector, b/c it's being modified while being traversed. I've not (yet?) been successful in refactoring the above to remove the `unsafe` blocks. Perhaps some method type signature changes I'm not (currently) aware of would be required.If you have specific suggestions, please post a comment.
- Here's the solution I ended up with a while back to traverse the (sub-)tree, starting at the given root component. In short, the models's field, `components`, is used directly and small `unsafe` blocks are used to push the root's children into the vector-backed queue that's currently being traversed.
- While a full working example can be found at [this playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e0e914ae50d38b8b6a481e0bfd5070cc), the minimal/core part of it is below:
- ```rust
- impl Component for Model {
- fn children(&self) -> Vec<&dyn Component> {
- let mut v: Vec<&dyn Component> = self.components
- .iter()
- .map(|c| c.deref())
- .collect();
- let q = &mut v as *mut Vec<&dyn Component>;
- v.iter().for_each(|c| unsafe {
- (*q).append(&mut c.children())
- });
- v
- }
- fn children_mut(&mut self) -> Vec<&mut dyn Component> {
- let mut v: Vec<&mut dyn Component> = self.components
- .iter_mut()
- .map(|c| c.deref_mut())
- .collect();
- let q = &mut v as *mut Vec<&mut dyn Component>;
- unsafe {
- (*q).iter_mut().for_each(|c| {
- (*q).append(&mut c.children_mut())
- })
- }
- v
- }
- }
- ```
- The caveat/con here is that, under the *experimental* "Stacked Borrows" memory model in the *nightly* toolchain, Miri says the above causes UB inside the `Vec` implementation:
- ```text
- error: Undefined Behavior: deallocating while item [SharedReadOnly for <9045>] is strongly protected
- --> /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:776:13
- |
- 776 | alloc.grow(ptr, old_layout, new_layout)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item [SharedReadOnly for <9045>] is strongly protected
- |
- = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
- = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
- = note: BACKTRACE:
- = note: inside `alloc::raw_vec::finish_grow::<std::alloc::Global>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:776:13: 776:52
- = note: inside `alloc::raw_vec::RawVecInner::grow_amortized` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:661:19: 661:93
- = note: inside `alloc::raw_vec::RawVecInner::<A>::reserve::do_reserve_and_handle::<std::alloc::Global>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:554:31: 554:79
- note: inside closure
- ```
- In short, Miri says the `Vec` implementation runs into UB while allocating memory for the vector, likely b/c the `Vec` is being modified while being traversed.
- I've not (yet?) been successful in refactoring the above to remove the `unsafe` blocks. Perhaps some method type signature changes I'm not (currently) aware of would be required.
- If you have specific suggestions, please post them in a comment.
#1: Initial revision
Here's the solution I ended up with a while back to traverse the (sub-)tree, starting at the given root component. In short, the models's field, `components`, is used directly and small `unsafe` blocks are used to push the root's children into the vector-backed queue that's currently being traversed. While a full working example can be found at [this playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e0e914ae50d38b8b6a481e0bfd5070cc), the minimal/core part of it is below: ```rust impl Component for Model { fn children(&self) -> Vec<&dyn Component> { let mut v: Vec<&dyn Component> = self.components .iter() .map(|c| c.deref()) .collect(); let q = &mut v as *mut Vec<&dyn Component>; v.iter().for_each(|c| unsafe { (*q).append(&mut c.children()) }); v } fn children_mut(&mut self) -> Vec<&mut dyn Component> { let mut v: Vec<&mut dyn Component> = self.components .iter_mut() .map(|c| c.deref_mut()) .collect(); let q = &mut v as *mut Vec<&mut dyn Component>; unsafe { (*q).iter_mut().for_each(|c| { (*q).append(&mut c.children_mut()) }) } v } } ``` The caveat/con here is that, under the *experimental* "Stacked Borrows" memory model in the *nightly* toolchain, Miri says the above causes UB: ```text error: Undefined Behavior: deallocating while item [SharedReadOnly for <9045>] is strongly protected --> /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:776:13 | 776 | alloc.grow(ptr, old_layout, new_layout) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item [SharedReadOnly for <9045>] is strongly protected | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information = note: BACKTRACE: = note: inside `alloc::raw_vec::finish_grow::<std::alloc::Global>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:776:13: 776:52 = note: inside `alloc::raw_vec::RawVecInner::grow_amortized` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:661:19: 661:93 = note: inside `alloc::raw_vec::RawVecInner::<A>::reserve::do_reserve_and_handle::<std::alloc::Global>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:554:31: 554:79 note: inside closure ``` In short, Miri says the `Vec` implementation runs into UB while allocating memory for the vector, b/c it's being modified while being traversed. I've not (yet?) been successful in refactoring the above to remove the `unsafe` blocks. Perhaps some method type signature changes I'm not (currently) aware of would be required. If you have specific suggestions, please post a comment.