|
@@ -2,7 +2,6 @@
|
|
|
//!
|
|
|
//! VNodes represent lazily-constructed VDom trees that support diffing and event handlers. These VNodes should be *very*
|
|
|
//! cheap and *very* fast to construct - building a full tree should be quick.
|
|
|
-
|
|
|
use crate::{
|
|
|
innerlude::{AttributeValue, ComponentPtr, Element, Properties, Scope, ScopeId, ScopeState},
|
|
|
lazynodes::LazyNodes,
|
|
@@ -375,7 +374,6 @@ pub struct Listener<'bump> {
|
|
|
|
|
|
pub type InternalHandler<'bump> = &'bump RefCell<Option<InternalListenerCallback<'bump>>>;
|
|
|
type InternalListenerCallback<'bump> = BumpBox<'bump, dyn FnMut(AnyEvent) + 'bump>;
|
|
|
-
|
|
|
type ExternalListenerCallback<'bump, T> = BumpBox<'bump, dyn FnMut(T) + 'bump>;
|
|
|
|
|
|
/// The callback type generated by the `rsx!` macro when an `on` field is specified for components.
|
|
@@ -706,43 +704,11 @@ impl<'a> NodeFactory<'a> {
|
|
|
}
|
|
|
|
|
|
/// Create a new [`VNode::Fragment`] from any iterator
|
|
|
- pub fn fragment_from_iter<'b, 'c>(
|
|
|
+ pub fn fragment_from_iter<'c, I, J>(
|
|
|
self,
|
|
|
- node_iter: impl IntoIterator<Item = impl IntoVNode<'a> + 'c> + 'b,
|
|
|
+ node_iter: impl IntoVNode<'a, I, J> + 'c,
|
|
|
) -> VNode<'a> {
|
|
|
- let mut nodes = bumpalo::collections::Vec::new_in(self.bump);
|
|
|
-
|
|
|
- for node in node_iter {
|
|
|
- nodes.push(node.into_vnode(self));
|
|
|
- }
|
|
|
-
|
|
|
- if nodes.is_empty() {
|
|
|
- VNode::Placeholder(self.bump.alloc(VPlaceholder { id: empty_cell() }))
|
|
|
- } else {
|
|
|
- let children = nodes.into_bump_slice();
|
|
|
-
|
|
|
- if cfg!(debug_assertions)
|
|
|
- && children.len() > 1
|
|
|
- && children.last().unwrap().key().is_none()
|
|
|
- {
|
|
|
- // todo: make the backtrace prettier or remove it altogether
|
|
|
- log::error!(
|
|
|
- r#"
|
|
|
- Warning: Each child in an array or iterator should have a unique "key" prop.
|
|
|
- Not providing a key will lead to poor performance with lists.
|
|
|
- See docs.rs/dioxus for more information.
|
|
|
- -------------
|
|
|
- {:?}
|
|
|
- "#,
|
|
|
- backtrace::Backtrace::new()
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- VNode::Fragment(self.bump.alloc(VFragment {
|
|
|
- children,
|
|
|
- key: None,
|
|
|
- }))
|
|
|
- }
|
|
|
+ node_iter.into_vnode(self)
|
|
|
}
|
|
|
|
|
|
/// Create a new [`VNode`] from any iterator of children
|
|
@@ -800,20 +766,11 @@ impl Debug for NodeFactory<'_> {
|
|
|
///
|
|
|
/// As such, all node creation must go through the factory, which is only available in the component context.
|
|
|
/// These strict requirements make it possible to manage lifetimes and state.
|
|
|
-pub trait IntoVNode<'a> {
|
|
|
+pub trait IntoVNode<'a, I = (), J = ()> {
|
|
|
/// Convert this into a [`VNode`], using the [`NodeFactory`] as a source of allocation
|
|
|
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a>;
|
|
|
}
|
|
|
|
|
|
-// For the case where a rendered VNode is passed into the rsx! macro through curly braces
|
|
|
-impl<'a> IntoIterator for VNode<'a> {
|
|
|
- type Item = VNode<'a>;
|
|
|
- type IntoIter = std::iter::Once<Self::Item>;
|
|
|
- fn into_iter(self) -> Self::IntoIter {
|
|
|
- std::iter::once(self)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
// TODO: do we even need this? It almost seems better not to
|
|
|
// // For the case where a rendered VNode is passed into the rsx! macro through curly braces
|
|
|
impl<'a> IntoVNode<'a> for VNode<'a> {
|
|
@@ -825,37 +782,7 @@ impl<'a> IntoVNode<'a> for VNode<'a> {
|
|
|
// Conveniently, we also support "null" (nothing) passed in
|
|
|
impl IntoVNode<'_> for () {
|
|
|
fn into_vnode(self, cx: NodeFactory) -> VNode {
|
|
|
- cx.fragment_from_iter(None as Option<VNode>)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// Conveniently, we also support "None"
|
|
|
-impl IntoVNode<'_> for Option<()> {
|
|
|
- fn into_vnode(self, cx: NodeFactory) -> VNode {
|
|
|
- cx.fragment_from_iter(None as Option<VNode>)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl<'a> IntoVNode<'a> for Option<VNode<'a>> {
|
|
|
- fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
|
|
- self.unwrap_or_else(|| cx.fragment_from_iter(None as Option<VNode>))
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl<'a> IntoVNode<'a> for Option<LazyNodes<'a, '_>> {
|
|
|
- fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
|
|
- match self {
|
|
|
- Some(lazy) => lazy.call(cx),
|
|
|
- None => VNode::Placeholder(cx.bump.alloc(VPlaceholder { id: empty_cell() })),
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl<'a, 'b> IntoIterator for LazyNodes<'a, 'b> {
|
|
|
- type Item = LazyNodes<'a, 'b>;
|
|
|
- type IntoIter = std::iter::Once<Self::Item>;
|
|
|
- fn into_iter(self) -> Self::IntoIter {
|
|
|
- std::iter::once(self)
|
|
|
+ VNode::Placeholder(cx.bump.alloc(VPlaceholder { id: empty_cell() }))
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -883,17 +810,53 @@ impl IntoVNode<'_> for Arguments<'_> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<'a> IntoVNode<'a> for &Option<VNode<'a>> {
|
|
|
- fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
|
|
- self.as_ref()
|
|
|
- .map(|f| f.into_vnode(cx))
|
|
|
- .unwrap_or_else(|| cx.fragment_from_iter(None as Option<VNode>))
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
impl<'a> IntoVNode<'a> for &VNode<'a> {
|
|
|
fn into_vnode(self, _cx: NodeFactory<'a>) -> VNode<'a> {
|
|
|
// borrowed nodes are strange
|
|
|
self.decouple()
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+// Note that we're using the E as a generic but this is never crafted anyways.
|
|
|
+pub struct FromNodeIterator;
|
|
|
+impl<'a, T, I, E> IntoVNode<'a, FromNodeIterator, E> for T
|
|
|
+where
|
|
|
+ T: IntoIterator<Item = I>,
|
|
|
+ I: IntoVNode<'a, E>,
|
|
|
+{
|
|
|
+ fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
|
|
+ let mut nodes = bumpalo::collections::Vec::new_in(cx.bump);
|
|
|
+
|
|
|
+ for node in self {
|
|
|
+ nodes.push(node.into_vnode(cx));
|
|
|
+ }
|
|
|
+
|
|
|
+ if nodes.is_empty() {
|
|
|
+ VNode::Placeholder(cx.bump.alloc(VPlaceholder { id: empty_cell() }))
|
|
|
+ } else {
|
|
|
+ let children = nodes.into_bump_slice();
|
|
|
+
|
|
|
+ if cfg!(debug_assertions)
|
|
|
+ && children.len() > 1
|
|
|
+ && children.last().unwrap().key().is_none()
|
|
|
+ {
|
|
|
+ // todo: make the backtrace prettier or remove it altogether
|
|
|
+ log::error!(
|
|
|
+ r#"
|
|
|
+ Warning: Each child in an array or iterator should have a unique "key" prop.
|
|
|
+ Not providing a key will lead to poor performance with lists.
|
|
|
+ See docs.rs/dioxus for more information.
|
|
|
+ -------------
|
|
|
+ {:?}
|
|
|
+ "#,
|
|
|
+ backtrace::Backtrace::new()
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ VNode::Fragment(cx.bump.alloc(VFragment {
|
|
|
+ children,
|
|
|
+ key: None,
|
|
|
+ }))
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|