wip: remove scopechildren in favor of elements directly
This commit is contained in:
1 parent
b9fc5fc251
commit
574d7fdb9e
6 files changed
+153
-192
No files matched your search
@@ -5,40 +5,67 @@
|
|||||||
//! if the type supports PartialEq. The Properties trait is used by the rsx! and html! macros to generate the type-safe builder
|
//! 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.
|
//! that ensures compile-time required and optional fields on cx.
|
||||||
|
|
||||||
use crate::innerlude::{Context, Element, LazyNodes, ScopeChildren};
|
use crate::innerlude::{Context, Element, LazyNodes, NodeLink};
|
||||||
|
|
||||||
pub struct FragmentProps<'a> {
|
pub struct FragmentProps(Element);
|
||||||
children: ScopeChildren<'a>,
|
pub struct FragmentBuilder<const BUILT: bool>(Element);
|
||||||
|
impl FragmentBuilder<false> {
|
||||||
|
pub fn children(self, children: Option<NodeLink>) -> FragmentBuilder<true> {
|
||||||
|
FragmentBuilder(children)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
impl<const A: bool> FragmentBuilder<A> {
|
||||||
pub struct FragmentBuilder<'a, const BUILT: bool> {
|
pub fn build(self) -> FragmentProps {
|
||||||
children: Option<ScopeChildren<'a>>,
|
FragmentProps(self.0)
|
||||||
}
|
|
||||||
impl<'a> FragmentBuilder<'a, false> {
|
|
||||||
pub fn children(self, children: ScopeChildren<'a>) -> FragmentBuilder<'a, true> {
|
|
||||||
FragmentBuilder {
|
|
||||||
children: Some(children),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, const A: bool> FragmentBuilder<'a, A> {
|
/// Access the children elements passed into the component
|
||||||
pub fn build(self) -> FragmentProps<'a> {
|
///
|
||||||
FragmentProps {
|
/// This enables patterns where a component is passed children from its parent.
|
||||||
children: self.children.unwrap_or_default(),
|
///
|
||||||
}
|
/// ## 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
|
||||||
impl<'a> Properties for FragmentProps<'a> {
|
/// on the props that takes Context.
|
||||||
type Builder = FragmentBuilder<'a, false>;
|
///
|
||||||
|
/// 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
|
||||||
|
/// fn App(cx: Context, props: &()) -> Element {
|
||||||
|
/// cx.render(rsx!{
|
||||||
|
/// CustomCard {
|
||||||
|
/// h1 {}
|
||||||
|
/// p {}
|
||||||
|
/// }
|
||||||
|
/// })
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// #[derive(PartialEq, Props)]
|
||||||
|
/// struct CardProps {
|
||||||
|
/// children: Element
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn CustomCard(cx: Context, props: &CardProps) -> Element {
|
||||||
|
/// cx.render(rsx!{
|
||||||
|
/// div {
|
||||||
|
/// h1 {"Title card"}
|
||||||
|
/// {props.children}
|
||||||
|
/// }
|
||||||
|
/// })
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
impl Properties for FragmentProps {
|
||||||
|
type Builder = FragmentBuilder<false>;
|
||||||
const IS_STATIC: bool = false;
|
const IS_STATIC: bool = false;
|
||||||
|
|
||||||
fn builder() -> Self::Builder {
|
fn builder() -> Self::Builder {
|
||||||
FragmentBuilder { children: None }
|
FragmentBuilder(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn memoize(&self, _other: &Self) -> bool {
|
unsafe fn memoize(&self, _other: &Self) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@@ -46,9 +73,14 @@ impl<'a> Properties for FragmentProps<'a> {
|
|||||||
|
|
||||||
/// Create inline fragments using Component syntax.
|
/// Create inline fragments using Component syntax.
|
||||||
///
|
///
|
||||||
|
/// ## Details
|
||||||
|
///
|
||||||
/// Fragments capture a series of children without rendering extra nodes.
|
/// Fragments capture a series of children without rendering extra nodes.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// 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
|
/// ```rust
|
||||||
/// rsx!{
|
/// rsx!{
|
||||||
@@ -56,20 +88,17 @@ impl<'a> Properties for FragmentProps<'a> {
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// # Details
|
/// ## Usage
|
||||||
///
|
///
|
||||||
/// Fragments are incredibly useful when necessary, but *do* add cost in the diffing phase.
|
/// Fragments are incredibly useful when necessary, but *do* add cost in the diffing phase.
|
||||||
/// Try to avoid nesting fragments if you can. There is no protection against infinitely nested fragments.
|
/// 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.
|
/// 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.
|
/// 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)]
|
#[allow(non_upper_case_globals, non_snake_case)]
|
||||||
pub fn Fragment<'a>(cx: Context<'a>, props: &'a FragmentProps<'a>) -> Element {
|
pub fn Fragment(cx: Context, props: &FragmentProps) -> Element {
|
||||||
cx.render(Some(LazyNodes::new(|f| {
|
cx.render(Some(LazyNodes::new(|f| f.fragment_from_iter(&props.0))))
|
||||||
f.fragment_from_iter(&props.children)
|
|
||||||
})))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Every "Props" used for a component must implement the `Properties` trait. This trait gives some hints to Dioxus
|
/// Every "Props" used for a component must implement the `Properties` trait. This trait gives some hints to Dioxus
|
||||||
@@ -131,7 +160,6 @@ impl Properties for () {
|
|||||||
// that the macros use to anonymously complete prop construction.
|
// that the macros use to anonymously complete prop construction.
|
||||||
pub struct EmptyBuilder;
|
pub struct EmptyBuilder;
|
||||||
impl EmptyBuilder {
|
impl EmptyBuilder {
|
||||||
#[inline]
|
|
||||||
pub fn build(self) {}
|
pub fn build(self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -442,7 +442,7 @@ impl<'bump> DiffState<'bump> {
|
|||||||
let height = parent_scope.height + 1;
|
let height = parent_scope.height + 1;
|
||||||
let subtree = parent_scope.subtree.get();
|
let subtree = parent_scope.subtree.get();
|
||||||
|
|
||||||
let parent_scope = unsafe { self.scopes.get_scope_mut(&parent_idx) };
|
let parent_scope = unsafe { self.scopes.get_scope_raw(&parent_idx) };
|
||||||
let caller = unsafe { std::mem::transmute(vcomponent.caller as *const _) };
|
let caller = unsafe { std::mem::transmute(vcomponent.caller as *const _) };
|
||||||
let fc_ptr = vcomponent.user_fc;
|
let fc_ptr = vcomponent.user_fc;
|
||||||
|
|
||||||
|
|||||||
@@ -37,17 +37,14 @@ pub(crate) mod innerlude {
|
|||||||
|
|
||||||
pub use crate::innerlude::{
|
pub use crate::innerlude::{
|
||||||
Attribute, Context, DioxusElement, DomEdit, Element, ElementId, EventPriority, IntoVNode,
|
Attribute, Context, DioxusElement, DomEdit, Element, ElementId, EventPriority, IntoVNode,
|
||||||
LazyNodes, Listener, MountType, Mutations, NodeFactory, Properties, SchedulerMsg,
|
LazyNodes, Listener, MountType, Mutations, NodeFactory, Properties, SchedulerMsg, ScopeId,
|
||||||
ScopeChildren, ScopeId, UserEvent, VAnchor, VElement, VFragment, VNode, VSuspended, VirtualDom,
|
UserEvent, VAnchor, VElement, VFragment, VNode, VSuspended, VirtualDom, FC,
|
||||||
FC,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::component::{fc_to_builder, Fragment, Properties};
|
pub use crate::component::{fc_to_builder, Fragment, Properties};
|
||||||
pub use crate::innerlude::Context;
|
pub use crate::innerlude::Context;
|
||||||
pub use crate::innerlude::{
|
pub use crate::innerlude::{DioxusElement, Element, LazyNodes, NodeFactory, Scope, FC};
|
||||||
DioxusElement, Element, LazyNodes, NodeFactory, Scope, ScopeChildren, FC,
|
|
||||||
};
|
|
||||||
pub use crate::nodes::VNode;
|
pub use crate::nodes::VNode;
|
||||||
pub use crate::VirtualDom;
|
pub use crate::VirtualDom;
|
||||||
}
|
}
|
||||||
|
|||||||
+62
-126
@@ -14,26 +14,11 @@ use std::{
|
|||||||
fmt::{Arguments, Debug, Formatter},
|
fmt::{Arguments, Debug, Formatter},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A cached node is a "pointer" to a "rendered" node in a particular scope
|
|
||||||
///
|
|
||||||
/// It does not provide direct access to the node, so it doesn't carry any lifetime information with it
|
|
||||||
///
|
|
||||||
/// It is used during the diffing/rendering process as a runtime key into an existing set of nodes. The "render" key
|
|
||||||
/// is essentially a unique key to guarantee safe usage of the Node.
|
|
||||||
///
|
|
||||||
/// todo: remove "clone"
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct NodeLink {
|
|
||||||
pub(crate) link_idx: usize,
|
|
||||||
pub(crate) gen_id: u32,
|
|
||||||
pub(crate) scope_id: ScopeId,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A composable "VirtualNode" to declare a User Interface in the Dioxus VirtualDOM.
|
/// A composable "VirtualNode" to declare a User Interface in the Dioxus VirtualDOM.
|
||||||
///
|
///
|
||||||
/// VNodes are designed to be lightweight and used with with a bump allocator. To create a VNode, you can use either of:
|
/// VNodes are designed to be lightweight and used with with a bump allocator. To create a VNode, you can use either of:
|
||||||
|
///
|
||||||
/// - the [`rsx`] macro
|
/// - the [`rsx`] macro
|
||||||
/// - the [`html`] macro
|
|
||||||
/// - the [`NodeFactory`] API
|
/// - the [`NodeFactory`] API
|
||||||
pub enum VNode<'src> {
|
pub enum VNode<'src> {
|
||||||
/// Text VNodes simply bump-allocated (or static) string slices
|
/// Text VNodes simply bump-allocated (or static) string slices
|
||||||
@@ -41,7 +26,8 @@ pub enum VNode<'src> {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let node = cx.render(rsx!{ "hello" }).unwrap();
|
/// let mut vdom = VirtualDom::new();
|
||||||
|
/// let node = vdom.render_vnode(rsx!( "hello" ));
|
||||||
///
|
///
|
||||||
/// if let VNode::Text(vtext) = node {
|
/// if let VNode::Text(vtext) = node {
|
||||||
/// assert_eq!(vtext.text, "hello");
|
/// assert_eq!(vtext.text, "hello");
|
||||||
@@ -56,7 +42,9 @@ pub enum VNode<'src> {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// let node = cx.render(rsx!{
|
/// let mut vdom = VirtualDom::new();
|
||||||
|
///
|
||||||
|
/// let node = vdom.render_vnode(rsx!{
|
||||||
/// div {
|
/// div {
|
||||||
/// key: "a",
|
/// key: "a",
|
||||||
/// onclick: |e| log::info!("clicked"),
|
/// onclick: |e| log::info!("clicked"),
|
||||||
@@ -64,7 +52,8 @@ pub enum VNode<'src> {
|
|||||||
/// style: { background_color: "red" }
|
/// style: { background_color: "red" }
|
||||||
/// "hello"
|
/// "hello"
|
||||||
/// }
|
/// }
|
||||||
/// }).unwrap();
|
/// });
|
||||||
|
///
|
||||||
/// if let VNode::Element(velement) = node {
|
/// if let VNode::Element(velement) = node {
|
||||||
/// assert_eq!(velement.tag_name, "div");
|
/// assert_eq!(velement.tag_name, "div");
|
||||||
/// assert_eq!(velement.namespace, None);
|
/// assert_eq!(velement.namespace, None);
|
||||||
@@ -93,13 +82,13 @@ pub enum VNode<'src> {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// fn Example(cx: Context<()>) -> DomTree {
|
/// fn Example(cx: Context, props: &()) -> Element {
|
||||||
/// todo!()
|
/// todo!()
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let node = cx.render(rsx!{
|
/// let mut vdom = VirtualDom::new();
|
||||||
/// Example {}
|
///
|
||||||
/// }).unwrap();
|
/// let node = vdom.render_vnode(rsx!( Example {} ));
|
||||||
///
|
///
|
||||||
/// if let VNode::Component(vcomp) = node {
|
/// if let VNode::Component(vcomp) = node {
|
||||||
/// assert_eq!(vcomp.user_fc, Example as *const ());
|
/// assert_eq!(vcomp.user_fc, Example as *const ());
|
||||||
@@ -109,13 +98,11 @@ pub enum VNode<'src> {
|
|||||||
|
|
||||||
/// Suspended VNodes represent chunks of the UI tree that are not yet ready to be displayed.
|
/// Suspended VNodes represent chunks of the UI tree that are not yet ready to be displayed.
|
||||||
///
|
///
|
||||||
/// These nodes currently can only be constructed via the [`use_suspense`] hook.
|
|
||||||
///
|
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// rsx!{
|
///
|
||||||
/// }
|
///
|
||||||
/// ```
|
/// ```
|
||||||
Suspended(&'src VSuspended<'src>),
|
Suspended(&'src VSuspended<'src>),
|
||||||
|
|
||||||
@@ -126,7 +113,10 @@ pub enum VNode<'src> {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// let node = cx.render(rsx! ( Fragment {} )).unwrap();
|
/// let mut vdom = VirtualDom::new();
|
||||||
|
///
|
||||||
|
/// let node = vdom.render_vnode(rsx!( Fragment {} ));
|
||||||
|
///
|
||||||
/// if let VNode::Fragment(frag) = node {
|
/// if let VNode::Fragment(frag) = node {
|
||||||
/// let root = &frag.children[0];
|
/// let root = &frag.children[0];
|
||||||
/// assert_eq!(root, VNode::Anchor);
|
/// assert_eq!(root, VNode::Anchor);
|
||||||
@@ -134,11 +124,20 @@ pub enum VNode<'src> {
|
|||||||
/// ```
|
/// ```
|
||||||
Anchor(&'src VAnchor),
|
Anchor(&'src VAnchor),
|
||||||
|
|
||||||
/// A type of node that links this node to another scope or render cycle
|
/// A VNode that is actually a pointer to some nodes rather than the nodes directly. Useful when rendering portals
|
||||||
|
/// or eliding lifetimes on VNodes through runtime checks.
|
||||||
///
|
///
|
||||||
/// Is essentially a "pointer" to a "rendered" node in a particular scope
|
/// Linked VNodes can only be made through the [`Context::render`] method
|
||||||
///
|
///
|
||||||
/// Used in portals
|
/// Typically, linked nodes are found *not* in a VNode. When NodeLinks are in a VNode, the NodeLink was passed into
|
||||||
|
/// an `rsx!` call.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```rust
|
||||||
|
/// let mut vdom = VirtualDom::new();
|
||||||
|
///
|
||||||
|
/// let node: NodeLink = vdom.render_vnode(rsx!( "hello" ));
|
||||||
|
/// ```
|
||||||
Linked(NodeLink),
|
Linked(NodeLink),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +272,6 @@ pub struct VText<'src> {
|
|||||||
/// A list of VNodes with no single root.
|
/// A list of VNodes with no single root.
|
||||||
pub struct VFragment<'src> {
|
pub struct VFragment<'src> {
|
||||||
pub key: Option<&'src str>,
|
pub key: Option<&'src str>,
|
||||||
|
|
||||||
pub children: &'src [VNode<'src>],
|
pub children: &'src [VNode<'src>],
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,6 +406,24 @@ pub struct VSuspended<'a> {
|
|||||||
pub callback: RefCell<Option<BumpBox<'a, dyn FnMut() -> Element + 'a>>>,
|
pub callback: RefCell<Option<BumpBox<'a, dyn FnMut() -> Element + 'a>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A cached node is a "pointer" to a "rendered" node in a particular scope
|
||||||
|
///
|
||||||
|
/// It does not provide direct access to the node, so it doesn't carry any lifetime information with it
|
||||||
|
///
|
||||||
|
/// It is used during the diffing/rendering process as a runtime key into an existing set of nodes. The "render" key
|
||||||
|
/// is essentially a unique key to guarantee safe usage of the Node.
|
||||||
|
///
|
||||||
|
/// Linked VNodes can only be made through the [`Context::render`] method
|
||||||
|
///
|
||||||
|
/// Typically, NodeLinks are found *not* in a VNode. When NodeLinks are in a VNode, the NodeLink was passed into
|
||||||
|
/// an `rsx!` call.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct NodeLink {
|
||||||
|
pub(crate) link_idx: usize,
|
||||||
|
pub(crate) gen_id: u32,
|
||||||
|
pub(crate) scope_id: ScopeId,
|
||||||
|
}
|
||||||
|
|
||||||
/// This struct provides an ergonomic API to quickly build VNodes.
|
/// This struct provides an ergonomic API to quickly build VNodes.
|
||||||
///
|
///
|
||||||
/// NodeFactory is used to build VNodes in the component's memory space.
|
/// NodeFactory is used to build VNodes in the component's memory space.
|
||||||
@@ -549,20 +565,6 @@ impl<'a> NodeFactory<'a> {
|
|||||||
where
|
where
|
||||||
P: Properties + 'a,
|
P: Properties + 'a,
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
our strategy:
|
|
||||||
- unsafe hackery
|
|
||||||
- lol
|
|
||||||
|
|
||||||
- we don't want to hit the global allocator
|
|
||||||
- allocate into our bump arena
|
|
||||||
- if the props aren't static, then we convert them into a box which we pass off between renders
|
|
||||||
*/
|
|
||||||
|
|
||||||
// let bump = self.bump();
|
|
||||||
|
|
||||||
// // later, we'll do a hard allocation
|
|
||||||
// let raw_ptr = bump.alloc(props);
|
|
||||||
let bump = self.bump();
|
let bump = self.bump();
|
||||||
let props = bump.alloc(props);
|
let props = bump.alloc(props);
|
||||||
let bump_props = props as *mut P as *mut ();
|
let bump_props = props as *mut P as *mut ();
|
||||||
@@ -758,21 +760,6 @@ impl IntoVNode<'_> for Option<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conveniently, we also support "None"
|
|
||||||
impl IntoVNode<'_> for Option<NodeLink> {
|
|
||||||
fn into_vnode(self, cx: NodeFactory) -> VNode {
|
|
||||||
todo!()
|
|
||||||
// cx.fragment_from_iter(None as Option<VNode>)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Conveniently, we also support "None"
|
|
||||||
impl IntoVNode<'_> for NodeLink {
|
|
||||||
fn into_vnode(self, cx: NodeFactory) -> VNode {
|
|
||||||
todo!()
|
|
||||||
// cx.fragment_from_iter(None as Option<VNode>)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IntoVNode<'a> for Option<VNode<'a>> {
|
impl<'a> IntoVNode<'a> for Option<VNode<'a>> {
|
||||||
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
||||||
self.unwrap_or_else(|| cx.fragment_from_iter(None as Option<VNode>))
|
self.unwrap_or_else(|| cx.fragment_from_iter(None as Option<VNode>))
|
||||||
@@ -809,79 +796,28 @@ impl IntoVNode<'_> for Arguments<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the children elements passed into the component
|
impl IntoVNode<'_> for Option<NodeLink> {
|
||||||
///
|
fn into_vnode(self, cx: NodeFactory) -> VNode {
|
||||||
/// This enables patterns where a component is passed children from its parent.
|
todo!()
|
||||||
///
|
|
||||||
/// ## 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
|
|
||||||
/// const App: FC<()> = |cx, props|{
|
|
||||||
/// cx.render(rsx!{
|
|
||||||
/// CustomCard {
|
|
||||||
/// h1 {}
|
|
||||||
/// p {}
|
|
||||||
/// }
|
|
||||||
/// })
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// const CustomCard: FC<()> = |cx, props|{
|
|
||||||
/// cx.render(rsx!{
|
|
||||||
/// div {
|
|
||||||
/// h1 {"Title card"}
|
|
||||||
/// {props.children}
|
|
||||||
/// }
|
|
||||||
/// })
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ## Notes:
|
|
||||||
///
|
|
||||||
/// This method returns a "ScopeChildren" object. This object is copy-able and preserve the correct lifetime.
|
|
||||||
pub struct ScopeChildren<'a> {
|
|
||||||
root: Option<VNode<'a>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for ScopeChildren<'_> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self { root: None }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ScopeChildren<'a> {
|
impl IntoVNode<'_> for &Option<NodeLink> {
|
||||||
pub fn new(root: VNode<'a>) -> Self {
|
fn into_vnode(self, cx: NodeFactory) -> VNode {
|
||||||
Self { root: Some(root) }
|
todo!()
|
||||||
}
|
|
||||||
pub fn new_option(root: Option<VNode<'a>>) -> Self {
|
|
||||||
Self { root }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoIterator for &ScopeChildren<'_> {
|
// Conveniently, we also support "None"
|
||||||
type Item = Self;
|
impl IntoVNode<'_> for NodeLink {
|
||||||
|
fn into_vnode(self, cx: NodeFactory) -> VNode {
|
||||||
type IntoIter = std::iter::Once<Self>;
|
todo!()
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
|
||||||
std::iter::once(self)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IntoVNode<'a> for &ScopeChildren<'a> {
|
// Conveniently, we also support "None"
|
||||||
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
impl IntoVNode<'_> for &NodeLink {
|
||||||
match &self.root {
|
fn into_vnode(self, cx: NodeFactory) -> VNode {
|
||||||
Some(n) => n.decouple(),
|
todo!()
|
||||||
None => cx.fragment_from_iter(None as Option<VNode>),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+11
-18
@@ -315,10 +315,7 @@ impl Scope {
|
|||||||
/// rsx!(cx, div { "hello {state.0}" })
|
/// rsx!(cx, div { "hello {state.0}" })
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn provide_state<T>(&self, value: T)
|
pub fn provide_state<T: 'static>(&self, value: T) {
|
||||||
where
|
|
||||||
T: 'static,
|
|
||||||
{
|
|
||||||
self.shared_contexts
|
self.shared_contexts
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.insert(TypeId::of::<T>(), Rc::new(value))
|
.insert(TypeId::of::<T>(), Rc::new(value))
|
||||||
@@ -354,13 +351,20 @@ impl Scope {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// static App: FC<()> = |cx, props| {
|
/// fn App(cx: Context, props: &()) -> Element {
|
||||||
/// todo!();
|
/// todo!();
|
||||||
/// rsx!(cx, div { "Subtree {id}"})
|
/// rsx!(cx, div { "Subtree {id}"})
|
||||||
/// };
|
/// };
|
||||||
/// ```
|
/// ```
|
||||||
pub fn create_subtree(&self) -> Option<u32> {
|
pub fn create_subtree(&self) -> Option<u32> {
|
||||||
self.new_subtree()
|
if self.is_subtree_root.get() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
todo!()
|
||||||
|
// let cur = self.subtree().get();
|
||||||
|
// self.shared.cur_subtree.set(cur + 1);
|
||||||
|
// Some(cur)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the subtree ID that this scope belongs to.
|
/// Get the subtree ID that this scope belongs to.
|
||||||
@@ -371,7 +375,7 @@ impl Scope {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// static App: FC<()> = |cx, props| {
|
/// fn App(cx: Context, props: &()) -> Element {
|
||||||
/// let id = cx.get_current_subtree();
|
/// let id = cx.get_current_subtree();
|
||||||
/// rsx!(cx, div { "Subtree {id}"})
|
/// rsx!(cx, div { "Subtree {id}"})
|
||||||
/// };
|
/// };
|
||||||
@@ -492,17 +496,6 @@ impl Scope {
|
|||||||
effect();
|
effect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new_subtree(&self) -> Option<u32> {
|
|
||||||
todo!()
|
|
||||||
// if self.is_subtree_root.get() {
|
|
||||||
// None
|
|
||||||
// } else {
|
|
||||||
// let cur = self.shared.cur_subtree.get();
|
|
||||||
// self.shared.cur_subtree.set(cur + 1);
|
|
||||||
// Some(cur)
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BumpFrame {
|
pub struct BumpFrame {
|
||||||
|
|||||||
@@ -38,12 +38,17 @@ impl ScopeArena {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_scope(&self, id: &ScopeId) -> Option<&Scope> {
|
pub fn get_scope(&self, id: &ScopeId) -> Option<&Scope> {
|
||||||
unsafe { Some(&*self.scopes.borrow()[id.0]) }
|
unsafe { self.scopes.borrow().get(id.0).map(|f| &**f) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is unsafe
|
// this is unsafe
|
||||||
pub unsafe fn get_scope_mut(&self, id: &ScopeId) -> Option<*mut Scope> {
|
pub unsafe fn get_scope_raw(&self, id: &ScopeId) -> Option<*mut Scope> {
|
||||||
Some(self.scopes.borrow()[id.0])
|
self.scopes.borrow().get(id.0).map(|f| *f)
|
||||||
|
}
|
||||||
|
// this is unsafe
|
||||||
|
|
||||||
|
pub unsafe fn get_scope_mut(&self, id: &ScopeId) -> Option<&mut Scope> {
|
||||||
|
self.scopes.borrow().get(id.0).map(|s| &mut **s)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_with_key(
|
pub fn new_with_key(
|
||||||
@@ -182,9 +187,11 @@ impl ScopeArena {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn run_scope(&self, id: &ScopeId) -> bool {
|
pub(crate) fn run_scope(&self, id: &ScopeId) -> bool {
|
||||||
let scope = self
|
let scope = unsafe {
|
||||||
.get_scope(id)
|
&mut *self
|
||||||
.expect("The base scope should never be moved");
|
.get_scope_mut(id)
|
||||||
|
.expect("The base scope should never be moved")
|
||||||
|
};
|
||||||
|
|
||||||
// Cycle to the next frame and then reset it
|
// Cycle to the next frame and then reset it
|
||||||
// This breaks any latent references, invalidating every pointer referencing into it.
|
// This breaks any latent references, invalidating every pointer referencing into it.
|
||||||
|
|||||||
Reference in new issue
Block a user