diff --git a/examples/borrowed.rs b/examples/borrowed.rs index bf779f3b5..35ec2cfba 100644 --- a/examples/borrowed.rs +++ b/examples/borrowed.rs @@ -20,7 +20,7 @@ fn main() { dioxus::desktop::launch(App, |c| c); } -fn App(cx: Context, props: &()) -> Element { +fn App(cx: Scope, props: &()) -> Element { let text: &mut Vec = cx.use_hook(|_| vec![String::from("abc=def")], |f| f); let first = text.get_mut(0).unwrap(); @@ -39,7 +39,7 @@ struct C1Props<'a> { text: &'a mut String, } -fn Child1(cx: Context, props: &C1Props) -> Element { +fn Child1(cx: Scope, props: &C1Props) -> Element { let (left, right) = props.text.split_once("=").unwrap(); cx.render(rsx! { @@ -55,7 +55,7 @@ struct C2Props<'a> { text: &'a str, } -fn Child2(cx: Context, props: &C2Props) -> Element { +fn Child2(cx: Scope, props: &C2Props) -> Element { cx.render(rsx! { Child3 { text: props.text @@ -68,7 +68,7 @@ struct C3Props<'a> { text: &'a str, } -fn Child3(cx: Context, props: &C3Props) -> Element { +fn Child3(cx: Scope, props: &C3Props) -> Element { cx.render(rsx! { div { "{props.text}"} }) diff --git a/examples/calculator.rs b/examples/calculator.rs index d17d35b84..442ddb7f8 100644 --- a/examples/calculator.rs +++ b/examples/calculator.rs @@ -120,7 +120,7 @@ struct CalculatorKeyProps<'a> { children: Element, } -fn CalculatorKey<'a>(cx: Context, props: &CalculatorKeyProps) -> Element { +fn CalculatorKey<'a>(cx: Scope, props: &CalculatorKeyProps) -> Element { rsx!(cx, button { class: "calculator-key {props.name}" onclick: {props.onclick} diff --git a/examples/coroutine.rs b/examples/coroutine.rs index 2fa8e25e6..61bed91c3 100644 --- a/examples/coroutine.rs +++ b/examples/coroutine.rs @@ -61,7 +61,7 @@ struct HorseyProps<'a> { children: ScopeChildren<'a>, } -fn Horsey<'a>((cx, props): Scope<'a, HorseyProps<'a>>) -> Element { +fn Horsey<'a>((cx, props): ScopeState<'a, HorseyProps<'a>>) -> Element { cx.render(rsx! { div { button { "pause" } diff --git a/examples/framework_benchmark.rs b/examples/framework_benchmark.rs index 0330357a5..44fe202e1 100644 --- a/examples/framework_benchmark.rs +++ b/examples/framework_benchmark.rs @@ -95,7 +95,7 @@ struct ActionButtonProps<'a> { onclick: &'a dyn Fn(), } -fn ActionButton(cx: Context, props: &ActionButtonProps) -> Element { +fn ActionButton(cx: Scope, props: &ActionButtonProps) -> Element { rsx!(cx, div { class: "col-sm-6 smallpad" button { class:"btn btn-primary btn-block", r#type: "button", id: "{props.id}", onclick: move |_| (props.onclick)(), "{props.name}" diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 7eaf74d7d..e6c874ba5 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -4,7 +4,7 @@ fn main() { dioxus::desktop::launch(App, |c| c); } -fn App((cx, props): Scope<()>) -> Element { +fn App((cx, props): ScopeState<()>) -> Element { cx.render(rsx! ( div { "Hello, world!" } )) diff --git a/examples/pattern_model.rs b/examples/pattern_model.rs index 518f60101..d0a9e7290 100644 --- a/examples/pattern_model.rs +++ b/examples/pattern_model.rs @@ -77,7 +77,7 @@ struct CalculatorKeyProps<'a> { children: ScopeChildren<'a>, } -fn CalculatorKey<'a>((cx, props): Scope<'a, CalculatorKeyProps<'a>>) -> Element<'a> { +fn CalculatorKey<'a>((cx, props): ScopeState<'a, CalculatorKeyProps<'a>>) -> Element<'a> { cx.render(rsx! { button { class: "calculator-key {props.name}" diff --git a/examples/rsx_usage.rs b/examples/rsx_usage.rs index 7a69c6de9..e27d4c828 100644 --- a/examples/rsx_usage.rs +++ b/examples/rsx_usage.rs @@ -178,7 +178,7 @@ pub static Example: Component<()> = |cx, props| { }) }; -fn helper(cx: Context, text: &str) -> Element { +fn helper(cx: Scope, text: &str) -> Element { rsx!(cx, p { "{text}" }) } @@ -188,7 +188,7 @@ mod baller { pub struct BallerProps {} /// This component totally balls - pub fn Baller(_: Scope) -> Element { + pub fn Baller(_: ScopeState) -> Element { todo!() } } @@ -202,7 +202,7 @@ pub struct TallerProps<'a> { } /// This component is taller than most :) -pub fn Taller<'a>(_: Scope<'a, TallerProps<'a>>) -> Element { +pub fn Taller<'a>(_: ScopeState<'a, TallerProps<'a>>) -> Element { let b = true; todo!() } diff --git a/examples/ssr.rs b/examples/ssr.rs index 87bb4328e..e23251ada 100644 --- a/examples/ssr.rs +++ b/examples/ssr.rs @@ -21,6 +21,6 @@ static App: Component<()> = |cx, props| { struct MyProps<'a> { text: &'a str, } -fn App2(cx: Context, props: &MyProps) -> Element { +fn App2(cx: Scope, props: &MyProps) -> Element { None } diff --git a/examples/todomvc.rs b/examples/todomvc.rs index 9d8969c33..395b86696 100644 --- a/examples/todomvc.rs +++ b/examples/todomvc.rs @@ -85,7 +85,7 @@ pub struct TodoEntryProps { todo: Rc, } -pub fn TodoEntry(cx: Context, props: &TodoEntryProps) -> Element { +pub fn TodoEntry(cx: Scope, props: &TodoEntryProps) -> Element { let mut is_editing = use_state(cx, || false); let mut contents = use_state(cx, || String::from("")); let todo = &props.todo; diff --git a/examples/web_tick.rs b/examples/web_tick.rs index a1913e766..3a24ce523 100644 --- a/examples/web_tick.rs +++ b/examples/web_tick.rs @@ -45,7 +45,7 @@ struct RowProps { row_id: usize, label: Label, } -fn Row((cx, props): Scope) -> Element { +fn Row((cx, props): ScopeState) -> Element { let [adj, col, noun] = props.label.0; cx.render(rsx! { tr { diff --git a/packages/core/benches/jsframework.rs b/packages/core/benches/jsframework.rs index f8e53bc88..4f5f762d1 100644 --- a/packages/core/benches/jsframework.rs +++ b/packages/core/benches/jsframework.rs @@ -53,7 +53,7 @@ struct RowProps { row_id: usize, label: Label, } -fn Row(cx: Context, props: &RowProps) -> Element { +fn Row(cx: Scope, props: &RowProps) -> Element { let [adj, col, noun] = props.label.0; cx.render(rsx! { tr { diff --git a/packages/core/examples/borrowed.rs b/packages/core/examples/borrowed.rs new file mode 100644 index 000000000..71a4f2fb9 --- /dev/null +++ b/packages/core/examples/borrowed.rs @@ -0,0 +1,51 @@ +use dioxus::prelude::*; +use dioxus_core as dioxus; +use dioxus_core_macro::*; +use dioxus_html as dioxus_elements; + +fn main() {} + +fn App(cx: Scope<()>) -> Element { + cx.render(rsx!(div { + App2 { + p: "asd" + } + })) +} + +#[derive(Props)] +struct Borrowed<'a> { + p: &'a str, +} + +fn App2<'a>(cx: Scope<'a, Borrowed<'a>>) -> Element { + let g = eat2(&cx); + todo!() +} + +fn eat2(s: &ScopeState) {} + +fn eat(f: &str) {} + +fn bleat() { + let blah = String::from("asd"); + eat(&blah); +} + +// struct Lower {} + +// #[derive(Clone, Copy)] +// struct Upper {} +// impl std::ops::Deref for Upper { +// type Target = Lower; + +// fn deref(&self) -> &Self::Target { +// todo!() +// } +// } + +// fn mark(f: &Lower) {} +// fn bark() { +// let up = Upper {}; +// mark(&up); +// } diff --git a/packages/core/examples/handler_thru_props.rs b/packages/core/examples/handler_thru_props.rs index 368a58894..cb22bb9d7 100644 --- a/packages/core/examples/handler_thru_props.rs +++ b/packages/core/examples/handler_thru_props.rs @@ -9,7 +9,7 @@ fn main() { let _ = VirtualDom::new(App); } -fn App(cx: Context, _props: &()) -> Element { +fn App(cx: Scope<()>) -> Element { // cx.render(rsx!( div { @@ -18,11 +18,7 @@ fn App(cx: Context, _props: &()) -> Element { )) } -struct ChildProps<'a> { - click_handler: EventHandler<'a>, -} - -fn Child(cx: Context, _props: &()) -> Element { +fn Child(cx: Scope<()>) -> Element { // cx.render(rsx!( div { diff --git a/packages/core/examples/rows.rs b/packages/core/examples/rows.rs index 40ab0af7a..72761379a 100644 --- a/packages/core/examples/rows.rs +++ b/packages/core/examples/rows.rs @@ -50,7 +50,7 @@ struct RowProps { row_id: usize, label: Label, } -fn Row(cx: Context, props: &RowProps) -> Element { +fn Row(cx: Scope, props: &RowProps) -> Element { let [adj, col, noun] = props.label.0; cx.render(rsx! { tr { diff --git a/packages/core/examples/works.rs b/packages/core/examples/works.rs index 7e49da1ce..03800b97d 100644 --- a/packages/core/examples/works.rs +++ b/packages/core/examples/works.rs @@ -9,7 +9,7 @@ fn main() { let _ = VirtualDom::new(Parent); } -fn Parent(cx: Context, _props: &()) -> Element { +fn Parent(cx: Scope, _props: &()) -> Element { let value = cx.use_hook(|_| String::new(), |f| f); cx.render(rsx! { @@ -25,7 +25,7 @@ struct ChildProps<'a> { name: &'a str, } -fn Child(cx: Context, props: &ChildProps) -> Element { +fn Child(cx: Scope, props: &ChildProps) -> Element { cx.render(rsx! { div { h1 { "it's nested" } @@ -39,7 +39,7 @@ struct Grandchild<'a> { name: &'a str, } -fn Child2(cx: Context, props: &Grandchild) -> Element { +fn Child2(cx: Scope, props: &Grandchild) -> Element { cx.render(rsx! { div { "Hello {props.name}!" } }) diff --git a/packages/core/src/component.rs b/packages/core/src/component.rs index a0093da1d..554f05b36 100644 --- a/packages/core/src/component.rs +++ b/packages/core/src/component.rs @@ -5,17 +5,18 @@ //! 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::{Context, Element, LazyNodes, VPortal}; +use crate::innerlude::{Element, LazyNodes, Scope, VPortal}; -pub struct FragmentProps(Element); -pub struct FragmentBuilder(Element); -impl FragmentBuilder { - pub fn children(self, children: Option) -> FragmentBuilder { - FragmentBuilder(children) +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> { + todo!() + // FragmentBuilder(children) } } -impl FragmentBuilder { - pub fn build(self) -> FragmentProps { +impl<'a, const A: bool> FragmentBuilder<'a, A> { + pub fn build(self) -> FragmentProps<'a> { FragmentProps(self.0) } } @@ -60,8 +61,8 @@ impl FragmentBuilder { /// }) /// } /// ``` -impl Properties for FragmentProps { - type Builder = FragmentBuilder; +impl<'a> Properties for FragmentProps<'a> { + type Builder = FragmentBuilder<'a, false>; const IS_STATIC: bool = false; fn builder() -> Self::Builder { FragmentBuilder(None) @@ -97,8 +98,9 @@ impl Properties for FragmentProps { /// /// 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(cx: Context) -> Element { - cx.render(Some(LazyNodes::new(|f| f.fragment_from_iter(&cx.props.0)))) +pub fn Fragment<'a>(cx: Scope<'a, FragmentProps<'a>>) -> Element { + todo!() + // cx.render(Some(LazyNodes::new(|f| f.fragment_from_iter(&cx.props.0)))) } /// Every "Props" used for a component must implement the `Properties` trait. This trait gives some hints to Dioxus @@ -165,6 +167,6 @@ impl EmptyBuilder { /// 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(Context<'a, T>) -> Element) -> T::Builder { +pub fn fc_to_builder<'a, T: Properties + 'a>(_: fn(Scope<'a, T>) -> Element) -> T::Builder { T::builder() } diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index a738faeeb..596c1a8b6 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -1370,7 +1370,7 @@ impl<'bump> DiffState<'bump> { } /// Adds a listener closure to a scope during diff. - fn attach_listener_to_scope(&mut self, listener: &'bump Listener<'bump>, scope: &Scope) { + fn attach_listener_to_scope(&mut self, listener: &'bump Listener<'bump>, scope: &ScopeState) { let long_listener = unsafe { std::mem::transmute(listener) }; scope.items.borrow_mut().listeners.push(long_listener) } diff --git a/packages/core/src/lib.rs b/packages/core/src/lib.rs index ba8d71e6e..37a52411f 100644 --- a/packages/core/src/lib.rs +++ b/packages/core/src/lib.rs @@ -20,21 +20,21 @@ pub(crate) mod innerlude { pub(crate) use crate::scopearena::*; pub use crate::virtual_dom::*; - pub type Element = Option; - pub type Component

= for<'a> fn(Context<'a, P>) -> Element; + pub type Element<'a> = Option>; + pub type Component

= for<'a> fn(Scope<'a, P>) -> Element<'a>; } pub use crate::innerlude::{ - AnyContext, Attribute, Component, Context, DioxusElement, DomEdit, Element, ElementId, - EventHandler, EventPriority, IntoVNode, LazyNodes, Listener, Mutations, NodeFactory, - Properties, SchedulerMsg, Scope, ScopeId, UserEvent, VElement, VFragment, VNode, VirtualDom, + Attribute, Component, DioxusElement, DomEdit, Element, ElementId, EventHandler, EventPriority, + IntoVNode, LazyNodes, Listener, Mutations, NodeFactory, Properties, SchedulerMsg, Scope, + ScopeId, ScopeState, UserEvent, VElement, VFragment, VNode, VirtualDom, }; pub mod prelude { pub use crate::component::{fc_to_builder, Fragment, Properties}; - pub use crate::innerlude::Context; + pub use crate::innerlude::Scope; pub use crate::innerlude::{ - AnyContext, Component, DioxusElement, Element, EventHandler, LazyNodes, NodeFactory, Scope, + Component, DioxusElement, Element, EventHandler, LazyNodes, NodeFactory, ScopeState, }; pub use crate::nodes::VNode; pub use crate::VirtualDom; diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index 9693024d0..206fcb7c2 100644 --- a/packages/core/src/nodes.rs +++ b/packages/core/src/nodes.rs @@ -4,7 +4,7 @@ //! cheap and *very* fast to construct - building a full tree should be quick. use crate::{ - innerlude::{Context, Element, Properties, Scope, ScopeId}, + innerlude::{Element, Properties, Scope, ScopeId, ScopeState}, lazynodes::LazyNodes, }; use bumpalo::{boxed::Box as BumpBox, Bump}; @@ -412,7 +412,7 @@ pub struct VComponent<'src> { pub(crate) bump_props: *const (), // during the "teardown" process we'll take the caller out so it can be dropped properly - pub(crate) caller: &'src dyn Fn(&'src Scope) -> Element, + pub(crate) caller: &'src dyn Fn(&'src ScopeState) -> Element, pub(crate) comparator: Option<&'src dyn Fn(&VComponent) -> bool>, @@ -554,7 +554,7 @@ impl<'a> NodeFactory<'a> { pub fn component

( &self, - component: fn(Context<'a, P>) -> Element, + component: fn(Scope<'a, P>) -> Element, props: P, key: Option, ) -> VNode<'a> @@ -612,10 +612,10 @@ impl<'a> NodeFactory<'a> { let key = key.map(|f| self.raw_text(f).0); - let caller: &'a mut dyn Fn(&'a Scope) -> Element = - bump.alloc(move |scope: &Scope| -> Element { + let caller: &'a mut dyn Fn(&'a ScopeState) -> Element = + bump.alloc(move |scope: &ScopeState| -> Element { let props: &'_ P = unsafe { &*(bump_props as *const P) }; - component(Context { scope, props }) + component(Scope { scope, props }) }); let can_memoize = P::IS_STATIC; @@ -707,7 +707,7 @@ impl<'a> NodeFactory<'a> { pub fn create_children( self, node_iter: impl IntoIterator>, - ) -> Element { + ) -> Element<'a> { let bump = self.bump; let mut nodes = bumpalo::collections::Vec::new_in(bump); @@ -726,16 +726,10 @@ impl<'a> NodeFactory<'a> { // TODO // We need a dedicated path in the rsx! macro that will trigger the "you need keys" warning - let frag = VNode::Fragment(VFragment { + Some(VNode::Fragment(VFragment { children, key: None, - }); - let ptr = self.bump.alloc(frag) as *const _; - Some(VPortal { - link_idx: Default::default(), - scope_id: Default::default(), - node: unsafe { std::mem::transmute(ptr) }, - }) + })) } } diff --git a/packages/core/src/scope.rs b/packages/core/src/scope.rs index 36730a6b3..92e81341b 100644 --- a/packages/core/src/scope.rs +++ b/packages/core/src/scope.rs @@ -31,11 +31,39 @@ use bumpalo::{boxed::Box as BumpBox, Bump}; /// cx.render(rsx!{ div {"Hello, {props.name}"} }) /// } /// ``` -pub struct Context<'a, P: 'static> { - pub scope: &'a Scope, +pub struct Scope<'a, P> { + pub scope: &'a ScopeState, pub props: &'a P, } -impl

Clone for Context<'_, P> { + +impl<'a, P> Scope<'a, P> { + /// Take a lazy VNode structure and actually build it with the context of the VDom's efficient VNode allocator. + /// + /// This function consumes the context and absorb the lifetime, so these VNodes *must* be returned. + /// + /// ## Example + /// + /// ```ignore + /// fn Component(cx: Scope, props: &Props) -> Element { + /// // Lazy assemble the VNode tree + /// let lazy_nodes = rsx!("hello world"); + /// + /// // Actually build the tree and allocate it + /// cx.render(lazy_tree) + /// } + ///``` + pub fn render(self, rsx: Option>) -> Option> { + let fac = NodeFactory { + bump: &self.scope.wip_frame().bump, + }; + match rsx { + Some(s) => Some(s.call(fac)), + None => todo!(), + } + } +} + +impl

Clone for Scope<'_, P> { fn clone(&self) -> Self { Self { scope: self.scope, @@ -43,21 +71,13 @@ impl

Clone for Context<'_, P> { } } } -impl

Copy for Context<'_, P> {} -impl

std::ops::Deref for Context<'_, P> { - type Target = Scope; +impl

Copy for Scope<'_, P> {} +impl

std::ops::Deref for Scope<'_, P> { + type Target = ScopeState; fn deref(&self) -> &Self::Target { &self.scope } } -pub trait AnyContext<'a> { - fn get_scope(&self) -> &'a Scope; -} -impl<'a, P> AnyContext<'a> for Context<'a, P> { - fn get_scope(&self) -> &'a Scope { - &self.scope - } -} /// A component's unique identifier. /// @@ -76,8 +96,8 @@ pub struct ScopeId(pub usize); /// /// We expose the `Scope` type so downstream users can traverse the Dioxus VirtualDOM for whatever /// use case they might have. -pub struct Scope { - pub(crate) parent_scope: Option<*mut Scope>, +pub struct ScopeState { + pub(crate) parent_scope: Option<*mut ScopeState>, pub(crate) container: ElementId, @@ -93,7 +113,7 @@ pub struct Scope { pub(crate) frames: [BumpFrame; 2], - pub(crate) caller: *const dyn Fn(&Scope) -> Element, + pub(crate) caller: *const dyn Fn(&ScopeState) -> Element, pub(crate) items: RefCell>, @@ -113,7 +133,7 @@ pub struct SelfReferentialItems<'a> { } // Public methods exposed to libraries and components -impl Scope { +impl ScopeState { /// Get the subtree ID that this scope belongs to. /// /// Each component has its own subtree ID - the root subtree has an ID of 0. This ID is used by the renderer to route @@ -342,36 +362,31 @@ impl Scope { items.tasks.len() - 1 } - /// Take a lazy VNode structure and actually build it with the context of the VDom's efficient VNode allocator. - /// - /// This function consumes the context and absorb the lifetime, so these VNodes *must* be returned. - /// - /// ## Example - /// - /// ```ignore - /// fn Component(cx: Scope, props: &Props) -> Element { - /// // Lazy assemble the VNode tree - /// let lazy_nodes = rsx!("hello world"); - /// - /// // Actually build the tree and allocate it - /// cx.render(lazy_tree) - /// } - ///``` - pub fn render<'src>(&'src self, rsx: Option>) -> Option { - let bump = &self.wip_frame().bump; - - let owned_node: VNode<'src> = rsx.map(|f| f.call(NodeFactory { bump }))?; - let alloced_vnode: &'src mut VNode<'src> = bump.alloc(owned_node); - let node_ptr: *mut VNode<'src> = alloced_vnode as *mut _; - - let node: *mut VNode<'static> = unsafe { std::mem::transmute(node_ptr) }; - - Some(VPortal { - scope_id: Cell::new(Some(self.our_arena_idx)), - link_idx: Cell::new(0), - node, - }) - } + // /// Take a lazy VNode structure and actually build it with the context of the VDom's efficient VNode allocator. + // /// + // /// This function consumes the context and absorb the lifetime, so these VNodes *must* be returned. + // /// + // /// ## Example + // /// + // /// ```ignore + // /// fn Component(cx: Scope, props: &Props) -> Element { + // /// // Lazy assemble the VNode tree + // /// let lazy_nodes = rsx!("hello world"); + // /// + // /// // Actually build the tree and allocate it + // /// cx.render(lazy_tree) + // /// } + // ///``` + // pub fn render<'src>(&self, rsx: Option>) -> Option> { + // let fac = NodeFactory { + // bump: &self.wip_frame().bump, + // }; + // match rsx { + // Some(s) => Some(s.call(fac)), + // None => todo!(), + // } + // // rsx.map(|f| f.call(fac)) + // } /// Store a value between renders /// @@ -505,5 +520,5 @@ impl BumpFrame { #[test] fn sizeof() { - dbg!(std::mem::size_of::()); + dbg!(std::mem::size_of::()); } diff --git a/packages/core/src/scopearena.rs b/packages/core/src/scopearena.rs index 4f871e401..b2c4bd593 100644 --- a/packages/core/src/scopearena.rs +++ b/packages/core/src/scopearena.rs @@ -24,9 +24,9 @@ pub(crate) struct ScopeArena { bump: Bump, pub pending_futures: RefCell>, scope_counter: Cell, - pub scopes: RefCell>, + pub scopes: RefCell>, pub heuristics: RefCell>, - free_scopes: RefCell>, + free_scopes: RefCell>, nodes: RefCell>>, pub(crate) sender: UnboundedSender, } @@ -68,23 +68,23 @@ impl ScopeArena { /// Safety: /// - Obtaining a mutable refernece to any Scope is unsafe /// - Scopes use interior mutability when sharing data into components - pub(crate) fn get_scope(&self, id: &ScopeId) -> Option<&Scope> { + pub(crate) fn get_scope(&self, id: &ScopeId) -> Option<&ScopeState> { unsafe { self.scopes.borrow().get(id).map(|f| &**f) } } - pub(crate) unsafe fn get_scope_raw(&self, id: &ScopeId) -> Option<*mut Scope> { + pub(crate) unsafe fn get_scope_raw(&self, id: &ScopeId) -> Option<*mut ScopeState> { self.scopes.borrow().get(id).copied() } - pub(crate) unsafe fn get_scope_mut(&self, id: &ScopeId) -> Option<&mut Scope> { + pub(crate) unsafe fn get_scope_mut(&self, id: &ScopeId) -> Option<&mut ScopeState> { self.scopes.borrow().get(id).map(|s| &mut **s) } pub(crate) fn new_with_key( &self, fc_ptr: *const (), - caller: *const dyn Fn(&Scope) -> Element, - parent_scope: Option<*mut Scope>, + caller: *const dyn Fn(&ScopeState) -> Element, + parent_scope: Option<*mut ScopeState>, container: ElementId, height: u32, subtree: u32, @@ -160,7 +160,7 @@ impl ScopeArena { unsafe { std::mem::transmute(vnode as *mut VNode) } }); - let scope = self.bump.alloc(Scope { + let scope = self.bump.alloc(ScopeState { sender: self.sender.clone(), container, our_arena_idx: new_scope_id, @@ -330,18 +330,9 @@ impl ScopeArena { scope.wip_frame().nodes.borrow_mut().clear(); } - let render: &dyn Fn(&Scope) -> Element = unsafe { &*scope.caller }; + let render: &dyn Fn(&ScopeState) -> Element = unsafe { &*scope.caller }; if let Some(link) = render(scope) { - // right now, it's a panic to render a nodelink from another scope - // todo: enable this. it should (reasonably) work even if it doesnt make much sense - assert_eq!(link.scope_id.get(), Some(*id)); - - // nodelinks are not assigned when called and must be done so through the create/diff phase - // however, we need to link this one up since it will never be used in diffing - scope.wip_frame().assign_nodelink(&link); - debug_assert_eq!(scope.wip_frame().nodes.borrow().len(), 1); - if !scope.items.borrow().tasks.is_empty() { self.pending_futures.borrow_mut().insert(*id); } diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 665bf0e9e..dad8693cb 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -196,13 +196,18 @@ impl VirtualDom { ) -> Self { let scopes = ScopeArena::new(sender.clone()); - let mut caller = Box::new(move |scp: &Scope| -> Element { - root(Context { - scope: scp, - props: &root_props, - }) - }); - let caller_ref: *mut dyn Fn(&Scope) -> Element = caller.as_mut() as *mut _; + let root_props = Box::new(root_props); + let props_ref: *const P = root_props.as_ref(); + let mut caller: Box Element> = + Box::new(move |scp: &ScopeState| -> Element { + let p = unsafe { &*props_ref }; + todo!() + // root(Context { + // scope: scp, + // props: p, + // }) + }); + let caller_ref: *mut dyn Fn(&ScopeState) -> Element = caller.as_mut(); let base_scope = scopes.new_with_key(root as _, caller_ref, None, ElementId(0), 0, 0); let pending_messages = VecDeque::new(); @@ -213,7 +218,7 @@ impl VirtualDom { scopes: Box::new(scopes), base_scope, receiver, - _root_props: caller, + _root_props: root_props, pending_messages, dirty_scopes, sender, @@ -226,7 +231,7 @@ impl VirtualDom { /// directly. /// /// # Example - pub fn base_scope(&self) -> &Scope { + pub fn base_scope(&self) -> &ScopeState { self.get_scope(&self.base_scope).unwrap() } @@ -236,7 +241,7 @@ impl VirtualDom { /// /// /// - pub fn get_scope<'a>(&'a self, id: &ScopeId) -> Option<&'a Scope> { + pub fn get_scope<'a>(&'a self, id: &ScopeId) -> Option<&'a ScopeState> { self.scopes.get_scope(id) } diff --git a/packages/core/tests/borrowedstate.rs b/packages/core/tests/borrowedstate.rs index fbfcf5096..c9eda3017 100644 --- a/packages/core/tests/borrowedstate.rs +++ b/packages/core/tests/borrowedstate.rs @@ -10,7 +10,7 @@ fn test_borrowed_state() { let _ = VirtualDom::new(Parent); } -fn Parent(cx: Context, _props: &()) -> Element { +fn Parent(cx: Scope, _props: &()) -> Element { let value = cx.use_hook(|_| String::new(), |f| &*f); cx.render(rsx! { @@ -28,7 +28,7 @@ struct ChildProps<'a> { name: &'a str, } -fn Child(cx: Context, props: &ChildProps) -> Element { +fn Child(cx: Scope, props: &ChildProps) -> Element { cx.render(rsx! { div { h1 { "it's nested" } @@ -42,7 +42,7 @@ struct Grandchild<'a> { name: &'a str, } -fn Child2(cx: Context, props: &Grandchild) -> Element { +fn Child2(cx: Scope, props: &Grandchild) -> Element { cx.render(rsx! { div { "Hello {props.name}!" } }) diff --git a/packages/core/tests/create_dom.rs b/packages/core/tests/create_dom.rs index f6e1d57e6..82eb1ee07 100644 --- a/packages/core/tests/create_dom.rs +++ b/packages/core/tests/create_dom.rs @@ -220,7 +220,7 @@ fn create_components() { children: Element, } - fn Child(cx: Context, props: &ChildProps) -> Element { + fn Child(cx: Scope, props: &ChildProps) -> Element { cx.render(rsx! { h1 {} div { {&props.children} } diff --git a/packages/hooks/src/use_shared_state.rs b/packages/hooks/src/use_shared_state.rs index df4549ed2..c051bdb92 100644 --- a/packages/hooks/src/use_shared_state.rs +++ b/packages/hooks/src/use_shared_state.rs @@ -1,4 +1,4 @@ -use dioxus_core::{AnyContext, Scope, ScopeId}; +use dioxus_core::{ScopeId, ScopeState}; use std::{ cell::{Cell, Ref, RefCell, RefMut}, collections::HashSet, @@ -59,8 +59,7 @@ impl ProvidedStateInner { /// /// /// -pub fn use_shared_state<'a, T: 'static>(cx: &dyn AnyContext<'a>) -> Option> { - let cx = cx.get_scope(); +pub fn use_shared_state<'a, T: 'static>(cx: &'a ScopeState) -> Option> { cx.use_hook( |_| { let scope_id = cx.scope_id(); @@ -111,7 +110,7 @@ impl Drop for SharedStateInner { } pub struct UseSharedState<'a, T: 'static> { - pub(crate) cx: &'a Scope, + pub(crate) cx: &'a ScopeState, pub(crate) value: &'a Rc>, pub(crate) root: &'a Rc>>, pub(crate) needs_notification: &'a Cell, @@ -176,8 +175,7 @@ where /// /// /// -pub fn use_provide_state<'a, T: 'static>(cx: &dyn AnyContext<'a>, f: impl FnOnce() -> T) { - let cx = cx.get_scope(); +pub fn use_provide_state<'a, T: 'static>(cx: &'a ScopeState, f: impl FnOnce() -> T) { cx.use_hook( |_| { let state: ProvidedState = RefCell::new(ProvidedStateInner { diff --git a/packages/hooks/src/usecoroutine.rs b/packages/hooks/src/usecoroutine.rs index f6cfc2cee..f04fb4f12 100644 --- a/packages/hooks/src/usecoroutine.rs +++ b/packages/hooks/src/usecoroutine.rs @@ -1,4 +1,4 @@ -use dioxus_core::{AnyContext, Scope}; +use dioxus_core::ScopeState; use futures::Future; use std::{ cell::{Cell, RefCell}, @@ -7,10 +7,9 @@ use std::{ }; pub fn use_coroutine<'a, F: Future + 'static>( - cx: &dyn AnyContext<'a>, + cx: &'a ScopeState, mut f: impl FnMut() -> F + 'a, ) -> CoroutineHandle<'a> { - let cx = cx.get_scope(); cx.use_hook( move |_| State { running: Default::default(), @@ -56,7 +55,7 @@ struct State { } pub struct CoroutineHandle<'a> { - cx: &'a Scope, + cx: &'a ScopeState, inner: &'a State, } impl Clone for CoroutineHandle<'_> { diff --git a/packages/hooks/src/usemodel.rs b/packages/hooks/src/usemodel.rs index b84bf3eb1..47981af0f 100644 --- a/packages/hooks/src/usemodel.rs +++ b/packages/hooks/src/usemodel.rs @@ -4,7 +4,7 @@ //! //! In these cases, we provide `use_model` - a convenient way of abstracting over some state and async functions. -use dioxus_core::prelude::AnyContext; +use dioxus_core::prelude::ScopeState; use futures::Future; use std::{ cell::{Cell, Ref, RefCell, RefMut}, @@ -13,11 +13,7 @@ use std::{ rc::Rc, }; -pub fn use_model<'a, T: 'static>( - cx: &dyn AnyContext<'a>, - f: impl FnOnce() -> T, -) -> UseModel<'a, T> { - let cx = cx.get_scope(); +pub fn use_model<'a, T: 'static>(cx: &'a ScopeState, f: impl FnOnce() -> T) -> UseModel<'a, T> { cx.use_hook( |_| UseModelInner { update_scheduled: Cell::new(false), @@ -81,11 +77,10 @@ impl<'a, T: 'static> UseModel<'a, T> { // keep a coroutine going pub fn use_model_coroutine<'a, T, F: Future + 'static>( - cx: &dyn AnyContext<'a>, + cx: &'a ScopeState, _model: UseModel, _f: impl FnOnce(AppModels) -> F, ) -> UseModelCoroutine { - let cx = cx.get_scope(); cx.use_hook( |_| { // diff --git a/packages/hooks/src/useref.rs b/packages/hooks/src/useref.rs index 243508660..f80572293 100644 --- a/packages/hooks/src/useref.rs +++ b/packages/hooks/src/useref.rs @@ -3,10 +3,9 @@ use std::{ rc::Rc, }; -use dioxus_core::AnyContext; +use dioxus_core::ScopeState; -pub fn use_ref<'a, T: 'static>(cx: &dyn AnyContext<'a>, f: impl FnOnce() -> T) -> UseRef<'a, T> { - let cx = cx.get_scope(); +pub fn use_ref<'a, T: 'static>(cx: &'a ScopeState, f: impl FnOnce() -> T) -> UseRef<'a, T> { cx.use_hook( |_| UseRefInner { update_scheduled: Cell::new(false), diff --git a/packages/hooks/src/usestate.rs b/packages/hooks/src/usestate.rs index 1629cdb60..97624f3d7 100644 --- a/packages/hooks/src/usestate.rs +++ b/packages/hooks/src/usestate.rs @@ -50,10 +50,9 @@ use std::{ /// } /// ``` pub fn use_state<'a, T: 'static>( - cx: &dyn AnyContext<'a>, + cx: &'a ScopeState, initial_state_fn: impl FnOnce() -> T, ) -> UseState<'a, T> { - let cx = cx.get_scope(); cx.use_hook( move |_| { let first_val = initial_state_fn(); diff --git a/packages/router/src/lib.rs b/packages/router/src/lib.rs index 54411239e..62c14eb9a 100644 --- a/packages/router/src/lib.rs +++ b/packages/router/src/lib.rs @@ -66,7 +66,7 @@ impl RouterService { /// This hould only be used once per app /// /// You can manually parse the route if you want, but the derived `parse` method on `Routable` will also work just fine -pub fn use_router(cx: Context, mut parse: impl FnMut(&str) -> R + 'static) -> &R { +pub fn use_router(cx: Scope, mut parse: impl FnMut(&str) -> R + 'static) -> &R { // for the web, attach to the history api cx.use_hook( |f| { @@ -133,7 +133,7 @@ pub fn use_router(cx: Context, mut parse: impl FnMut(&str) -> R + ' ) } -pub fn use_router_service(cx: Context) -> Option<&Rc>> { +pub fn use_router_service(cx: Scope) -> Option<&Rc>> { cx.use_hook(|_| cx.consume_state::>(), |f| f.as_ref()) } @@ -160,7 +160,7 @@ pub struct LinkProps { children: Element, } -pub fn Link(cx: Context, props: &LinkProps) -> Element { +pub fn Link(cx: Scope, props: &LinkProps) -> Element { let service = use_router_service::(cx)?; cx.render(rsx! { a { diff --git a/packages/web/examples/js_bench.rs b/packages/web/examples/js_bench.rs index eeb7dc622..e81b1f04b 100644 --- a/packages/web/examples/js_bench.rs +++ b/packages/web/examples/js_bench.rs @@ -175,7 +175,7 @@ struct ActionButtonProps<'a> { onclick: &'a dyn Fn(), } -fn ActionButton(cx: Context, props: &ActionButtonProps) -> Element { +fn ActionButton(cx: Scope, props: &ActionButtonProps) -> Element { rsx!(cx, div { class: "col-sm-6 smallpad" button { class:"btn btn-primary btn-block", r#type: "button", id: "{props.id}", onclick: move |_| (props.onclick)(), "{props.name}"