From e939373616680ae74948fa2c36388332c52d0d1f Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Sun, 7 Feb 2021 16:21:38 -0500 Subject: [PATCH] Feat: capture pointer type --- .vscode/settings.json | 2 +- packages/core/examples/sketch.rs | 51 ++++++++++++++++++++++++-------- packages/core/examples/step.rs | 36 ++++++++++++++++++++++ packages/core/src/virtual_dom.rs | 28 ++++++++++++++++-- 4 files changed, 101 insertions(+), 16 deletions(-) create mode 100644 packages/core/examples/step.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index 2f418701b..80f51cff8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "rust-analyzer.inlayHints.enable": true + "rust-analyzer.inlayHints.enable": false } \ No newline at end of file diff --git a/packages/core/examples/sketch.rs b/packages/core/examples/sketch.rs index 61ff2c8ba..5f09da37b 100644 --- a/packages/core/examples/sketch.rs +++ b/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! { - //
- // - //

{ "Current value: {val}" }

- //
- // } + ctx.view(html! { +
+ +

"Current value: {val}"

+
+ }) +}; + +/// 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! { +
+ +

"Current value: {val}"

+
+ }) } + +// +// diff --git a/packages/core/examples/step.rs b/packages/core/examples/step.rs new file mode 100644 index 000000000..36b94153b --- /dev/null +++ b/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::(); + 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 = |ctx| { + ctx.view(html! { +
+

+
+ }) +}; diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 45f9d2eee..8fff4ff45 100644 --- a/packages/core/src/virtual_dom.rs +++ b/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, hooks: RefCell>, 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(&self, f: FC) {} + + fn call(&mut self, val: T) { + if self.props_type == TypeId::of::() { + /* + 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>(self.caller) }; + let ctx = self.create_context::(); + 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.