Skip to content

Commit

Permalink
create arena tree
Browse files Browse the repository at this point in the history
  • Loading branch information
KGrewal1 committed Nov 26, 2024
1 parent af96e78 commit bbd9cd8
Show file tree
Hide file tree
Showing 20 changed files with 943 additions and 136 deletions.
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ members = [
"xilem_web/web_examples/spawn_tasks",
"xilem_web/web_examples/svgtoy",
"xilem_web/web_examples/svgdraw",
"tree_arena",
]

[workspace.package]
Expand Down Expand Up @@ -105,6 +106,7 @@ clippy.duplicated_attributes = "allow"
[workspace.dependencies]
masonry = { version = "0.2.0", path = "masonry" }
xilem_core = { version = "0.1.0", path = "xilem_core" }
tree_arena = { version = "0.1.0", path = "tree_arena" }
vello = "0.3"
wgpu = "22.1.0"
kurbo = "0.11.1"
Expand Down
1 change: 1 addition & 0 deletions masonry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ vello.workspace = true
wgpu.workspace = true
parley.workspace = true
winit.workspace = true
tree_arena.workspace = true
smallvec.workspace = true
tracing = { workspace = true, features = ["default"] }
image.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion masonry/src/contexts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ use crate::passes::layout::run_layout_on;
use crate::render_root::{MutateCallback, RenderRootSignal, RenderRootState};
use crate::text::BrushIndex;
use crate::theme::get_debug_color;
use crate::tree_arena::{ArenaMutChildren, ArenaRefChildren};
use crate::widget::{WidgetMut, WidgetRef, WidgetState};
use crate::{AllowRawMut, BoxConstraints, Insets, Point, Rect, Size, Widget, WidgetId, WidgetPod};
use tree_arena::{ArenaMutChildren, ArenaRefChildren};

// Note - Most methods defined in this file revolve around `WidgetState` fields.
// Consider reading `WidgetState` documentation (especially the documented naming scheme)
Expand Down
1 change: 0 additions & 1 deletion masonry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,6 @@ mod paint_scene_helpers;
mod passes;
mod render_root;
mod tracing_backend;
mod tree_arena;

pub mod event_loop_runner;
pub mod testing;
Expand Down
2 changes: 1 addition & 1 deletion masonry/src/passes/accessibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use vello::kurbo::Rect;

use crate::passes::recurse_on_children;
use crate::render_root::{RenderRoot, RenderRootState};
use crate::tree_arena::ArenaMut;
use crate::{AccessCtx, Widget, WidgetState};
use tree_arena::ArenaMut;

use super::enter_span_if;

Expand Down
2 changes: 1 addition & 1 deletion masonry/src/passes/anim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use tracing::info_span;

use crate::passes::{enter_span_if, recurse_on_children};
use crate::render_root::{RenderRoot, RenderRootState};
use crate::tree_arena::ArenaMut;
use crate::{UpdateCtx, Widget, WidgetState};
use tree_arena::ArenaMut;

// --- MARK: UPDATE ANIM ---
fn update_anim_for_widget(
Expand Down
2 changes: 1 addition & 1 deletion masonry/src/passes/compose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use vello::kurbo::Vec2;

use crate::passes::{enter_span_if, recurse_on_children};
use crate::render_root::{RenderRoot, RenderRootSignal, RenderRootState};
use crate::tree_arena::ArenaMut;
use crate::{ComposeCtx, Widget, WidgetState};
use tree_arena::ArenaMut;

// --- MARK: RECURSE ---
fn compose_widget(
Expand Down
2 changes: 1 addition & 1 deletion masonry/src/passes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
use tracing::span::EnteredSpan;

use crate::render_root::RenderRootState;
use crate::tree_arena::{ArenaMut, ArenaMutChildren, ArenaRef};
use crate::widget::WidgetArena;
use crate::{QueryCtx, Widget, WidgetId, WidgetState};
use tree_arena::{ArenaMut, ArenaMutChildren, ArenaRef};

pub(crate) mod accessibility;
pub(crate) mod anim;
Expand Down
2 changes: 1 addition & 1 deletion masonry/src/passes/paint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use vello::Scene;
use crate::passes::{enter_span_if, recurse_on_children};
use crate::render_root::{RenderRoot, RenderRootState};
use crate::theme::get_debug_color;
use crate::tree_arena::ArenaMut;
use crate::{PaintCtx, Widget, WidgetId, WidgetState};
use tree_arena::ArenaMut;

// --- MARK: PAINT WIDGET ---
fn paint_widget(
Expand Down
2 changes: 1 addition & 1 deletion masonry/src/passes/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ use tracing::{info_span, trace};
use crate::passes::event::run_on_pointer_event_pass;
use crate::passes::{enter_span, enter_span_if, merge_state_up, recurse_on_children};
use crate::render_root::{RenderRoot, RenderRootSignal, RenderRootState};
use crate::tree_arena::ArenaMut;
use crate::{
PointerEvent, QueryCtx, RegisterCtx, Update, UpdateCtx, Widget, WidgetId, WidgetState,
};
use tree_arena::ArenaMut;

// --- MARK: HELPERS ---
fn get_id_path(root: &RenderRoot, widget_id: Option<WidgetId>) -> Vec<WidgetId> {
Expand Down
2 changes: 1 addition & 1 deletion masonry/src/render_root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ use crate::passes::update::{
};
use crate::passes::{recurse_on_children, PassTracing};
use crate::text::BrushIndex;
use crate::tree_arena::{ArenaMut, TreeArena};
use crate::widget::{WidgetArena, WidgetMut, WidgetRef, WidgetState};
use crate::{AccessEvent, Action, CursorIcon, Handled, QueryCtx, Widget, WidgetId, WidgetPod};
use tree_arena::{ArenaMut, TreeArena};

// --- MARK: STRUCTS ---

Expand Down
2 changes: 1 addition & 1 deletion masonry/src/widget/widget_arena.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Copyright 2024 the Xilem Authors
// SPDX-License-Identifier: Apache-2.0

use crate::tree_arena::{ArenaMut, ArenaRef, TreeArena};
use crate::{Widget, WidgetId, WidgetState};
use tree_arena::{ArenaMut, ArenaRef, TreeArena};

pub(crate) struct WidgetArena {
pub(crate) widgets: TreeArena<Box<dyn Widget>>,
Expand Down
33 changes: 33 additions & 0 deletions tree_arena/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Tree Arena

## Architecture

The unsafe tree arena contains a `DataMap` which **owns** all nodes. The `DataMap` contains:

* A `HashMap` associating `NodeId` with `Box<UnsafeCell<TreeNode<T>>>`, owning the node data, (boxed to prevent movement of the node when the `HashMap` is resized and `UnsafeCell` to express the interior mutability)

* A `HashMap` associating `NodeId` with `Option<NodeId>`, containing the parent information for the nodes

* `Box<UnsafeCell<Vec<NodeId>>>` containing the roots of the tree

It is possible to get shared (immutable) access or exclusive (mutable) access to the tree. These return `ArenaRef<'arena, T>` or `ArenaMut<'arena, T>` respectively

### Shared References

`ArenaRef<'arena, T>` contains the identity of the parent node, a reference to the node data, and `ArenaRefChildren<'arena, T>`. The `ArenaRefChildren<'arena, T>` contains the ids of the children of the node, the id of the node, and a reference to the arena. From this `ArenaRefChildren<'arena, T>` it is possible to get shared access to children of the node.

### Exclusive References

`ArenaMut<'arena, T>` contains the identity of the parent node, a mutable reference to the node data, and `ArenaMutChildren<'arena, T>`. The `ArenaMutChildren<'arena, T>` contains the ids of the children of the node, the id of the node, and a mutable reference to the arena. From this `ArenaMutChildren<'arena, T>` it is possible to get exclusive access to children of the node.

## Safety

From the `ArenaMutChildren<'arena, T>`, it is important that we can only access descendants of that node, such that we can only ever have exclusive mutable access to the contents of a node, and never have multiple mutable references. This invariant is not checked by the compiler and thus relies on the logic to determine whether a node is a descendant being correct.

## Complexity

Of finding children: $O(1)$ - previously $O(\text{children})$

Of finding deeper descendants: $O(\text{depth})$ - ideally will be made $O(1)$

Access from the root: $O(1)$, previously $O(\text{depth})$ - improved as all nodes are known to be descended from the root
20 changes: 20 additions & 0 deletions tree_arena/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "tree_arena"
version = "0.1.0"
description = "An arena allocated tree designed for Linebender"
keywords = ["arena", "tree"]
categories = ["gui"]
edition.workspace = true
rust-version.workspace = true
license.workspace = true
repository.workspace = true
homepage.workspace = true

[dependencies]

[features]
default = ["safe_tree"]
safe_tree = []

[lints]
workspace = true
3 changes: 3 additions & 0 deletions tree_arena/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Tree Arena

An arena allocated tree
24 changes: 24 additions & 0 deletions tree_arena/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2024 the Xilem Authors
// SPDX-License-Identifier: Apache-2.0

//! This module will eventually be factored out into a separate crate.
//!
//! In the meantime, we intentionally don't make the types in this module part of
//! our public API, but still implement methods that a standalone crate would have.
//!
//! The types defined in this module don't *actually* implement an arena. They use
//! 100% safe code, which has a significant performance overhead. The final version
//! will use an arena and unsafe code, but should have the exact same exported API as
//! this module.
type NodeId = u64;

#[cfg(not(feature = "safe_tree"))]
mod tree_arena_unsafe;
#[cfg(not(feature = "safe_tree"))]
pub use tree_arena_unsafe::*;

#[cfg(feature = "safe_tree")]
mod tree_arena_safe;
#[cfg(feature = "safe_tree")]
pub use tree_arena_safe::*;
Loading

0 comments on commit bbd9cd8

Please sign in to comment.