Subtree memorization / reactive templates (#488)
This commit adds subtree memoization to Dioxus. Subtree memoization is basically a compile-time step that drastically reduces the amount of work the diffing engine needs to do at runtime by extracting non-changing nodes out into a static "template." Templates are then understood by the various renderers in the ecosystem as a faster way of rendering the same items. For example, in the web, templates are simply a set of DOM Nodes created once and then cloned later. This is the same pattern frameworks like Lithtml and SolidJS use to achieve near-perfect performance. Subtree memoization adds an additional level of complexity to Dioxus. The RSX macro needs to be much smarter to identify changing/nonchanging nodes and generate a mapping between the Template and its runtime counterparts. This commit represents a working starter point for this work, adding support for templates for the web, desktop, liveview, ssr, and native-core renderers. In the future we will try to shrink code generation, generally improve performance, and simplify our implementation.
This commit is contained in:
1 parent
b32fd2d2cd
commit
047ed1e553
80 files changed
+6774
-2552
No files matched your search
@@ -233,3 +233,204 @@ impl<'a> AttributeValue<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A owned attribute value.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[cfg_attr(
|
||||
all(feature = "serialize"),
|
||||
derive(serde::Serialize, serde::Deserialize)
|
||||
)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum OwnedAttributeValue {
|
||||
Text(String),
|
||||
Float32(f32),
|
||||
Float64(f64),
|
||||
Int32(i32),
|
||||
Int64(i64),
|
||||
Uint32(u32),
|
||||
Uint64(u64),
|
||||
Bool(bool),
|
||||
|
||||
Vec3Float(f32, f32, f32),
|
||||
Vec3Int(i32, i32, i32),
|
||||
Vec3Uint(u32, u32, u32),
|
||||
|
||||
Vec4Float(f32, f32, f32, f32),
|
||||
Vec4Int(i32, i32, i32, i32),
|
||||
Vec4Uint(u32, u32, u32, u32),
|
||||
|
||||
Bytes(Vec<u8>),
|
||||
// TODO: support other types
|
||||
// Any(ArbitraryAttributeValue<'a>),
|
||||
}
|
||||
|
||||
impl PartialEq<AttributeValue<'_>> for OwnedAttributeValue {
|
||||
fn eq(&self, other: &AttributeValue<'_>) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Text(l0), AttributeValue::Text(r0)) => l0 == r0,
|
||||
(Self::Float32(l0), AttributeValue::Float32(r0)) => l0 == r0,
|
||||
(Self::Float64(l0), AttributeValue::Float64(r0)) => l0 == r0,
|
||||
(Self::Int32(l0), AttributeValue::Int32(r0)) => l0 == r0,
|
||||
(Self::Int64(l0), AttributeValue::Int64(r0)) => l0 == r0,
|
||||
(Self::Uint32(l0), AttributeValue::Uint32(r0)) => l0 == r0,
|
||||
(Self::Uint64(l0), AttributeValue::Uint64(r0)) => l0 == r0,
|
||||
(Self::Bool(l0), AttributeValue::Bool(r0)) => l0 == r0,
|
||||
(Self::Vec3Float(l0, l1, l2), AttributeValue::Vec3Float(r0, r1, r2)) => {
|
||||
l0 == r0 && l1 == r1 && l2 == r2
|
||||
}
|
||||
(Self::Vec3Int(l0, l1, l2), AttributeValue::Vec3Int(r0, r1, r2)) => {
|
||||
l0 == r0 && l1 == r1 && l2 == r2
|
||||
}
|
||||
(Self::Vec3Uint(l0, l1, l2), AttributeValue::Vec3Uint(r0, r1, r2)) => {
|
||||
l0 == r0 && l1 == r1 && l2 == r2
|
||||
}
|
||||
(Self::Vec4Float(l0, l1, l2, l3), AttributeValue::Vec4Float(r0, r1, r2, r3)) => {
|
||||
l0 == r0 && l1 == r1 && l2 == r2 && l3 == r3
|
||||
}
|
||||
(Self::Vec4Int(l0, l1, l2, l3), AttributeValue::Vec4Int(r0, r1, r2, r3)) => {
|
||||
l0 == r0 && l1 == r1 && l2 == r2 && l3 == r3
|
||||
}
|
||||
(Self::Vec4Uint(l0, l1, l2, l3), AttributeValue::Vec4Uint(r0, r1, r2, r3)) => {
|
||||
l0 == r0 && l1 == r1 && l2 == r2 && l3 == r3
|
||||
}
|
||||
(Self::Bytes(l0), AttributeValue::Bytes(r0)) => l0 == r0,
|
||||
(_, _) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<AttributeValue<'a>> for OwnedAttributeValue {
|
||||
fn from(attr: AttributeValue<'a>) -> Self {
|
||||
match attr {
|
||||
AttributeValue::Text(t) => OwnedAttributeValue::Text(t.to_owned()),
|
||||
AttributeValue::Float32(f) => OwnedAttributeValue::Float32(f),
|
||||
AttributeValue::Float64(f) => OwnedAttributeValue::Float64(f),
|
||||
AttributeValue::Int32(i) => OwnedAttributeValue::Int32(i),
|
||||
AttributeValue::Int64(i) => OwnedAttributeValue::Int64(i),
|
||||
AttributeValue::Uint32(u) => OwnedAttributeValue::Uint32(u),
|
||||
AttributeValue::Uint64(u) => OwnedAttributeValue::Uint64(u),
|
||||
AttributeValue::Bool(b) => OwnedAttributeValue::Bool(b),
|
||||
AttributeValue::Vec3Float(f1, f2, f3) => OwnedAttributeValue::Vec3Float(f1, f2, f3),
|
||||
AttributeValue::Vec3Int(f1, f2, f3) => OwnedAttributeValue::Vec3Int(f1, f2, f3),
|
||||
AttributeValue::Vec3Uint(f1, f2, f3) => OwnedAttributeValue::Vec3Uint(f1, f2, f3),
|
||||
AttributeValue::Vec4Float(f1, f2, f3, f4) => {
|
||||
OwnedAttributeValue::Vec4Float(f1, f2, f3, f4)
|
||||
}
|
||||
AttributeValue::Vec4Int(f1, f2, f3, f4) => OwnedAttributeValue::Vec4Int(f1, f2, f3, f4),
|
||||
AttributeValue::Vec4Uint(f1, f2, f3, f4) => {
|
||||
OwnedAttributeValue::Vec4Uint(f1, f2, f3, f4)
|
||||
}
|
||||
AttributeValue::Bytes(b) => OwnedAttributeValue::Bytes(b.to_owned()),
|
||||
AttributeValue::Any(_) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// todo
|
||||
#[allow(missing_docs)]
|
||||
impl OwnedAttributeValue {
|
||||
pub fn as_text(&self) -> Option<&str> {
|
||||
match self {
|
||||
OwnedAttributeValue::Text(s) => Some(s),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_float32(&self) -> Option<f32> {
|
||||
match self {
|
||||
OwnedAttributeValue::Float32(f) => Some(*f),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_float64(&self) -> Option<f64> {
|
||||
match self {
|
||||
OwnedAttributeValue::Float64(f) => Some(*f),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_int32(&self) -> Option<i32> {
|
||||
match self {
|
||||
OwnedAttributeValue::Int32(i) => Some(*i),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_int64(&self) -> Option<i64> {
|
||||
match self {
|
||||
OwnedAttributeValue::Int64(i) => Some(*i),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_uint32(&self) -> Option<u32> {
|
||||
match self {
|
||||
OwnedAttributeValue::Uint32(i) => Some(*i),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_uint64(&self) -> Option<u64> {
|
||||
match self {
|
||||
OwnedAttributeValue::Uint64(i) => Some(*i),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_bool(&self) -> Option<bool> {
|
||||
match self {
|
||||
OwnedAttributeValue::Bool(b) => Some(*b),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vec3_float(&self) -> Option<(f32, f32, f32)> {
|
||||
match self {
|
||||
OwnedAttributeValue::Vec3Float(x, y, z) => Some((*x, *y, *z)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vec3_int(&self) -> Option<(i32, i32, i32)> {
|
||||
match self {
|
||||
OwnedAttributeValue::Vec3Int(x, y, z) => Some((*x, *y, *z)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vec3_uint(&self) -> Option<(u32, u32, u32)> {
|
||||
match self {
|
||||
OwnedAttributeValue::Vec3Uint(x, y, z) => Some((*x, *y, *z)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vec4_float(&self) -> Option<(f32, f32, f32, f32)> {
|
||||
match self {
|
||||
OwnedAttributeValue::Vec4Float(x, y, z, w) => Some((*x, *y, *z, *w)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vec4_int(&self) -> Option<(i32, i32, i32, i32)> {
|
||||
match self {
|
||||
OwnedAttributeValue::Vec4Int(x, y, z, w) => Some((*x, *y, *z, *w)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vec4_uint(&self) -> Option<(u32, u32, u32, u32)> {
|
||||
match self {
|
||||
OwnedAttributeValue::Vec4Uint(x, y, z, w) => Some((*x, *y, *z, *w)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_bytes(&self) -> Option<&[u8]> {
|
||||
match self {
|
||||
OwnedAttributeValue::Bytes(b) => Some(b),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user