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

chore: continue to consolidate

Jonathan Kelley преди 3 години
родител
ревизия
21e00c1
променени са 5 файла, в които са добавени 236 реда и са изтрити 232 реда
  1. 26 18
      packages/core/README.md
  2. 9 0
      packages/core/examples/simple_hello.rs
  3. 0 174
      packages/core/src/component.rs
  4. 1 3
      packages/core/src/lib.rs
  5. 200 37
      packages/core/src/virtual_dom.rs

+ 26 - 18
packages/core/README.md

@@ -7,16 +7,12 @@ To build new apps with Dioxus or to extend the ecosystem with new hooks or compo
 
 ```rust
 fn app(cx: Scope<()>) -> Element {
-    cx.render(rsx!(
-        div { "hello world" }
-    ))
+    rsx!(cx, div { "hello world" })
 }
 
-
 fn main() {
     let mut renderer = SomeRenderer::new();
 
-
     // Creating a new virtualdom from a component
     let mut dom = VirtualDom::new(app);
 
@@ -25,23 +21,35 @@ fn main() {
     renderer.apply(edits);
 
     // Injecting events
-    dom.handle_message(SchedulerMsg::UserEvent());
+    dom.handle_message(SchedulerMsg::Event(UserEvent {
+        scope_id: None,
+        priority: EventPriority::High,
+        element: ElementId(0),
+        name: "onclick",
+        data: Arc::new(()),
+    }));
+
+    // polling asynchronously
+    dom.wait_for_work().await;
+
+    // working with a deadline
+    if let Some(edits) = dom.work_with_deadline(|| false) {
+        renderer.apply(edits);
+    }
+
+    // getting state of scopes
+    let scope = dom.get_scope(ScopeId(0)).unwrap();
+
+    // iterating through the tree
+    match scope.root_node() {
+        VNodes::Text(vtext) => dbg!(vtext),
+        VNodes::Element(vel) => dbg!(vel),
+        _ => todo!()
+    }
 
 }
 
 
-
-
-
-
-
-
-
-
-
-
-
-
 ```
 ## Internals
 

+ 9 - 0
packages/core/examples/simple_hello.rs

@@ -0,0 +1,9 @@
+use dioxus::prelude::*;
+use dioxus_core as dioxus;
+use dioxus_core_macro::*;
+use dioxus_html as dioxus_elements;
+
+// very tiny hello world
+fn main() {
+    dioxus::VirtualDom::new(|cx| rsx!(cx, "hello world"));
+}

+ 0 - 174
packages/core/src/component.rs

@@ -1,174 +0,0 @@
-//! This file handles the supporting infrastructure for the `Component` trait and `Properties` which makes it possible
-//! for components to be used within Nodes.
-//!
-//! Note - using the builder pattern does not required the Properties trait to be implemented - the only thing that matters is
-//! if the type supports PartialEq. The Properties trait is used by the rsx! and html! macros to generate the type-safe builder
-//! that ensures compile-time required and optional fields on cx.
-
-use crate::{
-    innerlude::{Element, Scope},
-    LazyNodes,
-};
-
-pub struct FragmentProps<'a>(Element<'a>);
-pub struct FragmentBuilder<'a, const BUILT: bool>(Element<'a>);
-impl<'a> FragmentBuilder<'a, false> {
-    pub fn children(self, children: Element<'a>) -> FragmentBuilder<'a, true> {
-        FragmentBuilder(children)
-    }
-}
-impl<'a, const A: bool> FragmentBuilder<'a, A> {
-    pub fn build(self) -> FragmentProps<'a> {
-        FragmentProps(self.0)
-    }
-}
-
-/// Access the children elements passed into the component
-///
-/// This enables patterns where a component is passed children from its parent.
-///
-/// ## Details
-///
-/// Unlike React, Dioxus allows *only* lists of children to be passed from parent to child - not arbitrary functions
-/// or classes. If you want to generate nodes instead of accepting them as a list, consider declaring a closure
-/// on the props that takes Context.
-///
-/// If a parent passes children into a component, the child will always re-render when the parent re-renders. In other
-/// words, a component cannot be automatically memoized if it borrows nodes from its parent, even if the component's
-/// props are valid for the static lifetime.
-///
-/// ## Example
-///
-/// ```rust, ignore
-/// fn App(cx: Scope<()>) -> Element {
-///     cx.render(rsx!{
-///         CustomCard {
-///             h1 {}2
-///             p {}
-///         }
-///     })
-/// }
-///
-/// #[derive(PartialEq, Props)]
-/// struct CardProps {
-///     children: Element
-/// }
-///
-/// fn CustomCard(cx: Scope<CardProps>) -> Element {
-///     cx.render(rsx!{
-///         div {
-///             h1 {"Title card"}
-///             {cx.props.children}
-///         }
-///     })
-/// }
-/// ```
-impl<'a> Properties for FragmentProps<'a> {
-    type Builder = FragmentBuilder<'a, false>;
-    const IS_STATIC: bool = false;
-    fn builder() -> Self::Builder {
-        FragmentBuilder(None)
-    }
-    unsafe fn memoize(&self, _other: &Self) -> bool {
-        false
-    }
-}
-
-/// Create inline fragments using Component syntax.
-///
-/// ## Details
-///
-/// Fragments capture a series of children without rendering extra nodes.
-///
-/// Creating fragments explicitly with the Fragment component is particularly useful when rendering lists or tables and
-/// a key is needed to identify each item.
-///
-/// ## Example
-///
-/// ```rust, ignore
-/// rsx!{
-///     Fragment { key: "abc" }
-/// }
-/// ```
-///
-/// ## Usage
-///
-/// Fragments are incredibly useful when necessary, but *do* add cost in the diffing phase.
-/// Try to avoid highly nested fragments if you can. Unlike React, there is no protection against infinitely nested fragments.
-///
-/// This function defines a dedicated `Fragment` component that can be used to create inline fragments in the RSX macro.
-///
-/// You want to use this free-function when your fragment needs a key and simply returning multiple nodes from rsx! won't cut it.
-#[allow(non_upper_case_globals, non_snake_case)]
-pub fn Fragment<'a>(cx: Scope<'a, FragmentProps<'a>>) -> Element {
-    let i = cx.props.0.as_ref().map(|f| f.decouple());
-    cx.render(Some(LazyNodes::new(|f| f.fragment_from_iter(i))))
-}
-
-/// Every "Props" used for a component must implement the `Properties` trait. This trait gives some hints to Dioxus
-/// on how to memoize the props and some additional optimizations that can be made. We strongly encourage using the
-/// derive macro to implement the `Properties` trait automatically as guarantee that your memoization strategy is safe.
-///
-/// If your props are 'static, then Dioxus will require that they also be PartialEq for the derived memoize strategy. However,
-/// if your props borrow data, then the memoization strategy will simply default to "false" and the PartialEq will be ignored.
-/// This tends to be useful when props borrow something that simply cannot be compared (IE a reference to a closure);
-///
-/// By default, the memoization strategy is very conservative, but can be tuned to be more aggressive manually. However,
-/// this is only safe if the props are 'static - otherwise you might borrow references after-free.
-///
-/// We strongly suggest that any changes to memoization be done at the "PartialEq" level for 'static props. Additionally,
-/// we advise the use of smart pointers in cases where memoization is important.
-///
-/// ## Example
-///
-/// For props that are 'static:
-/// ```rust, ignore ignore
-/// #[derive(Props, PartialEq)]
-/// struct MyProps {
-///     data: String
-/// }
-/// ```
-///
-/// For props that borrow:
-///
-/// ```rust, ignore ignore
-/// #[derive(Props)]
-/// struct MyProps<'a >{
-///     data: &'a str
-/// }
-/// ```
-pub trait Properties: Sized {
-    type Builder;
-    const IS_STATIC: bool;
-    fn builder() -> Self::Builder;
-
-    /// Memoization can only happen if the props are valid for the 'static lifetime
-    ///
-    /// # Safety
-    /// The user must know if their props are static, but if they make a mistake, UB happens
-    /// Therefore it's unsafe to memoize.
-    unsafe fn memoize(&self, other: &Self) -> bool;
-}
-
-impl Properties for () {
-    type Builder = EmptyBuilder;
-    const IS_STATIC: bool = true;
-    fn builder() -> Self::Builder {
-        EmptyBuilder {}
-    }
-    unsafe fn memoize(&self, _other: &Self) -> bool {
-        true
-    }
-}
-// We allow components to use the () generic parameter if they have no props. This impl enables the "build" method
-// that the macros use to anonymously complete prop construction.
-pub struct EmptyBuilder;
-impl EmptyBuilder {
-    pub fn build(self) {}
-}
-
-/// This utility function launches the builder method so rsx! and html! macros can use the typed-builder pattern
-/// to initialize a component's props.
-pub fn fc_to_builder<'a, T: Properties + 'a>(_: fn(Scope<'a, T>) -> Element) -> T::Builder {
-    T::builder()
-}

+ 1 - 3
packages/core/src/lib.rs

@@ -1,7 +1,6 @@
 #![allow(non_snake_case)]
 #![doc = include_str!("../README.md")]
 
-pub(crate) mod component;
 pub(crate) mod diff;
 pub(crate) mod lazynodes;
 pub(crate) mod mutations;
@@ -10,7 +9,6 @@ pub(crate) mod scopes;
 pub(crate) mod virtual_dom;
 
 pub(crate) mod innerlude {
-    pub use crate::component::*;
     pub(crate) use crate::diff::*;
     pub use crate::lazynodes::*;
     pub use crate::mutations::*;
@@ -69,12 +67,12 @@ pub use crate::innerlude::{
 };
 
 pub mod prelude {
-    pub use crate::component::{fc_to_builder, Fragment, Properties};
     pub use crate::innerlude::Scope;
     pub use crate::innerlude::{
         Component, DioxusElement, Element, EventHandler, LazyNodes, NodeFactory, ScopeState,
     };
     pub use crate::nodes::VNode;
+    pub use crate::virtual_dom::{fc_to_builder, Fragment, Properties};
     pub use crate::VirtualDom;
 }
 

+ 200 - 37
packages/core/src/virtual_dom.rs

@@ -697,6 +697,51 @@ impl Drop for VirtualDom {
     }
 }
 
+struct PollTasks<'a>(&'a mut ScopeArena);
+
+impl<'a> Future for PollTasks<'a> {
+    type Output = ();
+
+    fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
+        let mut all_pending = true;
+
+        let mut unfinished_tasks: SmallVec<[_; 10]> = smallvec::smallvec![];
+        let mut scopes_to_clear: SmallVec<[_; 10]> = smallvec::smallvec![];
+
+        // Poll every scope manually
+        for fut in self.0.pending_futures.borrow().iter().copied() {
+            let scope = self.0.get_scope(fut).expect("Scope should never be moved");
+
+            let mut items = scope.items.borrow_mut();
+
+            // really this should just be retain_mut but that doesn't exist yet
+            while let Some(mut task) = items.tasks.pop() {
+                if task.as_mut().poll(cx).is_ready() {
+                    all_pending = false
+                } else {
+                    unfinished_tasks.push(task);
+                }
+            }
+
+            if unfinished_tasks.is_empty() {
+                scopes_to_clear.push(fut);
+            }
+
+            items.tasks.extend(unfinished_tasks.drain(..));
+        }
+
+        for scope in scopes_to_clear {
+            self.0.pending_futures.borrow_mut().remove(&scope);
+        }
+
+        // Resolve the future if any singular task is ready
+        match all_pending {
+            true => Poll::Pending,
+            false => Poll::Ready(()),
+        }
+    }
+}
+
 #[derive(Debug)]
 pub enum SchedulerMsg {
     // events from the host
@@ -810,47 +855,165 @@ pub enum EventPriority {
     Low = 0,
 }
 
-struct PollTasks<'a>(&'a mut ScopeArena);
-
-impl<'a> Future for PollTasks<'a> {
-    type Output = ();
-
-    fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
-        let mut all_pending = true;
-
-        let mut unfinished_tasks: SmallVec<[_; 10]> = smallvec::smallvec![];
-        let mut scopes_to_clear: SmallVec<[_; 10]> = smallvec::smallvec![];
-
-        // Poll every scope manually
-        for fut in self.0.pending_futures.borrow().iter().copied() {
-            let scope = self.0.get_scope(fut).expect("Scope should never be moved");
-
-            let mut items = scope.items.borrow_mut();
+pub struct FragmentProps<'a>(Element<'a>);
+pub struct FragmentBuilder<'a, const BUILT: bool>(Element<'a>);
+impl<'a> FragmentBuilder<'a, false> {
+    pub fn children(self, children: Element<'a>) -> FragmentBuilder<'a, true> {
+        FragmentBuilder(children)
+    }
+}
+impl<'a, const A: bool> FragmentBuilder<'a, A> {
+    pub fn build(self) -> FragmentProps<'a> {
+        FragmentProps(self.0)
+    }
+}
 
-            // really this should just be retain_mut but that doesn't exist yet
-            while let Some(mut task) = items.tasks.pop() {
-                if task.as_mut().poll(cx).is_ready() {
-                    all_pending = false
-                } else {
-                    unfinished_tasks.push(task);
-                }
-            }
+/// Access the children elements passed into the component
+///
+/// This enables patterns where a component is passed children from its parent.
+///
+/// ## Details
+///
+/// Unlike React, Dioxus allows *only* lists of children to be passed from parent to child - not arbitrary functions
+/// or classes. If you want to generate nodes instead of accepting them as a list, consider declaring a closure
+/// on the props that takes Context.
+///
+/// If a parent passes children into a component, the child will always re-render when the parent re-renders. In other
+/// words, a component cannot be automatically memoized if it borrows nodes from its parent, even if the component's
+/// props are valid for the static lifetime.
+///
+/// ## Example
+///
+/// ```rust, ignore
+/// fn App(cx: Scope<()>) -> Element {
+///     cx.render(rsx!{
+///         CustomCard {
+///             h1 {}2
+///             p {}
+///         }
+///     })
+/// }
+///
+/// #[derive(PartialEq, Props)]
+/// struct CardProps {
+///     children: Element
+/// }
+///
+/// fn CustomCard(cx: Scope<CardProps>) -> Element {
+///     cx.render(rsx!{
+///         div {
+///             h1 {"Title card"}
+///             {cx.props.children}
+///         }
+///     })
+/// }
+/// ```
+impl<'a> Properties for FragmentProps<'a> {
+    type Builder = FragmentBuilder<'a, false>;
+    const IS_STATIC: bool = false;
+    fn builder() -> Self::Builder {
+        FragmentBuilder(None)
+    }
+    unsafe fn memoize(&self, _other: &Self) -> bool {
+        false
+    }
+}
 
-            if unfinished_tasks.is_empty() {
-                scopes_to_clear.push(fut);
-            }
+/// Create inline fragments using Component syntax.
+///
+/// ## Details
+///
+/// Fragments capture a series of children without rendering extra nodes.
+///
+/// Creating fragments explicitly with the Fragment component is particularly useful when rendering lists or tables and
+/// a key is needed to identify each item.
+///
+/// ## Example
+///
+/// ```rust, ignore
+/// rsx!{
+///     Fragment { key: "abc" }
+/// }
+/// ```
+///
+/// ## Usage
+///
+/// Fragments are incredibly useful when necessary, but *do* add cost in the diffing phase.
+/// Try to avoid highly nested fragments if you can. Unlike React, there is no protection against infinitely nested fragments.
+///
+/// This function defines a dedicated `Fragment` component that can be used to create inline fragments in the RSX macro.
+///
+/// You want to use this free-function when your fragment needs a key and simply returning multiple nodes from rsx! won't cut it.
+#[allow(non_upper_case_globals, non_snake_case)]
+pub fn Fragment<'a>(cx: Scope<'a, FragmentProps<'a>>) -> Element {
+    let i = cx.props.0.as_ref().map(|f| f.decouple());
+    cx.render(Some(LazyNodes::new(|f| f.fragment_from_iter(i))))
+}
 
-            items.tasks.extend(unfinished_tasks.drain(..));
-        }
+/// Every "Props" used for a component must implement the `Properties` trait. This trait gives some hints to Dioxus
+/// on how to memoize the props and some additional optimizations that can be made. We strongly encourage using the
+/// derive macro to implement the `Properties` trait automatically as guarantee that your memoization strategy is safe.
+///
+/// If your props are 'static, then Dioxus will require that they also be PartialEq for the derived memoize strategy. However,
+/// if your props borrow data, then the memoization strategy will simply default to "false" and the PartialEq will be ignored.
+/// This tends to be useful when props borrow something that simply cannot be compared (IE a reference to a closure);
+///
+/// By default, the memoization strategy is very conservative, but can be tuned to be more aggressive manually. However,
+/// this is only safe if the props are 'static - otherwise you might borrow references after-free.
+///
+/// We strongly suggest that any changes to memoization be done at the "PartialEq" level for 'static props. Additionally,
+/// we advise the use of smart pointers in cases where memoization is important.
+///
+/// ## Example
+///
+/// For props that are 'static:
+/// ```rust, ignore ignore
+/// #[derive(Props, PartialEq)]
+/// struct MyProps {
+///     data: String
+/// }
+/// ```
+///
+/// For props that borrow:
+///
+/// ```rust, ignore ignore
+/// #[derive(Props)]
+/// struct MyProps<'a >{
+///     data: &'a str
+/// }
+/// ```
+pub trait Properties: Sized {
+    type Builder;
+    const IS_STATIC: bool;
+    fn builder() -> Self::Builder;
 
-        for scope in scopes_to_clear {
-            self.0.pending_futures.borrow_mut().remove(&scope);
-        }
+    /// Memoization can only happen if the props are valid for the 'static lifetime
+    ///
+    /// # Safety
+    /// The user must know if their props are static, but if they make a mistake, UB happens
+    /// Therefore it's unsafe to memoize.
+    unsafe fn memoize(&self, other: &Self) -> bool;
+}
 
-        // Resolve the future if any singular task is ready
-        match all_pending {
-            true => Poll::Pending,
-            false => Poll::Ready(()),
-        }
+impl Properties for () {
+    type Builder = EmptyBuilder;
+    const IS_STATIC: bool = true;
+    fn builder() -> Self::Builder {
+        EmptyBuilder {}
     }
+    unsafe fn memoize(&self, _other: &Self) -> bool {
+        true
+    }
+}
+// We allow components to use the () generic parameter if they have no props. This impl enables the "build" method
+// that the macros use to anonymously complete prop construction.
+pub struct EmptyBuilder;
+impl EmptyBuilder {
+    pub fn build(self) {}
+}
+
+/// This utility function launches the builder method so rsx! and html! macros can use the typed-builder pattern
+/// to initialize a component's props.
+pub fn fc_to_builder<'a, T: Properties + 'a>(_: fn(Scope<'a, T>) -> Element) -> T::Builder {
+    T::builder()
 }