components-arena 1.0.0

Simple library for creating complex domain-specific self-referential data structures.
Documentation
#![no_std]

#![deny(warnings)]
#![allow(dead_code)]

mod widget_tree {
    use macro_attr_2018::macro_attr;
    use components_arena::{Component, Arena, Id, ComponentClassToken};

    macro_attr! {
        #[derive(Component!)]
        struct WidgetNode {
            parent: Option<Id<WidgetNode>>,
            next: Id<WidgetNode>,
            last_child: Option<Id<WidgetNode>>,
        }
    }

    pub struct WidgetTree {
        arena: Arena<WidgetNode>,
        root: Id<WidgetNode>,
    }

    pub struct WidgetTreeToken(ComponentClassToken<WidgetNode>);

    impl WidgetTreeToken {
        pub fn new() -> Option<WidgetTreeToken> { ComponentClassToken::new().map(WidgetTreeToken) }
    }

    impl WidgetTree {
        pub fn new(token: &mut WidgetTreeToken) -> WidgetTree {
            let mut arena = Arena::new(&mut token.0);
            let root = arena.insert(|this| (WidgetNode {
                parent: None, next: this, last_child: None
            }, this));
            WidgetTree { arena, root }
        }

        pub fn root(&self) -> Widget { Widget(self.root) }
    }

    #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
    pub struct Widget(Id<WidgetNode>);

    impl Widget {
        pub fn new(tree: &mut WidgetTree, parent: Widget) -> Widget {
            let widget = tree.arena.insert(|this| (WidgetNode {
                parent: Some(parent.0), next: this, last_child: None
            }, this));
            if let Some(prev) = tree.arena[parent.0].last_child.replace(widget) {
                tree.arena[widget].next = prev;
            }
            Widget(widget)
        }

        pub fn drop(self, tree: &mut WidgetTree) {
            tree.arena.remove(self.0);
        }

        pub fn parent(self, tree: &WidgetTree) -> Option<Widget> {
            tree.arena[self.0].parent.map(Widget)
        }
    }
}

use widget_tree::*;

fn main() {
    let token = &mut WidgetTreeToken::new().unwrap();
    let tree = &mut WidgetTree::new(token);
    let widget = Widget::new(tree, tree.root());
    assert_eq!(widget.parent(tree), Some(tree.root()));
}