Procházet zdrojové kódy

Feat: capture pointer type

Jonathan Kelley před 4 roky
rodič
revize
e939373

+ 1 - 1
.vscode/settings.json

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

+ 38 - 13
packages/core/examples/sketch.rs

@@ -1,6 +1,7 @@
 use bumpalo::Bump;
+use dioxus_core as dioxus;
 use dioxus_core::{
-    prelude::{Context, VElement, VNode, FC},
+    prelude::{html, Context, VElement, VNode, FC},
     virtual_dom::{Properties, Scope},
 };
 use std::{
@@ -135,26 +136,50 @@ fn test_use_state(ctx: Context<()>) -> VNode {
     // whenever a listener wakes up, we take the reference directly from the bump arena and, with a small bit
     // of unsafe code, execute the associated closure / listener function
     // Those vnodes are then tossed out and new ones are installed, meaning and old references (potentially bad)
-    // are removed and UB is prevented from affecting the program
+    // are removed and UB is prevented from /affecting/ the program
     {
         VNode::Element(VElement::new("button"))
     }
 }
 
-fn test_use_state_2(ctx: Context<()>) -> VNode {
+#[allow(unused, non_upper_case_globals)]
+static UseStateBorrowedFc: FC<()> = |ctx| {
     let (val, set_val) = use_state(&ctx, || 0);
 
     let incr = || set_val(val + 1);
     let decr = || set_val(val - 1);
 
-    todo!()
-    // html! {
-    //     <div>
-    //         <nav class="menu">
-    //             <button onclick=incr> { "Increment" } </button>
-    //             <button onclick=decr> { "Decrement" } </button>
-    //         </nav>
-    //         <p> <b>{ "Current value: {val}" }</b> </p>
-    //     </div>
-    // }
+    ctx.view(html! {
+        <div>
+            <nav class="menu">
+                <button> "Increment" </button>
+                <button> "Decrement" </button>
+            </nav>
+            <p> "Current value: {val}" </p>
+        </div>
+    })
+};
+
+/// A useful component
+/// With some great documentation
+/// it practically speaks for itself.
+/// It's also only a server component :o
+fn use_state_borrowed(ctx: Context<()>) -> VNode {
+    let (val, set_val) = use_state(&ctx, || 0);
+
+    let incr = || set_val(val + 1);
+    let decr = || set_val(val - 1);
+
+    ctx.view(html! {
+        <div>
+            <nav class="menu">
+                <button> "Increment" </button>
+                <button> "Decrement" </button>
+            </nav>
+            <p> "Current value: {val}" </p>
+        </div>
+    })
 }
+
+// <button onclick=incr> { "Increment" } </button>
+// <button onclick=decr> { "Decrement" } </button>

+ 36 - 0
packages/core/examples/step.rs

@@ -0,0 +1,36 @@
+//! An example that shows how to:
+//!     create a scope,
+//!     render a component,
+//!     change some data
+//!     render it again
+//!     consume the diffs and write that to a renderer
+
+use dioxus_core::{
+    prelude::*,
+    virtual_dom::{Properties, Scope},
+};
+
+fn main() {
+    let mut scope = Scope::new(Example);
+    let ctx = scope.create_context::<Props>();
+    let p1 = Props { name: "bob".into() };
+
+    let p2 = Props { name: "bob".into() };
+}
+
+struct Props {
+    name: String,
+}
+impl Properties for Props {
+    fn new() -> Self {
+        todo!()
+    }
+}
+
+static Example: FC<Props> = |ctx| {
+    ctx.view(html! {
+        <div>
+            <h1> </h1>
+        </div>
+    })
+};

+ 26 - 2
packages/core/src/virtual_dom.rs

@@ -49,10 +49,11 @@ A Context
 */
 use crate::nodes::VNode;
 use crate::prelude::*;
+use any::Any;
 use bumpalo::Bump;
 use generational_arena::{Arena, Index};
 use std::{
-    any::TypeId,
+    any::{self, TypeId},
     cell::{RefCell, UnsafeCell},
     future::Future,
     marker::PhantomData,
@@ -279,6 +280,7 @@ pub struct Scope {
     arena: typed_arena::Arena<Hook>,
     hooks: RefCell<Vec<*mut Hook>>,
     props_type: TypeId,
+    caller: *const (),
 }
 
 impl Scope {
@@ -289,10 +291,13 @@ impl Scope {
         let arena = typed_arena::Arena::new();
         let hooks = RefCell::new(Vec::new());
 
+        let caller = f as *const ();
+
         Self {
             arena,
             hooks,
             props_type,
+            caller,
         }
     }
 
@@ -308,7 +313,26 @@ impl Scope {
 
     /// Create a new context and run the component with references from the Virtual Dom
     /// This function downcasts the function pointer based on the stored props_type
-    fn run() {}
+    fn run<T: 'static>(&self, f: FC<T>) {}
+
+    fn call<T: Properties + 'static>(&mut self, val: T) {
+        if self.props_type == TypeId::of::<T>() {
+            /*
+            SAFETY ALERT
+
+            This particular usage of transmute is outlined in its docs https://doc.rust-lang.org/std/mem/fn.transmute.html
+            We hide the generic bound on the function item by casting it to raw pointer. When the function is actually called,
+            we transmute the function back using the props as reference.
+
+            This is safe because we check that the generic type matches before casting.
+            */
+            let caller = unsafe { std::mem::transmute::<*const (), FC<T>>(self.caller) };
+            let ctx = self.create_context::<T>();
+            let nodes = caller(ctx);
+        } else {
+            panic!("Do not try to use `call` on Scopes with the wrong props type")
+        }
+    }
 }
 
 /// Components in Dioxus use the "Context" object to interact with their lifecycle.