Kaynağa Gözat

wip: go back to noisy lifetime solution

Jonathan Kelley 3 yıl önce
ebeveyn
işleme
8daf7a6

+ 4 - 4
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<String> = 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}"}
     })

+ 1 - 1
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}

+ 1 - 1
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" }

+ 1 - 1
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}"

+ 1 - 1
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!" }
     ))

+ 1 - 1
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}"

+ 3 - 3
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<BallerProps>) -> Element {
+    pub fn Baller(_: ScopeState<BallerProps>) -> 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!()
 }

+ 1 - 1
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
 }

+ 1 - 1
examples/todomvc.rs

@@ -85,7 +85,7 @@ pub struct TodoEntryProps {
     todo: Rc<TodoItem>,
 }
 
-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;

+ 1 - 1
examples/web_tick.rs

@@ -45,7 +45,7 @@ struct RowProps {
     row_id: usize,
     label: Label,
 }
-fn Row((cx, props): Scope<RowProps>) -> Element {
+fn Row((cx, props): ScopeState<RowProps>) -> Element {
     let [adj, col, noun] = props.label.0;
     cx.render(rsx! {
         tr {

+ 1 - 1
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 {

+ 51 - 0
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);
+// }

+ 2 - 6
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 {

+ 1 - 1
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 {

+ 3 - 3
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}!" }
     })

+ 15 - 13
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<const BUILT: bool>(Element);
-impl FragmentBuilder<false> {
-    pub fn children(self, children: Option<VPortal>) -> FragmentBuilder<true> {
-        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<const A: bool> FragmentBuilder<A> {
-    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<const A: bool> FragmentBuilder<A> {
 ///     })
 /// }
 /// ```
-impl Properties for FragmentProps {
-    type Builder = FragmentBuilder<false>;
+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<FragmentProps>) -> 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()
 }

+ 1 - 1
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)
     }

+ 7 - 7
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<VPortal>;
-    pub type Component<P> = for<'a> fn(Context<'a, P>) -> Element;
+    pub type Element<'a> = Option<VNode<'a>>;
+    pub type Component<P> = 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;

+ 9 - 15
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<P>(
         &self,
-        component: fn(Context<'a, P>) -> Element,
+        component: fn(Scope<'a, P>) -> Element,
         props: P,
         key: Option<Arguments>,
     ) -> 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<Item = impl IntoVNode<'a>>,
-    ) -> 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) },
-        })
+        }))
     }
 }
 

+ 64 - 49
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<P> 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<LazyNodes<'a, '_>>) -> Option<VNode<'a>> {
+        let fac = NodeFactory {
+            bump: &self.scope.wip_frame().bump,
+        };
+        match rsx {
+            Some(s) => Some(s.call(fac)),
+            None => todo!(),
+        }
+    }
+}
+
+impl<P> Clone for Scope<'_, P> {
     fn clone(&self) -> Self {
         Self {
             scope: self.scope,
@@ -43,21 +71,13 @@ impl<P> Clone for Context<'_, P> {
         }
     }
 }
-impl<P> Copy for Context<'_, P> {}
-impl<P> std::ops::Deref for Context<'_, P> {
-    type Target = Scope;
+impl<P> Copy for Scope<'_, P> {}
+impl<P> 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<SelfReferentialItems<'static>>,
 
@@ -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<LazyNodes<'src, '_>>) -> Option<VPortal> {
-        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<LazyNodes<'src, '_>>) -> Option<VNode<'src>> {
+    //     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::<Scope>());
+    dbg!(std::mem::size_of::<ScopeState>());
 }

+ 9 - 18
packages/core/src/scopearena.rs

@@ -24,9 +24,9 @@ pub(crate) struct ScopeArena {
     bump: Bump,
     pub pending_futures: RefCell<FxHashSet<ScopeId>>,
     scope_counter: Cell<usize>,
-    pub scopes: RefCell<FxHashMap<ScopeId, *mut Scope>>,
+    pub scopes: RefCell<FxHashMap<ScopeId, *mut ScopeState>>,
     pub heuristics: RefCell<FxHashMap<FcSlot, Heuristic>>,
-    free_scopes: RefCell<Vec<*mut Scope>>,
+    free_scopes: RefCell<Vec<*mut ScopeState>>,
     nodes: RefCell<Slab<*const VNode<'static>>>,
     pub(crate) sender: UnboundedSender<SchedulerMsg>,
 }
@@ -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);
             }

+ 15 - 10
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<dyn Fn(&ScopeState) -> 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)
     }
 

+ 3 - 3
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}!" }
     })

+ 1 - 1
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} }

+ 4 - 6
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<T> ProvidedStateInner<T> {
 ///
 ///
 ///
-pub fn use_shared_state<'a, T: 'static>(cx: &dyn AnyContext<'a>) -> Option<UseSharedState<'a, T>> {
-    let cx = cx.get_scope();
+pub fn use_shared_state<'a, T: 'static>(cx: &'a ScopeState) -> Option<UseSharedState<'a, T>> {
     cx.use_hook(
         |_| {
             let scope_id = cx.scope_id();
@@ -111,7 +110,7 @@ impl<T> Drop for SharedStateInner<T> {
 }
 
 pub struct UseSharedState<'a, T: 'static> {
-    pub(crate) cx: &'a Scope,
+    pub(crate) cx: &'a ScopeState,
     pub(crate) value: &'a Rc<RefCell<T>>,
     pub(crate) root: &'a Rc<RefCell<ProvidedStateInner<T>>>,
     pub(crate) needs_notification: &'a Cell<bool>,
@@ -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<T> = RefCell::new(ProvidedStateInner {

+ 3 - 4
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<Output = ()> + '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<'_> {

+ 3 - 8
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<Output = ()> + 'static>(
-    cx: &dyn AnyContext<'a>,
+    cx: &'a ScopeState,
     _model: UseModel<T>,
     _f: impl FnOnce(AppModels) -> F,
 ) -> UseModelCoroutine {
-    let cx = cx.get_scope();
     cx.use_hook(
         |_| {
             //

+ 2 - 3
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),

+ 1 - 2
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();

+ 3 - 3
packages/router/src/lib.rs

@@ -66,7 +66,7 @@ impl<R: Routable> RouterService<R> {
 /// 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<R: Routable>(cx: Context, mut parse: impl FnMut(&str) -> R + 'static) -> &R {
+pub fn use_router<R: Routable>(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<R: Routable>(cx: Context, mut parse: impl FnMut(&str) -> R + '
     )
 }
 
-pub fn use_router_service<R: Routable>(cx: Context) -> Option<&Rc<RouterService<R>>> {
+pub fn use_router_service<R: Routable>(cx: Scope) -> Option<&Rc<RouterService<R>>> {
     cx.use_hook(|_| cx.consume_state::<RouterService<R>>(), |f| f.as_ref())
 }
 
@@ -160,7 +160,7 @@ pub struct LinkProps<R: Routable> {
     children: Element,
 }
 
-pub fn Link<R: Routable>(cx: Context, props: &LinkProps<R>) -> Element {
+pub fn Link<R: Routable>(cx: Scope, props: &LinkProps<R>) -> Element {
     let service = use_router_service::<R>(cx)?;
     cx.render(rsx! {
         a {

+ 1 - 1
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}"