Skip to content
This repository has been archived by the owner on Jul 27, 2023. It is now read-only.

Alternative solution to "fn layout needs to mut borrow several nodes" #40

Open
matklad opened this issue Sep 6, 2018 · 0 comments
Open

Comments

@matklad
Copy link

matklad commented Sep 6, 2018

Hi! I've just seen your awesome talk about data-driven UI's in Rust, and got intrigued by the problem of traversing a ECS-style tree while borrowing nodes mutably.

I think I have a similar problem in other domain: structured editing of syntax trees. Don't want to go into details about it, but if you want to code stuff "find or create node X and add A, B and C children to it", you also sort-of want two mutable borrows of different indices.

I'd like to share my solution, which is different from yours "implement trampoline/state machine by hand". I think it is actually worse for your use case due to interactions with object safety, but it's still interesting.

The idea is that instead of passing a &mut Node, one uses &mut Tree, NodeId. That way, it's possible to reborrow &mut Node as &mut tree[node_id] several times, and use borrowing via other indices in between. Now, this does have to go a number of additional contortions to actually work for dyn Widget state: you need to explicitly separate widget's state and behavior, and then introduce an additional trait to make that object safe, but it does work out in the end, and result looks like this:

https://play.rust-lang.org/?gist=2075f9638163ba4e6187238861d15cba&version=stable&mode=debug&edition=2015

struct Counter;

impl Widget for Counter {
    type Data = usize;

    fn layout(
        ctx: &mut LayoutCtx, // insead of passing &mut Self, we pass an index and `&mut Ctx`
        me: TypedId<Self>,
        children: &[Id]
    ) -> usize {

        for &id in children.iter() {
            let child_layout = ctx.layout(id);
            *ctx.data_mut(me) += child_layout;
        }

        *ctx.data_mut(me)
    }
}

On to re watching Flutter rendering pipeline talk! :)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant