Merge pull request #953 from Demonthos/fix-native-core-dependancies-in-different-directions
Fix native core dependencies in a different direction than the pass direction
This commit is contained in:
5 files changed
+282
-46
No files matched your search
@@ -325,7 +325,7 @@ pub fn partial_derive_state(_: TokenStream, input: TokenStream) -> TokenStream {
|
|||||||
|
|
||||||
#(#items)*
|
#(#items)*
|
||||||
|
|
||||||
fn workload_system(type_id: std::any::TypeId, dependants: dioxus_native_core::exports::FxHashSet<std::any::TypeId>, pass_direction: dioxus_native_core::prelude::PassDirection) -> dioxus_native_core::exports::shipyard::WorkloadSystem {
|
fn workload_system(type_id: std::any::TypeId, dependants: std::sync::Arc<dioxus_native_core::prelude::Dependants>, pass_direction: dioxus_native_core::prelude::PassDirection) -> dioxus_native_core::exports::shipyard::WorkloadSystem {
|
||||||
use dioxus_native_core::exports::shipyard::{IntoWorkloadSystem, Get, AddComponent};
|
use dioxus_native_core::exports::shipyard::{IntoWorkloadSystem, Get, AddComponent};
|
||||||
use dioxus_native_core::tree::TreeRef;
|
use dioxus_native_core::tree::TreeRef;
|
||||||
use dioxus_native_core::prelude::{NodeType, NodeView};
|
use dioxus_native_core::prelude::{NodeType, NodeView};
|
||||||
|
|||||||
@@ -0,0 +1,175 @@
|
|||||||
|
use dioxus_native_core::exports::shipyard::Component;
|
||||||
|
use dioxus_native_core::node_ref::*;
|
||||||
|
use dioxus_native_core::prelude::*;
|
||||||
|
use dioxus_native_core::real_dom::NodeTypeMut;
|
||||||
|
use dioxus_native_core_macro::partial_derive_state;
|
||||||
|
|
||||||
|
// All states need to derive Component
|
||||||
|
#[derive(Default, Debug, Copy, Clone, Component)]
|
||||||
|
struct Size(f64, f64);
|
||||||
|
|
||||||
|
/// Derive some of the boilerplate for the State implementation
|
||||||
|
#[partial_derive_state]
|
||||||
|
impl State for Size {
|
||||||
|
type ParentDependencies = ();
|
||||||
|
|
||||||
|
// The size of the current node depends on the size of its children
|
||||||
|
type ChildDependencies = (Self,);
|
||||||
|
|
||||||
|
type NodeDependencies = (FontSize,);
|
||||||
|
|
||||||
|
// Size only cares about the width, height, and text parts of the current node
|
||||||
|
const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::new()
|
||||||
|
// Get access to the width and height attributes
|
||||||
|
.with_attrs(AttributeMaskBuilder::Some(&["width", "height"]))
|
||||||
|
// Get access to the text of the node
|
||||||
|
.with_text();
|
||||||
|
|
||||||
|
fn update<'a>(
|
||||||
|
&mut self,
|
||||||
|
node_view: NodeView<()>,
|
||||||
|
(font_size,): <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
|
||||||
|
_parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
|
||||||
|
children: Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
|
||||||
|
_: &SendAnyMap,
|
||||||
|
) -> bool {
|
||||||
|
let font_size = font_size.size;
|
||||||
|
let mut width;
|
||||||
|
let mut height;
|
||||||
|
if let Some(text) = node_view.text() {
|
||||||
|
// if the node has text, use the text to size our object
|
||||||
|
width = text.len() as f64 * font_size;
|
||||||
|
height = font_size;
|
||||||
|
} else {
|
||||||
|
// otherwise, the size is the maximum size of the children
|
||||||
|
width = children
|
||||||
|
.iter()
|
||||||
|
.map(|(item,)| item.0)
|
||||||
|
.reduce(|accum, item| if accum >= item { accum } else { item })
|
||||||
|
.unwrap_or(0.0);
|
||||||
|
|
||||||
|
height = children
|
||||||
|
.iter()
|
||||||
|
.map(|(item,)| item.1)
|
||||||
|
.reduce(|accum, item| if accum >= item { accum } else { item })
|
||||||
|
.unwrap_or(0.0);
|
||||||
|
}
|
||||||
|
// if the node contains a width or height attribute it overrides the other size
|
||||||
|
for a in node_view.attributes().into_iter().flatten() {
|
||||||
|
match &*a.attribute.name {
|
||||||
|
"width" => width = a.value.as_float().unwrap(),
|
||||||
|
"height" => height = a.value.as_float().unwrap(),
|
||||||
|
// because Size only depends on the width and height, no other attributes will be passed to the member
|
||||||
|
_ => panic!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// to determine what other parts of the dom need to be updated we return a boolean that marks if this member changed
|
||||||
|
let changed = (width != self.0) || (height != self.1);
|
||||||
|
*self = Self(width, height);
|
||||||
|
changed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Component)]
|
||||||
|
struct FontSize {
|
||||||
|
size: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for FontSize {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self { size: 16.0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[partial_derive_state]
|
||||||
|
impl State for FontSize {
|
||||||
|
// TextColor depends on the TextColor part of the parent
|
||||||
|
type ParentDependencies = (Self,);
|
||||||
|
|
||||||
|
type ChildDependencies = ();
|
||||||
|
|
||||||
|
type NodeDependencies = ();
|
||||||
|
|
||||||
|
// TextColor only cares about the color attribute of the current node
|
||||||
|
const NODE_MASK: NodeMaskBuilder<'static> =
|
||||||
|
// Get access to the color attribute
|
||||||
|
NodeMaskBuilder::new().with_attrs(AttributeMaskBuilder::Some(&["font-size"]));
|
||||||
|
|
||||||
|
fn update<'a>(
|
||||||
|
&mut self,
|
||||||
|
node_view: NodeView<()>,
|
||||||
|
_node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
|
||||||
|
parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
|
||||||
|
_children: Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
|
||||||
|
_context: &SendAnyMap,
|
||||||
|
) -> bool {
|
||||||
|
let mut new = None;
|
||||||
|
for attr in node_view.attributes().into_iter().flatten() {
|
||||||
|
if attr.attribute.name == "font-size" {
|
||||||
|
new = Some(FontSize {
|
||||||
|
size: attr.value.as_float().unwrap(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let new = new.unwrap_or(parent.map(|(p,)| *p).unwrap_or_default());
|
||||||
|
// check if the member has changed
|
||||||
|
let changed = new != *self;
|
||||||
|
*self = new;
|
||||||
|
changed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let mut rdom: RealDom = RealDom::new([FontSize::to_type_erased(), Size::to_type_erased()]);
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
|
||||||
|
// intial render
|
||||||
|
let text_id = rdom.create_node(format!("Count: {count}")).id();
|
||||||
|
let mut root = rdom.get_mut(rdom.root_id()).unwrap();
|
||||||
|
// set the color to red
|
||||||
|
if let NodeTypeMut::Element(mut element) = root.node_type_mut() {
|
||||||
|
element.set_attribute(("color", "style"), "red".to_string());
|
||||||
|
element.set_attribute(("font-size", "style"), 1.);
|
||||||
|
}
|
||||||
|
root.add_child(text_id);
|
||||||
|
|
||||||
|
let ctx = SendAnyMap::new();
|
||||||
|
// update the State for nodes in the real_dom tree
|
||||||
|
let _to_rerender = rdom.update_state(ctx);
|
||||||
|
|
||||||
|
// we need to run the vdom in a async runtime
|
||||||
|
tokio::runtime::Builder::new_current_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()?
|
||||||
|
.block_on(async {
|
||||||
|
loop {
|
||||||
|
// update the count and font size
|
||||||
|
count += 1;
|
||||||
|
let mut text = rdom.get_mut(text_id).unwrap();
|
||||||
|
if let NodeTypeMut::Text(mut text) = text.node_type_mut() {
|
||||||
|
*text = format!("Count: {count}");
|
||||||
|
}
|
||||||
|
if let NodeTypeMut::Element(mut element) =
|
||||||
|
rdom.get_mut(rdom.root_id()).unwrap().node_type_mut()
|
||||||
|
{
|
||||||
|
element.set_attribute(("font-size", "style"), count as f64);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ctx = SendAnyMap::new();
|
||||||
|
let _to_rerender = rdom.update_state(ctx);
|
||||||
|
|
||||||
|
// render...
|
||||||
|
rdom.traverse_depth_first(|node| {
|
||||||
|
let indent = " ".repeat(node.height() as usize);
|
||||||
|
let font_size = *node.get::<FontSize>().unwrap();
|
||||||
|
let size = *node.get::<Size>().unwrap();
|
||||||
|
let id = node.id();
|
||||||
|
println!("{indent}{id:?} {font_size:?} {size:?}");
|
||||||
|
});
|
||||||
|
|
||||||
|
// wait 1 second
|
||||||
|
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -35,7 +35,7 @@ pub mod prelude {
|
|||||||
pub use crate::node::{ElementNode, FromAnyValue, NodeType, OwnedAttributeView, TextNode};
|
pub use crate::node::{ElementNode, FromAnyValue, NodeType, OwnedAttributeView, TextNode};
|
||||||
pub use crate::node_ref::{AttributeMaskBuilder, NodeMaskBuilder, NodeView};
|
pub use crate::node_ref::{AttributeMaskBuilder, NodeMaskBuilder, NodeView};
|
||||||
pub use crate::passes::{run_pass, PassDirection, RunPassView, TypeErasedState};
|
pub use crate::passes::{run_pass, PassDirection, RunPassView, TypeErasedState};
|
||||||
pub use crate::passes::{Dependancy, DependancyView, State};
|
pub use crate::passes::{Dependancy, DependancyView, Dependants, State};
|
||||||
pub use crate::real_dom::{NodeImmutable, NodeMut, NodeRef, RealDom};
|
pub use crate::real_dom::{NodeImmutable, NodeMut, NodeRef, RealDom};
|
||||||
pub use crate::NodeId;
|
pub use crate::NodeId;
|
||||||
pub use crate::SendAnyMap;
|
pub use crate::SendAnyMap;
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ pub trait State<V: FromAnyValue + Send + Sync = ()>: Any + Send + Sync {
|
|||||||
/// Create a workload system for this state
|
/// Create a workload system for this state
|
||||||
fn workload_system(
|
fn workload_system(
|
||||||
type_id: TypeId,
|
type_id: TypeId,
|
||||||
dependants: FxHashSet<TypeId>,
|
dependants: Arc<Dependants>,
|
||||||
pass_direction: PassDirection,
|
pass_direction: PassDirection,
|
||||||
) -> WorkloadSystem;
|
) -> WorkloadSystem;
|
||||||
|
|
||||||
@@ -138,10 +138,16 @@ pub trait State<V: FromAnyValue + Send + Sync = ()>: Any + Send + Sync {
|
|||||||
let node_mask = Self::NODE_MASK.build();
|
let node_mask = Self::NODE_MASK.build();
|
||||||
TypeErasedState {
|
TypeErasedState {
|
||||||
this_type_id: TypeId::of::<Self>(),
|
this_type_id: TypeId::of::<Self>(),
|
||||||
combined_dependancy_type_ids: all_dependanices::<V, Self>().iter().copied().collect(),
|
parent_dependancies_ids: Self::ParentDependencies::type_ids()
|
||||||
parent_dependant: !Self::ParentDependencies::type_ids().is_empty(),
|
.iter()
|
||||||
child_dependant: !Self::ChildDependencies::type_ids().is_empty(),
|
.copied()
|
||||||
dependants: FxHashSet::default(),
|
.collect(),
|
||||||
|
child_dependancies_ids: Self::ChildDependencies::type_ids()
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.collect(),
|
||||||
|
node_dependancies_ids: Self::NodeDependencies::type_ids().iter().copied().collect(),
|
||||||
|
dependants: Default::default(),
|
||||||
mask: node_mask,
|
mask: node_mask,
|
||||||
pass_direction: pass_direction::<V, Self>(),
|
pass_direction: pass_direction::<V, Self>(),
|
||||||
workload: Self::workload_system,
|
workload: Self::workload_system,
|
||||||
@@ -166,13 +172,6 @@ fn pass_direction<V: FromAnyValue + Send + Sync, S: State<V>>() -> PassDirection
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_dependanices<V: FromAnyValue + Send + Sync, S: State<V>>() -> Box<[TypeId]> {
|
|
||||||
let mut dependencies = S::ParentDependencies::type_ids().to_vec();
|
|
||||||
dependencies.extend(S::ChildDependencies::type_ids().iter());
|
|
||||||
dependencies.extend(S::NodeDependencies::type_ids().iter());
|
|
||||||
dependencies.into_boxed_slice()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[derive(Borrow, BorrowInfo)]
|
#[derive(Borrow, BorrowInfo)]
|
||||||
pub struct RunPassView<'a, V: FromAnyValue + Send + Sync = ()> {
|
pub struct RunPassView<'a, V: FromAnyValue + Send + Sync = ()> {
|
||||||
@@ -188,7 +187,7 @@ pub struct RunPassView<'a, V: FromAnyValue + Send + Sync = ()> {
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn run_pass<V: FromAnyValue + Send + Sync>(
|
pub fn run_pass<V: FromAnyValue + Send + Sync>(
|
||||||
type_id: TypeId,
|
type_id: TypeId,
|
||||||
dependants: FxHashSet<TypeId>,
|
dependants: Arc<Dependants>,
|
||||||
pass_direction: PassDirection,
|
pass_direction: PassDirection,
|
||||||
view: RunPassView<V>,
|
view: RunPassView<V>,
|
||||||
mut update_node: impl FnMut(NodeId, &SendAnyMap) -> bool,
|
mut update_node: impl FnMut(NodeId, &SendAnyMap) -> bool,
|
||||||
@@ -206,11 +205,7 @@ pub fn run_pass<V: FromAnyValue + Send + Sync>(
|
|||||||
while let Some((height, id)) = dirty.pop_front(type_id) {
|
while let Some((height, id)) = dirty.pop_front(type_id) {
|
||||||
if (update_node)(id, ctx) {
|
if (update_node)(id, ctx) {
|
||||||
nodes_updated.insert(id);
|
nodes_updated.insert(id);
|
||||||
for id in tree.children_ids(id) {
|
dependants.mark_dirty(&dirty, id, &tree, height);
|
||||||
for dependant in &dependants {
|
|
||||||
dirty.insert(*dependant, id, height + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,11 +213,7 @@ pub fn run_pass<V: FromAnyValue + Send + Sync>(
|
|||||||
while let Some((height, id)) = dirty.pop_back(type_id) {
|
while let Some((height, id)) = dirty.pop_back(type_id) {
|
||||||
if (update_node)(id, ctx) {
|
if (update_node)(id, ctx) {
|
||||||
nodes_updated.insert(id);
|
nodes_updated.insert(id);
|
||||||
if let Some(id) = tree.parent_id(id) {
|
dependants.mark_dirty(&dirty, id, &tree, height);
|
||||||
for dependant in &dependants {
|
|
||||||
dirty.insert(*dependant, id, height - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -230,24 +221,53 @@ pub fn run_pass<V: FromAnyValue + Send + Sync>(
|
|||||||
while let Some((height, id)) = dirty.pop_back(type_id) {
|
while let Some((height, id)) = dirty.pop_back(type_id) {
|
||||||
if (update_node)(id, ctx) {
|
if (update_node)(id, ctx) {
|
||||||
nodes_updated.insert(id);
|
nodes_updated.insert(id);
|
||||||
for dependant in &dependants {
|
dependants.mark_dirty(&dirty, id, &tree, height);
|
||||||
dirty.insert(*dependant, id, height);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The states that depend on this state
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Dependants {
|
||||||
|
/// The states in the parent direction that should be invalidated when this state is invalidated
|
||||||
|
pub parent: Vec<TypeId>,
|
||||||
|
/// The states in the child direction that should be invalidated when this state is invalidated
|
||||||
|
pub child: Vec<TypeId>,
|
||||||
|
/// The states in the node direction that should be invalidated when this state is invalidated
|
||||||
|
pub node: Vec<TypeId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dependants {
|
||||||
|
fn mark_dirty(&self, dirty: &DirtyNodeStates, id: NodeId, tree: &impl TreeRef, height: u16) {
|
||||||
|
for dependant in &self.child {
|
||||||
|
for id in tree.children_ids(id) {
|
||||||
|
dirty.insert(*dependant, id, height + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for dependant in &self.parent {
|
||||||
|
if let Some(id) = tree.parent_id(id) {
|
||||||
|
dirty.insert(*dependant, id, height - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for dependant in &self.node {
|
||||||
|
dirty.insert(*dependant, id, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A type erased version of [`State`] that can be added to the [`crate::prelude::RealDom`] with [`crate::prelude::RealDom::new`]
|
/// A type erased version of [`State`] that can be added to the [`crate::prelude::RealDom`] with [`crate::prelude::RealDom::new`]
|
||||||
pub struct TypeErasedState<V: FromAnyValue + Send = ()> {
|
pub struct TypeErasedState<V: FromAnyValue + Send = ()> {
|
||||||
pub(crate) this_type_id: TypeId,
|
pub(crate) this_type_id: TypeId,
|
||||||
pub(crate) parent_dependant: bool,
|
pub(crate) parent_dependancies_ids: FxHashSet<TypeId>,
|
||||||
pub(crate) child_dependant: bool,
|
pub(crate) child_dependancies_ids: FxHashSet<TypeId>,
|
||||||
pub(crate) combined_dependancy_type_ids: FxHashSet<TypeId>,
|
pub(crate) node_dependancies_ids: FxHashSet<TypeId>,
|
||||||
pub(crate) dependants: FxHashSet<TypeId>,
|
pub(crate) dependants: Arc<Dependants>,
|
||||||
pub(crate) mask: NodeMask,
|
pub(crate) mask: NodeMask,
|
||||||
pub(crate) workload: fn(TypeId, FxHashSet<TypeId>, PassDirection) -> WorkloadSystem,
|
pub(crate) workload: fn(TypeId, Arc<Dependants>, PassDirection) -> WorkloadSystem,
|
||||||
pub(crate) pass_direction: PassDirection,
|
pub(crate) pass_direction: PassDirection,
|
||||||
phantom: PhantomData<V>,
|
phantom: PhantomData<V>,
|
||||||
}
|
}
|
||||||
@@ -260,10 +280,18 @@ impl<V: FromAnyValue + Send> TypeErasedState<V> {
|
|||||||
self.pass_direction,
|
self.pass_direction,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn combined_dependancy_type_ids(&self) -> impl Iterator<Item = TypeId> + '_ {
|
||||||
|
self.parent_dependancies_ids
|
||||||
|
.iter()
|
||||||
|
.chain(self.child_dependancies_ids.iter())
|
||||||
|
.chain(self.node_dependancies_ids.iter())
|
||||||
|
.copied()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The direction that a pass should be run in
|
/// The direction that a pass should be run in
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
pub enum PassDirection {
|
pub enum PassDirection {
|
||||||
/// The pass should be run from the root to the leaves
|
/// The pass should be run from the root to the leaves
|
||||||
ParentToChild,
|
ParentToChild,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use crate::node::{
|
|||||||
};
|
};
|
||||||
use crate::node_ref::{NodeMask, NodeMaskBuilder};
|
use crate::node_ref::{NodeMask, NodeMaskBuilder};
|
||||||
use crate::node_watcher::NodeWatcher;
|
use crate::node_watcher::NodeWatcher;
|
||||||
use crate::passes::{DirtyNodeStates, TypeErasedState};
|
use crate::passes::{DirtyNodeStates, PassDirection, TypeErasedState};
|
||||||
use crate::prelude::AttributeMaskBuilder;
|
use crate::prelude::AttributeMaskBuilder;
|
||||||
use crate::tree::{TreeMut, TreeMutView, TreeRef, TreeRefView};
|
use crate::tree::{TreeMut, TreeMutView, TreeRef, TreeRefView};
|
||||||
use crate::NodeId;
|
use crate::NodeId;
|
||||||
@@ -68,12 +68,13 @@ impl<V: FromAnyValue + Send + Sync> NodesDirty<V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mark a node as added or removed from the tree
|
/// Mark a node that has had a parent changed
|
||||||
fn mark_parent_added_or_removed(&mut self, node_id: NodeId) {
|
fn mark_parent_added_or_removed(&mut self, node_id: NodeId) {
|
||||||
let hm = self.passes_updated.entry(node_id).or_default();
|
let hm = self.passes_updated.entry(node_id).or_default();
|
||||||
for pass in &*self.passes {
|
for pass in &*self.passes {
|
||||||
if pass.parent_dependant {
|
// If any of the states in this node depend on the parent then mark them as dirty
|
||||||
hm.insert(pass.this_type_id);
|
for &pass in &pass.parent_dependancies_ids {
|
||||||
|
hm.insert(pass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -82,8 +83,9 @@ impl<V: FromAnyValue + Send + Sync> NodesDirty<V> {
|
|||||||
fn mark_child_changed(&mut self, node_id: NodeId) {
|
fn mark_child_changed(&mut self, node_id: NodeId) {
|
||||||
let hm = self.passes_updated.entry(node_id).or_default();
|
let hm = self.passes_updated.entry(node_id).or_default();
|
||||||
for pass in &*self.passes {
|
for pass in &*self.passes {
|
||||||
if pass.child_dependant {
|
// If any of the states in this node depend on the children then mark them as dirty
|
||||||
hm.insert(pass.this_type_id);
|
for &pass in &pass.child_dependancies_ids {
|
||||||
|
hm.insert(pass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,16 +118,46 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
|||||||
pub fn new(tracked_states: impl Into<Box<[TypeErasedState<V>]>>) -> RealDom<V> {
|
pub fn new(tracked_states: impl Into<Box<[TypeErasedState<V>]>>) -> RealDom<V> {
|
||||||
let mut tracked_states = tracked_states.into();
|
let mut tracked_states = tracked_states.into();
|
||||||
// resolve dependants for each pass
|
// resolve dependants for each pass
|
||||||
for i in 1..tracked_states.len() {
|
for i in 1..=tracked_states.len() {
|
||||||
let (before, after) = tracked_states.split_at_mut(i);
|
let (before, after) = tracked_states.split_at_mut(i);
|
||||||
let (current, before) = before.split_last_mut().unwrap();
|
let (current, before) = before.split_last_mut().unwrap();
|
||||||
for pass in before.iter_mut().chain(after.iter_mut()) {
|
for state in before.iter_mut().chain(after.iter_mut()) {
|
||||||
|
let dependants = Arc::get_mut(&mut state.dependants).unwrap();
|
||||||
|
// If this node depends on the other state as a parent, then the other state should update its children of the current type when it is invalidated
|
||||||
if current
|
if current
|
||||||
.combined_dependancy_type_ids
|
.parent_dependancies_ids
|
||||||
.contains(&pass.this_type_id)
|
.contains(&state.this_type_id)
|
||||||
|
&& !dependants.child.contains(¤t.this_type_id)
|
||||||
{
|
{
|
||||||
pass.dependants.insert(current.this_type_id);
|
dependants.child.push(current.this_type_id);
|
||||||
}
|
}
|
||||||
|
// If this node depends on the other state as a child, then the other state should update its parent of the current type when it is invalidated
|
||||||
|
if current.child_dependancies_ids.contains(&state.this_type_id)
|
||||||
|
&& !dependants.parent.contains(¤t.this_type_id)
|
||||||
|
{
|
||||||
|
dependants.parent.push(current.this_type_id);
|
||||||
|
}
|
||||||
|
// If this node depends on the other state as a sibling, then the other state should update its siblings of the current type when it is invalidated
|
||||||
|
if current.node_dependancies_ids.contains(&state.this_type_id)
|
||||||
|
&& !dependants.node.contains(¤t.this_type_id)
|
||||||
|
{
|
||||||
|
dependants.node.push(current.this_type_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If the current state depends on itself, then it should update itself when it is invalidated
|
||||||
|
let dependants = Arc::get_mut(&mut current.dependants).unwrap();
|
||||||
|
match current.pass_direction {
|
||||||
|
PassDirection::ChildToParent => {
|
||||||
|
if !dependants.parent.contains(¤t.this_type_id) {
|
||||||
|
dependants.parent.push(current.this_type_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PassDirection::ParentToChild => {
|
||||||
|
if !dependants.child.contains(¤t.this_type_id) {
|
||||||
|
dependants.child.push(current.this_type_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let workload = construct_workload(&mut tracked_states);
|
let workload = construct_workload(&mut tracked_states);
|
||||||
@@ -1011,7 +1043,8 @@ fn construct_workload<V: FromAnyValue + Send + Sync>(
|
|||||||
// mark any dependancies
|
// mark any dependancies
|
||||||
for i in 0..unresloved_workloads.len() {
|
for i in 0..unresloved_workloads.len() {
|
||||||
let (_, pass, _) = &unresloved_workloads[i];
|
let (_, pass, _) = &unresloved_workloads[i];
|
||||||
for ty_id in pass.combined_dependancy_type_ids.clone() {
|
let all_dependancies: Vec<_> = pass.combined_dependancy_type_ids().collect();
|
||||||
|
for ty_id in all_dependancies {
|
||||||
let &(dependancy_id, _, _) = unresloved_workloads
|
let &(dependancy_id, _, _) = unresloved_workloads
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(_, pass, _)| pass.this_type_id == ty_id)
|
.find(|(_, pass, _)| pass.this_type_id == ty_id)
|
||||||
|
|||||||
Reference in new issue
Block a user