|
@@ -141,9 +141,9 @@ impl<'src> VNode<'src> {
|
|
/// Returns None if the VNode is not mounted, or if the VNode cannot be presented by a mounted ID (Fragment/Component)
|
|
/// Returns None if the VNode is not mounted, or if the VNode cannot be presented by a mounted ID (Fragment/Component)
|
|
pub fn try_mounted_id(&self) -> Option<ElementId> {
|
|
pub fn try_mounted_id(&self) -> Option<ElementId> {
|
|
match &self {
|
|
match &self {
|
|
- VNode::Text(el) => el.dom_id.get(),
|
|
|
|
- VNode::Element(el) => el.dom_id.get(),
|
|
|
|
- VNode::Placeholder(el) => el.dom_id.get(),
|
|
|
|
|
|
+ VNode::Text(el) => el.id.get(),
|
|
|
|
+ VNode::Element(el) => el.id.get(),
|
|
|
|
+ VNode::Placeholder(el) => el.id.get(),
|
|
VNode::Fragment(_) => None,
|
|
VNode::Fragment(_) => None,
|
|
VNode::Component(_) => None,
|
|
VNode::Component(_) => None,
|
|
}
|
|
}
|
|
@@ -176,7 +176,7 @@ impl Debug for VNode<'_> {
|
|
match &self {
|
|
match &self {
|
|
VNode::Element(el) => s
|
|
VNode::Element(el) => s
|
|
.debug_struct("VNode::VElement")
|
|
.debug_struct("VNode::VElement")
|
|
- .field("name", &el.tag_name)
|
|
|
|
|
|
+ .field("name", &el.tag)
|
|
.field("key", &el.key)
|
|
.field("key", &el.key)
|
|
.field("attrs", &el.attributes)
|
|
.field("attrs", &el.attributes)
|
|
.field("children", &el.children)
|
|
.field("children", &el.children)
|
|
@@ -187,7 +187,6 @@ impl Debug for VNode<'_> {
|
|
write!(s, "VNode::VFragment {{ children: {:?} }}", frag.children)
|
|
write!(s, "VNode::VFragment {{ children: {:?} }}", frag.children)
|
|
}
|
|
}
|
|
VNode::Component(comp) => write!(s, "VNode::VComponent {{ fc: {:?}}}", comp.user_fc),
|
|
VNode::Component(comp) => write!(s, "VNode::VComponent {{ fc: {:?}}}", comp.user_fc),
|
|
- // VNode::Component(comp) => write!(s, "VNode::VComponent {{ fc: {:?}}}", comp.user_fc),
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -216,13 +215,13 @@ fn empty_cell() -> Cell<Option<ElementId>> {
|
|
|
|
|
|
/// A placeholder node only generated when Fragments don't have any children.
|
|
/// A placeholder node only generated when Fragments don't have any children.
|
|
pub struct VPlaceholder {
|
|
pub struct VPlaceholder {
|
|
- pub dom_id: Cell<Option<ElementId>>,
|
|
|
|
|
|
+ pub id: Cell<Option<ElementId>>,
|
|
}
|
|
}
|
|
|
|
|
|
/// A bump-allocated string slice and metadata.
|
|
/// A bump-allocated string slice and metadata.
|
|
pub struct VText<'src> {
|
|
pub struct VText<'src> {
|
|
pub text: &'src str,
|
|
pub text: &'src str,
|
|
- pub dom_id: Cell<Option<ElementId>>,
|
|
|
|
|
|
+ pub id: Cell<Option<ElementId>>,
|
|
pub is_static: bool,
|
|
pub is_static: bool,
|
|
}
|
|
}
|
|
|
|
|
|
@@ -238,11 +237,11 @@ pub struct VFragment<'src> {
|
|
|
|
|
|
/// An element like a "div" with children, listeners, and attributes.
|
|
/// An element like a "div" with children, listeners, and attributes.
|
|
pub struct VElement<'a> {
|
|
pub struct VElement<'a> {
|
|
- pub tag_name: &'static str,
|
|
|
|
|
|
+ pub tag: &'static str,
|
|
pub namespace: Option<&'static str>,
|
|
pub namespace: Option<&'static str>,
|
|
pub key: Option<&'a str>,
|
|
pub key: Option<&'a str>,
|
|
- pub dom_id: Cell<Option<ElementId>>,
|
|
|
|
- pub parent_id: Cell<Option<ElementId>>,
|
|
|
|
|
|
+ pub id: Cell<Option<ElementId>>,
|
|
|
|
+ pub parent: Cell<Option<ElementId>>,
|
|
pub listeners: &'a [Listener<'a>],
|
|
pub listeners: &'a [Listener<'a>],
|
|
pub attributes: &'a [Attribute<'a>],
|
|
pub attributes: &'a [Attribute<'a>],
|
|
pub children: &'a [VNode<'a>],
|
|
pub children: &'a [VNode<'a>],
|
|
@@ -251,11 +250,11 @@ pub struct VElement<'a> {
|
|
impl Debug for VElement<'_> {
|
|
impl Debug for VElement<'_> {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
f.debug_struct("VElement")
|
|
f.debug_struct("VElement")
|
|
- .field("tag_name", &self.tag_name)
|
|
|
|
|
|
+ .field("tag_name", &self.tag)
|
|
.field("namespace", &self.namespace)
|
|
.field("namespace", &self.namespace)
|
|
.field("key", &self.key)
|
|
.field("key", &self.key)
|
|
- .field("dom_id", &self.dom_id)
|
|
|
|
- .field("parent_id", &self.parent_id)
|
|
|
|
|
|
+ .field("id", &self.id)
|
|
|
|
+ .field("parent", &self.parent)
|
|
.field("listeners", &self.listeners.len())
|
|
.field("listeners", &self.listeners.len())
|
|
.field("attributes", &self.attributes)
|
|
.field("attributes", &self.attributes)
|
|
.field("children", &self.children)
|
|
.field("children", &self.children)
|
|
@@ -363,20 +362,13 @@ pub struct VComponent<'src> {
|
|
}
|
|
}
|
|
|
|
|
|
pub(crate) struct VComponentProps<P> {
|
|
pub(crate) struct VComponentProps<P> {
|
|
- // Props start local
|
|
|
|
- // If they are static, then they can get promoted onto the heap
|
|
|
|
pub render_fn: Component<P>,
|
|
pub render_fn: Component<P>,
|
|
- pub props: P,
|
|
|
|
pub memo: unsafe fn(&P, &P) -> bool,
|
|
pub memo: unsafe fn(&P, &P) -> bool,
|
|
|
|
+ pub props: P,
|
|
}
|
|
}
|
|
|
|
|
|
pub trait AnyProps {
|
|
pub trait AnyProps {
|
|
fn as_ptr(&self) -> *const ();
|
|
fn as_ptr(&self) -> *const ();
|
|
- fn release(&self);
|
|
|
|
- fn replace_heap(&self, new: Box<dyn Any>);
|
|
|
|
-
|
|
|
|
- // move the props from the bump arena onto the heap
|
|
|
|
- fn promote(&self);
|
|
|
|
fn render<'a>(&'a self, bump: &'a ScopeState) -> Element<'a>;
|
|
fn render<'a>(&'a self, bump: &'a ScopeState) -> Element<'a>;
|
|
unsafe fn memoize(&self, other: &dyn AnyProps) -> bool;
|
|
unsafe fn memoize(&self, other: &dyn AnyProps) -> bool;
|
|
}
|
|
}
|
|
@@ -384,16 +376,9 @@ pub trait AnyProps {
|
|
impl<P> AnyProps for VComponentProps<P> {
|
|
impl<P> AnyProps for VComponentProps<P> {
|
|
fn as_ptr(&self) -> *const () {
|
|
fn as_ptr(&self) -> *const () {
|
|
&self.props as *const _ as *const ()
|
|
&self.props as *const _ as *const ()
|
|
- // // todo: maybe move this into an enum
|
|
|
|
- // let heap_props = self.heap_props.borrow();
|
|
|
|
- // if let Some(b) = heap_props.as_ref() {
|
|
|
|
- // b.as_ref() as *const _ as *const ()
|
|
|
|
- // } else {
|
|
|
|
- // let local_props = self.local_props.borrow();
|
|
|
|
- // local_props.as_ref().unwrap() as *const _ as *const ()
|
|
|
|
- // }
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // Safety:
|
|
// this will downcat the other ptr as our swallowed type!
|
|
// this will downcat the other ptr as our swallowed type!
|
|
// you *must* make this check *before* calling this method
|
|
// you *must* make this check *before* calling this method
|
|
// if your functions are not the same, then you will downcast a pointer into a different type (UB)
|
|
// if your functions are not the same, then you will downcast a pointer into a different type (UB)
|
|
@@ -403,41 +388,9 @@ impl<P> AnyProps for VComponentProps<P> {
|
|
(self.memo)(real_us, real_other)
|
|
(self.memo)(real_us, real_other)
|
|
}
|
|
}
|
|
|
|
|
|
- fn release(&self) {
|
|
|
|
- panic!("don't release props anymore");
|
|
|
|
- // if let Some(heap_props) = self.heap_props.borrow_mut().take() {
|
|
|
|
- // dbg!("releasing heap");
|
|
|
|
- // drop(heap_props)
|
|
|
|
- // } else if let Some(local_props) = self.local_props.borrow_mut().take() {
|
|
|
|
- // dbg!("releasing local");
|
|
|
|
- // drop(local_props)
|
|
|
|
- // } else {
|
|
|
|
- // dbg!("trying to do a double release");
|
|
|
|
- // }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- fn promote(&self) {
|
|
|
|
- panic!("don't promote props anymore");
|
|
|
|
- // dbg!("promoting props");
|
|
|
|
- // if let Some(props) = self.local_props.borrow_mut().take() {
|
|
|
|
- // let mut heap_slot = self.heap_props.borrow_mut();
|
|
|
|
- // *heap_slot = Some(Box::new(props));
|
|
|
|
- // }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
fn render<'a>(&'a self, scope: &'a ScopeState) -> Element<'a> {
|
|
fn render<'a>(&'a self, scope: &'a ScopeState) -> Element<'a> {
|
|
- let props: &P = &self.props;
|
|
|
|
- let inline_props = unsafe { std::mem::transmute::<&P, &P>(props) };
|
|
|
|
-
|
|
|
|
- (self.render_fn)(Scope {
|
|
|
|
- scope,
|
|
|
|
- props: inline_props,
|
|
|
|
- })
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- fn replace_heap(&self, new: Box<dyn Any>) {
|
|
|
|
- // let new = new.downcast::<P>().unwrap();
|
|
|
|
- // self.heap_props.borrow_mut().replace(new);
|
|
|
|
|
|
+ let props = unsafe { std::mem::transmute::<&P, &P>(&self.props) };
|
|
|
|
+ (self.render_fn)(Scope { scope, props })
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -463,7 +416,7 @@ impl<'a> NodeFactory<'a> {
|
|
/// Directly pass in text blocks without the need to use the format_args macro.
|
|
/// Directly pass in text blocks without the need to use the format_args macro.
|
|
pub fn static_text(&self, text: &'static str) -> VNode<'a> {
|
|
pub fn static_text(&self, text: &'static str) -> VNode<'a> {
|
|
VNode::Text(self.bump.alloc(VText {
|
|
VNode::Text(self.bump.alloc(VText {
|
|
- dom_id: empty_cell(),
|
|
|
|
|
|
+ id: empty_cell(),
|
|
text,
|
|
text,
|
|
is_static: true,
|
|
is_static: true,
|
|
}))
|
|
}))
|
|
@@ -492,7 +445,7 @@ impl<'a> NodeFactory<'a> {
|
|
VNode::Text(self.bump.alloc(VText {
|
|
VNode::Text(self.bump.alloc(VText {
|
|
text,
|
|
text,
|
|
is_static,
|
|
is_static,
|
|
- dom_id: empty_cell(),
|
|
|
|
|
|
+ id: empty_cell(),
|
|
}))
|
|
}))
|
|
}
|
|
}
|
|
|
|
|
|
@@ -545,14 +498,14 @@ impl<'a> NodeFactory<'a> {
|
|
let key = key.map(|f| self.raw_text(f).0);
|
|
let key = key.map(|f| self.raw_text(f).0);
|
|
|
|
|
|
VNode::Element(self.bump.alloc(VElement {
|
|
VNode::Element(self.bump.alloc(VElement {
|
|
- tag_name,
|
|
|
|
|
|
+ tag: tag_name,
|
|
key,
|
|
key,
|
|
namespace,
|
|
namespace,
|
|
listeners,
|
|
listeners,
|
|
attributes,
|
|
attributes,
|
|
children,
|
|
children,
|
|
- dom_id: empty_cell(),
|
|
|
|
- parent_id: empty_cell(),
|
|
|
|
|
|
+ id: empty_cell(),
|
|
|
|
+ parent: empty_cell(),
|
|
}))
|
|
}))
|
|
}
|
|
}
|
|
|
|
|
|
@@ -621,9 +574,7 @@ impl<'a> NodeFactory<'a> {
|
|
}
|
|
}
|
|
|
|
|
|
if nodes.is_empty() {
|
|
if nodes.is_empty() {
|
|
- VNode::Placeholder(self.bump.alloc(VPlaceholder {
|
|
|
|
- dom_id: empty_cell(),
|
|
|
|
- }))
|
|
|
|
|
|
+ VNode::Placeholder(self.bump.alloc(VPlaceholder { id: empty_cell() }))
|
|
} else {
|
|
} else {
|
|
VNode::Fragment(VFragment {
|
|
VNode::Fragment(VFragment {
|
|
children: nodes.into_bump_slice(),
|
|
children: nodes.into_bump_slice(),
|
|
@@ -643,9 +594,7 @@ impl<'a> NodeFactory<'a> {
|
|
}
|
|
}
|
|
|
|
|
|
if nodes.is_empty() {
|
|
if nodes.is_empty() {
|
|
- VNode::Placeholder(self.bump.alloc(VPlaceholder {
|
|
|
|
- dom_id: empty_cell(),
|
|
|
|
- }))
|
|
|
|
|
|
+ VNode::Placeholder(self.bump.alloc(VPlaceholder { id: empty_cell() }))
|
|
} else {
|
|
} else {
|
|
let children = nodes.into_bump_slice();
|
|
let children = nodes.into_bump_slice();
|
|
|
|
|
|
@@ -686,9 +635,9 @@ impl<'a> NodeFactory<'a> {
|
|
}
|
|
}
|
|
|
|
|
|
if nodes.is_empty() {
|
|
if nodes.is_empty() {
|
|
- Some(VNode::Placeholder(self.bump.alloc(VPlaceholder {
|
|
|
|
- dom_id: empty_cell(),
|
|
|
|
- })))
|
|
|
|
|
|
+ Some(VNode::Placeholder(
|
|
|
|
+ self.bump.alloc(VPlaceholder { id: empty_cell() }),
|
|
|
|
+ ))
|
|
} else {
|
|
} else {
|
|
let children = nodes.into_bump_slice();
|
|
let children = nodes.into_bump_slice();
|
|
|
|
|
|
@@ -766,9 +715,7 @@ impl<'a> IntoVNode<'a> for Option<LazyNodes<'a, '_>> {
|
|
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
|
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
|
match self {
|
|
match self {
|
|
Some(lazy) => lazy.call(cx),
|
|
Some(lazy) => lazy.call(cx),
|
|
- None => VNode::Placeholder(cx.bump.alloc(VPlaceholder {
|
|
|
|
- dom_id: empty_cell(),
|
|
|
|
- })),
|
|
|
|
|
|
+ None => VNode::Placeholder(cx.bump.alloc(VPlaceholder { id: empty_cell() })),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|