add node dependancy

This commit is contained in:
Evan Almloff committed 2022-04-16 12:27:52 -05:00
1 parent 0fb9aed273
commit 436c6a02f7
18 files changed
+1312 -575

No files matched your search

+1 -1
View File
@@ -1,4 +1,4 @@
pub mod layout_attributes;
pub mod node_ref;
pub mod real_dom;
pub mod state;
pub use dioxus_native_core_macro;
+212
View File
@@ -0,0 +1,212 @@
use dioxus_core::*;
use crate::state::union_ordered_iter;
#[derive(Debug)]
pub struct NodeView<'a> {
inner: &'a VNode<'a>,
mask: NodeMask,
}
impl<'a> NodeView<'a> {
pub fn new(mut vnode: &'a VNode<'a>, view: NodeMask, vdom: &'a VirtualDom) -> Self {
if let VNode::Component(sc) = vnode {
let scope = vdom.get_scope(sc.scope.get().unwrap()).unwrap();
vnode = scope.root_node();
}
Self {
inner: vnode,
mask: view,
}
}
pub fn id(&self) -> ElementId {
self.inner.mounted_id()
}
pub fn tag(&self) -> Option<&'a str> {
self.mask.tag.then(|| self.el().map(|el| el.tag)).flatten()
}
pub fn namespace(&self) -> Option<&'a str> {
self.mask
.namespace
.then(|| self.el().map(|el| el.namespace).flatten())
.flatten()
}
pub fn attributes(&self) -> impl Iterator<Item = &Attribute<'a>> {
self.el()
.map(|el| el.attributes)
.unwrap_or_default()
.iter()
.filter(|a| self.mask.attritutes.contains_attribute(&a.name))
}
pub fn text(&self) -> Option<&str> {
self.mask
.text
.then(|| self.txt().map(|txt| txt.text))
.flatten()
}
fn el(&self) -> Option<&'a VElement<'a>> {
if let VNode::Element(el) = &self.inner {
Some(el)
} else {
None
}
}
fn txt(&self) -> Option<&'a VText<'a>> {
if let VNode::Text(txt) = &self.inner {
Some(txt)
} else {
None
}
}
}
#[derive(PartialEq, Clone, Debug)]
pub enum AttributeMask {
All,
Dynamic(Vec<&'static str>),
Static(&'static [&'static str]),
}
impl AttributeMask {
pub const NONE: Self = Self::Static(&[]);
fn contains_attribute(&self, attr: &'static str) -> bool {
match self {
AttributeMask::All => true,
AttributeMask::Dynamic(l) => l.binary_search(&attr).is_ok(),
AttributeMask::Static(l) => l.binary_search(&attr).is_ok(),
}
}
pub fn single(new: &'static str) -> Self {
Self::Dynamic(vec![new])
}
pub fn verify(&self) {
match &self {
AttributeMask::Static(attrs) => debug_assert!(
attrs.windows(2).all(|w| w[0] < w[1]),
"attritutes must be increasing"
),
AttributeMask::Dynamic(attrs) => debug_assert!(
attrs.windows(2).all(|w| w[0] < w[1]),
"attritutes must be increasing"
),
_ => (),
}
}
pub fn union(&self, other: &Self) -> Self {
let new = match (self, other) {
(AttributeMask::Dynamic(s), AttributeMask::Dynamic(o)) => AttributeMask::Dynamic(
union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
),
(AttributeMask::Static(s), AttributeMask::Dynamic(o)) => AttributeMask::Dynamic(
union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
),
(AttributeMask::Dynamic(s), AttributeMask::Static(o)) => AttributeMask::Dynamic(
union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
),
(AttributeMask::Static(s), AttributeMask::Static(o)) => AttributeMask::Dynamic(
union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
),
_ => AttributeMask::All,
};
new.verify();
new
}
fn overlaps(&self, other: &Self) -> bool {
fn overlaps_iter(
mut self_iter: impl Iterator<Item = &'static str>,
mut other_iter: impl Iterator<Item = &'static str>,
) -> bool {
if let Some(mut other_attr) = other_iter.next() {
while let Some(self_attr) = self_iter.next() {
while other_attr < self_attr {
if let Some(attr) = other_iter.next() {
other_attr = attr;
} else {
return false;
}
}
if other_attr == self_attr {
return true;
}
}
}
false
}
match (self, other) {
(AttributeMask::All, AttributeMask::All) => true,
(AttributeMask::All, AttributeMask::Dynamic(v)) => !v.is_empty(),
(AttributeMask::All, AttributeMask::Static(s)) => !s.is_empty(),
(AttributeMask::Dynamic(v), AttributeMask::All) => !v.is_empty(),
(AttributeMask::Static(s), AttributeMask::All) => !s.is_empty(),
(AttributeMask::Dynamic(v1), AttributeMask::Dynamic(v2)) => {
overlaps_iter(v1.iter().copied(), v2.iter().copied())
}
(AttributeMask::Dynamic(v), AttributeMask::Static(s)) => {
overlaps_iter(v.iter().copied(), s.iter().copied())
}
(AttributeMask::Static(s), AttributeMask::Dynamic(v)) => {
overlaps_iter(v.iter().copied(), s.iter().copied())
}
(AttributeMask::Static(s1), AttributeMask::Static(s2)) => {
overlaps_iter(s1.iter().copied(), s2.iter().copied())
}
}
}
}
impl Default for AttributeMask {
fn default() -> Self {
AttributeMask::Static(&[])
}
}
#[derive(Default, PartialEq, Clone, Debug)]
pub struct NodeMask {
// must be sorted
attritutes: AttributeMask,
tag: bool,
namespace: bool,
text: bool,
}
impl NodeMask {
pub const NONE: Self = Self::new(AttributeMask::Static(&[]), false, false, false);
pub const ALL: Self = Self::new(AttributeMask::All, true, true, true);
/// attritutes must be sorted!
pub const fn new(attritutes: AttributeMask, tag: bool, namespace: bool, text: bool) -> Self {
Self {
attritutes,
tag,
namespace,
text,
}
}
pub fn overlaps(&self, other: &Self) -> bool {
(self.tag && other.tag)
|| (self.namespace && other.namespace)
|| self.attritutes.overlaps(&other.attritutes)
|| (self.text && other.text)
}
pub fn union(&self, other: &Self) -> Self {
Self {
attritutes: self.attritutes.union(&other.attritutes),
tag: self.tag | other.tag,
namespace: self.namespace | other.namespace,
text: self.text | other.text,
}
}
}
+57 -16
View File
@@ -1,14 +1,17 @@
use anymap::AnyMap;
use fxhash::{FxHashMap, FxHashSet};
use std::{
any::TypeId,
collections::VecDeque,
ops::{Index, IndexMut},
};
use dioxus_core::{ElementId, Mutations, VNode, VirtualDom};
use crate::state::{union_ordered_iter, AttributeMask, NodeMask, State};
use crate::state::{union_ordered_iter, State};
use crate::{
node_ref::{AttributeMask, NodeMask},
state::MemberId,
};
/// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers.
/// The render state passes from parent to children and or accumulates state from children to parents.
@@ -211,7 +214,7 @@ impl<S: State> RealDom<S> {
#[derive(PartialEq, Clone, Debug)]
enum StatesToCheck {
All,
Some(Vec<TypeId>),
Some(Vec<MemberId>),
}
impl StatesToCheck {
fn union(&self, other: &Self) -> Self {
@@ -294,14 +297,28 @@ impl<S: State> RealDom<S> {
for node_ref in &nodes_updated {
let mut changed = false;
let node = &mut self[node_ref.id];
let ids = match &node_ref.to_check {
let mut ids = match &node_ref.to_check {
StatesToCheck::All => node.state.node_dep_types(&node_ref.node_mask),
// this should only be triggered from the current node, so all members will need to be checked
StatesToCheck::Some(_) => unreachable!(),
};
for ty in ids {
let mut i = 0;
while i < ids.len() {
let id = ids[i];
let node = &mut self[node_ref.id];
let vnode = node.element(vdom);
changed |= node.state.update_node_dep_state(ty, vnode, vdom, &ctx);
if let Some(members_effected) =
node.state.update_node_dep_state(id, vnode, vdom, &ctx)
{
debug_assert!(members_effected.node_dep.iter().all(|i| i >= &id));
for m in members_effected.node_dep {
if let Err(idx) = ids.binary_search(m) {
ids.insert(idx, *m);
}
}
changed = true;
}
i += 1;
}
if changed {
to_rerender.insert(node_ref.id);
@@ -319,19 +336,30 @@ impl<S: State> RealDom<S> {
} = node_ref;
let (node, children) = self.get_node_children_mut(id).unwrap();
let children_state: Vec<_> = children.iter().map(|c| &c.state).collect();
let ids = match to_check {
let mut ids = match to_check {
StatesToCheck::All => node.state.child_dep_types(&node_mask),
StatesToCheck::Some(ids) => ids,
};
let mut changed = Vec::new();
for ty in ids {
let mut i = 0;
while i < ids.len() {
let id = ids[i];
let vnode = node.element(vdom);
if node
.state
.update_child_dep_state(ty, vnode, vdom, &children_state, &ctx)
if let Some(members_effected) =
node.state
.update_child_dep_state(id, vnode, vdom, &children_state, &ctx)
{
changed.push(ty);
debug_assert!(members_effected.node_dep.iter().all(|i| i >= &id));
for m in members_effected.node_dep {
if let Err(idx) = ids.binary_search(m) {
ids.insert(idx, *m);
}
}
for m in members_effected.child_dep {
changed.push(*m);
}
}
i += 1;
}
if let Some(parent_id) = node.parent {
if !changed.is_empty() {
@@ -374,19 +402,32 @@ impl<S: State> RealDom<S> {
to_check,
} = node_ref;
let node = &self[id];
let ids = match to_check {
let mut ids = match to_check {
StatesToCheck::All => node.state.parent_dep_types(&node_mask),
StatesToCheck::Some(ids) => ids,
};
let mut changed = Vec::new();
let (node, parent) = self.get_node_parent_mut(id).unwrap();
for ty in ids {
let mut i = 0;
while i < ids.len() {
let id = ids[i];
let vnode = node.element(vdom);
let parent = parent.as_deref();
let state = &mut node.state;
if state.update_parent_dep_state(ty, vnode, vdom, parent.map(|n| &n.state), &ctx) {
changed.push(ty);
if let Some(members_effected) =
state.update_parent_dep_state(id, vnode, vdom, parent.map(|n| &n.state), &ctx)
{
debug_assert!(members_effected.node_dep.iter().all(|i| i >= &id));
for m in members_effected.node_dep {
if let Err(idx) = ids.binary_search(m) {
ids.insert(idx, *m);
}
}
for m in members_effected.parent_dep {
changed.push(*m);
}
}
i += 1;
}
to_rerender.insert(id);
+71 -223
View File
@@ -1,7 +1,9 @@
use std::{any::TypeId, fmt::Debug};
use std::fmt::Debug;
use anymap::AnyMap;
use dioxus_core::{Attribute, ElementId, VElement, VNode, VText, VirtualDom};
use dioxus_core::VNode;
use crate::node_ref::{NodeMask, NodeView};
pub(crate) fn union_ordered_iter<T: Ord + Debug>(
s_iter: impl Iterator<Item = T>,
@@ -34,215 +36,6 @@ pub(crate) fn union_ordered_iter<T: Ord + Debug>(
v
}
#[derive(Debug)]
pub struct NodeView<'a> {
inner: &'a VNode<'a>,
mask: NodeMask,
}
impl<'a> NodeView<'a> {
pub fn new(mut vnode: &'a VNode<'a>, view: NodeMask, vdom: &'a VirtualDom) -> Self {
if let VNode::Component(sc) = vnode {
let scope = vdom.get_scope(sc.scope.get().unwrap()).unwrap();
vnode = scope.root_node();
}
Self {
inner: vnode,
mask: view,
}
}
pub fn id(&self) -> ElementId {
self.inner.mounted_id()
}
pub fn tag(&self) -> Option<&'a str> {
self.mask.tag.then(|| self.el().map(|el| el.tag)).flatten()
}
pub fn namespace(&self) -> Option<&'a str> {
self.mask
.namespace
.then(|| self.el().map(|el| el.namespace).flatten())
.flatten()
}
pub fn attributes(&self) -> impl Iterator<Item = &Attribute<'a>> {
self.el()
.map(|el| el.attributes)
.unwrap_or_default()
.iter()
.filter(|a| self.mask.attritutes.contains_attribute(&a.name))
}
pub fn text(&self) -> Option<&str> {
self.mask
.text
.then(|| self.txt().map(|txt| txt.text))
.flatten()
}
fn el(&self) -> Option<&'a VElement<'a>> {
if let VNode::Element(el) = &self.inner {
Some(el)
} else {
None
}
}
fn txt(&self) -> Option<&'a VText<'a>> {
if let VNode::Text(txt) = &self.inner {
Some(txt)
} else {
None
}
}
}
#[derive(PartialEq, Clone, Debug)]
pub enum AttributeMask {
All,
Dynamic(Vec<&'static str>),
Static(&'static [&'static str]),
}
impl AttributeMask {
pub const NONE: Self = Self::Static(&[]);
fn contains_attribute(&self, attr: &'static str) -> bool {
match self {
AttributeMask::All => true,
AttributeMask::Dynamic(l) => l.binary_search(&attr).is_ok(),
AttributeMask::Static(l) => l.binary_search(&attr).is_ok(),
}
}
pub fn single(new: &'static str) -> Self {
Self::Dynamic(vec![new])
}
pub fn verify(&self) {
match &self {
AttributeMask::Static(attrs) => debug_assert!(
attrs.windows(2).all(|w| w[0] < w[1]),
"attritutes must be increasing"
),
AttributeMask::Dynamic(attrs) => debug_assert!(
attrs.windows(2).all(|w| w[0] < w[1]),
"attritutes must be increasing"
),
_ => (),
}
}
pub fn union(&self, other: &Self) -> Self {
let new = match (self, other) {
(AttributeMask::Dynamic(s), AttributeMask::Dynamic(o)) => AttributeMask::Dynamic(
union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
),
(AttributeMask::Static(s), AttributeMask::Dynamic(o)) => AttributeMask::Dynamic(
union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
),
(AttributeMask::Dynamic(s), AttributeMask::Static(o)) => AttributeMask::Dynamic(
union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
),
(AttributeMask::Static(s), AttributeMask::Static(o)) => AttributeMask::Dynamic(
union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
),
_ => AttributeMask::All,
};
new.verify();
new
}
fn overlaps(&self, other: &Self) -> bool {
fn overlaps_iter(
mut self_iter: impl Iterator<Item = &'static str>,
mut other_iter: impl Iterator<Item = &'static str>,
) -> bool {
if let Some(mut other_attr) = other_iter.next() {
while let Some(self_attr) = self_iter.next() {
while other_attr < self_attr {
if let Some(attr) = other_iter.next() {
other_attr = attr;
} else {
return false;
}
}
if other_attr == self_attr {
return true;
}
}
}
false
}
match (self, other) {
(AttributeMask::All, AttributeMask::All) => true,
(AttributeMask::All, AttributeMask::Dynamic(v)) => !v.is_empty(),
(AttributeMask::All, AttributeMask::Static(s)) => !s.is_empty(),
(AttributeMask::Dynamic(v), AttributeMask::All) => !v.is_empty(),
(AttributeMask::Static(s), AttributeMask::All) => !s.is_empty(),
(AttributeMask::Dynamic(v1), AttributeMask::Dynamic(v2)) => {
overlaps_iter(v1.iter().copied(), v2.iter().copied())
}
(AttributeMask::Dynamic(v), AttributeMask::Static(s)) => {
overlaps_iter(v.iter().copied(), s.iter().copied())
}
(AttributeMask::Static(s), AttributeMask::Dynamic(v)) => {
overlaps_iter(v.iter().copied(), s.iter().copied())
}
(AttributeMask::Static(s1), AttributeMask::Static(s2)) => {
overlaps_iter(s1.iter().copied(), s2.iter().copied())
}
}
}
}
impl Default for AttributeMask {
fn default() -> Self {
AttributeMask::Static(&[])
}
}
#[derive(Default, PartialEq, Clone, Debug)]
pub struct NodeMask {
// must be sorted
attritutes: AttributeMask,
tag: bool,
namespace: bool,
text: bool,
}
impl NodeMask {
pub const NONE: Self = Self::new(AttributeMask::Static(&[]), false, false, false);
pub const ALL: Self = Self::new(AttributeMask::All, true, true, true);
/// attritutes must be sorted!
pub const fn new(attritutes: AttributeMask, tag: bool, namespace: bool, text: bool) -> Self {
Self {
attritutes,
tag,
namespace,
text,
}
}
pub fn overlaps(&self, other: &Self) -> bool {
(self.tag && other.tag)
|| (self.namespace && other.namespace)
|| self.attritutes.overlaps(&other.attritutes)
|| (self.text && other.text)
}
pub fn union(&self, other: &Self) -> Self {
Self {
attritutes: self.attritutes.union(&other.attritutes),
tag: self.tag | other.tag,
namespace: self.namespace | other.namespace,
text: self.text | other.text,
}
}
}
/// This state is derived from children. For example a node's size could be derived from the size of children.
/// Called when the current node's node properties are modified, a child's [BubbledUpState] is modified or a child is removed.
/// Called at most once per update.
@@ -250,7 +43,8 @@ pub trait ChildDepState {
/// The context is passed to the [PushedDownState::reduce] when it is pushed down.
/// This is sometimes nessisary for lifetime purposes.
type Ctx;
type DepState: ChildDepState;
/// This must be either a [ChildDepState] or [NodeDepState]
type DepState;
const NODE_MASK: NodeMask = NodeMask::NONE;
fn reduce<'a>(
&mut self,
@@ -269,7 +63,8 @@ pub trait ParentDepState {
/// The context is passed to the [PushedDownState::reduce] when it is pushed down.
/// This is sometimes nessisary for lifetime purposes.
type Ctx;
type DepState: ParentDepState;
/// This must be either a [ParentDepState] or [NodeDepState]
type DepState;
const NODE_MASK: NodeMask = NodeMask::NONE;
fn reduce(&mut self, node: NodeView, parent: Option<&Self::DepState>, ctx: &Self::Ctx) -> bool;
}
@@ -279,40 +74,93 @@ pub trait ParentDepState {
/// Called at most once per update.
pub trait NodeDepState {
type Ctx;
type DepState: NodeDepState;
const NODE_MASK: NodeMask = NodeMask::NONE;
fn reduce(&mut self, node: NodeView, ctx: &Self::Ctx) -> bool;
fn reduce(&mut self, node: NodeView, sibling: &Self::DepState, ctx: &Self::Ctx) -> bool;
}
#[derive(Debug)]
pub struct ChildStatesChanged {
pub node_dep: &'static [MemberId],
pub child_dep: &'static [MemberId],
}
#[derive(Debug)]
pub struct ParentStatesChanged {
pub node_dep: &'static [MemberId],
pub parent_dep: &'static [MemberId],
}
#[derive(Debug)]
pub struct NodeStatesChanged {
pub node_dep: &'static [MemberId],
}
pub trait State: Default + Clone {
fn update_node_dep_state<'a>(
&'a mut self,
ty: TypeId,
ty: MemberId,
node: &'a VNode<'a>,
vdom: &'a dioxus_core::VirtualDom,
ctx: &AnyMap,
) -> bool;
) -> Option<NodeStatesChanged>;
/// This must be a valid resolution order. (no nodes updated before a state they rely on)
fn child_dep_types(&self, mask: &NodeMask) -> Vec<TypeId>;
fn child_dep_types(&self, mask: &NodeMask) -> Vec<MemberId>;
fn update_parent_dep_state<'a>(
&'a mut self,
ty: TypeId,
ty: MemberId,
node: &'a VNode<'a>,
vdom: &'a dioxus_core::VirtualDom,
parent: Option<&Self>,
ctx: &AnyMap,
) -> bool;
) -> Option<ParentStatesChanged>;
/// This must be a valid resolution order. (no nodes updated before a state they rely on)
fn parent_dep_types(&self, mask: &NodeMask) -> Vec<TypeId>;
fn parent_dep_types(&self, mask: &NodeMask) -> Vec<MemberId>;
fn update_child_dep_state<'a>(
&'a mut self,
ty: TypeId,
ty: MemberId,
node: &'a VNode<'a>,
vdom: &'a dioxus_core::VirtualDom,
children: &[&Self],
ctx: &AnyMap,
) -> bool;
) -> Option<ChildStatesChanged>;
/// This must be a valid resolution order. (no nodes updated before a state they rely on)
fn node_dep_types(&self, mask: &NodeMask) -> Vec<TypeId>;
fn node_dep_types(&self, mask: &NodeMask) -> Vec<MemberId>;
}
impl ChildDepState for () {
type Ctx = ();
type DepState = ();
fn reduce<'a>(
&mut self,
_: NodeView,
_: impl Iterator<Item = &'a Self::DepState>,
_: &Self::Ctx,
) -> bool
where
Self::DepState: 'a,
{
false
}
}
impl ParentDepState for () {
type Ctx = ();
type DepState = ();
fn reduce(&mut self, _: NodeView, _: Option<&Self::DepState>, _: &Self::Ctx) -> bool {
false
}
}
impl NodeDepState for () {
type Ctx = ();
type DepState = ();
fn reduce(&mut self, _: NodeView, _sibling: &Self::DepState, _: &Self::Ctx) -> bool {
false
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct MemberId(pub usize);