finish shipyard migration in native-core
This commit is contained in:
1 parent
b91e010ac7
commit
a8566b4e71
7 files changed
+414
-307
No files matched your search
@@ -17,6 +17,7 @@ members = [
|
||||
"packages/rsx",
|
||||
"packages/tui",
|
||||
"packages/native-core",
|
||||
"packages/native-core-macro",
|
||||
"packages/rsx-rosetta",
|
||||
"packages/signals",
|
||||
"packages/hot-reload",
|
||||
|
||||
@@ -1,22 +1,126 @@
|
||||
extern crate proc_macro;
|
||||
|
||||
mod sorted_slice;
|
||||
use std::collections::HashSet;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::{quote, ToTokens, __private::Span};
|
||||
use sorted_slice::StrSlice;
|
||||
use syn::parenthesized;
|
||||
use syn::parse::ParseBuffer;
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::{
|
||||
self,
|
||||
parse::{Parse, ParseStream, Result},
|
||||
parse_macro_input, parse_quote, Error, Field, Ident, Token, Type,
|
||||
};
|
||||
use quote::quote;
|
||||
use syn::Type;
|
||||
|
||||
/// A helper attribute for deriving `State` for a struct.
|
||||
#[proc_macro_attribute]
|
||||
pub fn my_attribute(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||
pub fn partial_derive_pass(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let impl_block: syn::ItemImpl = syn::parse(input).unwrap();
|
||||
|
||||
let parent_dependencies = impl_block
|
||||
.items
|
||||
.iter()
|
||||
.find_map(|item| {
|
||||
if let syn::ImplItem::Type(syn::ImplItemType {
|
||||
attrs, ident, ty, ..
|
||||
}) = item
|
||||
{
|
||||
(ident == "ParentDependencies").then_some(ty)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
let child_dependencies = impl_block
|
||||
.items
|
||||
.iter()
|
||||
.find_map(|item| {
|
||||
if let syn::ImplItem::Type(syn::ImplItemType {
|
||||
attrs, ident, ty, ..
|
||||
}) = item
|
||||
{
|
||||
(ident == "ChildDependencies").then_some(ty)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
let node_dependencies = impl_block
|
||||
.items
|
||||
.iter()
|
||||
.find_map(|item| {
|
||||
if let syn::ImplItem::Type(syn::ImplItemType {
|
||||
attrs, ident, ty, ..
|
||||
}) = item
|
||||
{
|
||||
(ident == "NodeDependencies").then_some(ty)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let this_type = &impl_block.self_ty;
|
||||
|
||||
let mut combined_dependencies = HashSet::new();
|
||||
|
||||
match parent_dependencies {
|
||||
Type::Tuple(tuple) => {
|
||||
for type_ in &tuple.elems {
|
||||
combined_dependencies.insert(type_.clone());
|
||||
}
|
||||
}
|
||||
_ => panic!("ParentDependencies must be a tuple"),
|
||||
}
|
||||
match child_dependencies {
|
||||
Type::Tuple(tuple) => {
|
||||
for type_ in &tuple.elems {
|
||||
combined_dependencies.insert(type_.clone());
|
||||
}
|
||||
}
|
||||
_ => panic!("ChildDependencies must be a tuple"),
|
||||
}
|
||||
match node_dependencies {
|
||||
Type::Tuple(tuple) => {
|
||||
for type_ in &tuple.elems {
|
||||
combined_dependencies.insert(type_.clone());
|
||||
}
|
||||
}
|
||||
_ => panic!("NodeDependencies must be a tuple"),
|
||||
}
|
||||
combined_dependencies.insert(*this_type.clone());
|
||||
|
||||
let combined_dependencies = combined_dependencies.into_iter();
|
||||
let combined_dependencies = quote!((#(#combined_dependencies),*));
|
||||
|
||||
quote!(#impl_block).into()
|
||||
}
|
||||
|
||||
// pub trait State<V: FromAnyValue + Send + Sync = ()>: Any + Send + Sync {
|
||||
// /// This is a tuple of (T: Pass, ..) of states read from the parent required to run this pass
|
||||
// type ParentDependencies: Dependancy;
|
||||
// /// This is a tuple of (T: Pass, ..) of states read from the children required to run this pass
|
||||
// type ChildDependencies: Dependancy;
|
||||
// /// This is a tuple of (T: Pass, ..) of states read from the node required to run this pass
|
||||
// type NodeDependencies: Dependancy;
|
||||
// /// A tuple of all the dependencies combined
|
||||
// type CombinedDependencies: Dependancy;
|
||||
// /// This is a mask of what aspects of the node are required to run this pass
|
||||
// const NODE_MASK: NodeMaskBuilder<'static>;
|
||||
//
|
||||
// /// Update this state in a node, returns if the state was updated
|
||||
// fn update<'a>(
|
||||
// &mut self,
|
||||
// node_view: NodeView<V>,
|
||||
// node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
|
||||
// parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
|
||||
// children: Option<Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>>,
|
||||
// context: &SendAnyMap,
|
||||
// ) -> bool;
|
||||
//
|
||||
// /// Create a new instance of this state
|
||||
// fn create<'a>(
|
||||
// node_view: NodeView<V>,
|
||||
// node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
|
||||
// parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
|
||||
// children: Option<Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>>,
|
||||
// context: &SendAnyMap,
|
||||
// ) -> Self;
|
||||
//
|
||||
// /// Create a workload system for this state
|
||||
// fn workload_system(dependants: FxHashSet<TypeId>) -> WorkloadSystem;
|
||||
// }
|
||||
@@ -29,6 +29,7 @@ lightningcss = "1.0.0-alpha.39"
|
||||
|
||||
rayon = "1.6.1"
|
||||
shipyard = "0.6.2"
|
||||
shipyard_hierarchy = "0.6.0"
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::tree::TreeMut;
|
||||
use dioxus_core::{BorrowedAttributeValue, ElementId, Mutations, TemplateNode};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use shipyard::Component;
|
||||
@@ -155,7 +156,7 @@ impl DioxusState {
|
||||
let new_nodes = self.stack.split_off(self.stack.len() - m);
|
||||
let old_node_id = self.element_to_node_id(id);
|
||||
for new in new_nodes {
|
||||
rdom.tree.insert_before(old_node_id, new);
|
||||
rdom.tree_mut().insert_before(old_node_id, new);
|
||||
}
|
||||
}
|
||||
SetAttribute {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use anymap::AnyMap;
|
||||
use parking_lot::RwLock;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use shipyard::{Component, IntoBorrow, Unique, View, WorkloadSystem};
|
||||
use shipyard::{
|
||||
BorrowInfo, Component, IntoBorrow, IntoWorkloadSystem, Unique, UniqueView, View,
|
||||
WorkloadSystem, World,
|
||||
};
|
||||
use std::any::{Any, TypeId};
|
||||
use std::collections::BTreeMap;
|
||||
use std::marker::PhantomData;
|
||||
@@ -9,7 +12,9 @@ use std::sync::Arc;
|
||||
|
||||
use crate::node::FromAnyValue;
|
||||
use crate::node_ref::{NodeMaskBuilder, NodeView};
|
||||
use crate::SendAnyMap;
|
||||
use crate::real_dom::{DirtyNodesResult, SendAnyMapWrapper};
|
||||
use crate::tree::{TreeMut, TreeRef, TreeRefView};
|
||||
use crate::{FxDashSet, SendAnyMap};
|
||||
use crate::{NodeId, NodeMask};
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -108,6 +113,7 @@ pub trait State<V: FromAnyValue + Send + Sync = ()>: Any + Send + Sync {
|
||||
type ChildDependencies: Dependancy;
|
||||
/// This is a tuple of (T: Pass, ..) of states read from the node required to run this pass
|
||||
type NodeDependencies: Dependancy;
|
||||
/// A tuple of all the dependencies combined
|
||||
type CombinedDependencies: Dependancy;
|
||||
/// This is a mask of what aspects of the node are required to run this pass
|
||||
const NODE_MASK: NodeMaskBuilder<'static>;
|
||||
@@ -130,39 +136,93 @@ pub trait State<V: FromAnyValue + Send + Sync = ()>: Any + Send + Sync {
|
||||
children: Option<Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>>,
|
||||
context: &SendAnyMap,
|
||||
) -> Self;
|
||||
|
||||
/// Create a workload system for this state
|
||||
fn workload_system(dependants: FxHashSet<TypeId>) -> WorkloadSystem;
|
||||
}
|
||||
|
||||
pub struct RunPassView<'a> {
|
||||
type_id: TypeId,
|
||||
dependants: FxHashSet<TypeId>,
|
||||
pass_direction: PassDirection,
|
||||
tree: TreeRefView<'a>,
|
||||
nodes_updated: UniqueView<'a, DirtyNodesResult>,
|
||||
dirty: UniqueView<'a, DirtyNodeStates>,
|
||||
ctx: UniqueView<'a, SendAnyMapWrapper>,
|
||||
}
|
||||
|
||||
impl<'a> RunPassView<'a> {
|
||||
pub fn borrow(
|
||||
type_id: TypeId,
|
||||
dependants: FxHashSet<TypeId>,
|
||||
pass_direction: PassDirection,
|
||||
world: &'a World,
|
||||
) -> Self {
|
||||
Self {
|
||||
type_id,
|
||||
dependants,
|
||||
pass_direction,
|
||||
tree: world.borrow().unwrap(),
|
||||
nodes_updated: world.borrow().unwrap(),
|
||||
dirty: world.borrow().unwrap(),
|
||||
ctx: world.borrow().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_pass(view: RunPassView, mut update_node: impl FnMut(NodeId, &SendAnyMap) -> bool) {
|
||||
let RunPassView {
|
||||
type_id,
|
||||
dependants,
|
||||
pass_direction,
|
||||
tree,
|
||||
nodes_updated,
|
||||
dirty,
|
||||
ctx,
|
||||
} = view;
|
||||
let ctx = ctx.as_ref();
|
||||
match pass_direction {
|
||||
PassDirection::ParentToChild => {
|
||||
while let Some((height, id)) = dirty.pop_front(type_id) {
|
||||
let id = tree.id_at(id).unwrap();
|
||||
if (update_node)(id, ctx) {
|
||||
nodes_updated.insert(id);
|
||||
for id in tree.children_ids(id).unwrap() {
|
||||
for dependant in &dependants {
|
||||
dirty.insert(*dependant, id, height + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PassDirection::ChildToParent => {
|
||||
while let Some((height, id)) = dirty.pop_back(type_id) {
|
||||
let id = tree.id_at(id).unwrap();
|
||||
if (update_node)(id, ctx) {
|
||||
nodes_updated.insert(id);
|
||||
if let Some(id) = tree.parent_id(id) {
|
||||
for dependant in &dependants {
|
||||
dirty.insert(*dependant, id, height - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PassDirection::AnyOrder => {
|
||||
while let Some((height, id)) = dirty.pop_back(type_id) {
|
||||
let id = tree.id_at(id).unwrap();
|
||||
if (update_node)(id, ctx) {
|
||||
nodes_updated.insert(id);
|
||||
for dependant in &dependants {
|
||||
dirty.insert(*dependant, id, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AnyState<V: FromAnyValue + Send + Sync = ()>: State<V> {
|
||||
fn workload_system() -> WorkloadSystem;
|
||||
// Box::new(
|
||||
// move |node_id: NodeId, tree: &mut TreeStateView, context: &SendAnyMap| {
|
||||
// debug_assert!(!Self::NodeDependencies::type_ids()
|
||||
// .iter()
|
||||
// .any(|id| *id == TypeId::of::<Self>()));
|
||||
// // get all of the states from the tree view
|
||||
// // Safety: No node has itself as a parent or child.
|
||||
// let myself: SlabEntry<'static, Self> = unsafe {
|
||||
// std::mem::transmute(tree.get_slab_mut::<Self>().unwrap().entry(node_id))
|
||||
// };
|
||||
// let node_data = tree.get_single::<NodeType<V>>(node_id).unwrap();
|
||||
// let node = tree.get::<Self::NodeDependencies>(node_id).unwrap();
|
||||
// let children = tree.children::<Self::ChildDependencies>(node_id);
|
||||
// let parent = tree.parent::<Self::ParentDependencies>(node_id);
|
||||
|
||||
// let view = NodeView::new(node_id, node_data, &node_mask);
|
||||
// if myself.value.is_none() {
|
||||
// *myself.value = Some(Self::create(view, node, parent, children, context));
|
||||
// true
|
||||
// } else {
|
||||
// myself
|
||||
// .value
|
||||
// .as_mut()
|
||||
// .unwrap()
|
||||
// .update(view, node, parent, children, context)
|
||||
// }
|
||||
// },
|
||||
// ) as PassCallback
|
||||
|
||||
fn to_type_erased() -> TypeErasedPass<V>
|
||||
where
|
||||
Self: Sized,
|
||||
@@ -174,9 +234,9 @@ pub trait AnyState<V: FromAnyValue + Send + Sync = ()>: State<V> {
|
||||
parent_dependant: !Self::parent_type_ids().is_empty(),
|
||||
child_dependant: !Self::child_type_ids().is_empty(),
|
||||
dependants: FxHashSet::default(),
|
||||
mask: node_mask.clone(),
|
||||
mask: node_mask,
|
||||
pass_direction: Self::pass_direction(),
|
||||
workload: Some(Self::workload_system()),
|
||||
workload: Self::workload_system,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -224,58 +284,11 @@ pub struct TypeErasedPass<V: FromAnyValue + Send = ()> {
|
||||
pub(crate) combined_dependancy_type_ids: FxHashSet<TypeId>,
|
||||
pub(crate) dependants: FxHashSet<TypeId>,
|
||||
pub(crate) mask: NodeMask,
|
||||
pub(crate) workload: Option<WorkloadSystem>,
|
||||
pub(crate) workload: fn(FxHashSet<TypeId>) -> WorkloadSystem,
|
||||
pub(crate) pass_direction: PassDirection,
|
||||
phantom: PhantomData<V>,
|
||||
}
|
||||
|
||||
// impl<V: FromAnyValue + Send> TypeErasedPass<V> {
|
||||
// fn resolve(
|
||||
// &self,
|
||||
// mut tree: TreeStateView,
|
||||
// dirty: &DirtyNodeStates,
|
||||
// nodes_updated: &FxDashSet<NodeId>,
|
||||
// ctx: &SendAnyMap,
|
||||
// ) {
|
||||
// match self.pass_direction {
|
||||
// PassDirection::ParentToChild => {
|
||||
// while let Some((height, id)) = dirty.pop_front(self.this_type_id) {
|
||||
// if (self.pass)(id, &mut tree, ctx) {
|
||||
// nodes_updated.insert(id);
|
||||
// for id in tree.children_ids(id).unwrap() {
|
||||
// for dependant in &self.dependants {
|
||||
// dirty.insert(*dependant, *id, height + 1);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// PassDirection::ChildToParent => {
|
||||
// while let Some((height, id)) = dirty.pop_back(self.this_type_id) {
|
||||
// if (self.pass)(id, &mut tree, ctx) {
|
||||
// nodes_updated.insert(id);
|
||||
// if let Some(id) = tree.parent_id(id) {
|
||||
// for dependant in &self.dependants {
|
||||
// dirty.insert(*dependant, id, height - 1);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// PassDirection::AnyOrder => {
|
||||
// while let Some((height, id)) = dirty.pop_back(self.this_type_id) {
|
||||
// if (self.pass)(id, &mut tree, ctx) {
|
||||
// nodes_updated.insert(id);
|
||||
// for dependant in &self.dependants {
|
||||
// dirty.insert(*dependant, id, height);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PassDirection {
|
||||
ParentToChild,
|
||||
@@ -300,7 +313,7 @@ impl<'a> AnyMapLike<'a> for &'a SendAnyMap {
|
||||
}
|
||||
|
||||
pub trait Dependancy {
|
||||
type ElementBorrowed<'a>: IntoBorrow;
|
||||
type ElementBorrowed<'a>: IntoBorrow + BorrowInfo;
|
||||
|
||||
fn type_ids() -> Box<[TypeId]> {
|
||||
Box::new([])
|
||||
@@ -330,60 +343,3 @@ impl_dependancy!(A, B, C, D, E, F, G);
|
||||
impl_dependancy!(A, B, C, D, E, F, G, H);
|
||||
impl_dependancy!(A, B, C, D, E, F, G, H, I);
|
||||
impl_dependancy!(A, B, C, D, E, F, G, H, I, J);
|
||||
|
||||
// pub fn resolve_passes<V: FromAnyValue + Send + Sync>(
|
||||
// dom: &mut RealDom<V>,
|
||||
// dirty_nodes: DirtyNodeStates,
|
||||
// ctx: SendAnyMap,
|
||||
// parallel: bool,
|
||||
// ) -> FxDashSet<NodeId> {
|
||||
// let passes = &dom.dirty_nodes.passes;
|
||||
// let mut resolved_passes: FxHashSet<TypeId> = FxHashSet::default();
|
||||
// let mut resolving = Vec::new();
|
||||
// let nodes_updated = Arc::new(FxDashSet::default());
|
||||
// let ctx = Arc::new(ctx);
|
||||
// let mut pass_indexes_remaining: Vec<_> = (0..passes.len()).collect::<Vec<_>>();
|
||||
// while !pass_indexes_remaining.is_empty() {
|
||||
// let mut currently_in_use = FxHashSet::<TypeId>::default();
|
||||
// let dynamically_borrowed_tree = dom.tree.dynamically_borrowed();
|
||||
// rayon::in_place_scope(|s| {
|
||||
// let mut i = 0;
|
||||
// while i < pass_indexes_remaining.len() {
|
||||
// let passes_idx = pass_indexes_remaining[i];
|
||||
// let pass = &passes[passes_idx];
|
||||
// let pass_id = pass.this_type_id;
|
||||
// // check if the pass is ready to be run
|
||||
// if pass.combined_dependancy_type_ids.iter().all(|d| {
|
||||
// (resolved_passes.contains(d) || *d == pass_id) && !currently_in_use.contains(d)
|
||||
// }) {
|
||||
// pass_indexes_remaining.remove(i);
|
||||
// resolving.push(pass_id);
|
||||
// currently_in_use.insert(pass.this_type_id);
|
||||
// let tree_view = dynamically_borrowed_tree.view(
|
||||
// pass.combined_dependancy_type_ids
|
||||
// .iter()
|
||||
// .filter(|id| **id != pass.this_type_id)
|
||||
// .copied()
|
||||
// .chain(std::iter::once(TypeId::of::<NodeType<V>>())),
|
||||
// [pass.this_type_id],
|
||||
// );
|
||||
// let dirty_nodes = dirty_nodes.clone();
|
||||
// let nodes_updated = nodes_updated.clone();
|
||||
// let ctx = ctx.clone();
|
||||
// if parallel {
|
||||
// s.spawn(move |_| {
|
||||
// pass.resolve(tree_view, &dirty_nodes, &nodes_updated, &ctx);
|
||||
// });
|
||||
// } else {
|
||||
// pass.resolve(tree_view, &dirty_nodes, &nodes_updated, &ctx);
|
||||
// }
|
||||
// } else {
|
||||
// i += 1;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// resolved_passes.extend(resolving.iter().copied());
|
||||
// resolving.clear()
|
||||
// }
|
||||
// std::sync::Arc::try_unwrap(nodes_updated).unwrap()
|
||||
// }
|
||||
@@ -1,10 +1,8 @@
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use shipyard::error::GetStorage;
|
||||
use shipyard::track::Untracked;
|
||||
use shipyard::{
|
||||
Component, Get, IntoBorrow, ScheduledWorkload, System, Unique, View, ViewMut, Workload,
|
||||
WorkloadSystem,
|
||||
};
|
||||
use shipyard::{Component, Get, IntoBorrow, ScheduledWorkload, Unique, View, ViewMut, Workload};
|
||||
use shipyard::{SystemModificator, World};
|
||||
use std::any::TypeId;
|
||||
use std::collections::VecDeque;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
@@ -17,17 +15,33 @@ use crate::node_ref::{NodeMask, NodeMaskBuilder};
|
||||
use crate::node_watcher::NodeWatcher;
|
||||
use crate::passes::{DirtyNodeStates, TypeErasedPass};
|
||||
use crate::prelude::AttributeMaskBuilder;
|
||||
use crate::tree::Tree;
|
||||
use crate::tree::{TreeMut, TreeMutView, TreeRef, TreeRefView};
|
||||
use crate::NodeId;
|
||||
use crate::{FxDashSet, SendAnyMap};
|
||||
|
||||
#[derive(Unique)]
|
||||
struct SendAnyMapWrapper(SendAnyMap);
|
||||
pub struct SendAnyMapWrapper(SendAnyMap);
|
||||
|
||||
impl Deref for SendAnyMapWrapper {
|
||||
type Target = SendAnyMap;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Unique, Default)]
|
||||
struct DirtyNodes(FxDashSet<NodeId>);
|
||||
pub struct DirtyNodesResult(FxDashSet<NodeId>);
|
||||
|
||||
pub(crate) struct NodesDirty<V: FromAnyValue + Send + Sync> {
|
||||
impl Deref for DirtyNodesResult {
|
||||
type Target = FxDashSet<NodeId>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NodesDirty<V: FromAnyValue + Send + Sync> {
|
||||
passes_updated: FxHashMap<NodeId, FxHashSet<TypeId>>,
|
||||
nodes_updated: FxHashMap<NodeId, NodeMask>,
|
||||
pub(crate) passes: Box<[TypeErasedPass<V>]>,
|
||||
@@ -76,31 +90,27 @@ type NodeWatchers<V> = Arc<RwLock<Vec<Box<dyn NodeWatcher<V> + Send + Sync>>>>;
|
||||
/// # Custom values
|
||||
/// To allow custom values to be passed into attributes implement FromAnyValue on a type that can represent your custom value and specify the V generic to be that type. If you have many different custom values, it can be useful to use a enum type to represent the varients.
|
||||
pub struct RealDom<V: FromAnyValue + Send + Sync = ()> {
|
||||
pub(crate) tree: Tree,
|
||||
pub(crate) world: World,
|
||||
nodes_listening: FxHashMap<String, FxHashSet<NodeId>>,
|
||||
pub(crate) dirty_nodes: NodesDirty<V>,
|
||||
node_watchers: NodeWatchers<V>,
|
||||
workload: ScheduledWorkload,
|
||||
root_id: NodeId,
|
||||
phantom: std::marker::PhantomData<V>,
|
||||
}
|
||||
|
||||
impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
||||
pub fn new(mut passes: Box<[TypeErasedPass<V>]>) -> RealDom<V> {
|
||||
let mut tree = Tree::new();
|
||||
let mut workload = Workload::new("Main Workload");
|
||||
for pass in &mut *passes {
|
||||
let system = pass.workload.take().unwrap();
|
||||
workload = workload.with_system(system);
|
||||
}
|
||||
let workload = construct_workload(&mut passes);
|
||||
let (workload, _) = workload.build().unwrap();
|
||||
let root_id = tree.root();
|
||||
let mut world = World::new();
|
||||
let root_node: NodeType<V> = NodeType::Element(ElementNode {
|
||||
tag: "Root".to_string(),
|
||||
namespace: Some("Root".to_string()),
|
||||
attributes: FxHashMap::default(),
|
||||
listeners: FxHashSet::default(),
|
||||
});
|
||||
tree.insert(root_id, root_node);
|
||||
let root_id = world.add_entity(root_node);
|
||||
|
||||
// resolve dependants for each pass
|
||||
for i in 1..passes.len() {
|
||||
@@ -122,7 +132,7 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
||||
nodes_updated.insert(root_id, NodeMaskBuilder::ALL.build());
|
||||
|
||||
RealDom {
|
||||
tree,
|
||||
world,
|
||||
nodes_listening: FxHashMap::default(),
|
||||
dirty_nodes: NodesDirty {
|
||||
passes_updated,
|
||||
@@ -131,19 +141,27 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
||||
},
|
||||
node_watchers: Default::default(),
|
||||
workload,
|
||||
root_id,
|
||||
phantom: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tree_mut(&self) -> TreeMutView {
|
||||
self.world.borrow().unwrap()
|
||||
}
|
||||
|
||||
pub fn tree_ref(&self) -> TreeRefView {
|
||||
self.world.borrow().unwrap()
|
||||
}
|
||||
|
||||
pub fn create_node(&mut self, node: NodeType<V>) -> NodeMut<'_, V> {
|
||||
let mut node_entry = self.tree.create_node();
|
||||
let id = node_entry.id();
|
||||
let id = self.world.add_entity(node);
|
||||
self.tree_mut().create_node(id);
|
||||
self.dirty_nodes
|
||||
.passes_updated
|
||||
.entry(id)
|
||||
.or_default()
|
||||
.extend(self.dirty_nodes.passes.iter().map(|x| x.this_type_id));
|
||||
node_entry.insert(node);
|
||||
let watchers = self.node_watchers.clone();
|
||||
for watcher in &*watchers.read().unwrap() {
|
||||
watcher.on_node_added(NodeMut::new(id, self));
|
||||
@@ -157,7 +175,7 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
||||
if let Some(nodes) = self.nodes_listening.get(event) {
|
||||
let mut listening: Vec<_> = nodes
|
||||
.iter()
|
||||
.map(|id| (*id, self.tree.height(*id).unwrap()))
|
||||
.map(|id| (*id, self.tree_ref().height(*id).unwrap()))
|
||||
.collect();
|
||||
listening.sort_by(|(_, h1), (_, h2)| h1.cmp(h2).reverse());
|
||||
listening
|
||||
@@ -171,26 +189,29 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
||||
|
||||
/// Returns the id of the root node.
|
||||
pub fn root_id(&self) -> NodeId {
|
||||
self.tree.root()
|
||||
self.root_id
|
||||
}
|
||||
|
||||
pub fn get(&self, id: NodeId) -> Option<NodeRef<'_, V>> {
|
||||
self.tree.contains(id).then_some(NodeRef { id, dom: self })
|
||||
self.tree_ref()
|
||||
.contains(id)
|
||||
.then_some(NodeRef { id, dom: self })
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, id: NodeId) -> Option<NodeMut<'_, V>> {
|
||||
self.tree.contains(id).then(|| NodeMut::new(id, self))
|
||||
let contains = { self.tree_ref().contains(id) };
|
||||
contains.then(|| NodeMut::new(id, self))
|
||||
}
|
||||
|
||||
fn borrow_raw<'a, B: IntoBorrow>(&'a self) -> Result<B, GetStorage>
|
||||
where
|
||||
B::Borrow: shipyard::Borrow<'a, View = B>,
|
||||
{
|
||||
self.tree.nodes.borrow()
|
||||
self.world.borrow()
|
||||
}
|
||||
|
||||
fn borrow_node_type_mut(&self) -> Result<ViewMut<NodeType<V>>, GetStorage> {
|
||||
self.tree.nodes.borrow()
|
||||
self.world.borrow()
|
||||
}
|
||||
|
||||
/// Update the state of the dom, after appling some mutations. This will keep the nodes in the dom up to date with their VNode counterparts.
|
||||
@@ -202,34 +223,36 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
||||
let nodes_updated = std::mem::take(&mut self.dirty_nodes.nodes_updated);
|
||||
let dirty_nodes =
|
||||
DirtyNodeStates::with_passes(self.dirty_nodes.passes.iter().map(|p| p.this_type_id));
|
||||
let tree = self.tree_ref();
|
||||
for (node_id, passes) in passes {
|
||||
// remove any nodes that were created and then removed in the same mutations from the dirty nodes list
|
||||
if let Some(height) = self.tree.height(node_id) {
|
||||
if let Some(height) = tree.height(node_id) {
|
||||
for pass in passes {
|
||||
dirty_nodes.insert(pass, node_id, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let _ = self.tree.remove_unique::<DirtyNodeStates>();
|
||||
let _ = self.tree.remove_unique::<SendAnyMapWrapper>();
|
||||
self.tree.add_unique(dirty_nodes);
|
||||
self.tree.add_unique(SendAnyMapWrapper(ctx));
|
||||
self.tree.add_unique(DirtyNodes::default());
|
||||
let _ = self.world.remove_unique::<DirtyNodeStates>();
|
||||
let _ = self.world.remove_unique::<SendAnyMapWrapper>();
|
||||
self.world.add_unique(dirty_nodes);
|
||||
self.world.add_unique(SendAnyMapWrapper(ctx));
|
||||
self.world.add_unique(DirtyNodesResult::default());
|
||||
|
||||
self.workload.run_with_world(&self.tree.nodes).unwrap();
|
||||
self.workload.run_with_world(&self.world).unwrap();
|
||||
|
||||
let dirty = self.tree.remove_unique::<DirtyNodes>().unwrap();
|
||||
let dirty = self.world.remove_unique::<DirtyNodesResult>().unwrap();
|
||||
|
||||
(dirty.0, nodes_updated)
|
||||
}
|
||||
|
||||
pub fn traverse_depth_first(&self, mut f: impl FnMut(NodeRef<V>)) {
|
||||
let mut stack = vec![self.root_id()];
|
||||
let tree = self.tree_ref();
|
||||
while let Some(id) = stack.pop() {
|
||||
if let Some(node) = self.get(id) {
|
||||
f(node);
|
||||
if let Some(children) = self.tree.children_ids(id) {
|
||||
if let Some(children) = tree.children_ids(id) {
|
||||
stack.extend(children.iter().copied().rev());
|
||||
}
|
||||
}
|
||||
@@ -239,10 +262,11 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
||||
pub fn traverse_breadth_first(&self, mut f: impl FnMut(NodeRef<V>)) {
|
||||
let mut queue = VecDeque::new();
|
||||
queue.push_back(self.root_id());
|
||||
let tree = self.tree_ref();
|
||||
while let Some(id) = queue.pop_front() {
|
||||
if let Some(node) = self.get(id) {
|
||||
f(node);
|
||||
if let Some(children) = self.tree.children_ids(id) {
|
||||
if let Some(children) = tree.children_ids(id) {
|
||||
for id in children {
|
||||
queue.push_back(id);
|
||||
}
|
||||
@@ -254,8 +278,10 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
||||
pub fn traverse_depth_first_mut(&mut self, mut f: impl FnMut(NodeMut<V>)) {
|
||||
let mut stack = vec![self.root_id()];
|
||||
while let Some(id) = stack.pop() {
|
||||
if let Some(children) = self.tree.children_ids(id) {
|
||||
let children = children.iter().copied().rev().collect::<Vec<_>>();
|
||||
let tree = self.tree_ref();
|
||||
if let Some(mut children) = tree.children_ids(id) {
|
||||
drop(tree);
|
||||
children.reverse();
|
||||
if let Some(node) = self.get_mut(id) {
|
||||
let node = node;
|
||||
f(node);
|
||||
@@ -269,8 +295,9 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
||||
let mut queue = VecDeque::new();
|
||||
queue.push_back(self.root_id());
|
||||
while let Some(id) = queue.pop_front() {
|
||||
if let Some(children) = self.tree.children_ids(id) {
|
||||
let children = children.to_vec();
|
||||
let tree = self.tree_ref();
|
||||
if let Some(children) = tree.children_ids(id) {
|
||||
drop(tree);
|
||||
if let Some(node) = self.get_mut(id) {
|
||||
f(node);
|
||||
for id in children {
|
||||
@@ -349,7 +376,7 @@ pub trait NodeImmutable<V: FromAnyValue + Send + Sync>: Sized {
|
||||
|
||||
#[inline]
|
||||
fn child_ids(&self) -> Option<Vec<NodeId>> {
|
||||
self.real_dom().tree.children_ids(self.id())
|
||||
self.real_dom().tree_ref().children_ids(self.id())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -368,7 +395,7 @@ pub trait NodeImmutable<V: FromAnyValue + Send + Sync>: Sized {
|
||||
|
||||
#[inline]
|
||||
fn parent_id(&self) -> Option<NodeId> {
|
||||
self.real_dom().tree.parent_id(self.id())
|
||||
self.real_dom().tree_ref().parent_id(self.id())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -382,7 +409,7 @@ pub trait NodeImmutable<V: FromAnyValue + Send + Sync>: Sized {
|
||||
#[inline]
|
||||
fn next(&self) -> Option<NodeRef<V>> {
|
||||
let parent = self.parent_id()?;
|
||||
let children = self.real_dom().tree.children_ids(parent)?;
|
||||
let children = self.real_dom().tree_ref().children_ids(parent)?;
|
||||
let index = children.iter().position(|id| *id == self.id())?;
|
||||
if index + 1 < children.len() {
|
||||
Some(NodeRef {
|
||||
@@ -397,7 +424,7 @@ pub trait NodeImmutable<V: FromAnyValue + Send + Sync>: Sized {
|
||||
#[inline]
|
||||
fn prev(&self) -> Option<NodeRef<V>> {
|
||||
let parent = self.parent_id()?;
|
||||
let children = self.real_dom().tree.children_ids(parent)?;
|
||||
let children = self.real_dom().tree_ref().children_ids(parent)?;
|
||||
let index = children.iter().position(|id| *id == self.id())?;
|
||||
if index > 0 {
|
||||
Some(NodeRef {
|
||||
@@ -411,7 +438,7 @@ pub trait NodeImmutable<V: FromAnyValue + Send + Sync>: Sized {
|
||||
|
||||
#[inline]
|
||||
fn height(&self) -> u16 {
|
||||
self.real_dom().tree.height(self.id()).unwrap()
|
||||
self.real_dom().tree_ref().height(self.id()).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,13 +528,13 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
|
||||
.entry(self.id)
|
||||
.or_default()
|
||||
.insert(TypeId::of::<T>());
|
||||
self.dom.tree.insert(self.id, value);
|
||||
self.dom.world.add_component(self.id, value);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn next_mut(self) -> Option<NodeMut<'a, V>> {
|
||||
let parent = self.parent_id()?;
|
||||
let children = self.dom.tree.children_ids(parent)?;
|
||||
let children = self.dom.tree_mut().children_ids(parent)?;
|
||||
let index = children.iter().position(|id| *id == self.id)?;
|
||||
if index + 1 < children.len() {
|
||||
Some(NodeMut::new(children[index + 1], self.dom))
|
||||
@@ -519,7 +546,7 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
|
||||
#[inline]
|
||||
pub fn prev_mut(self) -> Option<NodeMut<'a, V>> {
|
||||
let parent = self.parent_id()?;
|
||||
let children = self.dom.tree.children_ids(parent)?;
|
||||
let children = self.dom.tree_ref().children_ids(parent)?;
|
||||
let index = children.iter().position(|id| *id == self.id)?;
|
||||
if index > 0 {
|
||||
Some(NodeMut::new(children[index - 1], self.dom))
|
||||
@@ -532,29 +559,31 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
|
||||
pub fn add_child(&mut self, child: NodeId) {
|
||||
self.dom.dirty_nodes.mark_child_changed(self.id);
|
||||
self.dom.dirty_nodes.mark_parent_added_or_removed(child);
|
||||
self.dom.tree.add_child(self.id, child);
|
||||
self.dom.tree_mut().add_child(self.id, child);
|
||||
NodeMut::new(child, self.dom).mark_moved();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn insert_after(&mut self, old: NodeId) {
|
||||
let id = self.id();
|
||||
if let Some(parent_id) = self.dom.tree.parent_id(old) {
|
||||
let parent_id = { self.dom.tree_ref().parent_id(old) };
|
||||
if let Some(parent_id) = parent_id {
|
||||
self.dom.dirty_nodes.mark_child_changed(parent_id);
|
||||
self.dom.dirty_nodes.mark_parent_added_or_removed(id);
|
||||
}
|
||||
self.dom.tree.insert_after(old, id);
|
||||
self.dom.tree_mut().insert_after(old, id);
|
||||
self.mark_moved();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn insert_before(&mut self, old: NodeId) {
|
||||
let id = self.id();
|
||||
if let Some(parent_id) = self.dom.tree.parent_id(old) {
|
||||
let parent_id = { self.dom.tree_ref().parent_id(old) };
|
||||
if let Some(parent_id) = parent_id {
|
||||
self.dom.dirty_nodes.mark_child_changed(parent_id);
|
||||
self.dom.dirty_nodes.mark_parent_added_or_removed(id);
|
||||
}
|
||||
self.dom.tree.insert_before(old, id);
|
||||
self.dom.tree_mut().insert_before(old, id);
|
||||
self.mark_moved();
|
||||
}
|
||||
|
||||
@@ -563,11 +592,11 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
|
||||
let id = self.id();
|
||||
{
|
||||
let RealDom {
|
||||
tree,
|
||||
world,
|
||||
nodes_listening,
|
||||
..
|
||||
} = &mut self.dom;
|
||||
let mut view: ViewMut<NodeType<V>> = tree.nodes.borrow().unwrap();
|
||||
let mut view: ViewMut<NodeType<V>> = world.borrow().unwrap();
|
||||
if let NodeType::Element(ElementNode { listeners, .. })
|
||||
| NodeType::Text(TextNode { listeners, .. }) = (&mut view).get(id).unwrap()
|
||||
{
|
||||
@@ -578,7 +607,8 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
|
||||
}
|
||||
}
|
||||
self.mark_removed();
|
||||
if let Some(parent_id) = self.real_dom_mut().tree.parent_id(id) {
|
||||
let parent_id = { self.dom.tree_ref().parent_id(id) };
|
||||
if let Some(parent_id) = parent_id {
|
||||
self.real_dom_mut()
|
||||
.dirty_nodes
|
||||
.mark_child_changed(parent_id);
|
||||
@@ -589,7 +619,7 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
|
||||
self.dom.get_mut(child).unwrap().remove();
|
||||
}
|
||||
}
|
||||
self.dom.tree.remove_single(id);
|
||||
self.dom.tree_mut().remove_single(id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -604,19 +634,19 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
|
||||
.mark_parent_added_or_removed(new);
|
||||
}
|
||||
let id = self.id();
|
||||
self.dom.tree.replace(id, new);
|
||||
self.dom.tree_mut().replace(id, new);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn add_event_listener(&mut self, event: &str) {
|
||||
let id = self.id();
|
||||
let RealDom {
|
||||
tree,
|
||||
world,
|
||||
dirty_nodes,
|
||||
nodes_listening,
|
||||
..
|
||||
} = &mut self.dom;
|
||||
let mut view: ViewMut<NodeType<V>> = tree.nodes.borrow().unwrap();
|
||||
let mut view: ViewMut<NodeType<V>> = world.borrow().unwrap();
|
||||
let node_type: &mut NodeType<V> = (&mut view).get(self.id).unwrap();
|
||||
if let NodeType::Element(ElementNode { listeners, .. })
|
||||
| NodeType::Text(TextNode { listeners, .. }) = node_type
|
||||
@@ -640,12 +670,12 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
|
||||
pub fn remove_event_listener(&mut self, event: &str) {
|
||||
let id = self.id();
|
||||
let RealDom {
|
||||
tree,
|
||||
world,
|
||||
dirty_nodes,
|
||||
nodes_listening,
|
||||
..
|
||||
} = &mut self.dom;
|
||||
let mut view: ViewMut<NodeType<V>> = tree.nodes.borrow().unwrap();
|
||||
let mut view: ViewMut<NodeType<V>> = world.borrow().unwrap();
|
||||
let node_type: &mut NodeType<V> = (&mut view).get(self.id).unwrap();
|
||||
if let NodeType::Element(ElementNode { listeners, .. })
|
||||
| NodeType::Text(TextNode { listeners, .. }) = node_type
|
||||
@@ -674,9 +704,9 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
|
||||
pub fn node_type_mut(&mut self) -> NodeTypeMut<'_, V> {
|
||||
let id = self.id();
|
||||
let RealDom {
|
||||
tree, dirty_nodes, ..
|
||||
world, dirty_nodes, ..
|
||||
} = &mut self.dom;
|
||||
let view: ViewMut<NodeType<V>> = tree.nodes.borrow().unwrap();
|
||||
let view: ViewMut<NodeType<V>> = world.borrow().unwrap();
|
||||
let node_type = ViewEntryMut::new(view, id);
|
||||
match &*node_type {
|
||||
NodeType::Element(_) => NodeTypeMut::Element(ElementNodeMut {
|
||||
@@ -857,3 +887,37 @@ impl<V: FromAnyValue + Send + Sync> ElementNodeMut<'_, V> {
|
||||
&self.element().listeners
|
||||
}
|
||||
}
|
||||
|
||||
fn construct_workload<V: FromAnyValue + Send + Sync>(passes: &mut [TypeErasedPass<V>]) -> Workload {
|
||||
let mut workload = Workload::new("Main Workload");
|
||||
let mut unresloved_workloads = passes
|
||||
.iter_mut()
|
||||
.enumerate()
|
||||
.map(|(i, pass)| {
|
||||
let workload = Some((pass.workload)(pass.dependants.clone()));
|
||||
(i, pass, workload)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
// set all the labels
|
||||
for (id, _, workload) in &mut unresloved_workloads {
|
||||
*workload = Some(workload.take().unwrap().tag(id.to_string()));
|
||||
}
|
||||
// mark any dependancies
|
||||
for i in 0..unresloved_workloads.len() {
|
||||
let (_, pass, _) = &unresloved_workloads[i];
|
||||
for ty_id in pass.combined_dependancy_type_ids.clone() {
|
||||
let &(dependancy_id, _, _) = unresloved_workloads
|
||||
.iter()
|
||||
.find(|(_, pass, _)| pass.this_type_id == ty_id)
|
||||
.unwrap();
|
||||
let (_, _, workload) = &mut unresloved_workloads[i];
|
||||
*workload = workload
|
||||
.take()
|
||||
.map(|workload| workload.tag(dependancy_id.to_string()));
|
||||
}
|
||||
}
|
||||
for (_, _, mut workload_system) in unresloved_workloads {
|
||||
workload = workload.with_system(workload_system.take().unwrap());
|
||||
}
|
||||
workload
|
||||
}
|
||||
@@ -1,63 +1,65 @@
|
||||
use crate::NodeId;
|
||||
use shipyard::{Component, EntitiesView, EntityId, Get, Unique, View, ViewMut, World};
|
||||
use shipyard::{Component, EntitiesViewMut, Get, View, ViewMut};
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Component)]
|
||||
pub(crate) struct Node {
|
||||
pub struct Node {
|
||||
parent: Option<NodeId>,
|
||||
children: Vec<NodeId>,
|
||||
height: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Tree {
|
||||
pub(crate) nodes: World,
|
||||
root: NodeId,
|
||||
pub type TreeRefView<'a> = View<'a, Node>;
|
||||
pub type TreeMutView<'a> = (EntitiesViewMut<'a>, ViewMut<'a, Node>);
|
||||
|
||||
pub trait TreeRef {
|
||||
fn parent_id(&self, id: NodeId) -> Option<NodeId>;
|
||||
fn children_ids(&self, id: NodeId) -> Option<Vec<NodeId>>;
|
||||
fn height(&self, id: NodeId) -> Option<u16>;
|
||||
fn contains(&self, id: NodeId) -> bool;
|
||||
}
|
||||
|
||||
impl Tree {
|
||||
pub fn new() -> Self {
|
||||
let mut nodes = World::default();
|
||||
let node = Node {
|
||||
parent: None,
|
||||
children: Vec::new(),
|
||||
height: 0,
|
||||
};
|
||||
let root = nodes.add_entity((node,));
|
||||
Self { nodes, root }
|
||||
pub trait TreeMut: TreeRef {
|
||||
fn remove(&mut self, id: NodeId);
|
||||
fn remove_single(&mut self, id: NodeId);
|
||||
fn set_height(&mut self, node: NodeId, height: u16);
|
||||
fn create_node(&mut self, id: NodeId);
|
||||
fn add_child(&mut self, parent: NodeId, new: NodeId);
|
||||
fn replace(&mut self, old_id: NodeId, new_id: NodeId);
|
||||
fn insert_before(&mut self, old_id: NodeId, new_id: NodeId);
|
||||
fn insert_after(&mut self, old_id: NodeId, new_id: NodeId);
|
||||
}
|
||||
|
||||
impl<'a> TreeRef for TreeRefView<'a> {
|
||||
fn parent_id(&self, id: NodeId) -> Option<NodeId> {
|
||||
self.get(id).unwrap().parent
|
||||
}
|
||||
|
||||
pub fn add_unique<T: Unique + Send + Sync>(&mut self, data: T) {
|
||||
self.nodes.add_unique(data);
|
||||
fn children_ids(&self, id: NodeId) -> Option<Vec<NodeId>> {
|
||||
Some(self.get(id).unwrap().children.clone())
|
||||
}
|
||||
|
||||
pub fn remove_unique<T: Unique + Send + Sync>(
|
||||
&mut self,
|
||||
) -> Result<T, shipyard::error::UniqueRemove> {
|
||||
self.nodes.remove_unique::<T>()
|
||||
fn height(&self, id: NodeId) -> Option<u16> {
|
||||
Some(self.get(id).unwrap().height)
|
||||
}
|
||||
|
||||
fn node_data(&self) -> View<Node> {
|
||||
self.nodes.borrow().unwrap()
|
||||
fn contains(&self, id: NodeId) -> bool {
|
||||
self.get(id).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
fn node_data_mut(&self) -> ViewMut<Node> {
|
||||
self.nodes.borrow().unwrap()
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, id: NodeId) {
|
||||
fn recurse(tree: &mut Tree, id: NodeId) {
|
||||
impl<'a> TreeMut for TreeMutView<'a> {
|
||||
fn remove(&mut self, id: NodeId) {
|
||||
fn recurse<'a>(tree: &mut TreeMutView<'a>, id: NodeId) {
|
||||
let children = tree.children_ids(id);
|
||||
if let Some(children) = children {
|
||||
for child in children {
|
||||
recurse(tree, child);
|
||||
}
|
||||
}
|
||||
|
||||
tree.nodes.delete_entity(id);
|
||||
}
|
||||
{
|
||||
let mut node_data_mut = self.node_data_mut();
|
||||
let mut node_data_mut = &mut self.1;
|
||||
if let Some(parent) = node_data_mut.get(id).unwrap().parent {
|
||||
let parent = (&mut node_data_mut).get(parent).unwrap();
|
||||
parent.children.retain(|&child| child != id);
|
||||
@@ -67,21 +69,19 @@ impl Tree {
|
||||
recurse(self, id);
|
||||
}
|
||||
|
||||
pub fn remove_single(&mut self, id: NodeId) {
|
||||
fn remove_single(&mut self, id: NodeId) {
|
||||
{
|
||||
let mut node_data_mut = self.node_data_mut();
|
||||
let mut node_data_mut = &mut self.1;
|
||||
if let Some(parent) = node_data_mut.get(id).unwrap().parent {
|
||||
let parent = (&mut node_data_mut).get(parent).unwrap();
|
||||
parent.children.retain(|&child| child != id);
|
||||
}
|
||||
}
|
||||
|
||||
self.nodes.delete_entity(id);
|
||||
}
|
||||
|
||||
fn set_height(&mut self, node: NodeId, height: u16) {
|
||||
let children = {
|
||||
let mut node_data_mut = self.node_data_mut();
|
||||
let mut node_data_mut = &mut self.1;
|
||||
let mut node = (&mut node_data_mut).get(node).unwrap();
|
||||
node.height = height;
|
||||
node.children.clone()
|
||||
@@ -91,19 +91,23 @@ impl Tree {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_node(&mut self) -> NodeBuilder<'_> {
|
||||
let node = self.nodes.add_entity((Node {
|
||||
parent: None,
|
||||
children: Vec::new(),
|
||||
height: 0,
|
||||
},));
|
||||
NodeBuilder { tree: self, node }
|
||||
fn create_node(&mut self, id: NodeId) {
|
||||
let (entities, node_data_mut) = self;
|
||||
entities.add_component(
|
||||
id,
|
||||
node_data_mut,
|
||||
Node {
|
||||
parent: None,
|
||||
children: Vec::new(),
|
||||
height: 0,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
pub fn add_child(&mut self, parent: NodeId, new: NodeId) {
|
||||
fn add_child(&mut self, parent: NodeId, new: NodeId) {
|
||||
let height;
|
||||
{
|
||||
let mut node_state = self.node_data_mut();
|
||||
let mut node_state = &mut self.1;
|
||||
(&mut node_state).get(new).unwrap().parent = Some(parent);
|
||||
let parent = (&mut node_state).get(parent).unwrap();
|
||||
parent.children.push(new);
|
||||
@@ -112,9 +116,9 @@ impl Tree {
|
||||
self.set_height(new, height);
|
||||
}
|
||||
|
||||
pub fn replace(&mut self, old_id: NodeId, new_id: NodeId) {
|
||||
fn replace(&mut self, old_id: NodeId, new_id: NodeId) {
|
||||
{
|
||||
let mut node_state = self.node_data_mut();
|
||||
let mut node_state = &mut self.1;
|
||||
// update the parent's link to the child
|
||||
if let Some(parent_id) = node_state.get(old_id).unwrap().parent {
|
||||
let parent = (&mut node_state).get(parent_id).unwrap();
|
||||
@@ -125,7 +129,6 @@ impl Tree {
|
||||
}
|
||||
}
|
||||
let height = parent.height + 1;
|
||||
drop(node_state);
|
||||
self.set_height(new_id, height);
|
||||
}
|
||||
}
|
||||
@@ -133,8 +136,8 @@ impl Tree {
|
||||
self.remove(old_id);
|
||||
}
|
||||
|
||||
pub fn insert_before(&mut self, old_id: NodeId, new_id: NodeId) {
|
||||
let mut node_state = self.node_data_mut();
|
||||
fn insert_before(&mut self, old_id: NodeId, new_id: NodeId) {
|
||||
let mut node_state = &mut self.1;
|
||||
let old_node = node_state.get(old_id).unwrap();
|
||||
let parent_id = old_node.parent.expect("tried to insert before root");
|
||||
(&mut node_state).get(new_id).unwrap().parent = Some(parent_id);
|
||||
@@ -146,12 +149,11 @@ impl Tree {
|
||||
.unwrap();
|
||||
parent.children.insert(index, new_id);
|
||||
let height = parent.height + 1;
|
||||
drop(node_state);
|
||||
self.set_height(new_id, height);
|
||||
}
|
||||
|
||||
pub fn insert_after(&mut self, old_id: NodeId, new_id: NodeId) {
|
||||
let mut node_state = self.node_data_mut();
|
||||
fn insert_after(&mut self, old_id: NodeId, new_id: NodeId) {
|
||||
let mut node_state = &mut self.1;
|
||||
let old_node = node_state.get(old_id).unwrap();
|
||||
let parent_id = old_node.parent.expect("tried to insert before root");
|
||||
(&mut node_state).get(new_id).unwrap().parent = Some(parent_id);
|
||||
@@ -163,36 +165,29 @@ impl Tree {
|
||||
.unwrap();
|
||||
parent.children.insert(index + 1, new_id);
|
||||
let height = parent.height + 1;
|
||||
drop(node_state);
|
||||
self.set_height(new_id, height);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert<T: Component + Sync + Send>(&mut self, id: NodeId, value: T) {
|
||||
self.nodes.add_component(id, value);
|
||||
}
|
||||
|
||||
pub fn contains(&self, id: NodeId) -> bool {
|
||||
self.nodes.borrow::<EntitiesView>().unwrap().is_alive(id)
|
||||
}
|
||||
|
||||
pub fn root(&self) -> NodeId {
|
||||
self.root
|
||||
}
|
||||
|
||||
pub fn parent_id(&self, id: NodeId) -> Option<NodeId> {
|
||||
let node_data = self.node_data();
|
||||
impl<'a> TreeRef for TreeMutView<'a> {
|
||||
fn parent_id(&self, id: NodeId) -> Option<NodeId> {
|
||||
let node_data = &self.1;
|
||||
node_data.get(id).unwrap().parent
|
||||
}
|
||||
|
||||
pub fn children_ids(&self, id: NodeId) -> Option<Vec<NodeId>> {
|
||||
let node_data = self.node_data();
|
||||
fn children_ids(&self, id: NodeId) -> Option<Vec<NodeId>> {
|
||||
let node_data = &self.1;
|
||||
node_data.get(id).map(|node| node.children.clone()).ok()
|
||||
}
|
||||
|
||||
pub fn height(&self, id: NodeId) -> Option<u16> {
|
||||
let node_data = self.node_data();
|
||||
fn height(&self, id: NodeId) -> Option<u16> {
|
||||
let node_data = &self.1;
|
||||
node_data.get(id).map(|node| node.height).ok()
|
||||
}
|
||||
|
||||
fn contains(&self, id: NodeId) -> bool {
|
||||
self.1.get(id).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -326,18 +321,3 @@ fn deletion() {
|
||||
assert_eq!(*tree.get::<i32>(parent).unwrap(), 0);
|
||||
assert_eq!(tree.get::<i32>(after), None);
|
||||
}
|
||||
|
||||
pub struct NodeBuilder<'a> {
|
||||
tree: &'a mut Tree,
|
||||
node: EntityId,
|
||||
}
|
||||
|
||||
impl<'a> NodeBuilder<'a> {
|
||||
pub fn insert<T: Component + Send + Sync>(&mut self, component: T) {
|
||||
self.tree.insert(self.node, component);
|
||||
}
|
||||
|
||||
pub fn id(&self) -> EntityId {
|
||||
self.node
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user