Merge branch 'upstream' into make-widgets-cross-framework
This commit is contained in:
commit
43372c7609
8 files changed
+295
-91
No files matched your search
@@ -37,7 +37,7 @@ pub mod prelude {
|
||||
pub use crate::node::{ElementNode, FromAnyValue, NodeType, OwnedAttributeView, TextNode};
|
||||
pub use crate::node_ref::{AttributeMaskBuilder, NodeMaskBuilder, NodeView};
|
||||
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::NodeId;
|
||||
pub use crate::SendAnyMap;
|
||||
|
||||
@@ -129,7 +129,7 @@ pub trait State<V: FromAnyValue + Send + Sync = ()>: Any + Send + Sync {
|
||||
/// Create a workload system for this state
|
||||
fn workload_system(
|
||||
type_id: TypeId,
|
||||
dependants: FxHashSet<TypeId>,
|
||||
dependants: Arc<Dependants>,
|
||||
pass_direction: PassDirection,
|
||||
) -> WorkloadSystem;
|
||||
|
||||
@@ -141,10 +141,16 @@ pub trait State<V: FromAnyValue + Send + Sync = ()>: Any + Send + Sync {
|
||||
let node_mask = Self::NODE_MASK.build();
|
||||
TypeErasedState {
|
||||
this_type_id: TypeId::of::<Self>(),
|
||||
combined_dependancy_type_ids: all_dependanices::<V, Self>().iter().copied().collect(),
|
||||
parent_dependant: !Self::ParentDependencies::type_ids().is_empty(),
|
||||
child_dependant: !Self::ChildDependencies::type_ids().is_empty(),
|
||||
dependants: FxHashSet::default(),
|
||||
parent_dependancies_ids: Self::ParentDependencies::type_ids()
|
||||
.iter()
|
||||
.copied()
|
||||
.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,
|
||||
pass_direction: pass_direction::<V, Self>(),
|
||||
workload: Self::workload_system,
|
||||
@@ -169,13 +175,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)]
|
||||
#[derive(Borrow, BorrowInfo)]
|
||||
pub struct RunPassView<'a, V: FromAnyValue + Send + Sync = ()> {
|
||||
@@ -191,7 +190,7 @@ pub struct RunPassView<'a, V: FromAnyValue + Send + Sync = ()> {
|
||||
#[doc(hidden)]
|
||||
pub fn run_pass<V: FromAnyValue + Send + Sync>(
|
||||
type_id: TypeId,
|
||||
dependants: FxHashSet<TypeId>,
|
||||
dependants: Arc<Dependants>,
|
||||
pass_direction: PassDirection,
|
||||
view: RunPassView<V>,
|
||||
enter_shadow_dom: bool,
|
||||
@@ -210,34 +209,7 @@ pub fn run_pass<V: FromAnyValue + Send + Sync>(
|
||||
while let Some((height, id)) = dirty.pop_front(type_id) {
|
||||
if (update_node)(id, ctx) {
|
||||
nodes_updated.insert(id);
|
||||
let shadow_tree = tree.shadow_tree(id);
|
||||
match (enter_shadow_dom, shadow_tree) {
|
||||
(true, Some(shadow_tree)) => {
|
||||
// If this pass uses the shadow dom, update the shadow dom children instead of the normal children
|
||||
for id in &shadow_tree.shadow_roots {
|
||||
for dependant in &dependants {
|
||||
dirty.insert(*dependant, *id, height + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
for id in tree.children_ids(id) {
|
||||
for dependant in &dependants {
|
||||
dirty.insert(*dependant, id, height + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// If this pass uses the shadow dom, update the light dom's children if this node is a slot
|
||||
if enter_shadow_dom {
|
||||
if let Some(slot_for_light_tree) = tree.slot_for_light_tree(id) {
|
||||
for id in tree.children_ids(slot_for_light_tree) {
|
||||
for dependant in &dependants {
|
||||
dirty.insert(*dependant, id, height + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dependants.mark_dirty(&dirty, id, &tree, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -245,23 +217,7 @@ pub fn run_pass<V: FromAnyValue + Send + Sync>(
|
||||
while let Some((height, id)) = dirty.pop_back(type_id) {
|
||||
if (update_node)(id, ctx) {
|
||||
nodes_updated.insert(id);
|
||||
|
||||
// If this pass uses the shadow dom, update the light dom root if this node is a root
|
||||
let light_tree_root = tree.light_tree_root(id);
|
||||
match (enter_shadow_dom, light_tree_root) {
|
||||
(true, Some(light_tree_root)) => {
|
||||
for dependant in &dependants {
|
||||
dirty.insert(*dependant, light_tree_root, height + 1);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if let Some(id) = tree.parent_id(id) {
|
||||
for dependant in &dependants {
|
||||
dirty.insert(*dependant, id, height - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dependants.mark_dirty(&dirty, id, &tree, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -269,24 +225,53 @@ pub fn run_pass<V: FromAnyValue + Send + Sync>(
|
||||
while let Some((height, id)) = dirty.pop_back(type_id) {
|
||||
if (update_node)(id, ctx) {
|
||||
nodes_updated.insert(id);
|
||||
for dependant in &dependants {
|
||||
dirty.insert(*dependant, id, height);
|
||||
}
|
||||
dependants.mark_dirty(&dirty, id, &tree, 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`]
|
||||
pub struct TypeErasedState<V: FromAnyValue + Send = ()> {
|
||||
pub(crate) this_type_id: TypeId,
|
||||
pub(crate) parent_dependant: bool,
|
||||
pub(crate) child_dependant: bool,
|
||||
pub(crate) combined_dependancy_type_ids: FxHashSet<TypeId>,
|
||||
pub(crate) dependants: FxHashSet<TypeId>,
|
||||
pub(crate) parent_dependancies_ids: FxHashSet<TypeId>,
|
||||
pub(crate) child_dependancies_ids: FxHashSet<TypeId>,
|
||||
pub(crate) node_dependancies_ids: FxHashSet<TypeId>,
|
||||
pub(crate) dependants: Arc<Dependants>,
|
||||
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,
|
||||
phantom: PhantomData<V>,
|
||||
}
|
||||
@@ -299,10 +284,18 @@ impl<V: FromAnyValue + Send> TypeErasedState<V> {
|
||||
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
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||
pub enum PassDirection {
|
||||
/// The pass should be run from the root to the leaves
|
||||
ParentToChild,
|
||||
|
||||
@@ -16,7 +16,7 @@ use crate::node::{
|
||||
};
|
||||
use crate::node_ref::{NodeMask, NodeMaskBuilder};
|
||||
use crate::node_watcher::{AttributeWatcher, NodeWatcher};
|
||||
use crate::passes::{DirtyNodeStates, TypeErasedState};
|
||||
use crate::passes::{DirtyNodeStates, PassDirection, TypeErasedState};
|
||||
use crate::prelude::AttributeMaskBuilder;
|
||||
use crate::tree::{TreeMut, TreeMutView, TreeRef, TreeRefView};
|
||||
use crate::NodeId;
|
||||
@@ -70,12 +70,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) {
|
||||
let hm = self.passes_updated.entry(node_id).or_default();
|
||||
for pass in &*self.passes {
|
||||
if pass.parent_dependant {
|
||||
hm.insert(pass.this_type_id);
|
||||
// If any of the states in this node depend on the parent then mark them as dirty
|
||||
for &pass in &pass.parent_dependancies_ids {
|
||||
hm.insert(pass);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,8 +85,9 @@ impl<V: FromAnyValue + Send + Sync> NodesDirty<V> {
|
||||
fn mark_child_changed(&mut self, node_id: NodeId) {
|
||||
let hm = self.passes_updated.entry(node_id).or_default();
|
||||
for pass in &*self.passes {
|
||||
if pass.child_dependant {
|
||||
hm.insert(pass.this_type_id);
|
||||
// If any of the states in this node depend on the children then mark them as dirty
|
||||
for &pass in &pass.child_dependancies_ids {
|
||||
hm.insert(pass);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,16 +123,46 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
||||
pub fn new(tracked_states: impl Into<Box<[TypeErasedState<V>]>>) -> RealDom<V> {
|
||||
let mut tracked_states = tracked_states.into();
|
||||
// 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 (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
|
||||
.combined_dependancy_type_ids
|
||||
.contains(&pass.this_type_id)
|
||||
.parent_dependancies_ids
|
||||
.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);
|
||||
@@ -1107,7 +1139,8 @@ fn construct_workload<V: FromAnyValue + Send + Sync>(
|
||||
// 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 all_dependancies: Vec<_> = pass.combined_dependancy_type_ids().collect();
|
||||
for ty_id in all_dependancies {
|
||||
let &(dependancy_id, _, _) = unresloved_workloads
|
||||
.iter()
|
||||
.find(|(_, pass, _)| pass.this_type_id == ty_id)
|
||||
|
||||
Reference in new issue
Block a user