HTML element is the generic container for flow content. It has no effect on the content or layout until
+/// styled in some way using CSS (e.g. styling is directly applied to it, or some kind of layout model like Flexbox is
+/// applied to its parent element).
+///
+/// As a "pure" container, the
element does not inherently represent anything. Instead, it's used to group content
+/// so it can be easily styled using the class or id attributes, marking a section of a document as being written in a
+/// different language (using the lang attribute), and so on.
+///
+/// ## Usage
+/// ```
+/// rsx!{
+/// div { class: "tall", id: "unique id"
+/// h1 {}
+/// p {}
+/// }
+/// }
+///
+/// ```
+///
+/// ## Specifications
+/// - Content categories: Flow content, palpable content.
+/// - Permitted content: Flow content.
+/// - Permitted parents: Any element that accepts flow content.
+#[allow(non_camel_case_types)]
+struct div {}
+
+struct h1 {}
+
+struct h2 {}
+
+trait BasicElement: Sized {
+ const TagName: &'static str;
+ fn get_bump(&self) -> &Bump;
+ fn new(factory: Factory) -> Self;
+ fn add_children(self) -> Self {
+ self
+ }
+ fn iter_children(self) -> Self {
+ self
+ }
+ fn finish(self) -> Self {
+ self
+ }
+}
+
+impl BasicElement for div {
+ const TagName: &'static str = "div";
+
+ fn get_bump(&self) -> &Bump {
+ todo!()
+ }
+
+ fn new(factory: Factory) -> Self {
+ todo!()
+ }
+}
+
+impl div {
+ fn class(self) -> Self {
+ self
+ }
+ fn tag(self) -> Self {
+ self
+ }
+ fn r#type(self) -> Self {
+ self
+ }
+}
+
+#[derive(Clone, Copy)]
+struct Factory<'a> {
+ bump: &'a bumpalo::Bump,
+}
+
+impl<'a> Factory<'a> {
+ fn text(&self) -> &str {
+ todo!()
+ }
+ fn new_el(&'a self, tag: &'static str) -> ElementBuilder<'a> {
+ ElementBuilder {
+ bump: self.bump,
+ tag,
+ }
+ }
+}
+
+struct ElementBuilder<'a> {
+ tag: &'static str,
+ bump: &'a bumpalo::Bump,
+}
diff --git a/packages/core/src/arena.rs b/packages/core/src/arena.rs
index 210a04c4e..4340b7eec 100644
--- a/packages/core/src/arena.rs
+++ b/packages/core/src/arena.rs
@@ -21,6 +21,75 @@ enum MutStatus {
Mut,
}
+// impl ScopeArenaInner {
+// pub fn new(arena: Arena) -> Self {
+// ScopeArenaInner {
+// arena: UnsafeCell::new(arena),
+// locks: Default::default(),
+// }
+// }
+
+// /// THIS METHOD IS CURRENTLY UNSAFE
+// /// THERE ARE NO CHECKS TO VERIFY THAT WE ARE ALLOWED TO DO THIS
+// pub fn try_get(&self, idx: ScopeIdx) -> Result<&Scope> {
+// let inner = unsafe { &*self.arena.get() };
+// let scope = inner.get(idx);
+// scope.ok_or_else(|| Error::FatalInternal("Scope not found"))
+// }
+
+// /// THIS METHOD IS CURRENTLY UNSAFE
+// /// THERE ARE NO CHECKS TO VERIFY THAT WE ARE ALLOWED TO DO THIS
+// pub fn try_get_mut(&self, idx: ScopeIdx) -> Result<&mut Scope> {
+// let inner = unsafe { &mut *self.arena.get() };
+// let scope = inner.get_mut(idx);
+// scope.ok_or_else(|| Error::FatalInternal("Scope not found"))
+// }
+
+// fn inner(&self) -> &Arena {
+// todo!()
+// }
+
+// fn inner_mut(&mut self) -> &mut Arena {
+// todo!()
+// }
+
+// /// THIS METHOD IS CURRENTLY UNSAFE
+// /// THERE ARE NO CHECKS TO VERIFY THAT WE ARE ALLOWED TO DO THIS
+// pub fn with(&self, f: impl FnOnce(&mut Arena) -> T) -> Result {
+// let inner = unsafe { &mut *self.arena.get() };
+// Ok(f(inner))
+// // todo!()
+// }
+
+// pub fn with_scope<'b, O: 'static>(
+// &'b self,
+// id: ScopeIdx,
+// f: impl FnOnce(&'b mut Scope) -> O,
+// ) -> Result {
+// todo!()
+// }
+
+// // return a bumpframe with a lifetime attached to the arena borrow
+// // this is useful for merging lifetimes
+// pub fn with_scope_vnode<'b>(
+// &self,
+// id: ScopeIdx,
+// f: impl FnOnce(&mut Scope) -> &VNode<'b>,
+// ) -> Result<&VNode<'b>> {
+// todo!()
+// }
+
+// pub fn try_remove(&mut self, id: ScopeIdx) -> Result {
+// let inner = unsafe { &mut *self.arena.get() };
+// inner
+// .remove(id)
+// .ok_or_else(|| Error::FatalInternal("Scope not found"))
+// }
+
+// unsafe fn inner_unchecked<'s>() -> &'s mut Arena {
+// todo!()
+// }
+// }
impl ScopeArena {
pub fn new(arena: Arena) -> Self {
ScopeArena(Rc::new(RefCell::new(ScopeArenaInner {
@@ -79,7 +148,7 @@ impl ScopeArena {
todo!()
}
- pub fn try_remove(&mut self, id: ScopeIdx) -> Result {
+ pub fn try_remove(&self, id: ScopeIdx) -> Result {
let inner = unsafe { &mut *self.0.borrow().arena.get() };
inner
.remove(id)
diff --git a/packages/core/src/debug_renderer.rs b/packages/core/src/debug_renderer.rs
index 82eb10538..13486bb4a 100644
--- a/packages/core/src/debug_renderer.rs
+++ b/packages/core/src/debug_renderer.rs
@@ -38,9 +38,9 @@ impl DebugRenderer {
Ok(())
}
- pub fn step(&mut self, machine: &mut DiffMachine) -> Result<()> {
- Ok(())
- }
+ // pub fn step(&mut self, machine: &mut DiffMachine) -> Result<()> {
+ // Ok(())
+ // }
// this does a "holy" compare - if something is missing in the rhs, it doesn't complain.
// it only complains if something shows up that's not in the lhs, *or* if a value is different.
diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs
index 399720991..5d7265e35 100644
--- a/packages/core/src/diff.rs
+++ b/packages/core/src/diff.rs
@@ -22,13 +22,17 @@
//! More info on how to improve this diffing algorithm:
//! - https://hacks.mozilla.org/2019/03/fast-bump-allocated-virtual-doms-with-rust-and-wasm/
-use crate::{arena::ScopeArena, innerlude::*};
+use crate::{
+ arena::{ScopeArena, ScopeArenaInner},
+ innerlude::*,
+};
use fxhash::{FxHashMap, FxHashSet};
use std::{
any::Any,
cell::Cell,
cmp::Ordering,
+ marker::PhantomData,
rc::{Rc, Weak},
};
@@ -42,7 +46,7 @@ use std::{
/// will receive modifications. However, instead of using child-based methods for descending through the tree, we instead
/// ask the RealDom to either push or pop real nodes onto the stack. This saves us the indexing cost while working on a
/// single node
-pub trait RealDom {
+pub trait RealDom<'a> {
// Navigation
fn push_root(&mut self, root: RealDomNode);
@@ -55,27 +59,27 @@ pub trait RealDom {
fn remove_all_children(&mut self);
// Create
- fn create_text_node(&mut self, text: &str) -> RealDomNode;
- fn create_element(&mut self, tag: &str) -> RealDomNode;
- fn create_element_ns(&mut self, tag: &str, namespace: &str) -> RealDomNode;
+ fn create_text_node(&mut self, text: &'a str) -> RealDomNode;
+ fn create_element(&mut self, tag: &'static str) -> RealDomNode;
+ fn create_element_ns(&mut self, tag: &'static str, namespace: &'static str) -> RealDomNode;
// placeholders are nodes that don't get rendered but still exist as an "anchor" in the real dom
fn create_placeholder(&mut self) -> RealDomNode;
// events
fn new_event_listener(
&mut self,
- event: &str,
+ event: &'static str,
scope: ScopeIdx,
element_id: usize,
realnode: RealDomNode,
);
// fn new_event_listener(&mut self, event: &str);
- fn remove_event_listener(&mut self, event: &str);
+ fn remove_event_listener(&mut self, event: &'static str);
// modify
- fn set_text(&mut self, text: &str);
- fn set_attribute(&mut self, name: &str, value: &str, is_namespaced: bool);
- fn remove_attribute(&mut self, name: &str);
+ fn set_text(&mut self, text: &'a str);
+ fn set_attribute(&mut self, name: &'static str, value: &'a str, is_namespaced: bool);
+ fn remove_attribute(&mut self, name: &'static str);
// node ref
fn raw_node_as_any_mut(&self) -> &mut dyn Any;
@@ -93,19 +97,19 @@ pub trait RealDom {
/// The order of these re-entrances is stored in the DiffState itself. The DiffState comes pre-loaded with a set of components
/// that were modified by the eventtrigger. This prevents doubly evaluating components if they were both updated via
/// subscriptions and props changes.
-pub struct DiffMachine<'a, Dom: RealDom> {
- pub dom: &'a mut Dom,
+pub struct DiffMachine<'real, 'bump, Dom: RealDom<'bump>> {
+ pub dom: &'real mut Dom,
+ pub components: &'bump ScopeArena,
pub cur_idx: ScopeIdx,
pub diffed: FxHashSet,
- pub components: ScopeArena,
pub event_queue: EventQueue,
pub seen_nodes: FxHashSet,
}
-impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
+impl<'real, 'bump, Dom: RealDom<'bump>> DiffMachine<'real, 'bump, Dom> {
pub fn new(
- dom: &'a mut Dom,
- components: ScopeArena,
+ dom: &'real mut Dom,
+ components: &'bump ScopeArena,
cur_idx: ScopeIdx,
event_queue: EventQueue,
) -> Self {
@@ -128,8 +132,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
//
// The change list stack is in the same state when this function exits.
// In the case of Fragments, the parent node is on the stack
- pub fn diff_node(&mut self, old_node: &VNode<'a>, new_node: &VNode<'a>) {
- // pub fn diff_node(&self, old: &VNode<'a>, new: &VNode<'a>) {
+ pub fn diff_node(&mut self, old_node: &'bump VNode<'bump>, new_node: &'bump VNode<'bump>) {
/*
For each valid case, we "commit traversal", meaning we save this current position in the tree.
Then, we diff and queue an edit event (via chagelist). s single trees - when components show up, we save that traversal and then re-enter later.
@@ -326,7 +329,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
// When this function returns, the new node is on top of the change list stack:
//
// [... node]
- fn create(&mut self, node: &VNode<'a>) {
+ fn create(&mut self, node: &'bump VNode<'bump>) {
// debug_assert!(self.dom.traversal_is_committed());
match node {
VNode::Text(text) => {
@@ -434,7 +437,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
// yaaaaay lifetimes out of thin air
// really tho, we're merging the frame lifetimes together
- let inner: &'a mut _ = unsafe { &mut *self.components.0.borrow().arena.get() };
+ let inner: &'bump mut _ = unsafe { &mut *self.components.0.borrow().arena.get() };
let new_component = inner.get_mut(idx).unwrap();
// Actually initialize the caller's slot with the right address
@@ -467,7 +470,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
}
}
-impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
+impl<'a, 'bump, Dom: RealDom<'bump>> DiffMachine<'a, 'bump, Dom> {
/// Destroy a scope and all of its descendents.
///
/// Calling this will run the destuctors on all hooks in the tree.
@@ -559,8 +562,8 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
// The change list stack is left unchanged.
fn diff_attr(
&mut self,
- old: &'a [Attribute<'a>],
- new: &'a [Attribute<'a>],
+ old: &'bump [Attribute<'bump>],
+ new: &'bump [Attribute<'bump>],
is_namespaced: bool,
) {
// Do O(n^2) passes to add/update and remove attributes, since
@@ -613,7 +616,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
// [... parent]
//
// the change list stack is in the same state when this function returns.
- fn diff_children(&mut self, old: &'a [VNode<'a>], new: &'a [VNode<'a>]) {
+ fn diff_children(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) {
if new.is_empty() {
if !old.is_empty() {
// self.dom.commit_traversal();
@@ -693,11 +696,11 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
// [... parent]
//
// Upon exiting, the change list stack is in the same state.
- fn diff_keyed_children(&self, old: &'a [VNode<'a>], new: &'a [VNode<'a>]) {
+ fn diff_keyed_children(&self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) {
// todo!();
if cfg!(debug_assertions) {
let mut keys = fxhash::FxHashSet::default();
- let mut assert_unique_keys = |children: &'a [VNode<'a>]| {
+ let mut assert_unique_keys = |children: &'bump [VNode<'bump>]| {
keys.clear();
for child in children {
let key = child.key();
@@ -777,7 +780,11 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
// [... parent]
//
// Upon exit, the change list stack is the same.
- fn diff_keyed_prefix(&self, old: &[VNode<'a>], new: &[VNode<'a>]) -> KeyedPrefixResult {
+ fn diff_keyed_prefix(
+ &self,
+ old: &'bump [VNode<'bump>],
+ new: &'bump [VNode<'bump>],
+ ) -> KeyedPrefixResult {
todo!()
// self.dom.go_down();
// let mut shared_prefix_count = 0;
@@ -831,8 +838,8 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
// Upon exit from this function, it will be restored to that same state.
fn diff_keyed_middle(
&self,
- old: &[VNode<'a>],
- mut new: &[VNode<'a>],
+ old: &[VNode<'bump>],
+ mut new: &[VNode<'bump>],
shared_prefix_count: usize,
shared_suffix_count: usize,
old_shared_suffix_start: usize,
@@ -1059,8 +1066,8 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
// When this function exits, the change list stack remains the same.
fn diff_keyed_suffix(
&self,
- old: &[VNode<'a>],
- new: &[VNode<'a>],
+ old: &[VNode<'bump>],
+ new: &[VNode<'bump>],
new_shared_suffix_start: usize,
) {
todo!()
@@ -1088,7 +1095,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
// [... parent]
//
// the change list stack is in the same state when this function returns.
- fn diff_non_keyed_children(&mut self, old: &'a [VNode<'a>], new: &'a [VNode<'a>]) {
+ fn diff_non_keyed_children(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) {
// Handled these cases in `diff_children` before calling this function.
debug_assert!(!new.is_empty());
debug_assert!(!old.is_empty());
@@ -1163,7 +1170,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
// [... parent]
//
// When this function returns, the change list stack is in the same state.
- pub fn remove_all_children(&mut self, old: &[VNode<'a>]) {
+ pub fn remove_all_children(&mut self, old: &'bump [VNode<'bump>]) {
// debug_assert!(self.dom.traversal_is_committed());
log::debug!("REMOVING CHILDREN");
for _child in old {
@@ -1182,7 +1189,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
// [... parent]
//
// When this function returns, the change list stack is in the same state.
- pub fn create_and_append_children(&mut self, new: &[VNode<'a>]) {
+ pub fn create_and_append_children(&mut self, new: &'bump [VNode<'bump>]) {
// debug_assert!(self.dom.traversal_is_committed());
for child in new {
// self.create_and_append(node, parent)
@@ -1200,7 +1207,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
// After the function returns, the child is no longer on the change list stack:
//
// [... parent]
- pub fn remove_self_and_next_siblings(&self, old: &[VNode<'a>]) {
+ pub fn remove_self_and_next_siblings(&self, old: &[VNode<'bump>]) {
// debug_assert!(self.dom.traversal_is_committed());
for child in old {
if let VNode::Component(vcomp) = child {
diff --git a/packages/core/src/lib.rs b/packages/core/src/lib.rs
index 0ae0e6301..81f1d6b13 100644
--- a/packages/core/src/lib.rs
+++ b/packages/core/src/lib.rs
@@ -8,9 +8,9 @@
//!
//!
-pub mod util;
pub mod arena;
-pub mod component; // Logic for extending FC
+pub mod component;
+pub mod util; // Logic for extending FC
pub mod debug_renderer;
pub mod diff;
diff --git a/packages/core/src/util.rs b/packages/core/src/util.rs
index b5c4f86c5..f5f921685 100644
--- a/packages/core/src/util.rs
+++ b/packages/core/src/util.rs
@@ -8,7 +8,7 @@ impl DebugDom {
Self { counter: 0 }
}
}
-impl RealDom for DebugDom {
+impl<'a> RealDom<'a> for DebugDom {
fn push_root(&mut self, root: RealDomNode) {}
fn append_child(&mut self) {}
diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs
index d55790fb2..07e3476d4 100644
--- a/packages/core/src/virtual_dom.rs
+++ b/packages/core/src/virtual_dom.rs
@@ -196,10 +196,10 @@ impl VirtualDom {
impl VirtualDom {
/// Performs a *full* rebuild of the virtual dom, returning every edit required to generate the actual dom rom scratch
/// Currently this doesn't do what we want it to do
- pub fn rebuild<'s, Dom: RealDom>(&'s mut self, realdom: &mut Dom) -> Result<()> {
+ pub fn rebuild<'s, Dom: RealDom<'s>>(&'s mut self, realdom: &mut Dom) -> Result<()> {
let mut diff_machine = DiffMachine::new(
realdom,
- self.components.clone(),
+ &self.components,
self.base_scope,
self.event_queue.clone(),
);
@@ -207,7 +207,6 @@ impl VirtualDom {
// Schedule an update and then immediately call it on the root component
// This is akin to a hook being called from a listener and requring a re-render
// Instead, this is done on top-level component
-
let base = self.components.try_get(self.base_scope)?;
let update = &base.event_channel;
@@ -260,21 +259,17 @@ impl VirtualDom {
// but the guarantees provide a safe, fast, and efficient abstraction for the VirtualDOM updating framework.
//
// A good project would be to remove all unsafe from this crate and move the unsafety into safer abstractions.
- pub fn progress_with_event(
- &mut self,
- realdom: &mut Dom,
+ pub fn progress_with_event<'s, Dom: RealDom<'s>>(
+ &'s mut self,
+ realdom: &'_ mut Dom,
trigger: EventTrigger,
) -> Result<()> {
let id = trigger.component_id.clone();
self.components.try_get_mut(id)?.call_listener(trigger)?;
- let mut diff_machine = DiffMachine::new(
- realdom,
- self.components.clone(),
- id,
- self.event_queue.clone(),
- );
+ let mut diff_machine =
+ DiffMachine::new(realdom, &self.components, id, self.event_queue.clone());
self.progress_completely(&mut diff_machine)?;
@@ -285,9 +280,9 @@ impl VirtualDom {
/// Only ever run each component once.
///
/// The DiffMachine logs its progress as it goes which might be useful for certain types of renderers.
- pub(crate) fn progress_completely<'s, Dom: RealDom>(
- &'s mut self,
- diff_machine: &'_ mut DiffMachine<'s, Dom>,
+ pub(crate) fn progress_completely<'a, 'bump, Dom: RealDom<'bump>>(
+ &'bump self,
+ diff_machine: &'_ mut DiffMachine<'a, 'bump, Dom>,
) -> Result<()> {
// Add this component to the list of components that need to be difed
// #[allow(unused_assignments)]
diff --git a/packages/web/examples/jackjill.rs b/packages/web/examples/jackjill.rs
index d01021a4e..0df2b2749 100644
--- a/packages/web/examples/jackjill.rs
+++ b/packages/web/examples/jackjill.rs
@@ -15,35 +15,35 @@ static Example: FC<()> = |cx| {
log::debug!("Running component....");
cx.render(html! {
-
-
-
- // Tagline
-
- "Dioxus Example: Jack and Jill"
-
+
+
+
+ // Tagline
+
+ "Dioxus Example: Jack and Jill"
+
- // Header
-