dimanche 10 mai 2020

Designing a UI element tree structure in Rust

I've stumbled upon a somewhat quirky situation due to lack of inheritance in Rust.

I'm designing an element structure where all elements have some common behaviour (e.g. having children) and need to propagate function calls down the tree.

My current design is to have a View trait and a ViewInner struct that encapsulates all common behaviour. However it appears that doing so would spawn tons of boilerplate code that forwards calls from View to its ViewInner. And as it appears, adding another level of encapsulation (e.g. AutoLayoutView) would triple the call depth.

Here's a short example:

// "Base" view trait
pub trait View {
    fn render(&self, ...);
    fn handle_events(&self, ...);
}

// View internals
pub struct ViewInner {
    children: Vec<Box<View>>
}

impl ViewInner {
    ...
    pub fn add_child(...);
    pub fn layout(...);
}

// Forwarded calls
impl View for ViewInner {
    fn render(&self, ...) {
        for child in self.children.iter() {
            child.render(...);
        }
    }

    fn handle_events(&self, ...) {
        for child in self.children.iter() {
            child.handle_events(...);
        }
    }
}

// Actual entity
pub struct SomeView {
    inner: ViewInner,
    ...
}

impl SomeView {
    pub fn new() -> Self {
        return Self {
            inner: ViewInner::new()
        }
    }
}

impl View for SomeView {
    // Forwarding all over again
    fn render(&self, ...) {
        self.inner.render(...)
    }
    fn handle_events(&self, ...) {
        self.inner.handle_events(...)
    }
}

What would be a more optimal way to structure this and minimize boilerplate in the future (in case of more tree-crawling calls and View variations)?

Aucun commentaire:

Enregistrer un commentaire