Преглед на файлове

fix: use annotation method from rust/58052 to fix closure lifetimes

Jonathan Kelley преди 3 години
родител
ревизия
27d8919

+ 3 - 12
packages/core-macro/src/rsx/body.rs

@@ -49,7 +49,7 @@ impl ToTokens for CallBody {
         match &self.custom_context {
             // The `in cx` pattern allows directly rendering
             Some(ident) => out_tokens.append_all(quote! {
-                #ident.render(dioxus::prelude::LazyNodes::new(move |__cx: NodeFactory|{
+                #ident.render(dioxus::prelude::LazyNodes::new(move |__cx: NodeFactory| -> VNode {
                     use dioxus_elements::{GlobalAttributes, SvgAttributes};
 
                     #inner
@@ -57,21 +57,12 @@ impl ToTokens for CallBody {
             }),
             // Otherwise we just build the LazyNode wrapper
             None => out_tokens.append_all(quote! {
-
                 {
-
-                    let ___p: Box<dyn FnOnce(NodeFactory) -> VNode + '_> = Box::new(move |__cx: NodeFactory|{
+                    NodeFactory::annotate_lazy(move |__cx: NodeFactory| -> VNode {
                         use dioxus_elements::{GlobalAttributes, SvgAttributes};
-
                         #inner
-                    });
-                    Some(___p)
+                    })
                 }
-                // dioxus::prelude::LazyNodes::new(move |__cx: NodeFactory|{
-                //     use dioxus_elements::{GlobalAttributes, SvgAttributes};
-
-                //     #inner
-                // })
             }),
         };
     }

+ 11 - 3
packages/core/examples/alternative.rs

@@ -1,4 +1,7 @@
 use dioxus_core::prelude::*;
+use dioxus_core_macro::format_args_f;
+use dioxus_core_macro::rsx;
+use dioxus_html as dioxus_elements;
 
 fn main() {
     let mut dom = VirtualDom::new(EXAMPLE);
@@ -7,9 +10,14 @@ fn main() {
 }
 
 pub static EXAMPLE: FC<()> = |(cx, _)| {
-    let list = (0..10).map(|_f| LazyNodes::new(move |_f| todo!()));
+    let list = (0..10).map(|_f| {
+        rsx! {
+            "{_f}"
+        }
+    });
+    // let list = (0..10).map(|_f| Some(Box::new(move |_f| todo!())));
 
-    cx.render(LazyNodes::new(move |cx| {
+    cx.render(Some(Box::new(move |cx| {
         cx.raw_element(
             "div",
             None,
@@ -22,5 +30,5 @@ pub static EXAMPLE: FC<()> = |(cx, _)| {
             ],
             None,
         )
-    }))
+    })))
 };

+ 24 - 23
packages/core/examples/borrowed.rs

@@ -23,28 +23,29 @@ struct ListItem {
 fn app<'a>(cx: Context<'a>, props: &AppProps) -> Element<'a> {
     // let (val, set_val) = use_state_classic(cx, || 0);
 
-    cx.render(LazyNodes::new(move |_nodecx| {
-        todo!()
-        // builder::ElementBuilder::new(_nodecx, "div")
-        //     .iter_child({
-        //         cx.items.iter().map(|child| {
-        //             builder::virtual_child(
-        //                 _nodecx,
-        //                 ChildItem,
-        //                 ChildProps {
-        //                     item: child.clone(),
-        //                     item_handler: set_val.clone(),
-        //                 },
-        //                 None,
-        //                 &[],
-        //             )
-        //         })
-        //     })
-        //     .iter_child([builder::ElementBuilder::new(_nodecx, "div")
-        //         .iter_child([builder::text3(_nodecx.bump(), format_args!("{}", val))])
-        //         .finish()])
-        //     .finish()
-    }))
+    todo!()
+    // cx.render(LazyNodes::new(move |_nodecx| {
+    //     todo!()
+    //     // builder::ElementBuilder::new(_nodecx, "div")
+    //     //     .iter_child({
+    //     //         cx.items.iter().map(|child| {
+    //     //             builder::virtual_child(
+    //     //                 _nodecx,
+    //     //                 ChildItem,
+    //     //                 ChildProps {
+    //     //                     item: child.clone(),
+    //     //                     item_handler: set_val.clone(),
+    //     //                 },
+    //     //                 None,
+    //     //                 &[],
+    //     //             )
+    //     //         })
+    //     //     })
+    //     //     .iter_child([builder::ElementBuilder::new(_nodecx, "div")
+    //     //         .iter_child([builder::text3(_nodecx.bump(), format_args!("{}", val))])
+    //     //         .finish()])
+    //     //     .finish()
+    // }))
 }
 
 // props should derive a partialeq implementation automatically, but implement ptr compare for & fields
@@ -57,7 +58,7 @@ struct ChildProps {
 }
 
 fn ChildItem<'a>(cx: Context<'a>, props: &'a ChildProps) -> Element<'a> {
-    cx.render(LazyNodes::new(move |__cx| todo!()))
+    todo!()
 }
 
 impl PartialEq for ChildProps {

+ 38 - 37
packages/core/examples/fragment_from_iter.rs

@@ -3,43 +3,44 @@ use dioxus_core::prelude::*;
 fn main() {}
 
 fn app<'a>(cx: Context<'a>, props: &()) -> Element<'a> {
-    let vak = use_suspense(
-        cx,
-        || async {},
-        |c, _res| c.render(LazyNodes::new(move |f| f.text(format_args!("")))),
-    );
+    // let vak = use_suspense(
+    //     cx,
+    //     || async {},
+    //     |c, _res| c.render(LazyNodes::new(move |f| f.text(format_args!("")))),
+    // );
 
-    let d1 = cx.render(LazyNodes::new(move |f| {
-        f.raw_element(
-            "div",
-            None,
-            [],
-            [],
-            [
-                f.fragment_from_iter(vak),
-                f.text(format_args!("")),
-                f.text(format_args!("")),
-                f.text(format_args!("")),
-                f.text(format_args!("")),
-            ],
-            None,
-        )
-    }));
+    // let d1 = cx.render(to_lazy_nodes(move |f| {
+    //     f.raw_element(
+    //         "div",
+    //         None,
+    //         [],
+    //         [],
+    //         [
+    //             // f.fragment_from_iter(vak),
+    //             f.text(format_args!("")),
+    //             f.text(format_args!("")),
+    //             f.text(format_args!("")),
+    //             f.text(format_args!("")),
+    //         ],
+    //         None,
+    //     )
+    // }));
 
-    cx.render(LazyNodes::new(move |f| {
-        f.raw_element(
-            "div",
-            None,
-            [],
-            [],
-            [
-                f.text(format_args!("")),
-                f.text(format_args!("")),
-                f.text(format_args!("")),
-                f.text(format_args!("")),
-                d1.unwrap(),
-            ],
-            None,
-        )
-    }))
+    todo!()
+    // cx.render(LazyNodes::new(move |f| {
+    //     f.raw_element(
+    //         "div",
+    //         None,
+    //         [],
+    //         [],
+    //         [
+    //             f.text(format_args!("")),
+    //             f.text(format_args!("")),
+    //             f.text(format_args!("")),
+    //             f.text(format_args!("")),
+    //             d1.unwrap(),
+    //         ],
+    //         None,
+    //     )
+    // }))
 }

+ 2 - 7
packages/core/examples/syntax.rs

@@ -2,7 +2,7 @@ use std::marker::PhantomData;
 
 use dioxus::component::Scope;
 use dioxus::events::on::MouseEvent;
-use dioxus::nodes::{IntoVNode, IntoVNodeList};
+use dioxus::nodes::IntoVNode;
 use dioxus_core as dioxus;
 use dioxus_core::prelude::*;
 use dioxus_core_macro::*;
@@ -28,7 +28,7 @@ fn html_usage() {
         .filter(|f| f.starts_with('b'))
         .map(|f| rsx!("hello {f}"));
 
-    let p = rsx!(div { {f} });
+    // let p = rsx!(div { {f} });
 }
 
 static App2: FC<()> = |(cx, _)| cx.render(rsx!("hello world!"));
@@ -98,11 +98,6 @@ impl<'a> Children<'a> {
         }
     }
 }
-// impl<'a> IntoVNodeList<'a> for &Children<'a> {
-//     fn into_vnode_list(self, cx: NodeFactory<'a>) -> &'a [VNode<'a>] {
-//         todo!()
-//     }
-// }
 
 static Bapp: FC<()> = |(cx, props)| {
     let name = cx.use_state(|| 0);

+ 169 - 11
packages/core/examples/syntax2.rs

@@ -2,7 +2,7 @@ use std::marker::PhantomData;
 
 use dioxus::component::Scope;
 use dioxus::events::on::MouseEvent;
-use dioxus::nodes::{IntoVNode, IntoVNodeList};
+use dioxus::nodes::{annotate_lazy, IntoVNode};
 use dioxus_core as dioxus;
 use dioxus_core::prelude::*;
 use dioxus_core_macro::*;
@@ -29,10 +29,16 @@ fn t() {
     };
 }
 
-fn App((cx, props): Scope<()>) -> Element {
+#[derive(PartialEq, Props)]
+struct OurProps {
+    foo: String,
+}
+
+fn App<'a>((cx, props): Scope<'a, OurProps>) -> Element<'a> {
     let a = rsx! {
         div {
             "asd"
+            "{props.foo}"
         }
     };
 
@@ -45,8 +51,12 @@ fn App((cx, props): Scope<()>) -> Element {
     });
 
     let g = match "text" {
-        "a" => rsx!("asd"),
-        b => rsx!("asd"),
+        "a" => {
+            rsx!("asd")
+        }
+        _ => {
+            rsx!("asd")
+        }
     };
 
     let items = ["bob", "bill", "jack"];
@@ -56,16 +66,164 @@ fn App((cx, props): Scope<()>) -> Element {
         .filter(|f| f.starts_with('b'))
         .map(|f| rsx!("hello {f}"));
 
+    // use dioxus_hooks;
+    // let g = use_state(|| "hello".to_string());
+
+    let s: &'a mut String = cx.use_hook(|_| String::new(), |f| f, |_| {});
+
+    /*
+    the final closure is allowed to borrow anything provided it
+    */
+
+    // cx.render({
+    //     let p: Option<Box<dyn FnOnce(_) -> _>> = Some(Box::new(move |__cx: NodeFactory| {
+    //         use dioxus_elements::{GlobalAttributes, SvgAttributes};
+
+    //         let props = Child2Props { foo: s };
+    //         let ch: VNode = __cx.component(Child2, props, None, []);
+    //         __cx.element(
+    //             dioxus_elements::div,
+    //             [],
+    //             [],
+    //             [ch],
+    //             // [__cx.component(Child2, fc_to_builder(Child2).foo(s).build(), None, [])],
+    //             None,
+    //         )
+    //     }));
+    //     p
+    //     // let ___p: Box<dyn FnOnce(NodeFactory) -> VNode> = Box::new(move |__cx| {
+    //     //     use dioxus_elements::{GlobalAttributes, SvgAttributes};
+
+    //     //     let props = Child2Props { foo: s };
+    //     //     let ch: VNode = __cx.component(Child2, props, None, []);
+    //     //     __cx.element(
+    //     //         dioxus_elements::div,
+    //     //         [],
+    //     //         [],
+    //     //         [ch],
+    //     //         // [__cx.component(Child2, fc_to_builder(Child2).foo(s).build(), None, [])],
+    //     //         None,
+    //     //     )
+    //     // });
+    //     // Some(___p)
+    // })
+
+    let a = annotate_lazy(move |f| {
+        //
+        todo!()
+    });
+    let b = annotate_lazy(move |f| {
+        //
+        f.text(format_args!("{}", props.foo))
+    });
+
+    let c = annotate_lazy(move |f| {
+        //
+        f.component(
+            Child,
+            OurProps {
+                //
+                foo: "hello".to_string(),
+            },
+            None,
+            [],
+        )
+    });
+
+    let st: &'a String = cx.use_hook(|_| "hello".to_string(), |f| f, |_| {});
+
+    let d = annotate_lazy(move |f| {
+        //
+        f.component(
+            Child2,
+            Child2Props {
+                //
+                foo: st,
+            },
+            None,
+            [],
+        )
+    });
+
+    let e = match "asd" {
+        b => {
+            //
+
+            annotate_lazy(move |f| {
+                //
+                f.text(format_args!("{}", props.foo))
+            })
+        }
+        a => {
+            //
+
+            annotate_lazy(move |f| {
+                //
+                f.text(format_args!("{}", props.foo))
+            })
+        }
+    };
+
+    cx.render(annotate_lazy(move |f| {
+        //
+
+        f.raw_element(
+            "div",
+            None,
+            [],
+            [],
+            [
+                //
+                f.fragment_from_iter(a),
+                f.fragment_from_iter(b),
+                f.fragment_from_iter(c),
+                f.fragment_from_iter(e),
+            ],
+            None,
+        )
+        // todo!()
+    }))
+    // cx.render(rsx! {
+    //     div {
+    //         div {
+    //             {a}
+    //             // {p}
+    //             // {g}
+    //             // {f}
+    //         }
+    //         // div {
+    //         //     "asd"
+    //         //     div {
+    //         //         "asd"
+    //         //     }
+    //         // }
+    //         // Child {
+    //         //     foo: "asd".to_string(),
+    //         // }
+    //         Child2 {
+    //             foo: s,
+    //         }
+    //     }
+    // })
+}
+
+fn Child((cx, props): Scope<OurProps>) -> Element {
     cx.render(rsx! {
         div {
-            div {
-                {a}
-                {p}
-                {g}
-                {f}
-            }
+            div {}
         }
     })
 }
 
-// std::boxed::Box<dyn for<'r> std::ops::FnOnce(dioxus_core::NodeFactory<'r>) -> dioxus_core::VNode<'_>>
+#[derive(Props)]
+struct Child2Props<'a> {
+    foo: &'a String,
+}
+
+fn Child2<'a>((cx, props): Scope<'a, Child2Props>) -> Element<'a> {
+    cx.render(rsx! {
+        div {
+            // div {}
+        }
+    })
+}

+ 2 - 1
packages/core/examples/vdom_usage.rs

@@ -4,7 +4,8 @@ use dioxus_core::prelude::*;
 
 #[async_std::main]
 async fn main() {
-    static App: FC<()> = |(cx, props)| cx.render(LazyNodes::new(|f| f.text(format_args!("hello"))));
+    static App: FC<()> =
+        |(cx, props)| cx.render(Some(Box::new(move |f| f.text(format_args!("hello")))));
 
     let mut dom = VirtualDom::new(App);
 

+ 1 - 1
packages/core/src/component.rs

@@ -6,7 +6,7 @@
 //! that ensures compile-time required and optional fields on cx.
 
 use crate::{
-    innerlude::{Context, Element, LazyNodes, FC},
+    innerlude::{Context, Element, FC},
     NodeFactory, VNode,
 };
 

+ 2 - 1
packages/core/src/context.rs

@@ -139,7 +139,8 @@ impl<'src> Context<'src> {
     ///```
     pub fn render(
         self,
-        lazy_nodes: Option<LazyNodes<'_>>,
+        lazy_nodes: Option<Box<dyn FnOnce(NodeFactory<'src>) -> VNode<'src> + '_>>,
+        // lazy_nodes: Option<Box<dyn FnOnce(NodeFactory) -> VNode + '_>>,
         // lazy_nodes: Box<dyn FnOnce(NodeFactory<'src>) -> VNode<'src> + '_>,
     ) -> Option<VNode<'src>> {
         // pub fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(

+ 10 - 10
packages/core/src/hooks.rs

@@ -180,17 +180,17 @@ pub struct SuspendedContext<'a> {
 }
 
 impl<'src> SuspendedContext<'src> {
+    // // pub fn render(
     // pub fn render(
-    pub fn render(
-        // pub fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
-        self,
-        lazy_nodes: LazyNodes<'_>,
-        // lazy_nodes: LazyNodes<'src, '_>,
-    ) -> Element<'src> {
-        let bump = &self.inner.scope.frames.wip_frame().bump;
-        todo!("suspense")
-        // Some(lazy_nodes.into_vnode(NodeFactory { bump }))
-    }
+    //     // pub fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
+    //     self,
+    //     lazy_nodes: LazyNodes<'_>,
+    //     // lazy_nodes: LazyNodes<'src, '_>,
+    // ) -> Element<'src> {
+    //     let bump = &self.inner.scope.frames.wip_frame().bump;
+    //     todo!("suspense")
+    //     // Some(lazy_nodes.into_vnode(NodeFactory { bump }))
+    // }
 }
 
 #[derive(Clone, Copy)]

+ 7 - 1
packages/core/src/lazynodes.rs

@@ -32,7 +32,13 @@ use crate::innerlude::{IntoVNode, NodeFactory, VNode};
 //     // inner: StackNodeStorage<'a>,
 //     // inner: StackNodeStorage<'a>,
 // }
-pub type LazyNodes<'b> = Box<dyn for<'a> FnOnce(NodeFactory<'a>) -> VNode<'a> + 'b>;
+// pub type LazyNodes<'b> = Box<dyn for<'a> FnOnce(NodeFactory<'a>) -> VNode<'a> + 'b>;
+
+// pub fn to_lazy_nodes<'b>(
+//     f: impl for<'a> FnOnce(NodeFactory<'a>) -> VNode<'a> + 'b,
+// ) -> Option<LazyNodes<'b>> {
+//     Some(Box::new(f))
+// }
 
 type StackHeapSize = [usize; 12];
 

+ 4 - 5
packages/core/src/lib.rs

@@ -46,7 +46,6 @@ pub(crate) mod innerlude {
     pub use crate::heuristics::*;
     pub(crate) use crate::hooklist::*;
     pub use crate::hooks::*;
-    pub use crate::lazynodes::LazyNodes;
     pub use crate::mutations::*;
     pub use crate::nodes::*;
     pub(crate) use crate::resources::*;
@@ -63,16 +62,16 @@ pub(crate) mod innerlude {
 }
 
 pub use crate::innerlude::{
-    Context, DioxusElement, DomEdit, Element, ElementId, EventPriority, LazyNodes, MountType,
-    Mutations, NodeFactory, Properties, SchedulerMsg, ScopeId, SuspendedContext, TaskHandle,
-    TestDom, ThreadsafeVirtualDom, UserEvent, VNode, VirtualDom, FC,
+    Context, DioxusElement, DomEdit, Element, ElementId, EventPriority, MountType, Mutations,
+    NodeFactory, Properties, SchedulerMsg, ScopeId, SuspendedContext, TaskHandle, TestDom,
+    ThreadsafeVirtualDom, UserEvent, VNode, VirtualDom, FC,
 };
 
 pub mod prelude {
     pub use crate::component::{fc_to_builder, Fragment, Properties, Scope};
     pub use crate::context::Context;
     pub use crate::hooks::*;
-    pub use crate::innerlude::{DioxusElement, Element, LazyNodes, Mutations, NodeFactory, FC};
+    pub use crate::innerlude::{DioxusElement, Element, Mutations, NodeFactory, FC};
     pub use crate::nodes::VNode;
     pub use crate::VirtualDom;
 }

+ 46 - 54
packages/core/src/nodes.rs

@@ -4,8 +4,7 @@
 //! cheap and *very* fast to construct - building a full tree should be quick.
 
 use crate::innerlude::{
-    empty_cell, Context, Element, ElementId, LazyNodes, Properties, ScopeId, ScopeInner,
-    SuspendedContext, FC,
+    empty_cell, Context, Element, ElementId, Properties, ScopeId, ScopeInner, SuspendedContext, FC,
 };
 use bumpalo::{boxed::Box as BumpBox, Bump};
 use std::{
@@ -329,21 +328,6 @@ impl<'a> NodeFactory<'a> {
         self.bump
     }
 
-    pub fn render_directly(&self, lazy_nodes: LazyNodes<'_>) -> Element<'a>
-// pub fn render_directly(&self, lazy_nodes: LazyNodes<'a, '_>) -> Element<'a>
-// where
-    //     F: FnOnce(NodeFactory<'a>) -> VNode<'a>,
-    {
-        // pub fn render_directly<F>(&self, lazy_nodes: LazyNodes<'a, F>) -> Element<'a>
-        // where
-        //     F: FnOnce(NodeFactory<'a>) -> VNode<'a>,
-        // {
-        // pub fn render_directly<F>(&self, lazy_nodes: LazyNodes<'a>) -> Option<VNode<'a>> {
-        // Some(lazy_nodes.into_vnode(NodeFactory { bump: self.bump }))
-
-        todo!()
-    }
-
     pub fn unstable_place_holder() -> VNode<'static> {
         VNode::Text(VText {
             text: "",
@@ -474,7 +458,8 @@ impl<'a> NodeFactory<'a> {
     ) -> VNode<'a>
     where
         P: Properties + 'a,
-        V: 'a + AsRef<[VNode<'a>]>,
+        V: AsRef<[VNode<'a>]> + 'a,
+        // V: 'a + AsRef<[VNode<'a>]>,
     {
         let bump = self.bump();
         let children: &'a V = bump.alloc(children);
@@ -559,8 +544,24 @@ impl<'a> NodeFactory<'a> {
         }))
     }
 
-    pub fn fragment_from_iter(self, node_iter: impl IntoVNodeList) -> VNode<'a> {
-        let children = node_iter.into_vnode_list(self);
+    pub fn fragment_from_iter(
+        self,
+        node_iter: impl IntoIterator<Item = impl IntoVNode<'a>>,
+    ) -> VNode<'a> {
+        let bump = self.bump();
+        let mut nodes = bumpalo::collections::Vec::new_in(bump);
+
+        for node in node_iter {
+            nodes.push(node.into_vnode(self));
+        }
+
+        if nodes.is_empty() {
+            nodes.push(VNode::Anchor(VAnchor {
+                dom_id: empty_cell(),
+            }));
+        }
+
+        let children = nodes.into_bump_slice();
 
         // TODO
         // We need a dedicated path in the rsx! macro that will trigger the "you need keys" warning
@@ -587,6 +588,15 @@ impl<'a> NodeFactory<'a> {
             is_static: false,
         })
     }
+
+    pub fn annotate_lazy<'z, 'b, F>(
+        f: F,
+    ) -> Option<Box<dyn FnOnce(NodeFactory<'z>) -> VNode<'z> + 'b>>
+    where
+        F: FnOnce(NodeFactory<'z>) -> VNode<'z> + 'b,
+    {
+        Some(Box::new(f))
+    }
 }
 
 /// Trait implementations for use in the rsx! and html! macros.
@@ -604,34 +614,8 @@ impl<'a> NodeFactory<'a> {
 ///
 /// 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 {
-    fn into_vnode<'a>(self, cx: NodeFactory<'a>) -> VNode<'a>;
-}
-
-pub trait IntoVNodeList {
-    fn into_vnode_list<'a>(self, cx: NodeFactory<'a>) -> &'a [VNode<'a>];
-}
-
-impl<T, V> IntoVNodeList for T
-where
-    T: IntoIterator<Item = V>,
-    V: IntoVNode,
-{
-    fn into_vnode_list<'a>(self, cx: NodeFactory<'a>) -> &'a [VNode<'a>] {
-        let mut nodes = bumpalo::collections::Vec::new_in(cx.bump());
-
-        for node in self.into_iter() {
-            nodes.push(node.into_vnode(cx));
-        }
-
-        if nodes.is_empty() {
-            nodes.push(VNode::Anchor(VAnchor {
-                dom_id: empty_cell(),
-            }));
-        }
-
-        nodes.into_bump_slice()
-    }
+pub trait IntoVNode<'a> {
+    fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a>;
 }
 
 /// Child nodes of the parent component.
@@ -684,6 +668,7 @@ impl<'a> IntoIterator for VNode<'a> {
     }
 }
 
+// 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 IntoVNode for VNode<'_> {
 //     fn into_vnode<'a>(self, _: NodeFactory<'a>) -> VNode<'a> {
@@ -714,8 +699,15 @@ impl<'a> IntoIterator for VNode<'a> {
 //     }
 // }
 
-impl IntoVNode for Option<Box<dyn for<'r> FnOnce(NodeFactory<'r>) -> VNode<'_> + '_>> {
-    fn into_vnode<'a>(self, cx: NodeFactory<'a>) -> VNode<'a> {
+pub fn annotate_lazy<'a, 'b, F>(f: F) -> Option<Box<dyn FnOnce(NodeFactory<'a>) -> VNode<'a> + 'b>>
+where
+    F: FnOnce(NodeFactory<'a>) -> VNode<'a> + 'b,
+{
+    Some(Box::new(f))
+}
+
+impl<'a> IntoVNode<'a> for Option<Box<dyn FnOnce(NodeFactory<'a>) -> VNode<'a> + '_>> {
+    fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
         match self {
             Some(n) => {
                 //
@@ -731,8 +723,8 @@ impl IntoVNode for Option<Box<dyn for<'r> FnOnce(NodeFactory<'r>) -> VNode<'_> +
     }
 }
 
-impl IntoVNode for Box<dyn for<'r> FnOnce(NodeFactory<'r>) -> VNode<'_> + '_> {
-    fn into_vnode<'a>(self, cx: NodeFactory<'a>) -> VNode<'a> {
+impl<'a> IntoVNode<'a> for Box<dyn FnOnce(NodeFactory<'a>) -> VNode<'a> + '_> {
+    fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
         self(cx)
     }
 }
@@ -746,12 +738,12 @@ impl IntoVNode for Box<dyn for<'r> FnOnce(NodeFactory<'r>) -> VNode<'_> + '_> {
 //     }
 // }
 
-impl IntoVNode for &'static str {
+impl IntoVNode<'_> for &'static str {
     fn into_vnode(self, cx: NodeFactory) -> VNode {
         cx.static_text(self)
     }
 }
-impl IntoVNode for Arguments<'_> {
+impl IntoVNode<'_> for Arguments<'_> {
     fn into_vnode(self, cx: NodeFactory) -> VNode {
         cx.text(self)
     }

+ 6 - 6
packages/core/tests/borrowedstate.rs

@@ -13,14 +13,14 @@ fn test_borrowed_state() {
 fn Parent((cx, _): Scope<()>) -> Element {
     let value = cx.use_hook(|_| String::new(), |f| &*f, |_| {});
 
-    rsx! {
+    cx.render(rsx! {
         div {
             Child { name: value }
             Child { name: value }
             Child { name: value }
             Child { name: value }
         }
-    }
+    })
 }
 
 #[derive(Props)]
@@ -29,12 +29,12 @@ struct ChildProps<'a> {
 }
 
 fn Child<'a>((cx, props): Scope<'a, ChildProps>) -> Element<'a> {
-    rsx! {
+    cx.render(rsx! {
         div {
             h1 { "it's nested" }
             Child2 { name: props.name }
         }
-    }
+    })
 }
 
 #[derive(Props)]
@@ -43,7 +43,7 @@ struct Grandchild<'a> {
 }
 
 fn Child2<'a>((cx, props): Scope<'a, Grandchild>) -> Element<'a> {
-    rsx! {
+    cx.render(rsx! {
         div { "Hello {props.name}!" }
-    }
+    })
 }

+ 8 - 8
packages/core/tests/display_vdom.rs

@@ -14,23 +14,23 @@ mod test_logging;
 #[test]
 fn please_work() {
     static App: FC<()> = |(cx, props)| {
-        rsx! {
+        cx.render(rsx! {
             div {
                 hidden: "true"
                 "hello"
                 div { "hello" }
-                Child {}
-                Child {}
-                Child {}
+                // Child {}
+                // Child {}
+                // Child {}
             }
-            div { "hello" }
-        }
+            // div { "hello" }
+        })
     };
 
     static Child: FC<()> = |(cx, props)| {
-        rsx! {
+        cx.render(rsx! {
             div { "child" }
-        }
+        })
     };
 
     let mut dom = VirtualDom::new(App);