Skip to content

Break recursive ElementFlattener loop with recursive structs #7

@technobaboo

Description

@technobaboo

on dev branch, go cargo test grabbable

❯ cargo test grabbable
   Compiling asteroids v2.0.0 (/run/media/nova/MEDIA/xr/stardust/asteroids2)
error[E0275]: overflow evaluating the requirement `impl Element<grabbable::asteroids_grabbable_element::{closure#0}::TestState> == _`

For more information about this error, try `rustc --explain E0275`.
error: could not compile `asteroids` (lib test) due to 1 previous error

this error happens due to the output element containing itself,

.maybe_child(
self.second
.as_ref()
.map(|s| s.reify_substate(|state: &mut Self| state.second.as_deref_mut())),
),

however, this produces a type that's roughly:

ElementWrapper<TestState, Grabbable, Mapper<TestState, TestState, Option<ElementWrapper<TestState, Grabbable, ...>>>>

with ... being itself as the grabbable is a child of itself and has no indirection.

Problem is, given ElementFlattener takes self when flattening

asteroids/src/element.rs

Lines 25 to 28 in f6486b1

pub(crate) trait ElementFlattener<State: ValidState>: Sized + Send + Sync + 'static {
// return a vector of this element and all its known siblings
fn flatten(self, bump: &Bump) -> Vec<Box<dyn ElementDiffer<State>>>;
}

we cannot create a trait object for indirection as self has to be sized... and we need self in ElementFlattener as we have to rip apart the zero cost abstraction structs and put them into the bumps to... flatten them.

asteroids/src/element.rs

Lines 134 to 157 in f6486b1

impl<State: ValidState, E: CustomElement<State>, C: Element<State>> ElementFlattener<State>
for ElementWrapper<State, E, C>
{
fn flatten(self, bump: &Bump) -> Vec<Box<dyn ElementDiffer<State>>> {
let children =
bumpalo::collections::vec::Vec::from_iter_in(self.children.flatten(bump), bump);
let flat_element = Box::new_in(
FlatElement {
element: self.custom_element,
children,
id: self.id,
phantom: PhantomData,
},
bump,
);
// rust doesn't let third party crates like bumpalo do proper trait object coercion so this is manual
let flat_element = unsafe {
let raw = Box::into_raw(flat_element);
let trait_obj: *mut dyn ElementDiffer<State> = raw as *mut dyn ElementDiffer<State>;
Box::from_raw(trait_obj)
};
vec![flat_element]
}
}

I just don't know what else I can realistically do here, anyone got any ideas??

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghelp wantedExtra attention is needed

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions