Skip to content
This repository was 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

@matklad

Description

@matklad

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! :)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions