Ver código fonte

wip: comment out examples and move lifetime in FC type

Jonathan Kelley 4 anos atrás
pai
commit
62d4ad5

+ 24 - 24
examples/Cargo.toml

@@ -41,34 +41,34 @@ path = "common.rs"
 # Examples are manually keyed in
 # ================================
 
-[[example]]
-path = "hello_web.rs"
-name = "hello_web"
+# [[example]]
+# path = "hello_web.rs"
+# name = "hello_web"
 
-[[example]]
-path = "tide_ssr.rs"
-name = "tide_ssr"
+# [[example]]
+# path = "tide_ssr.rs"
+# name = "tide_ssr"
 
-[[example]]
-path = "doc_generator.rs"
-name = "doc_generator"
+# [[example]]
+# path = "doc_generator.rs"
+# name = "doc_generator"
 
-[[example]]
-path = "router.rs"
-name = "router"
+# [[example]]
+# path = "router.rs"
+# name = "router"
 
-[[example]]
-path = "fc_macro.rs"
-name = "fc_macro"
+# [[example]]
+# path = "fc_macro.rs"
+# name = "fc_macro"
 
-[[example]]
-path = "webview.rs"
-name = "webview"
+# [[example]]
+# path = "webview.rs"
+# name = "webview"
 
-[[example]]
-path = "blah.rs"
-name = "blah"
+# [[example]]
+# path = "blah.rs"
+# name = "blah"
 
-[[example]]
-path = "live.rs"
-name = "live"
+# [[example]]
+# path = "live.rs"
+# name = "live"

+ 6 - 5
packages/core-macro/src/lib.rs

@@ -45,8 +45,6 @@ fn function_component_impl(
     //     ));
     // }
 
-    let ret_type = quote_spanned!(return_type.span()=> VNode);
-
     let quoted = quote! {
         #[doc(hidden)]
         #[allow(non_camel_case_types)]
@@ -54,14 +52,17 @@ fn function_component_impl(
             use super::*;
 
             #[derive(PartialEq)]
-            pub struct Props {
-                name: String
+            pub struct Props<'a> {
+                name: &'a str
             }
 
-            pub fn component(ctx: &mut Context<Props>) -> #ret_type {
+            pub fn component<'a>(ctx: &'a Context<'a, Props>) -> VNode<'a> {
+                // Destructure the props into the parent scope
+                // todo: handle expansion of lifetimes
                 let Props {
                     name
                 } = ctx.props;
+
                 #block
             }
         }

+ 1 - 1
packages/core/.vscode/settings.json

@@ -1,3 +1,3 @@
 {
-    "rust-analyzer.inlayHints.enable": true
+    "rust-analyzer.inlayHints.enable": false
 }

+ 1 - 1
packages/core/Cargo.toml

@@ -11,7 +11,7 @@ description = "Core functionality for Dioxus - a concurrent renderer-agnostic Vi
 
 [dependencies]
 dioxus-html-macro = { path = "../html-macro", version = "0.1.0" }
-
+dioxus-core-macro = { path = "../core-macro" }
 # Backs some static data
 once_cell = "1.5.2"
 

+ 31 - 3
packages/core/README.md

@@ -6,8 +6,8 @@ This is the core crate for the Dioxus Virtual DOM. This README will focus on the
 Dioxus-core builds off the many frameworks that came before it. Notably, Dioxus borrows these concepts:
 
 - React: hooks, concurrency, suspense
-- Dodrio: bump allocation / custom faster allocators, stack machine for fast changes
-- Percy: html! macro implementation and agnostic edit list
+- Dodrio: bump allocation, double buffering
+- Percy: html! macro architecture, platform-agnostic edits
 - Yew: passion and inspiration ❤️
 
 ## Goals
@@ -15,6 +15,7 @@ Dioxus-core builds off the many frameworks that came before it. Notably, Dioxus
 We have big goals for Dioxus. The final implementation must:
 
 - Be **fast**. Allocators are typically slow in WASM/Rust, so we should have a smart way of allocating.
+- Be extremely memory efficient. Servers should handle tens of thousands of simultaneous VDoms with no problem.
 - Be concurrent. Components should be able to pause rendering using a threading mechanism.
 - Support "broadcasting". Edit lists should be separate from the Renderer implementation.
 - Support SSR. VNodes should render to a string that can be served via a web server.
@@ -30,10 +31,37 @@ We have big goals for Dioxus. The final implementation must:
 ## Design Quirks
 
 - Use of "Context" as a way of mitigating threading issues and the borrow checker. (JS relies on globals)
-- html! is lazy - needs to be used with a partner function to actually allocate the html.
+- html! is lazy - needs to be used with a partner function to actually allocate the html. (Good be a good thing or a bad thing)
 
 ```rust
 let text = TextRenderer::render(html! {<div>"hello world"</div>});
 // <div>hello world</div>
 ```
 
+```rust
+
+fn main() {
+    tide::new()
+        .get("blah", serve_app("../"))
+        .get("blah", ws_handler(serve_app))
+}
+
+
+fn serve_app(ctx: &Context<()>) -> VNode {
+    let livecontext = LiveContext::new()
+        .with_handler("graph", graph_component)
+        .with_handler("graph", graph_component)
+        .with_handler("graph", graph_component)
+        .with_handler("graph", graph_component)
+        .with_handler("graph", graph_component)
+        .with_handler("graph", graph_component)
+        .build();
+
+    ctx.view(html! {
+        <LiveContext ctx={livecontext}>
+            <App />
+        </ LiveContext>
+    })
+}
+
+```

+ 58 - 5
packages/core/examples/dummy.rs

@@ -1,11 +1,64 @@
-// #![allow(unused, non_upper_case_globals)]
-// use bumpalo::Bump;
-// use dioxus_core::nodebuilder::*;
-// use dioxus_core::{nodes::DomTree, prelude::*};
-// use std::{collections::HashMap, future::Future, marker::PhantomData};
+#![allow(unused, non_upper_case_globals)]
+use bumpalo::Bump;
+use dioxus_core::prelude::VNode;
+use dioxus_core::prelude::*;
+use dioxus_core::{nodebuilder::*, virtual_dom::Properties};
+use once_cell::sync::{Lazy, OnceCell};
+use std::{collections::HashMap, future::Future, marker::PhantomData};
 
 fn main() {}
 
+// struct VC<P, F = fn(Context<P>) -> VNode> {
+//     f: F,
+//     _a: std::marker::PhantomData<(P, F)>, // cell: OnceCell<T>,
+//                                           // init: Cell<Option<F>>
+// }
+// impl<P, F> VC<P, F> {
+//     const fn new(init: F) -> VC<P, F> {
+//         Self {
+//             _a: std::marker::PhantomData {},
+//             f: init,
+//         }
+//     }
+//     fn builder() -> P {
+//         // P::new()
+//     }
+// }
+
+// // Build a new functional component
+// static SomeComp: VC<()> = VC::new(|ctx| {
+//     // This is a component, apparently
+//     // still not useful because we can't have bounds
+
+//     ctx.view(html! {
+//         <div>
+
+//         </div>
+//     })
+// });
+
+/*
+
+
+
+
+
+
+
+
+
+
+
+*/
+static BILL: Lazy<fn(Context<()>) -> String> = Lazy::new(|| {
+    //
+    |c| "BLAH".to_string()
+});
+
+// struct FUNC<F = fn() -> T> {}
+
+struct SomeBuilder {}
+
 // struct DummyRenderer {
 //     alloc: Bump,
 // }

+ 75 - 28
packages/core/examples/macrosrc.rs

@@ -1,19 +1,19 @@
-#![allow(unused, non_upper_case_globals)]
+#![allow(unused, non_upper_case_globals, non_snake_case)]
 use bumpalo::Bump;
 use dioxus_core::prelude::*;
 use dioxus_core::{nodebuilder::*, virtual_dom::DomTree};
 use std::{collections::HashMap, future::Future, marker::PhantomData};
 
 fn main() {}
-struct Props<'a> {
-    use_macro: bool,
 
-    // todo uh not static
-    // incorporate lifetimes into the thing somehow
-    text: &'a str,
+// ~~~ Text shared between components via props can be done with lifetimes! ~~~
+// Super duper efficient :)
+struct Props {
+    blah: bool,
+    text: String,
 }
 
-fn Component(ctx: Context<Props>) -> VNode {
+fn Component<'a>(ctx: &'a Context<Props>) -> VNode<'a> {
     // Write asynchronous rendering code that immediately returns a "suspended" VNode
     // The concurrent API will then progress this component when the future finishes
     // You can suspend the entire component, or just parts of it
@@ -25,30 +25,77 @@ fn Component(ctx: Context<Props>) -> VNode {
         }
     });
 
+    ctx.view(html! {
+        <div>
+            // <h1> "Products" </h1>
+            // // Subnodes can even be suspended
+            // // When completely rendered, they won't cause the component itself to re-render, just their slot
+            // <p> { product_list } </p>
+        </div>
+    })
+}
+
+fn BuilderComp(ctx: Context<Props>) -> VNode {
+    // VNodes can be constructed via a builder or the html! macro
+    // However, both of these are "lazy" - they need to be evaluated (aka, "viewed")
+    // We can "view" them with Context for ultimate speed while inside components
+    ctx.view(|bump| {
+        div(bump)
+            .attr("class", "edit")
+            .child(text("Hello"))
+            .child(text(ctx.props.text.as_str()))
+            .finish()
+    })
+}
+
+#[fc]
+fn EffcComp(ctx: &Context, name: &str) -> VNode {
     // VNodes can be constructed via a builder or the html! macro
     // However, both of these are "lazy" - they need to be evaluated (aka, "viewed")
     // We can "view" them with Context for ultimate speed while inside components
-    if ctx.props.use_macro {
-        ctx.view(|bump| {
-            div(bump)
-                .attr("class", "edit")
-                .child(text("Hello"))
-                .child(text(ctx.props.text))
-                .finish()
-        })
-    } else {
-        // "View" indicates exactly *when* allocations take place, everything is lazy up to this point
-        ctx.view(html! {
-            <div>
-                // TODO!
-                // Get all this working again
-                // <h1>"Products"</h1>
-                // // Subnodes can even be suspended
-                // // When completely rendered, they won't cause the component itself to re-render, just their slot
-                // <p> {product_list} </p>
-            </div>
-        })
-    }
+    // use "phase" style allocation;
+    /*
+    nodes...
+    text...
+    attrs...
+    <div> // node0
+        <div> </div> // node1
+        {// support some expression} // node 2
+    </div>
+    let node0;
+    let node1;
+    let node2 = evaluate{}.into();
+    let g= |bump| {1};
+    g(bump).into()
+
+    */
+
+    // should we automatically view the output or leave it?
+    ctx.view(html! {
+        <div>
+            // your template goes here
+            // feel free to directly use "name"
+        </div>
+    })
+}
+
+fn FullySuspended(ctx: Context<Props>) -> VNode {
+    ctx.suspend(async {
+        let i: i32 = 0;
+
+        // full suspended works great with just returning VNodes!
+        let tex = match i {
+            1 => html! { <div> </div> },
+            2 => html! { <div> </div> },
+            _ => html! { <div> </div> },
+        };
+
+        if ctx.props.blah {
+            html! { <div> </div> }
+        } else {
+            tex
+        }
+    })
 }
 
 /// An example of a datafetching service

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

@@ -81,11 +81,8 @@ pub mod prelude {
     pub use nodes::*;
     // pub use nodes::iterables::IterableNodes;
 
-    // FC is a shorthand for statics to easily declare a function that takes a context and produces a dom tree
-    // The DomTree is lazy and needs to be evaluated with an arena for any allocation to take place
-    // Hmmm, maybe get statics to work again?
-    // pub type FC<'a, T> = fn(&'a Context<T>) -> VNode<'a>;
-    pub use crate::virtual_dom::{__domtree_helper, FC};
+    /// This type alias is an internal way of abstracting over the static functions that represent components.
+    pub type FC<P> = for<'a> fn(&'a Context<P>) -> VNode<'a>;
 
     // TODO @Jon, fix this
     // hack the VNode type until VirtualNode is fixed in the macro crate
@@ -93,4 +90,7 @@ pub mod prelude {
 
     // Re-export from the macro crate
     pub use dioxus_html_macro::html;
+
+    // Re-export the FC macro
+    pub use dioxus_core_macro::fc;
 }

+ 0 - 1
packages/core/src/nodebuilder.rs

@@ -2,7 +2,6 @@
 
 use crate::nodes::{Attribute, Listener, NodeKey, VNode};
 type Node<'g> = VNode<'g>;
-// use crate::{node::NodeKey, Attribute, Listener, Node, RootRender, VdomWeak};
 use bumpalo::Bump;
 
 /// A virtual DOM element builder.

+ 20 - 24
packages/core/src/virtual_dom.rs

@@ -71,7 +71,7 @@ impl VirtualDom {
     ///
     /// This means that the root component must either consumes its own context, or statics are used to generate the page.
     /// The root component can access things like routing in its context.
-    pub fn new<F: DomTree>(root: FC<(), F>) -> Self {
+    pub fn new(root: FC<()>) -> Self {
         Self::new_with_props(root)
     }
 
@@ -80,7 +80,7 @@ impl VirtualDom {
     ///
     /// This is useful when a component tree can be driven by external state (IE SSR) but it would be too expensive
     /// to toss out the entire tree.
-    pub fn new_with_props<P: Properties, F: DomTree>(root: FC<P, F>) -> Self {
+    pub fn new_with_props<P: Properties>(root: FC<P>) -> Self {
         Self {
             components: Arena::new(),
             event_queue: vec![],
@@ -116,19 +116,6 @@ where
     }
 }
 
-/// This type alias is an internal way of abstracting over the static functions that represent components.
-pub type FC<P: Properties, F: DomTree> = fn(&Context<P>) -> F;
-
-/// A gross AF helper that connects the dots for lifetimes
-/// sigh.. todo: move this into the html macro or core crates
-/// https://github.com/rust-lang/rust/issues/41078
-#[inline]
-pub fn __domtree_helper(
-    arg: impl for<'a> FnOnce(&'a Bump) -> VNode<'a>,
-) -> impl for<'a> FnOnce(&'a Bump) -> VNode<'a> {
-    arg
-}
-
 /// The `Component` trait refers to any struct or funciton that can be used as a component
 /// We automatically implement Component for FC<T>
 pub trait Component {
@@ -138,7 +125,7 @@ pub trait Component {
 
 // Auto implement component for a FC
 // Calling the FC is the same as "rendering" it
-impl<'a, P: Properties, F: DomTree> Component for FC<P, F> {
+impl<P: Properties> Component for FC<P> {
     type Props = P;
 
     fn builder(&self) -> Self::Props {
@@ -235,14 +222,14 @@ pub struct HookState {}
 ///     }
 /// }
 /// ```
-pub struct Context<T> {
-    // pub struct Context<'source, T> {
+// todo: force lifetime of source into T as a valid lifetime too
+// it's definitely possible, just needs some more messing around
+pub struct Context<'source, T> {
     /// Direct access to the properties used to create this component.
-    pub props: T,
-    // pub props: &'source T,
+    pub props: &'source T,
 }
 
-impl<'a, T> Context<T> {
+impl<'a, T> Context<'a, T> {
     // impl<'a, T> Context<'a, T> {
     /// Access the children elements passed into the component
     pub fn children(&self) -> Vec<VNode> {
@@ -260,9 +247,18 @@ impl<'a, T> Context<T> {
         || {}
     }
 
-    /// Create VNodes from macros that use efficient allcators
-    /// The VDOM is configured to use a special allocator for VNodes
-    pub fn view(&self, v: impl Fn(&'a Bump) -> VNode<'a>) -> VNode<'a> {
+    /// Take a lazy VNode structure and actually build it with the context of the VDom's efficient VNode allocator.
+    ///
+    /// ```ignore
+    /// fn Component(ctx: Context<Props>) -> VNode {
+    ///     // Lazy assemble the VNode tree
+    ///     let lazy_tree = html! {<div>"Hello World"</div>};
+    ///     
+    ///     // Actually build the tree and allocate it
+    ///     ctx.view(lazy_tree)
+    /// }
+    ///```
+    pub fn view(&self, v: impl FnOnce(&'a Bump) -> VNode<'a>) -> VNode<'a> {
         todo!()
     }
 

+ 48 - 48
packages/hooks/examples/lifecycle.rs

@@ -1,57 +1,57 @@
 use dioxus_core::prelude::*;
 
 fn main() {
-    let mut s = Context { props: &() };
-    let g = Component(&mut s);
+    // let mut s = Context { props: &() };
+    // let g = Component(&mut s);
 }
 
-struct CompState {
-    tasks: Vec<()>,
-}
-enum Actions {
-    Add,
-    MoveUp,
-    MoveDown,
-    Remvoe,
-}
+// struct CompState {
+//     tasks: Vec<()>,
+// }
+// enum Actions {
+//     Add,
+//     MoveUp,
+//     MoveDown,
+//     Remvoe,
+// }
 
-static Component: FC<()> = |ctx| {
-    let (tasks, dispatch) = use_reducer(
-        ctx,
-        || CompState { tasks: Vec::new() },
-        |state, action: Actions| match action {
-            Actions::Add => state,
-            Actions::MoveUp => state,
-            Actions::MoveDown => state,
-            Actions::Remvoe => state,
-        },
-    );
+// static Component: FC<()> = |ctx| {
+//     let (tasks, dispatch) = use_reducer(
+//         ctx,
+//         || CompState { tasks: Vec::new() },
+//         |state, action: Actions| match action {
+//             Actions::Add => state,
+//             Actions::MoveUp => state,
+//             Actions::MoveDown => state,
+//             Actions::Remvoe => state,
+//         },
+//     );
 
-    let tasklist = { (0..10).map(|f| html! { <li></li> }) }.collect::<Vec<_>>();
+//     let tasklist = { (0..10).map(|f| html! { <li></li> }) }.collect::<Vec<_>>();
 
-    html! {
-        <div>
-            <div>
-                <h1>"Tasks: "</h1>
-                <ul>
-                    {tasklist}
-                </ul>
-            </div>
-            <div>
-                <button onclick=|_| dispatch(Action::Add)>{"Add"}</button>
-                <button onclick=|_| dispatch(Action::MoveUp)>{"MoveUp"}</button>
-                <button onclick=|_| dispatch(Action::MoveDown)>{"MoveDown"}</button>
-                <button onclick=|_| dispatch(Action::Remvoe)>{"Remvoe"}</button>
-            </div>
-        </div>
-    }
-};
+//     html! {
+//         <div>
+//             <div>
+//                 <h1>"Tasks: "</h1>
+//                 <ul>
+//                     {tasklist}
+//                 </ul>
+//             </div>
+//             <div>
+//                 <button onclick=|_| dispatch(Action::Add)>{"Add"}</button>
+//                 <button onclick=|_| dispatch(Action::MoveUp)>{"MoveUp"}</button>
+//                 <button onclick=|_| dispatch(Action::MoveDown)>{"MoveDown"}</button>
+//                 <button onclick=|_| dispatch(Action::Remvoe)>{"Remvoe"}</button>
+//             </div>
+//         </div>
+//     }
+// };
 
-fn use_reducer<Props, State, Action>(
-    ctx: &mut Context<Props>,
-    init: fn() -> State,
-    reducer: fn(State, Action) -> State,
-) -> (State, impl Fn(Action)) {
-    let ii = init();
-    (ii, |_| {})
-}
+// fn use_reducer<Props, State, Action>(
+//     ctx: &mut Context<Props>,
+//     init: fn() -> State,
+//     reducer: fn(State, Action) -> State,
+// ) -> (State, impl Fn(Action)) {
+//     let ii = init();
+//     (ii, |_| {})
+// }

+ 31 - 30
packages/webview/src/lib.rs

@@ -38,38 +38,39 @@ impl<T> WebviewRenderer<T> {
     }
 
     pub fn launch(self, props: T) {
-        let mut ctx = Context { props: &props };
-        let WebviewRenderer { root } = self;
-        let content = root(&mut ctx);
-        let html_content = content.to_string();
-        /*
-        TODO: @Jon
-        Launch the webview with a premade VDom app
-        */
+        todo!()
+        // let mut ctx = Context { props: &props };
+        // let WebviewRenderer { root } = self;
+        // let content = root(&mut ctx);
+        // let html_content = content.to_string();
+        // /*
+        // TODO: @Jon
+        // Launch the webview with a premade VDom app
+        // */
 
-        web_view::builder()
-            .title("My Project")
-            .content(web_view::Content::Html(html_content))
-            .size(320, 480)
-            .resizable(true)
-            .debug(true)
-            .user_data(())
-            .invoke_handler(|_webview, _arg| Ok(()))
-            .run()
-            .unwrap();
+        // web_view::builder()
+        //     .title("My Project")
+        //     .content(web_view::Content::Html(html_content))
+        //     .size(320, 480)
+        //     .resizable(true)
+        //     .debug(true)
+        //     .user_data(())
+        //     .invoke_handler(|_webview, _arg| Ok(()))
+        //     .run()
+        //     .unwrap();
     }
 }
 
-mod receiver {
-    use dioxus_core::prelude::*;
+// mod receiver {
+//     use dioxus_core::prelude::*;
 
-    /// The receiver app is a container that builds a connection to the host process that shuttles events and patches.  
-    pub(crate) static ReceiverApp: FC<()> = |ctx| {
-        //
-        html! {
-            <div>
-                {}
-            </div>
-        }
-    };
-}
+//     /// The receiver app is a container that builds a connection to the host process that shuttles events and patches.
+//     pub(crate) static ReceiverApp: FC<()> = |ctx| {
+//         //
+//         html! {
+//             <div>
+//                 {}
+//             </div>
+//         }
+//     };
+// }