WIP: use shipyard ecs
This commit is contained in:
1 parent
fe3ad8ebe9
commit
b91e010ac7
12 files changed
+567
-738
No files matched your search
@@ -0,0 +1,2 @@
|
||||
/target
|
||||
Cargo.lock
|
||||
@@ -0,0 +1,26 @@
|
||||
[package]
|
||||
name = "dioxus-native-core-macro"
|
||||
version = "0.3.0"
|
||||
edition = "2021"
|
||||
description = "Build natively rendered apps with Dioxus"
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/DioxusLabs/dioxus/"
|
||||
homepage = "https://dioxuslabs.com"
|
||||
documentation = "https://dioxuslabs.com"
|
||||
keywords = ["dom", "ui", "gui", "react"]
|
||||
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[dependencies]
|
||||
syn = { version = "1.0.11", features = ["extra-traits", "full"] }
|
||||
quote = "1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
smallvec = "1.6"
|
||||
rustc-hash = "1.1.0"
|
||||
anymap = "0.12.1"
|
||||
dioxus = { path = "../dioxus" }
|
||||
dioxus-native-core = { path = "../native-core" }
|
||||
@@ -0,0 +1,43 @@
|
||||
# Dioxus Native Core Macro
|
||||
|
||||
[![Crates.io][crates-badge]][crates-url]
|
||||
[![MIT licensed][mit-badge]][mit-url]
|
||||
[![Build Status][actions-badge]][actions-url]
|
||||
[![Discord chat][discord-badge]][discord-url]
|
||||
|
||||
[crates-badge]: https://img.shields.io/crates/v/dioxus-native-core-macro.svg
|
||||
[crates-url]: https://crates.io/crates/dioxus-native-core-macro
|
||||
|
||||
[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg
|
||||
[mit-url]: https://github.com/dioxuslabs/dioxus/blob/master/LICENSE
|
||||
|
||||
[actions-badge]: https://github.com/dioxuslabs/dioxus/actions/workflows/main.yml/badge.svg
|
||||
[actions-url]: https://github.com/dioxuslabs/dioxus/actions?query=workflow%3ACI+branch%3Amaster
|
||||
|
||||
[discord-badge]: https://img.shields.io/discord/899851952891002890.svg?logo=discord&style=flat-square
|
||||
[discord-url]: https://discord.gg/XgGxMSkvUM
|
||||
|
||||
[Website](https://dioxuslabs.com) |
|
||||
[Guides](https://dioxuslabs.com/docs/0.3/guide/en/) |
|
||||
[API Docs](https://docs.rs/dioxus-native-core-macro/latest/dioxus_native_core_macro) |
|
||||
[Chat](https://discord.gg/XgGxMSkvUM)
|
||||
|
||||
|
||||
## Overview
|
||||
|
||||
`dioxus-native-core-macro` provides a handful of macros used by native-core for native renderers like TUI, Blitz, and Freya to derive their state.
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
- Report issues on our [issue tracker](https://github.com/dioxuslabs/dioxus/issues).
|
||||
- Join the discord and ask questions!
|
||||
|
||||
## License
|
||||
This project is licensed under the [MIT license].
|
||||
|
||||
[mit license]: https://github.com/DioxusLabs/dioxus/blob/master/LICENSE-MIT
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in Dioxus by you shall be licensed as MIT without any additional
|
||||
terms or conditions.
|
||||
@@ -0,0 +1,22 @@
|
||||
extern crate proc_macro;
|
||||
|
||||
mod sorted_slice;
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
/// A helper attribute for deriving `State` for a struct.
|
||||
#[proc_macro_attribute]
|
||||
pub fn my_attribute(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let impl_block: syn::ItemImpl = syn::parse(input).unwrap();
|
||||
quote!(#impl_block).into()
|
||||
}
|
||||
@@ -28,6 +28,8 @@ hashbrown = { version = "0.13.2", features = ["raw"] }
|
||||
lightningcss = "1.0.0-alpha.39"
|
||||
|
||||
rayon = "1.6.1"
|
||||
shipyard = "0.6.2"
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.8.5"
|
||||
@@ -37,4 +39,4 @@ dioxus-native-core = { path = ".", features = ["dioxus"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
dioxus = ["dioxus-core"]
|
||||
dioxus = ["dioxus-core"]
|
||||
@@ -1,5 +1,6 @@
|
||||
use dioxus_core::{BorrowedAttributeValue, ElementId, Mutations, TemplateNode};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use shipyard::Component;
|
||||
|
||||
use crate::{
|
||||
node::{
|
||||
@@ -11,6 +12,9 @@ use crate::{
|
||||
NodeId, NodeMut, RealDom,
|
||||
};
|
||||
|
||||
#[derive(Component)]
|
||||
struct ElementIdComponent(ElementId);
|
||||
|
||||
pub struct DioxusState {
|
||||
templates: FxHashMap<String, Vec<NodeId>>,
|
||||
stack: Vec<NodeId>,
|
||||
@@ -19,10 +23,9 @@ pub struct DioxusState {
|
||||
|
||||
impl DioxusState {
|
||||
pub fn create(rdom: &mut RealDom) -> Self {
|
||||
rdom.insert_slab::<ElementId>();
|
||||
let root_id = rdom.root_id();
|
||||
let mut root = rdom.get_mut(root_id).unwrap();
|
||||
root.insert(ElementId(0));
|
||||
root.insert(ElementIdComponent(ElementId(0)));
|
||||
Self {
|
||||
templates: FxHashMap::default(),
|
||||
stack: vec![root_id],
|
||||
@@ -40,7 +43,7 @@ impl DioxusState {
|
||||
|
||||
fn set_element_id(&mut self, mut node: NodeMut, element_id: ElementId) {
|
||||
let node_id = node.id();
|
||||
node.insert(element_id);
|
||||
node.insert(ElementIdComponent(element_id));
|
||||
if self.node_id_mapping.len() <= element_id.0 {
|
||||
self.node_id_mapping.resize(element_id.0 + 1, None);
|
||||
}
|
||||
@@ -104,9 +107,11 @@ impl DioxusState {
|
||||
let node = rdom.get_mut(node_id).unwrap();
|
||||
self.set_element_id(node, id);
|
||||
let mut node = rdom.get_mut(node_id).unwrap();
|
||||
if let NodeTypeMut::Text(text) = node.node_type_mut() {
|
||||
*text = value.to_string();
|
||||
let node_type_mut = node.node_type_mut();
|
||||
if let NodeTypeMut::Text(mut text) = node_type_mut {
|
||||
*text.text_mut() = value.to_string();
|
||||
} else {
|
||||
drop(node_type_mut);
|
||||
node.set_type(NodeType::Text(TextNode {
|
||||
text: value.to_string(),
|
||||
listeners: FxHashSet::default(),
|
||||
@@ -161,7 +166,8 @@ impl DioxusState {
|
||||
} => {
|
||||
let node_id = self.element_to_node_id(id);
|
||||
let mut node = rdom.get_mut(node_id).unwrap();
|
||||
if let NodeTypeMut::Element(element) = &mut node.node_type_mut() {
|
||||
let mut node_type_mut = node.node_type_mut();
|
||||
if let NodeTypeMut::Element(element) = &mut node_type_mut {
|
||||
if let BorrowedAttributeValue::None = &value {
|
||||
element.remove_attributes(&OwnedAttributeDiscription {
|
||||
name: name.to_string(),
|
||||
@@ -181,8 +187,9 @@ impl DioxusState {
|
||||
SetText { value, id } => {
|
||||
let node_id = self.element_to_node_id(id);
|
||||
let mut node = rdom.get_mut(node_id).unwrap();
|
||||
if let NodeTypeMut::Text(text) = node.node_type_mut() {
|
||||
*text = value.to_string();
|
||||
let node_type_mut = node.node_type_mut();
|
||||
if let NodeTypeMut::Text(mut text) = node_type_mut {
|
||||
*text.text_mut() = value.to_string();
|
||||
}
|
||||
}
|
||||
NewEventListener { name, id } => {
|
||||
@@ -260,7 +267,8 @@ fn create_template_node(rdom: &mut RealDom, node: &TemplateNode) -> NodeId {
|
||||
|
||||
pub trait NodeImmutableDioxusExt<V: FromAnyValue + Send + Sync>: NodeImmutable<V> {
|
||||
fn mounted_id(&self) -> Option<ElementId> {
|
||||
self.get().copied()
|
||||
let id = self.get::<ElementIdComponent>();
|
||||
id.map(|id| id.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ pub use passes::AnyMapLike;
|
||||
pub use passes::{Dependancy, State, TypeErasedPass};
|
||||
pub use real_dom::{NodeMut, NodeRef, RealDom};
|
||||
use rustc_hash::FxHasher;
|
||||
pub use tree::NodeId;
|
||||
|
||||
#[cfg(feature = "dioxus")]
|
||||
pub mod dioxus;
|
||||
@@ -18,13 +17,14 @@ mod passes;
|
||||
pub mod real_dom;
|
||||
pub mod tree;
|
||||
pub mod utils;
|
||||
pub use shipyard::EntityId as NodeId;
|
||||
|
||||
pub mod prelude {
|
||||
pub use crate::node::{ElementNode, FromAnyValue, NodeType, OwnedAttributeView, TextNode};
|
||||
pub use crate::node_ref::{AttributeMaskBuilder, NodeMaskBuilder, NodeView};
|
||||
pub use crate::passes::{Dependancy, State};
|
||||
pub use crate::real_dom::{NodeImmutable, NodeMut, NodeRef, RealDom};
|
||||
pub use crate::tree::NodeId;
|
||||
pub use crate::NodeId;
|
||||
pub use crate::SendAnyMap;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use shipyard::Component;
|
||||
use std::{any::Any, fmt::Debug};
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
@@ -25,7 +26,7 @@ impl TextNode {
|
||||
}
|
||||
|
||||
/// A type of node with data specific to the node type. The types are a subset of the [VNode] types.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Component)]
|
||||
pub enum NodeType<V: FromAnyValue = ()> {
|
||||
Text(TextNode),
|
||||
Element(ElementNode<V>),
|
||||
|
||||
+151
-202
@@ -1,17 +1,15 @@
|
||||
use anymap::AnyMap;
|
||||
use core::panic;
|
||||
use parking_lot::RwLock;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use shipyard::{Component, IntoBorrow, Unique, View, WorkloadSystem};
|
||||
use std::any::{Any, TypeId};
|
||||
use std::collections::BTreeMap;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::node::{FromAnyValue, NodeType};
|
||||
use crate::node::FromAnyValue;
|
||||
use crate::node_ref::{NodeMaskBuilder, NodeView};
|
||||
use crate::real_dom::RealDom;
|
||||
use crate::tree::{SlabEntry, Tree, TreeStateView};
|
||||
use crate::{FxDashSet, SendAnyMap};
|
||||
use crate::SendAnyMap;
|
||||
use crate::{NodeId, NodeMask};
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -21,7 +19,7 @@ struct DirtyNodes {
|
||||
|
||||
impl DirtyNodes {
|
||||
pub fn add_node(&mut self, node_id: NodeId) {
|
||||
let node_id = node_id.0;
|
||||
let node_id = node_id.uindex();
|
||||
let index = node_id / 64;
|
||||
let bit = node_id % 64;
|
||||
let encoded = 1 << bit;
|
||||
@@ -37,17 +35,17 @@ impl DirtyNodes {
|
||||
self.passes_dirty.iter().all(|dirty| *dirty == 0)
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Option<NodeId> {
|
||||
pub fn pop(&mut self) -> Option<usize> {
|
||||
let index = self.passes_dirty.iter().position(|dirty| *dirty != 0)?;
|
||||
let passes = self.passes_dirty[index];
|
||||
let node_id = passes.trailing_zeros();
|
||||
let encoded = 1 << node_id;
|
||||
self.passes_dirty[index] &= !encoded;
|
||||
Some(NodeId((index * 64) + node_id as usize))
|
||||
Some((index * 64) + node_id as usize)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Unique)]
|
||||
pub struct DirtyNodeStates {
|
||||
dirty: Arc<FxHashMap<TypeId, RwLock<BTreeMap<u16, DirtyNodes>>>>,
|
||||
}
|
||||
@@ -76,7 +74,7 @@ impl DirtyNodeStates {
|
||||
}
|
||||
}
|
||||
|
||||
fn pop_front(&self, pass_id: TypeId) -> Option<(u16, NodeId)> {
|
||||
fn pop_front(&self, pass_id: TypeId) -> Option<(u16, usize)> {
|
||||
let mut values = self.dirty.get(&pass_id)?.write();
|
||||
let mut value = values.first_entry()?;
|
||||
let height = *value.key();
|
||||
@@ -89,7 +87,7 @@ impl DirtyNodeStates {
|
||||
Some((height, id))
|
||||
}
|
||||
|
||||
fn pop_back(&self, pass_id: TypeId) -> Option<(u16, NodeId)> {
|
||||
fn pop_back(&self, pass_id: TypeId) -> Option<(u16, usize)> {
|
||||
let mut values = self.dirty.get(&pass_id)?.write();
|
||||
let mut value = values.last_entry()?;
|
||||
let height = *value.key();
|
||||
@@ -110,6 +108,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;
|
||||
type CombinedDependencies: Dependancy;
|
||||
/// This is a mask of what aspects of the node are required to run this pass
|
||||
const NODE_MASK: NodeMaskBuilder<'static>;
|
||||
|
||||
@@ -131,47 +130,43 @@ pub trait State<V: FromAnyValue + Send + Sync = ()>: Any + Send + Sync {
|
||||
children: Option<Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>>,
|
||||
context: &SendAnyMap,
|
||||
) -> Self;
|
||||
}
|
||||
|
||||
fn validate() {
|
||||
// this type should not be a node dependency
|
||||
for type_id in Self::node_type_ids().iter().copied() {
|
||||
if type_id == TypeId::of::<Self>() {
|
||||
panic!("The current type cannot be a node dependency");
|
||||
}
|
||||
}
|
||||
// this type cannot be both a parent and child dependency
|
||||
assert!(
|
||||
!(Self::parent_type_ids()
|
||||
.iter()
|
||||
.any(|type_id| *type_id == TypeId::of::<Self>())
|
||||
&& Self::child_type_ids()
|
||||
.iter()
|
||||
.any(|type_id| *type_id == TypeId::of::<Self>())),
|
||||
"The current type cannot be a parent and child dependency"
|
||||
);
|
||||
// no states have the same type id
|
||||
if Self::child_type_ids()
|
||||
.iter()
|
||||
.collect::<FxHashSet<_>>()
|
||||
.len()
|
||||
!= Self::child_type_ids().len()
|
||||
|| Self::parent_type_ids()
|
||||
.iter()
|
||||
.collect::<FxHashSet<_>>()
|
||||
.len()
|
||||
!= Self::parent_type_ids().len()
|
||||
|| Self::node_type_ids().iter().collect::<FxHashSet<_>>().len()
|
||||
!= Self::node_type_ids().len()
|
||||
{
|
||||
panic!("all states must have unique type ids");
|
||||
}
|
||||
}
|
||||
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,
|
||||
{
|
||||
Self::validate();
|
||||
let node_mask = Self::NODE_MASK.build();
|
||||
TypeErasedPass {
|
||||
this_type_id: TypeId::of::<Self>(),
|
||||
@@ -181,35 +176,7 @@ pub trait State<V: FromAnyValue + Send + Sync = ()>: Any + Send + Sync {
|
||||
dependants: FxHashSet::default(),
|
||||
mask: node_mask.clone(),
|
||||
pass_direction: Self::pass_direction(),
|
||||
pass: 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,
|
||||
create: Box::new(|tree: &mut Tree| tree.insert_slab::<Self>()) as CreatePassCallback,
|
||||
workload: Some(Self::workload_system()),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -257,58 +224,57 @@ pub struct TypeErasedPass<V: FromAnyValue + Send = ()> {
|
||||
pub(crate) combined_dependancy_type_ids: FxHashSet<TypeId>,
|
||||
pub(crate) dependants: FxHashSet<TypeId>,
|
||||
pub(crate) mask: NodeMask,
|
||||
pass: PassCallback,
|
||||
pub(crate) create: CreatePassCallback,
|
||||
pub(crate) workload: Option<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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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 {
|
||||
@@ -317,9 +283,6 @@ pub enum PassDirection {
|
||||
AnyOrder,
|
||||
}
|
||||
|
||||
type PassCallback = Box<dyn Fn(NodeId, &mut TreeStateView, &SendAnyMap) -> bool + Send + Sync>;
|
||||
type CreatePassCallback = Box<dyn Fn(&mut Tree) + Send + Sync>;
|
||||
|
||||
pub trait AnyMapLike<'a> {
|
||||
fn get<T: Any + Sync + Send>(self) -> Option<&'a T>;
|
||||
}
|
||||
@@ -337,25 +300,17 @@ impl<'a> AnyMapLike<'a> for &'a SendAnyMap {
|
||||
}
|
||||
|
||||
pub trait Dependancy {
|
||||
type ElementBorrowed<'a>
|
||||
where
|
||||
Self: 'a;
|
||||
type ElementBorrowed<'a>: IntoBorrow;
|
||||
|
||||
fn borrow_elements_from<'a, T: AnyMapLike<'a> + Copy>(
|
||||
map: T,
|
||||
) -> Option<Self::ElementBorrowed<'a>>;
|
||||
fn type_ids() -> Box<[TypeId]>;
|
||||
fn type_ids() -> Box<[TypeId]> {
|
||||
Box::new([])
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_dependancy {
|
||||
($($t:ident),*) => {
|
||||
impl< $($t: Any + Send + Sync),* > Dependancy for ($($t,)*) {
|
||||
type ElementBorrowed<'a> = ($(&'a $t,)*) where Self: 'a;
|
||||
|
||||
#[allow(unused_variables, clippy::unused_unit, non_snake_case)]
|
||||
fn borrow_elements_from<'a, T: AnyMapLike<'a> + Copy>(map: T) -> Option<Self::ElementBorrowed<'a>> {
|
||||
Some(($(map.get::<$t>()?,)*))
|
||||
}
|
||||
impl< $($t: Send + Sync + Component),* > Dependancy for ($($t,)*) {
|
||||
type ElementBorrowed<'a> = ($(View<'a, $t>,)*);
|
||||
|
||||
fn type_ids() -> Box<[TypeId]> {
|
||||
Box::new([$(TypeId::of::<$t>()),*])
|
||||
@@ -375,66 +330,60 @@ 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);
|
||||
impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K);
|
||||
impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L);
|
||||
impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M);
|
||||
impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
|
||||
impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
|
||||
impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
|
||||
|
||||
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()
|
||||
}
|
||||
// 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,6 +1,13 @@
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use std::any::{Any, TypeId};
|
||||
use shipyard::error::GetStorage;
|
||||
use shipyard::track::Untracked;
|
||||
use shipyard::{
|
||||
Component, Get, IntoBorrow, ScheduledWorkload, System, Unique, View, ViewMut, Workload,
|
||||
WorkloadSystem,
|
||||
};
|
||||
use std::any::TypeId;
|
||||
use std::collections::VecDeque;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use crate::node::{
|
||||
@@ -8,11 +15,18 @@ use crate::node::{
|
||||
};
|
||||
use crate::node_ref::{NodeMask, NodeMaskBuilder};
|
||||
use crate::node_watcher::NodeWatcher;
|
||||
use crate::passes::{resolve_passes, DirtyNodeStates, TypeErasedPass};
|
||||
use crate::passes::{DirtyNodeStates, TypeErasedPass};
|
||||
use crate::prelude::AttributeMaskBuilder;
|
||||
use crate::tree::{NodeId, Tree};
|
||||
use crate::tree::Tree;
|
||||
use crate::NodeId;
|
||||
use crate::{FxDashSet, SendAnyMap};
|
||||
|
||||
#[derive(Unique)]
|
||||
struct SendAnyMapWrapper(SendAnyMap);
|
||||
|
||||
#[derive(Unique, Default)]
|
||||
struct DirtyNodes(FxDashSet<NodeId>);
|
||||
|
||||
pub(crate) struct NodesDirty<V: FromAnyValue + Send + Sync> {
|
||||
passes_updated: FxHashMap<NodeId, FxHashSet<TypeId>>,
|
||||
nodes_updated: FxHashMap<NodeId, NodeMask>,
|
||||
@@ -66,16 +80,19 @@ pub struct RealDom<V: FromAnyValue + Send + Sync = ()> {
|
||||
nodes_listening: FxHashMap<String, FxHashSet<NodeId>>,
|
||||
pub(crate) dirty_nodes: NodesDirty<V>,
|
||||
node_watchers: NodeWatchers<V>,
|
||||
workload: ScheduledWorkload,
|
||||
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();
|
||||
tree.insert_slab::<NodeType<V>>();
|
||||
for pass in passes.iter() {
|
||||
(pass.create)(&mut tree);
|
||||
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, _) = workload.build().unwrap();
|
||||
let root_id = tree.root();
|
||||
let root_node: NodeType<V> = NodeType::Element(ElementNode {
|
||||
tag: "Root".to_string(),
|
||||
@@ -101,7 +118,6 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
||||
let mut passes_updated = FxHashMap::default();
|
||||
let mut nodes_updated = FxHashMap::default();
|
||||
|
||||
let root_id = NodeId(0);
|
||||
passes_updated.insert(root_id, passes.iter().map(|x| x.this_type_id).collect());
|
||||
nodes_updated.insert(root_id, NodeMaskBuilder::ALL.build());
|
||||
|
||||
@@ -114,6 +130,7 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
||||
passes,
|
||||
},
|
||||
node_watchers: Default::default(),
|
||||
workload,
|
||||
phantom: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -152,12 +169,6 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the number of nodes in the dom.
|
||||
pub fn size(&self) -> usize {
|
||||
// The dom has a root node, ignore it.
|
||||
self.tree.size() - 1
|
||||
}
|
||||
|
||||
/// Returns the id of the root node.
|
||||
pub fn root_id(&self) -> NodeId {
|
||||
self.tree.root()
|
||||
@@ -171,16 +182,21 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
||||
self.tree.contains(id).then(|| NodeMut::new(id, self))
|
||||
}
|
||||
|
||||
/// WARNING: This escapes the reactive system that the real dom uses. Any changes made with this method will not trigger updates in states when [RealDom::update_state] is called.
|
||||
pub fn get_state_mut_raw<T: Any + Send + Sync>(&mut self, id: NodeId) -> Option<&mut T> {
|
||||
self.tree.get_mut(id)
|
||||
fn borrow_raw<'a, B: IntoBorrow>(&'a self) -> Result<B, GetStorage>
|
||||
where
|
||||
B::Borrow: shipyard::Borrow<'a, View = B>,
|
||||
{
|
||||
self.tree.nodes.borrow()
|
||||
}
|
||||
|
||||
fn borrow_node_type_mut(&self) -> Result<ViewMut<NodeType<V>>, GetStorage> {
|
||||
self.tree.nodes.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.
|
||||
pub fn update_state(
|
||||
&mut self,
|
||||
ctx: SendAnyMap,
|
||||
parallel: bool,
|
||||
) -> (FxDashSet<NodeId>, FxHashMap<NodeId, NodeMask>) {
|
||||
let passes = std::mem::take(&mut self.dirty_nodes.passes_updated);
|
||||
let nodes_updated = std::mem::take(&mut self.dirty_nodes.nodes_updated);
|
||||
@@ -195,10 +211,17 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
||||
}
|
||||
}
|
||||
|
||||
(
|
||||
resolve_passes(self, dirty_nodes, ctx, parallel),
|
||||
nodes_updated,
|
||||
)
|
||||
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());
|
||||
|
||||
self.workload.run_with_world(&self.tree.nodes).unwrap();
|
||||
|
||||
let dirty = self.tree.remove_unique::<DirtyNodes>().unwrap();
|
||||
|
||||
(dirty.0, nodes_updated)
|
||||
}
|
||||
|
||||
pub fn traverse_depth_first(&self, mut f: impl FnMut(NodeRef<V>)) {
|
||||
@@ -221,7 +244,7 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
||||
f(node);
|
||||
if let Some(children) = self.tree.children_ids(id) {
|
||||
for id in children {
|
||||
queue.push_back(*id);
|
||||
queue.push_back(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,32 +281,74 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_slab<T: Any + Send + Sync>(&mut self) {
|
||||
self.tree.insert_slab::<T>();
|
||||
}
|
||||
|
||||
pub fn add_node_watcher(&mut self, watcher: impl NodeWatcher<V> + 'static + Send + Sync) {
|
||||
self.node_watchers.write().unwrap().push(Box::new(watcher));
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ViewEntry<'a, V: Component + Send + Sync> {
|
||||
view: View<'a, V>,
|
||||
id: NodeId,
|
||||
}
|
||||
|
||||
impl<'a, V: Component + Send + Sync> ViewEntry<'a, V> {
|
||||
fn new(view: View<'a, V>, id: NodeId) -> Self {
|
||||
Self { view, id }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, V: Component + Send + Sync> Deref for ViewEntry<'a, V> {
|
||||
type Target = V;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.view[self.id]
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ViewEntryMut<'a, V: Component<Tracking = Untracked> + Send + Sync> {
|
||||
view: ViewMut<'a, V, Untracked>,
|
||||
id: NodeId,
|
||||
}
|
||||
|
||||
impl<'a, V: Component<Tracking = Untracked> + Send + Sync> ViewEntryMut<'a, V> {
|
||||
fn new(view: ViewMut<'a, V, Untracked>, id: NodeId) -> Self {
|
||||
Self { view, id }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, V: Component<Tracking = Untracked> + Send + Sync> Deref for ViewEntryMut<'a, V> {
|
||||
type Target = V;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.view.get(self.id).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, V: Component<Tracking = Untracked> + Send + Sync> DerefMut for ViewEntryMut<'a, V> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
(&mut self.view).get(self.id).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait NodeImmutable<V: FromAnyValue + Send + Sync>: Sized {
|
||||
fn real_dom(&self) -> &RealDom<V>;
|
||||
|
||||
fn id(&self) -> NodeId;
|
||||
|
||||
#[inline]
|
||||
fn node_type(&self) -> &NodeType<V> {
|
||||
fn node_type(&self) -> ViewEntry<NodeType<V>> {
|
||||
self.get().unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get<T: Any + Sync + Send>(&self) -> Option<&T> {
|
||||
self.real_dom().tree.get(self.id())
|
||||
fn get<'a, T: Component + Sync + Send>(&'a self) -> Option<ViewEntry<'a, T>> {
|
||||
// self.real_dom().tree.get(self.id())
|
||||
let view: View<'a, T> = self.real_dom().borrow_raw().ok()?;
|
||||
Some(ViewEntry::new(view, self.id()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn child_ids(&self) -> Option<&[NodeId]> {
|
||||
fn child_ids(&self) -> Option<Vec<NodeId>> {
|
||||
self.real_dom().tree.children_ids(self.id())
|
||||
}
|
||||
|
||||
@@ -413,7 +478,9 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_mut<T: Any + Sync + Send>(&mut self) -> Option<&mut T> {
|
||||
pub fn get_mut<T: Component<Tracking = Untracked> + Sync + Send>(
|
||||
&mut self,
|
||||
) -> Option<ViewEntryMut<T>> {
|
||||
// mark the node state as dirty
|
||||
self.dom
|
||||
.dirty_nodes
|
||||
@@ -421,11 +488,12 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
|
||||
.entry(self.id)
|
||||
.or_default()
|
||||
.insert(TypeId::of::<T>());
|
||||
self.dom.tree.get_mut(self.id)
|
||||
let view_mut: ViewMut<T> = self.dom.borrow_raw().ok()?;
|
||||
Some(ViewEntryMut::new(view_mut, self.id))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn insert<T: Any + Sync + Send>(&mut self, value: T) {
|
||||
pub fn insert<T: Component + Sync + Send>(&mut self, value: T) {
|
||||
// mark the node state as dirty
|
||||
self.dom
|
||||
.dirty_nodes
|
||||
@@ -493,17 +561,20 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
|
||||
#[inline]
|
||||
pub fn remove(&mut self) {
|
||||
let id = self.id();
|
||||
if let NodeType::Element(ElementNode { listeners, .. })
|
||||
| NodeType::Text(TextNode { listeners, .. }) =
|
||||
self.dom.get_state_mut_raw::<NodeType<V>>(id).unwrap()
|
||||
{
|
||||
let listeners = std::mem::take(listeners);
|
||||
for event in listeners {
|
||||
self.dom
|
||||
.nodes_listening
|
||||
.get_mut(&event)
|
||||
.unwrap()
|
||||
.remove(&id);
|
||||
let RealDom {
|
||||
tree,
|
||||
nodes_listening,
|
||||
..
|
||||
} = &mut self.dom;
|
||||
let mut view: ViewMut<NodeType<V>> = tree.nodes.borrow().unwrap();
|
||||
if let NodeType::Element(ElementNode { listeners, .. })
|
||||
| NodeType::Text(TextNode { listeners, .. }) = (&mut view).get(id).unwrap()
|
||||
{
|
||||
let listeners = std::mem::take(listeners);
|
||||
for event in listeners {
|
||||
nodes_listening.get_mut(&event).unwrap().remove(&id);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.mark_removed();
|
||||
@@ -539,22 +610,27 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
|
||||
#[inline]
|
||||
pub fn add_event_listener(&mut self, event: &str) {
|
||||
let id = self.id();
|
||||
let node_type: &mut NodeType<V> = self.dom.tree.get_mut(self.id).unwrap();
|
||||
let RealDom {
|
||||
tree,
|
||||
dirty_nodes,
|
||||
nodes_listening,
|
||||
..
|
||||
} = &mut self.dom;
|
||||
let mut view: ViewMut<NodeType<V>> = tree.nodes.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
|
||||
{
|
||||
self.dom
|
||||
.dirty_nodes
|
||||
.mark_dirty(self.id, NodeMaskBuilder::new().with_listeners().build());
|
||||
dirty_nodes.mark_dirty(self.id, NodeMaskBuilder::new().with_listeners().build());
|
||||
listeners.insert(event.to_string());
|
||||
match self.dom.nodes_listening.get_mut(event) {
|
||||
match nodes_listening.get_mut(event) {
|
||||
Some(hs) => {
|
||||
hs.insert(id);
|
||||
}
|
||||
None => {
|
||||
let mut hs = FxHashSet::default();
|
||||
hs.insert(id);
|
||||
self.dom.nodes_listening.insert(event.to_string(), hs);
|
||||
nodes_listening.insert(event.to_string(), hs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -563,16 +639,21 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
|
||||
#[inline]
|
||||
pub fn remove_event_listener(&mut self, event: &str) {
|
||||
let id = self.id();
|
||||
let node_type: &mut NodeType<V> = self.dom.tree.get_mut(self.id).unwrap();
|
||||
let RealDom {
|
||||
tree,
|
||||
dirty_nodes,
|
||||
nodes_listening,
|
||||
..
|
||||
} = &mut self.dom;
|
||||
let mut view: ViewMut<NodeType<V>> = tree.nodes.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
|
||||
{
|
||||
self.dom
|
||||
.dirty_nodes
|
||||
.mark_dirty(self.id, NodeMaskBuilder::new().with_listeners().build());
|
||||
dirty_nodes.mark_dirty(self.id, NodeMaskBuilder::new().with_listeners().build());
|
||||
listeners.remove(event);
|
||||
|
||||
self.dom.nodes_listening.get_mut(event).unwrap().remove(&id);
|
||||
nodes_listening.get_mut(event).unwrap().remove(&id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -591,28 +672,32 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
|
||||
}
|
||||
|
||||
pub fn node_type_mut(&mut self) -> NodeTypeMut<'_, V> {
|
||||
let Self { id, dom } = self;
|
||||
let id = self.id();
|
||||
let RealDom {
|
||||
dirty_nodes, tree, ..
|
||||
} = dom;
|
||||
let node_type = tree.get_mut(*id).unwrap();
|
||||
match node_type {
|
||||
NodeType::Element(element) => NodeTypeMut::Element(ElementNodeMut {
|
||||
id: *id,
|
||||
element,
|
||||
tree, dirty_nodes, ..
|
||||
} = &mut self.dom;
|
||||
let view: ViewMut<NodeType<V>> = tree.nodes.borrow().unwrap();
|
||||
let node_type = ViewEntryMut::new(view, id);
|
||||
match &*node_type {
|
||||
NodeType::Element(_) => NodeTypeMut::Element(ElementNodeMut {
|
||||
id,
|
||||
element: node_type,
|
||||
dirty_nodes,
|
||||
}),
|
||||
NodeType::Text(_) => NodeTypeMut::Text(TextNodeMut {
|
||||
id,
|
||||
text: node_type,
|
||||
dirty_nodes,
|
||||
}),
|
||||
NodeType::Text(text) => {
|
||||
dirty_nodes.mark_dirty(self.id, NodeMaskBuilder::new().with_text().build());
|
||||
|
||||
NodeTypeMut::Text(&mut text.text)
|
||||
}
|
||||
NodeType::Placeholder => NodeTypeMut::Placeholder,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_type(&mut self, new: NodeType<V>) {
|
||||
*self.dom.tree.get_mut::<NodeType<V>>(self.id).unwrap() = new;
|
||||
{
|
||||
let mut view: ViewMut<NodeType<V>> = self.dom.borrow_node_type_mut().unwrap();
|
||||
*(&mut view).get(self.id).unwrap() = new;
|
||||
}
|
||||
self.dom
|
||||
.dirty_nodes
|
||||
.mark_dirty(self.id, NodeMaskBuilder::ALL.build())
|
||||
@@ -638,39 +723,94 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
|
||||
|
||||
pub enum NodeTypeMut<'a, V: FromAnyValue + Send + Sync = ()> {
|
||||
Element(ElementNodeMut<'a, V>),
|
||||
Text(&'a mut String),
|
||||
Text(TextNodeMut<'a, V>),
|
||||
Placeholder,
|
||||
}
|
||||
|
||||
pub struct TextNodeMut<'a, V: FromAnyValue + Send + Sync = ()> {
|
||||
id: NodeId,
|
||||
text: ViewEntryMut<'a, NodeType<V>>,
|
||||
dirty_nodes: &'a mut NodesDirty<V>,
|
||||
}
|
||||
|
||||
impl<V: FromAnyValue + Send + Sync> TextNodeMut<'_, V> {
|
||||
pub fn text(&self) -> &str {
|
||||
match &*self.text {
|
||||
NodeType::Text(text) => &text.text,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn text_mut(&mut self) -> &mut String {
|
||||
self.dirty_nodes
|
||||
.mark_dirty(self.id, NodeMaskBuilder::new().with_text().build());
|
||||
match &mut *self.text {
|
||||
NodeType::Text(text) => &mut text.text,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: FromAnyValue + Send + Sync> Deref for TextNodeMut<'_, V> {
|
||||
type Target = String;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match &*self.text {
|
||||
NodeType::Text(text) => &text.text,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: FromAnyValue + Send + Sync> DerefMut for TextNodeMut<'_, V> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.text_mut()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ElementNodeMut<'a, V: FromAnyValue + Send + Sync = ()> {
|
||||
id: NodeId,
|
||||
element: &'a mut ElementNode<V>,
|
||||
element: ViewEntryMut<'a, NodeType<V>>,
|
||||
dirty_nodes: &'a mut NodesDirty<V>,
|
||||
}
|
||||
|
||||
impl<V: FromAnyValue + Send + Sync> ElementNodeMut<'_, V> {
|
||||
fn element(&self) -> &ElementNode<V> {
|
||||
match &*self.element {
|
||||
NodeType::Element(element) => element,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn element_mut(&mut self) -> &mut ElementNode<V> {
|
||||
match &mut *self.element {
|
||||
NodeType::Element(element) => element,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tag(&self) -> &str {
|
||||
&self.element.tag
|
||||
&self.element().tag
|
||||
}
|
||||
|
||||
pub fn tag_mut(&mut self) -> &mut String {
|
||||
self.dirty_nodes
|
||||
.mark_dirty(self.id, NodeMaskBuilder::new().with_tag().build());
|
||||
&mut self.element.tag
|
||||
&mut self.element_mut().tag
|
||||
}
|
||||
|
||||
pub fn namespace(&self) -> Option<&str> {
|
||||
self.element.namespace.as_deref()
|
||||
self.element().namespace.as_deref()
|
||||
}
|
||||
|
||||
pub fn namespace_mut(&mut self) -> &mut Option<String> {
|
||||
self.dirty_nodes
|
||||
.mark_dirty(self.id, NodeMaskBuilder::new().with_namespace().build());
|
||||
&mut self.element.namespace
|
||||
&mut self.element_mut().namespace
|
||||
}
|
||||
|
||||
pub fn attributes(&self) -> &FxHashMap<OwnedAttributeDiscription, OwnedAttributeValue<V>> {
|
||||
&self.element.attributes
|
||||
&self.element().attributes
|
||||
}
|
||||
|
||||
pub fn set_attribute(
|
||||
@@ -684,7 +824,7 @@ impl<V: FromAnyValue + Send + Sync> ElementNodeMut<'_, V> {
|
||||
.with_attrs(AttributeMaskBuilder::Some(&[&name.name]))
|
||||
.build(),
|
||||
);
|
||||
self.element.attributes.insert(name, value)
|
||||
self.element_mut().attributes.insert(name, value)
|
||||
}
|
||||
|
||||
pub fn remove_attributes(
|
||||
@@ -697,7 +837,7 @@ impl<V: FromAnyValue + Send + Sync> ElementNodeMut<'_, V> {
|
||||
.with_attrs(AttributeMaskBuilder::Some(&[&name.name]))
|
||||
.build(),
|
||||
);
|
||||
self.element.attributes.remove(name)
|
||||
self.element_mut().attributes.remove(name)
|
||||
}
|
||||
|
||||
pub fn get_attribute_mut(
|
||||
@@ -710,10 +850,10 @@ impl<V: FromAnyValue + Send + Sync> ElementNodeMut<'_, V> {
|
||||
.with_attrs(AttributeMaskBuilder::Some(&[&name.name]))
|
||||
.build(),
|
||||
);
|
||||
self.element.attributes.get_mut(name)
|
||||
self.element_mut().attributes.get_mut(name)
|
||||
}
|
||||
|
||||
pub fn listeners(&self) -> &FxHashSet<String> {
|
||||
&self.element.listeners
|
||||
&self.element().listeners
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,8 @@
|
||||
use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
use rustc_hash::{FxHashMap, FxHasher};
|
||||
use std::any::{Any, TypeId};
|
||||
use std::collections::VecDeque;
|
||||
use crate::NodeId;
|
||||
use shipyard::{Component, EntitiesView, EntityId, Get, Unique, View, ViewMut, World};
|
||||
use std::fmt::Debug;
|
||||
use std::hash::BuildHasherDefault;
|
||||
|
||||
use crate::{AnyMapLike, Dependancy};
|
||||
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Hash)]
|
||||
pub struct NodeId(pub usize);
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Component)]
|
||||
pub(crate) struct Node {
|
||||
parent: Option<NodeId>,
|
||||
children: Vec<NodeId>,
|
||||
@@ -19,60 +11,55 @@ pub(crate) struct Node {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Tree {
|
||||
nodes: AnySlab,
|
||||
pub(crate) nodes: World,
|
||||
root: NodeId,
|
||||
}
|
||||
|
||||
impl Tree {
|
||||
pub fn new() -> Self {
|
||||
let mut nodes = AnySlab::default();
|
||||
let mut node = nodes.insert();
|
||||
node.insert(Node {
|
||||
let mut nodes = World::default();
|
||||
let node = Node {
|
||||
parent: None,
|
||||
children: Vec::new(),
|
||||
height: 0,
|
||||
});
|
||||
let root = node.id();
|
||||
};
|
||||
let root = nodes.add_entity((node,));
|
||||
Self { nodes, root }
|
||||
}
|
||||
|
||||
pub(crate) fn insert_slab<T: Any + Send + Sync>(&mut self) {
|
||||
self.nodes.get_or_insert_slab_mut::<T>();
|
||||
pub fn add_unique<T: Unique + Send + Sync>(&mut self, data: T) {
|
||||
self.nodes.add_unique(data);
|
||||
}
|
||||
|
||||
fn node_slab(&self) -> &SlabStorage<Node> {
|
||||
self.nodes.read_slab()
|
||||
pub fn remove_unique<T: Unique + Send + Sync>(
|
||||
&mut self,
|
||||
) -> Result<T, shipyard::error::UniqueRemove> {
|
||||
self.nodes.remove_unique::<T>()
|
||||
}
|
||||
|
||||
pub fn get_node_data(&self, id: NodeId) -> &Node {
|
||||
self.node_slab().get(id).unwrap()
|
||||
fn node_data(&self) -> View<Node> {
|
||||
self.nodes.borrow().unwrap()
|
||||
}
|
||||
|
||||
pub fn try_get_node_data(&self, id: NodeId) -> Option<&Node> {
|
||||
self.node_slab().get(id)
|
||||
}
|
||||
|
||||
fn node_slab_mut(&mut self) -> &mut SlabStorage<Node> {
|
||||
self.nodes.write_slab()
|
||||
}
|
||||
|
||||
pub fn get_node_data_mut(&mut self, id: NodeId) -> &mut Node {
|
||||
self.node_slab_mut().get_mut(id).unwrap()
|
||||
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) {
|
||||
let children = { tree.get_node_data(id).children.clone() };
|
||||
for child in children {
|
||||
recurse(tree, child);
|
||||
let children = tree.children_ids(id);
|
||||
if let Some(children) = children {
|
||||
for child in children {
|
||||
recurse(tree, child);
|
||||
}
|
||||
}
|
||||
|
||||
tree.nodes.remove(id);
|
||||
tree.nodes.delete_entity(id);
|
||||
}
|
||||
{
|
||||
let node_data_mut = self.node_slab_mut();
|
||||
let mut node_data_mut = self.node_data_mut();
|
||||
if let Some(parent) = node_data_mut.get(id).unwrap().parent {
|
||||
let parent = node_data_mut.get_mut(parent).unwrap();
|
||||
let parent = (&mut node_data_mut).get(parent).unwrap();
|
||||
parent.children.retain(|&child| child != id);
|
||||
}
|
||||
}
|
||||
@@ -82,19 +69,20 @@ impl Tree {
|
||||
|
||||
pub fn remove_single(&mut self, id: NodeId) {
|
||||
{
|
||||
let node_data_mut = self.node_slab_mut();
|
||||
let mut node_data_mut = self.node_data_mut();
|
||||
if let Some(parent) = node_data_mut.get(id).unwrap().parent {
|
||||
let parent = node_data_mut.get_mut(parent).unwrap();
|
||||
let parent = (&mut node_data_mut).get(parent).unwrap();
|
||||
parent.children.retain(|&child| child != id);
|
||||
}
|
||||
}
|
||||
|
||||
self.nodes.remove(id);
|
||||
self.nodes.delete_entity(id);
|
||||
}
|
||||
|
||||
fn set_height(&mut self, node: NodeId, height: u16) {
|
||||
let children = {
|
||||
let mut node = self.get_node_data_mut(node);
|
||||
let mut node_data_mut = self.node_data_mut();
|
||||
let mut node = (&mut node_data_mut).get(node).unwrap();
|
||||
node.height = height;
|
||||
node.children.clone()
|
||||
};
|
||||
@@ -103,31 +91,33 @@ impl Tree {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_node(&mut self) -> EntryBuilder<'_> {
|
||||
let mut node = self.nodes.insert();
|
||||
node.insert(Node {
|
||||
pub fn create_node(&mut self) -> NodeBuilder<'_> {
|
||||
let node = self.nodes.add_entity((Node {
|
||||
parent: None,
|
||||
children: Vec::new(),
|
||||
height: 0,
|
||||
});
|
||||
node
|
||||
},));
|
||||
NodeBuilder { tree: self, node }
|
||||
}
|
||||
|
||||
pub fn add_child(&mut self, parent: NodeId, new: NodeId) {
|
||||
let node_state = self.node_slab_mut();
|
||||
node_state.get_mut(new).unwrap().parent = Some(parent);
|
||||
let parent = node_state.get_mut(parent).unwrap();
|
||||
parent.children.push(new);
|
||||
let height = parent.height + 1;
|
||||
let height;
|
||||
{
|
||||
let mut node_state = self.node_data_mut();
|
||||
(&mut node_state).get(new).unwrap().parent = Some(parent);
|
||||
let parent = (&mut node_state).get(parent).unwrap();
|
||||
parent.children.push(new);
|
||||
height = parent.height + 1;
|
||||
}
|
||||
self.set_height(new, height);
|
||||
}
|
||||
|
||||
pub fn replace(&mut self, old_id: NodeId, new_id: NodeId) {
|
||||
{
|
||||
let node_state = self.node_slab_mut();
|
||||
let mut node_state = self.node_data_mut();
|
||||
// update the parent's link to the child
|
||||
if let Some(parent_id) = node_state.get(old_id).unwrap().parent {
|
||||
let parent = node_state.get_mut(parent_id).unwrap();
|
||||
let parent = (&mut node_state).get(parent_id).unwrap();
|
||||
for id in &mut parent.children {
|
||||
if *id == old_id {
|
||||
*id = new_id;
|
||||
@@ -135,6 +125,7 @@ impl Tree {
|
||||
}
|
||||
}
|
||||
let height = parent.height + 1;
|
||||
drop(node_state);
|
||||
self.set_height(new_id, height);
|
||||
}
|
||||
}
|
||||
@@ -143,11 +134,11 @@ impl Tree {
|
||||
}
|
||||
|
||||
pub fn insert_before(&mut self, old_id: NodeId, new_id: NodeId) {
|
||||
let node_state = self.node_slab_mut();
|
||||
let mut node_state = self.node_data_mut();
|
||||
let old_node = node_state.get(old_id).unwrap();
|
||||
let parent_id = old_node.parent.expect("tried to insert before root");
|
||||
node_state.get_mut(new_id).unwrap().parent = Some(parent_id);
|
||||
let parent = node_state.get_mut(parent_id).unwrap();
|
||||
(&mut node_state).get(new_id).unwrap().parent = Some(parent_id);
|
||||
let parent = (&mut node_state).get(parent_id).unwrap();
|
||||
let index = parent
|
||||
.children
|
||||
.iter()
|
||||
@@ -155,15 +146,16 @@ 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 node_state = self.node_slab_mut();
|
||||
let mut node_state = self.node_data_mut();
|
||||
let old_node = node_state.get(old_id).unwrap();
|
||||
let parent_id = old_node.parent.expect("tried to insert before root");
|
||||
node_state.get_mut(new_id).unwrap().parent = Some(parent_id);
|
||||
let parent = node_state.get_mut(parent_id).unwrap();
|
||||
(&mut node_state).get(new_id).unwrap().parent = Some(parent_id);
|
||||
let parent = (&mut node_state).get(parent_id).unwrap();
|
||||
let index = parent
|
||||
.children
|
||||
.iter()
|
||||
@@ -171,35 +163,16 @@ 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 size(&self) -> usize {
|
||||
self.nodes.len()
|
||||
}
|
||||
|
||||
pub fn dynamically_borrowed(&mut self) -> DynamicallyBorrowedTree<'_> {
|
||||
DynamicallyBorrowedTree {
|
||||
nodes: self.nodes.dynamically_borrowed(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get<T: Any + Sync + Send>(&self, id: NodeId) -> Option<&T> {
|
||||
self.nodes.try_read_slab().and_then(|slab| slab.get(id))
|
||||
}
|
||||
|
||||
pub fn get_mut<T: Any + Sync + Send>(&mut self, id: NodeId) -> Option<&mut T> {
|
||||
self.nodes
|
||||
.try_write_slab()
|
||||
.and_then(|slab| slab.get_mut(id))
|
||||
}
|
||||
|
||||
pub fn insert<T: Any + Sync + Send>(&mut self, id: NodeId, value: T) {
|
||||
self.nodes.get_or_insert_slab_mut().insert(id, value);
|
||||
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.contains(id)
|
||||
self.nodes.borrow::<EntitiesView>().unwrap().is_alive(id)
|
||||
}
|
||||
|
||||
pub fn root(&self) -> NodeId {
|
||||
@@ -207,128 +180,18 @@ impl Tree {
|
||||
}
|
||||
|
||||
pub fn parent_id(&self, id: NodeId) -> Option<NodeId> {
|
||||
self.try_get_node_data(id).and_then(|node| node.parent)
|
||||
let node_data = self.node_data();
|
||||
node_data.get(id).unwrap().parent
|
||||
}
|
||||
|
||||
pub fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> {
|
||||
self.try_get_node_data(id).map(|node| &*node.children)
|
||||
pub fn children_ids(&self, id: NodeId) -> Option<Vec<NodeId>> {
|
||||
let node_data = self.node_data();
|
||||
node_data.get(id).map(|node| node.children.clone()).ok()
|
||||
}
|
||||
|
||||
pub fn height(&self, id: NodeId) -> Option<u16> {
|
||||
self.try_get_node_data(id).map(|node| node.height)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct DynamicallyBorrowedTree<'a> {
|
||||
nodes: DynamiclyBorrowedAnySlabView<'a>,
|
||||
}
|
||||
|
||||
impl<'a> DynamicallyBorrowedTree<'a> {
|
||||
pub fn view(
|
||||
&self,
|
||||
immutable: impl IntoIterator<Item = TypeId>,
|
||||
mutable: impl IntoIterator<Item = TypeId>,
|
||||
) -> TreeStateView<'_, 'a> {
|
||||
let nodes_data = self.node_slab();
|
||||
let mut nodes = FxHashMap::default();
|
||||
for id in immutable {
|
||||
nodes.insert(id, MaybeRead::Read(self.nodes.get_slab(id).unwrap()));
|
||||
}
|
||||
for id in mutable {
|
||||
nodes.insert(id, MaybeRead::Write(self.nodes.get_slab_mut(id).unwrap()));
|
||||
}
|
||||
|
||||
TreeStateView { nodes_data, nodes }
|
||||
}
|
||||
|
||||
fn node_slab(&self) -> MappedRwLockReadGuard<SlabStorage<Node>> {
|
||||
RwLockReadGuard::map(self.nodes.get_slab(TypeId::of::<Node>()).unwrap(), |slab| {
|
||||
slab.as_any().downcast_ref().unwrap()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
enum MaybeRead<'a, 'b> {
|
||||
Read(RwLockReadGuard<'a, &'b mut dyn AnySlabStorageImpl>),
|
||||
Write(RwLockWriteGuard<'a, &'b mut dyn AnySlabStorageImpl>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct TreeStateViewEntry<'a, 'b> {
|
||||
view: &'a TreeStateView<'a, 'b>,
|
||||
id: NodeId,
|
||||
}
|
||||
|
||||
impl<'a, 'b> AnyMapLike<'a> for TreeStateViewEntry<'a, 'b> {
|
||||
fn get<T: Any + Sync + Send>(self) -> Option<&'a T> {
|
||||
let slab = self.view.get_slab();
|
||||
slab.and_then(|slab| slab.get(self.id))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TreeStateView<'a, 'b> {
|
||||
nodes_data: MappedRwLockReadGuard<'a, SlabStorage<Node>>,
|
||||
nodes: FxHashMap<TypeId, MaybeRead<'a, 'b>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> TreeStateView<'a, 'b> {
|
||||
pub fn get_slab<T: Any + Sync + Send>(&self) -> Option<&SlabStorage<T>> {
|
||||
self.nodes
|
||||
.get(&TypeId::of::<T>())
|
||||
.and_then(|gaurd| match gaurd {
|
||||
MaybeRead::Read(gaurd) => gaurd.as_any().downcast_ref::<SlabStorage<T>>(),
|
||||
MaybeRead::Write(gaurd) => gaurd.as_any().downcast_ref::<SlabStorage<T>>(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_slab_mut<T: Any + Sync + Send>(&mut self) -> Option<&mut SlabStorage<T>> {
|
||||
self.nodes
|
||||
.get_mut(&TypeId::of::<T>())
|
||||
.and_then(|gaurd| match gaurd {
|
||||
MaybeRead::Read(_gaurd) => None,
|
||||
MaybeRead::Write(gaurd) => gaurd.as_any_mut().downcast_mut::<SlabStorage<T>>(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> {
|
||||
self.nodes_data.get(id).map(|node| &*node.children)
|
||||
}
|
||||
|
||||
pub fn parent_id(&self, id: NodeId) -> Option<NodeId> {
|
||||
self.nodes_data.get(id).and_then(|node| node.parent)
|
||||
}
|
||||
|
||||
pub fn height(&self, id: NodeId) -> Option<u16> {
|
||||
self.nodes_data.get(id).map(|n| n.height)
|
||||
}
|
||||
|
||||
pub fn get<T: Dependancy>(&self, id: NodeId) -> Option<T::ElementBorrowed<'_>> {
|
||||
T::borrow_elements_from(self.entry(id))
|
||||
}
|
||||
|
||||
pub fn get_single<T: Any + Sync + Send>(&self, id: NodeId) -> Option<&T> {
|
||||
self.get_slab().and_then(|slab| slab.get(id))
|
||||
}
|
||||
|
||||
pub fn get_mut<T: Any + Sync + Send>(&mut self, id: NodeId) -> Option<&mut T> {
|
||||
self.get_slab_mut().and_then(|slab| slab.get_mut(id))
|
||||
}
|
||||
|
||||
pub fn entry(&self, id: NodeId) -> TreeStateViewEntry<'_, 'b> {
|
||||
TreeStateViewEntry { view: self, id }
|
||||
}
|
||||
|
||||
pub fn children<T: Dependancy>(&self, id: NodeId) -> Option<Vec<T::ElementBorrowed<'_>>> {
|
||||
let ids = self.children_ids(id);
|
||||
ids.and_then(|ids| {
|
||||
ids.iter()
|
||||
.map(|id| T::borrow_elements_from(self.entry(*id)))
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parent<T: Dependancy>(&self, id: NodeId) -> Option<T::ElementBorrowed<'_>> {
|
||||
T::borrow_elements_from(self.entry(self.parent_id(id)?))
|
||||
let node_data = self.node_data();
|
||||
node_data.get(id).map(|node| node.height).ok()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,244 +327,17 @@ fn deletion() {
|
||||
assert_eq!(tree.get::<i32>(after), None);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SlabStorage<T> {
|
||||
data: Vec<Option<T>>,
|
||||
pub struct NodeBuilder<'a> {
|
||||
tree: &'a mut Tree,
|
||||
node: EntityId,
|
||||
}
|
||||
|
||||
impl<T> Default for SlabStorage<T> {
|
||||
fn default() -> Self {
|
||||
Self { data: Vec::new() }
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
trait AnySlabStorageImpl: Any + Send + Sync {
|
||||
fn remove(&mut self, id: NodeId);
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
}
|
||||
|
||||
impl<T> SlabStorage<T> {
|
||||
fn get(&self, id: NodeId) -> Option<&T> {
|
||||
self.data.get(id.0).and_then(|x| x.as_ref())
|
||||
}
|
||||
|
||||
fn get_mut(&mut self, id: NodeId) -> Option<&mut T> {
|
||||
self.data.get_mut(id.0).and_then(|x| x.as_mut())
|
||||
}
|
||||
|
||||
pub fn entry(&mut self, id: NodeId) -> SlabEntry<'_, T> {
|
||||
let idx = id.0;
|
||||
if idx >= self.data.len() {
|
||||
self.data.resize_with(idx + 1, || None);
|
||||
}
|
||||
SlabEntry {
|
||||
value: &mut self.data[idx],
|
||||
}
|
||||
}
|
||||
|
||||
fn insert(&mut self, id: NodeId, value: T) {
|
||||
let idx = id.0;
|
||||
if idx >= self.data.len() {
|
||||
self.data.resize_with(idx + 1, || None);
|
||||
}
|
||||
self.data[idx] = Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SlabEntry<'a, T> {
|
||||
pub value: &'a mut Option<T>,
|
||||
}
|
||||
|
||||
impl<'a, T> SlabEntry<'a, T> {
|
||||
pub fn or_insert_with<F: FnOnce() -> T>(self, f: F) -> &'a mut T {
|
||||
self.value.get_or_insert_with(f)
|
||||
}
|
||||
|
||||
pub fn or_insert(self, value: T) -> &'a mut T {
|
||||
self.value.get_or_insert(value)
|
||||
}
|
||||
|
||||
pub fn or_default(self) -> &'a mut T
|
||||
where
|
||||
T: Default,
|
||||
{
|
||||
self.value.get_or_insert_with(Default::default)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static + Send + Sync> AnySlabStorageImpl for SlabStorage<T> {
|
||||
fn remove(&mut self, id: NodeId) {
|
||||
if let Some(entry) = self.data.get_mut(id.0) {
|
||||
let _ = entry.take();
|
||||
}
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct DynamiclyBorrowedAnySlabView<'a> {
|
||||
data: hashbrown::HashMap<
|
||||
TypeId,
|
||||
RwLock<&'a mut dyn AnySlabStorageImpl>,
|
||||
BuildHasherDefault<FxHasher>,
|
||||
>,
|
||||
}
|
||||
|
||||
impl<'a> DynamiclyBorrowedAnySlabView<'a> {
|
||||
fn get_slab<'b>(
|
||||
&'b self,
|
||||
type_id: TypeId,
|
||||
) -> Option<RwLockReadGuard<'b, &'a mut dyn AnySlabStorageImpl>> {
|
||||
self.data.get(&type_id).map(|x| x.read())
|
||||
}
|
||||
|
||||
fn get_slab_mut<'b>(
|
||||
&'b self,
|
||||
type_id: TypeId,
|
||||
) -> Option<RwLockWriteGuard<'b, &'a mut dyn AnySlabStorageImpl>> {
|
||||
self.data.get(&type_id).map(|x| x.write())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct AnySlab {
|
||||
data: hashbrown::HashMap<TypeId, Box<dyn AnySlabStorageImpl>, BuildHasherDefault<FxHasher>>,
|
||||
filled: Vec<bool>,
|
||||
free: VecDeque<NodeId>,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl Debug for AnySlab {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("AnySlab")
|
||||
.field("data", &self.data.keys().collect::<Vec<_>>())
|
||||
.field("free", &self.free)
|
||||
.field("len", &self.len)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AnySlab {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl AnySlab {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
data: Default::default(),
|
||||
filled: Default::default(),
|
||||
free: VecDeque::new(),
|
||||
len: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn try_read_slab<T: Any + Sync + Send>(&self) -> Option<&SlabStorage<T>> {
|
||||
self.data
|
||||
.get(&TypeId::of::<T>())
|
||||
.map(|x| x.as_any().downcast_ref().unwrap())
|
||||
}
|
||||
|
||||
fn read_slab<T: Any + Sync + Send>(&self) -> &SlabStorage<T> {
|
||||
self.try_read_slab().unwrap()
|
||||
}
|
||||
|
||||
fn try_write_slab<T: Any + Sync + Send>(&mut self) -> Option<&mut SlabStorage<T>> {
|
||||
self.data
|
||||
.get_mut(&TypeId::of::<T>())
|
||||
.map(|x| x.as_any_mut().downcast_mut().unwrap())
|
||||
}
|
||||
|
||||
fn write_slab<T: Any + Sync + Send>(&mut self) -> &mut SlabStorage<T> {
|
||||
self.try_write_slab().unwrap()
|
||||
}
|
||||
|
||||
fn get_or_insert_slab_mut<T: Any + Send + Sync>(&mut self) -> &mut SlabStorage<T> {
|
||||
self.data
|
||||
.entry(TypeId::of::<T>())
|
||||
.or_insert_with(|| Box::<SlabStorage<T>>::default())
|
||||
.as_any_mut()
|
||||
.downcast_mut()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn insert(&mut self) -> EntryBuilder<'_> {
|
||||
let id = if let Some(id) = self.free.pop_front() {
|
||||
self.filled[id.0] = true;
|
||||
id
|
||||
} else {
|
||||
let id = self.len;
|
||||
self.filled.push(true);
|
||||
self.len += 1;
|
||||
NodeId(id)
|
||||
};
|
||||
EntryBuilder { id, inner: self }
|
||||
}
|
||||
|
||||
fn remove(&mut self, id: NodeId) {
|
||||
for slab in self.data.values_mut() {
|
||||
slab.remove(id);
|
||||
}
|
||||
self.filled[id.0] = true;
|
||||
self.free.push_back(id);
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.len - self.free.len()
|
||||
}
|
||||
|
||||
fn contains(&self, id: NodeId) -> bool {
|
||||
self.filled.get(id.0).copied().unwrap_or_default()
|
||||
}
|
||||
|
||||
fn dynamically_borrowed(&mut self) -> DynamiclyBorrowedAnySlabView<'_> {
|
||||
DynamiclyBorrowedAnySlabView {
|
||||
data: self
|
||||
.data
|
||||
.iter_mut()
|
||||
.map(|(k, v)| (*k, RwLock::new(&mut **v)))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct EntryBuilder<'a> {
|
||||
id: NodeId,
|
||||
inner: &'a mut AnySlab,
|
||||
}
|
||||
|
||||
impl EntryBuilder<'_> {
|
||||
pub fn insert<T: Any + Send + Sync>(&mut self, value: T) {
|
||||
self.inner
|
||||
.get_or_insert_slab_mut::<T>()
|
||||
.insert(self.id, value);
|
||||
}
|
||||
|
||||
pub fn id(&self) -> NodeId {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remove() {
|
||||
let mut slab = AnySlab::new();
|
||||
let mut node1 = slab.insert();
|
||||
node1.insert(0i32);
|
||||
let node1_id = node1.id();
|
||||
let mut node2 = slab.insert();
|
||||
node2.insert(0i32);
|
||||
|
||||
assert_eq!(slab.len(), 2);
|
||||
|
||||
slab.remove(node1_id);
|
||||
|
||||
assert!(slab.read_slab::<i32>().get(node1_id).is_none());
|
||||
assert_eq!(slab.len(), 1);
|
||||
}
|
||||
@@ -73,7 +73,7 @@ pub struct PersistantElementIter {
|
||||
|
||||
impl PersistantElementIter {
|
||||
pub fn create<V: FromAnyValue + Send + Sync>(rdom: &mut RealDom<V>) -> Self {
|
||||
let inner = Arc::new(Mutex::new(smallvec::smallvec![NodeId(0)]));
|
||||
let inner = Arc::new(Mutex::new(smallvec::smallvec![rdom.root_id()]));
|
||||
|
||||
rdom.add_node_watcher(PersistantElementIterUpdater {
|
||||
stack: inner.clone(),
|
||||
@@ -87,7 +87,7 @@ impl PersistantElementIter {
|
||||
pub fn next<V: FromAnyValue + Send + Sync>(&mut self, rdom: &RealDom<V>) -> ElementProduced {
|
||||
let mut stack = self.stack.lock().unwrap();
|
||||
if stack.is_empty() {
|
||||
let id = NodeId(0);
|
||||
let id = rdom.root_id();
|
||||
let new = id;
|
||||
stack.push(new);
|
||||
ElementProduced::Looped(id)
|
||||
@@ -113,7 +113,7 @@ impl PersistantElementIter {
|
||||
// otherwise, continue the loop and go to the parent
|
||||
} else {
|
||||
// if there is no parent, loop back to the root
|
||||
let new = NodeId(0);
|
||||
let new = rdom.root_id();
|
||||
stack.clear();
|
||||
stack.push(new);
|
||||
return ElementProduced::Looped(new);
|
||||
@@ -139,7 +139,7 @@ impl PersistantElementIter {
|
||||
}
|
||||
let mut stack = self.stack.lock().unwrap();
|
||||
if stack.is_empty() {
|
||||
let id = NodeId(0);
|
||||
let id = rdom.root_id();
|
||||
let last = push_back(&mut stack, rdom.get(id).unwrap());
|
||||
ElementProduced::Looped(last)
|
||||
} else if let Some(current) = stack.pop().and_then(|last| rdom.get(last)) {
|
||||
@@ -154,13 +154,13 @@ impl PersistantElementIter {
|
||||
ElementProduced::Progressed(*parent)
|
||||
} else {
|
||||
// if there is no parent, loop back to the root
|
||||
let id = NodeId(0);
|
||||
let id = rdom.root_id();
|
||||
let last = push_back(&mut stack, rdom.get(id).unwrap());
|
||||
ElementProduced::Looped(last)
|
||||
}
|
||||
} else {
|
||||
// if there is no parent, loop back to the root
|
||||
let id = NodeId(0);
|
||||
let id = rdom.root_id();
|
||||
let last = push_back(&mut stack, rdom.get(id).unwrap());
|
||||
ElementProduced::Looped(last)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user