Jonathan Kelley 2 роки тому
батько
коміт
d2ce57ba6e

+ 8 - 17
packages/core/src/any_props.rs

@@ -3,20 +3,20 @@ use std::marker::PhantomData;
 use futures_util::Future;
 
 use crate::{
-    factory::ReturnType,
+    factory::{ComponentReturn, RenderReturn},
     scopes::{Scope, ScopeState},
     Element,
 };
 
 pub trait AnyProps<'a> {
     fn as_ptr(&self) -> *const ();
-    fn render(&'a self, bump: &'a ScopeState) -> Element<'a>;
+    fn render(&'a self, bump: &'a ScopeState) -> RenderReturn<'a>;
     unsafe fn memoize(&self, other: &dyn AnyProps) -> bool;
 }
 
 pub(crate) struct VComponentProps<'a, P, A, F = Element<'a>>
 where
-    F: ReturnType<'a, A>,
+    F: ComponentReturn<'a, A>,
 {
     pub render_fn: fn(Scope<'a, P>) -> F,
     pub memo: unsafe fn(&P, &P) -> bool,
@@ -35,7 +35,7 @@ impl<'a> VComponentProps<'a, (), ()> {
     }
 }
 
-impl<'a, P, A, F: ReturnType<'a, A>> VComponentProps<'a, P, A, F> {
+impl<'a, P, A, F: ComponentReturn<'a, A>> VComponentProps<'a, P, A, F> {
     pub(crate) fn new(
         render_fn: fn(Scope<'a, P>) -> F,
         memo: unsafe fn(&P, &P) -> bool,
@@ -50,7 +50,7 @@ impl<'a, P, A, F: ReturnType<'a, A>> VComponentProps<'a, P, A, F> {
     }
 }
 
-impl<'a, P, A, F: ReturnType<'a, A>> AnyProps<'a> for VComponentProps<'a, P, A, F> {
+impl<'a, P, A, F: ComponentReturn<'a, A>> AnyProps<'a> for VComponentProps<'a, P, A, F> {
     fn as_ptr(&self) -> *const () {
         &self.props as *const _ as *const ()
     }
@@ -65,25 +65,16 @@ impl<'a, P, A, F: ReturnType<'a, A>> AnyProps<'a> for VComponentProps<'a, P, A,
         (self.memo)(real_us, real_other)
     }
 
-    fn render<'b>(&'b self, scope: &'b ScopeState) -> Element<'b> {
+    fn render(&self, cx: &'a ScopeState) -> RenderReturn<'a> {
         // Make sure the scope ptr is not null
         // self.props.state.set(scope);
 
         let scope = Scope {
             props: unsafe { &*self.props },
-            scope,
+            scope: cx,
         };
 
         // Call the render function directly
-        // todo: implement async
-        // let res = match self.render_fn {
-        //     ComponentFn::Sync(f) => {
-        //         let f = unsafe { std::mem::transmute(f) };
-        //         f(scope)
-        //     }
-        //     ComponentFn::Async(_) => todo!(),
-        // };
-
-        todo!()
+        (self.render_fn)(scope).as_return(cx)
     }
 }

+ 4 - 4
packages/core/src/bump_frame.rs

@@ -2,23 +2,23 @@ use std::cell::Cell;
 
 use bumpalo::Bump;
 
-use crate::nodes::VNode;
+use crate::factory::RenderReturn;
 
 pub struct BumpFrame {
     pub bump: Bump,
-    pub node: Cell<*const VNode<'static>>,
+    pub node: Cell<*mut RenderReturn<'static>>,
 }
 impl BumpFrame {
     pub fn new(capacity: usize) -> Self {
         let bump = Bump::with_capacity(capacity);
         Self {
             bump,
-            node: Cell::new(std::ptr::null()),
+            node: Cell::new(std::ptr::null_mut()),
         }
     }
 
     pub fn reset(&mut self) {
         self.bump.reset();
-        self.node.set(std::ptr::null());
+        self.node.set(std::ptr::null_mut());
     }
 }

+ 58 - 13
packages/core/src/create.rs

@@ -1,9 +1,15 @@
+use std::task::Context;
+
+use futures_util::task::noop_waker_ref;
+use futures_util::{pin_mut, Future};
+
+use crate::factory::RenderReturn;
 use crate::mutations::Mutation;
 use crate::mutations::Mutation::*;
 use crate::nodes::VNode;
 use crate::nodes::{DynamicNode, TemplateNode};
 use crate::virtualdom::VirtualDom;
-use crate::{AttributeValue, ElementId, TemplateAttribute};
+use crate::{AttributeValue, Element, ElementId, TemplateAttribute};
 
 impl VirtualDom {
     /// Create this template and write its mutations
@@ -96,10 +102,12 @@ impl VirtualDom {
             while let Some((idx, path)) = dynamic_nodes.next_if(|(_, p)| p[0] == root_idx as u8) {
                 let node = &template.dynamic_nodes[idx];
                 let m = self.create_dynamic_node(mutations, template, node, idx);
-                mutations.push(ReplacePlaceholder {
-                    m,
-                    path: &path[1..],
-                });
+                if m > 0 {
+                    mutations.push(ReplacePlaceholder {
+                        m,
+                        path: &path[1..],
+                    });
+                }
             }
         }
 
@@ -172,16 +180,53 @@ impl VirtualDom {
             DynamicNode::Component { props, .. } => {
                 let id = self.new_scope(unsafe { std::mem::transmute(props.get()) });
 
-                let template = self.run_scope(id);
+                let render_ret = self.run_scope(id);
 
                 // shut up about lifetimes please, I know what I'm doing
-                let template: &VNode = unsafe { std::mem::transmute(template) };
-
-                self.scope_stack.push(id);
-                let created = self.create(mutations, template);
-                self.scope_stack.pop();
-
-                created
+                let render_ret: &mut RenderReturn = unsafe { std::mem::transmute(render_ret) };
+
+                match render_ret {
+                    RenderReturn::Sync(Some(template)) => {
+                        self.scope_stack.push(id);
+                        let created = self.create(mutations, template);
+                        self.scope_stack.pop();
+                        created
+                    }
+                    RenderReturn::Sync(None) => todo!("nodes that return nothing"),
+                    RenderReturn::Async(fut) => {
+                        use futures_util::FutureExt;
+
+                        // Poll the suspense node once to see if we can get any nodes from it
+                        let mut cx = Context::from_waker(&noop_waker_ref());
+                        let res = fut.poll_unpin(&mut cx);
+
+                        match res {
+                            std::task::Poll::Ready(Some(val)) => {
+                                let scope = self.get_scope(id).unwrap();
+                                let ready = &*scope.bump().alloc(val);
+                                let ready = unsafe { std::mem::transmute(ready) };
+
+                                self.scope_stack.push(id);
+                                let created = self.create(mutations, ready);
+                                self.scope_stack.pop();
+                                created
+                            }
+                            std::task::Poll::Ready(None) => {
+                                todo!("Pending suspense")
+                            }
+                            std::task::Poll::Pending => {
+                                let new_id = self.next_element(template);
+                                // id.set(new_id);
+                                mutations.push(AssignId {
+                                    id: new_id,
+                                    path: &template.template.node_paths[idx][1..],
+                                });
+
+                                0
+                            }
+                        }
+                    }
+                }
             }
 
             DynamicNode::Fragment(children) => children

+ 24 - 7
packages/core/src/factory.rs

@@ -1,5 +1,6 @@
-use std::{cell::Cell, fmt::Arguments};
+use std::{cell::Cell, fmt::Arguments, pin::Pin};
 
+use bumpalo::boxed::Box as BumpBox;
 use bumpalo::Bump;
 use futures_util::Future;
 
@@ -70,7 +71,7 @@ impl ScopeState {
     }
 
     /// Create a new [`VNode::Component`]
-    pub fn component<'a, P, A, F: ReturnType<'a, A>>(
+    pub fn component<'a, P, A, F: ComponentReturn<'a, A>>(
         &'a self,
         component: fn(Scope<'a, P>) -> F,
         props: P,
@@ -100,11 +101,27 @@ impl ScopeState {
     }
 }
 
-pub trait ReturnType<'a, A = ()> {}
-impl<'a> ReturnType<'a> for Element<'a> {}
+pub trait ComponentReturn<'a, A = ()> {
+    fn as_return(self, cx: &'a ScopeState) -> RenderReturn<'a>;
+}
+impl<'a> ComponentReturn<'a> for Element<'a> {
+    fn as_return(self, _cx: &ScopeState) -> RenderReturn<'a> {
+        RenderReturn::Sync(self)
+    }
+}
 
 pub struct AsyncMarker;
-impl<'a, F> ReturnType<'a, AsyncMarker> for F where F: Future<Output = Element<'a>> + 'a {}
+impl<'a, F> ComponentReturn<'a, AsyncMarker> for F
+where
+    F: Future<Output = Element<'a>> + 'a,
+{
+    fn as_return(self, cx: &'a ScopeState) -> RenderReturn<'a> {
+        let f: &mut dyn Future<Output = Element<'a>> = cx.bump().alloc(self);
+        let boxed = unsafe { BumpBox::from_raw(f) };
+        let pined: Pin<BumpBox<_>> = boxed.into();
+        RenderReturn::Async(pined)
+    }
+}
 
 #[test]
 fn takes_it() {
@@ -113,9 +130,9 @@ fn takes_it() {
     }
 }
 
-enum RenderReturn<'a> {
+pub enum RenderReturn<'a> {
     Sync(Element<'a>),
-    Async(*mut dyn Future<Output = Element<'a>>),
+    Async(Pin<BumpBox<'a, dyn Future<Output = Element<'a>> + 'a>>),
 }
 
 pub trait IntoVnode<'a, A = ()> {

+ 0 - 16
packages/core/src/lib.rs

@@ -132,19 +132,3 @@ macro_rules! to_owned {
         let mut $es = $es.to_owned();
     )*}
 }
-
-/// get the code location of the code that called this function
-#[macro_export]
-macro_rules! get_line_num {
-    () => {
-        concat!(
-            file!(),
-            ":",
-            line!(),
-            ":",
-            column!(),
-            ":",
-            env!("CARGO_MANIFEST_DIR")
-        )
-    };
-}

+ 4 - 3
packages/core/src/scope_arena.rs

@@ -2,6 +2,7 @@ use crate::{
     any_props::AnyProps,
     arena::ElementId,
     bump_frame::BumpFrame,
+    factory::RenderReturn,
     nodes::VNode,
     scopes::{ScopeId, ScopeState},
     virtualdom::VirtualDom,
@@ -48,15 +49,15 @@ impl VirtualDom {
             .and_then(|id| self.scopes.get_mut(id.0).map(|f| f as *mut ScopeState))
     }
 
-    pub fn run_scope(&mut self, id: ScopeId) -> &VNode {
+    pub fn run_scope(&mut self, id: ScopeId) -> &mut RenderReturn {
         let scope = &mut self.scopes[id.0];
         scope.hook_idx.set(0);
 
         let res = {
             let props = unsafe { &mut *scope.props };
             let props: &mut dyn AnyProps = unsafe { std::mem::transmute(props) };
-            let res: VNode = props.render(scope).unwrap();
-            let res: VNode<'static> = unsafe { std::mem::transmute(res) };
+            let res: RenderReturn = props.render(scope);
+            let res: RenderReturn<'static> = unsafe { std::mem::transmute(res) };
             res
         };
 

+ 12 - 7
packages/core/src/virtualdom.rs

@@ -2,6 +2,7 @@ use crate::any_props::VComponentProps;
 use crate::arena::ElementPath;
 use crate::component::Component;
 use crate::diff::DirtyScope;
+use crate::factory::RenderReturn;
 use crate::future_container::FutureQueue;
 use crate::innerlude::SchedulerMsg;
 use crate::mutations::Mutation;
@@ -57,13 +58,17 @@ impl VirtualDom {
     pub fn rebuild<'a>(&'a mut self, mutations: &mut Vec<Mutation<'a>>) {
         // let root = self.scopes.get(0).unwrap();
 
-        let root_node = unsafe { std::mem::transmute(self.run_scope(ScopeId(0))) };
-
-        // let root_node = unsafe { std::mem::transmute(root.root_node()) };
-
-        self.scope_stack.push(ScopeId(0));
-        self.create(mutations, root_node);
-        self.scope_stack.pop();
+        let root_node: &RenderReturn = self.run_scope(ScopeId(0));
+        let root_node: &RenderReturn = unsafe { std::mem::transmute(root_node) };
+        match root_node {
+            RenderReturn::Sync(Some(node)) => {
+                self.scope_stack.push(ScopeId(0));
+                self.create(mutations, node);
+                self.scope_stack.pop();
+            }
+            RenderReturn::Sync(None) => todo!("Handle empty root node"),
+            RenderReturn::Async(_) => unreachable!(),
+        }
     }
 
     /// Render what you can given the timeline and then move on

+ 12 - 1
packages/rsx/src/lib.rs

@@ -110,6 +110,9 @@ impl<'a> ToTokens for TemplateRenderer<'a> {
             None => quote! { None },
         };
 
+        let spndbg = format!("{:?}", self.roots[0].span());
+        let root_col = spndbg[9..].split("..").next().unwrap();
+
         let root_printer = self.roots.iter().enumerate().map(|(idx, root)| {
             context.current_path.push(idx as u8);
             let out = context.render_static_node(root);
@@ -126,7 +129,15 @@ impl<'a> ToTokens for TemplateRenderer<'a> {
 
         out_tokens.append_all(quote! {
             static TEMPLATE: ::dioxus::core::Template = ::dioxus::core::Template {
-                id: ::dioxus::core::get_line_num!(),
+                id: concat!(
+                    file!(),
+                    ":",
+                    line!(),
+                    ":",
+                    column!(),
+                    ":",
+                    #root_col
+                ),
                 roots: &[ #roots ],
                 node_paths: &[ #(#node_paths),* ],
                 attr_paths: &[ #(#attr_paths),* ],

+ 30 - 1
packages/ssr/src/template.rs

@@ -131,7 +131,7 @@ impl SsrRender {
                         // todo: escape the text
                         write!(buf, "{}", value)?
                     }
-                    DynamicNode::Fragment { children } => {
+                    DynamicNode::Fragment(children) => {
                         for child in *children {
                             self.render_template(buf, child)?;
                         }
@@ -140,6 +140,9 @@ impl SsrRender {
                     DynamicNode::Component { .. } => {
                         //
                     }
+                    DynamicNode::Placeholder(el) => {
+                        //
+                    }
                 },
 
                 Segment::PreRendered(text) => buf.push_str(&text),
@@ -217,3 +220,29 @@ fn children_processes_properly() {
     dom.rebuild(&mut mutations);
     dbg!(mutations);
 }
+
+#[test]
+fn async_children() {
+    use dioxus::prelude::*;
+
+    fn app(cx: Scope) -> Element {
+        let d = 123;
+
+        render! {
+            div {
+                async_child {}
+            }
+        }
+    }
+
+    async fn async_child(cx: Scope<'_>) -> Element {
+        let d = 123;
+        render! { p { "{d}" "hii" } }
+    }
+
+    let mut dom = VirtualDom::new(app);
+
+    let mut mutations = vec![];
+    dom.rebuild(&mut mutations);
+    dbg!(mutations);
+}