mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-23 12:43:08 +00:00
wip: begint to accept iterator types
This commit is contained in:
parent
f24d29130a
commit
742f150eb3
11 changed files with 528 additions and 143 deletions
51
Cargo.toml
51
Cargo.toml
|
@ -1,35 +1,34 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
# Built-in
|
|
||||||
"packages/dioxus",
|
"packages/dioxus",
|
||||||
"packages/core-macro",
|
"packages/core-macro",
|
||||||
"packages/core",
|
"packages/core",
|
||||||
"packages/web",
|
"packages/web",
|
||||||
"packages/webview/client",
|
|
||||||
"packages/webview",
|
|
||||||
"packages/liveview",
|
"packages/liveview",
|
||||||
# "packages/router",
|
|
||||||
# "packages/ssr",
|
|
||||||
# "packages/webview",
|
|
||||||
# "packages/livehost",
|
|
||||||
# "packages/vscode-ext",
|
|
||||||
# "packages/recoil",
|
|
||||||
# "packages/redux",
|
|
||||||
# "packages/macro",
|
|
||||||
# TODO @Jon, share the validation code
|
|
||||||
# "packages/web",
|
|
||||||
# "packages/hooks",
|
|
||||||
# "packages/cli",
|
|
||||||
# "examples",
|
|
||||||
# "packages/html-macro",
|
|
||||||
# "packages/html-macro-2",
|
|
||||||
#
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# Pulled from percy
|
|
||||||
# "packages/html-macro-test",
|
|
||||||
# "packages/virtual-dom-rs",
|
|
||||||
# "packages/virtual-node",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Built-in
|
||||||
|
# "packages/webview/client",
|
||||||
|
# "packages/webview",
|
||||||
|
# "packages/router",
|
||||||
|
# "packages/ssr",
|
||||||
|
# "packages/webview",
|
||||||
|
# "packages/livehost",
|
||||||
|
# "packages/vscode-ext",
|
||||||
|
# "packages/recoil",
|
||||||
|
# "packages/redux",
|
||||||
|
# "packages/macro",
|
||||||
|
# TODO @Jon, share the validation code
|
||||||
|
# "packages/web",
|
||||||
|
# "packages/hooks",
|
||||||
|
# "packages/cli",
|
||||||
|
# "examples",
|
||||||
|
# "packages/html-macro",
|
||||||
|
# "packages/html-macro-2",
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Pulled from percy
|
||||||
|
# "packages/html-macro-test",
|
||||||
|
# "packages/virtual-dom-rs",
|
||||||
|
# "packages/virtual-node",
|
||||||
|
|
|
@ -72,7 +72,7 @@ impl ToTokens for RsxRender {
|
||||||
|
|
||||||
// create a lazy tree that accepts a bump allocator
|
// create a lazy tree that accepts a bump allocator
|
||||||
let final_tokens = quote! {
|
let final_tokens = quote! {
|
||||||
move |ctx| {
|
move |ctx: &dioxus::prelude::NodeCtx<'_>| -> dioxus::prelude::VNode<'_>{
|
||||||
let bump = ctx.bump;
|
let bump = ctx.bump;
|
||||||
#new_toks
|
#new_toks
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,6 @@ pub struct Context<'src> {
|
||||||
pub(crate) hooks: &'src RefCell<Vec<*mut Hook>>,
|
pub(crate) hooks: &'src RefCell<Vec<*mut Hook>>,
|
||||||
pub(crate) bump: &'src Bump,
|
pub(crate) bump: &'src Bump,
|
||||||
|
|
||||||
pub(crate) final_nodes: Rc<RefCell<Option<VNode<'static>>>>,
|
|
||||||
|
|
||||||
pub listeners: &'src RefCell<Vec<*const dyn Fn(crate::events::VirtualEvent)>>,
|
pub listeners: &'src RefCell<Vec<*const dyn Fn(crate::events::VirtualEvent)>>,
|
||||||
|
|
||||||
// holder for the src lifetime
|
// holder for the src lifetime
|
||||||
|
@ -97,7 +95,7 @@ impl<'a> Context<'a> {
|
||||||
/// ctx.render(lazy_tree)
|
/// ctx.render(lazy_tree)
|
||||||
/// }
|
/// }
|
||||||
///```
|
///```
|
||||||
pub fn render(self, lazy_nodes: impl FnOnce(&'_ NodeCtx<'a>) -> VNode<'a> + 'a) -> DomTree {
|
pub fn render(&self, lazy_nodes: impl FnOnce(&'_ NodeCtx<'a>) -> VNode<'a> + 'a) -> DomTree {
|
||||||
let ctx = NodeCtx {
|
let ctx = NodeCtx {
|
||||||
bump: self.bump,
|
bump: self.bump,
|
||||||
scope: self.scope,
|
scope: self.scope,
|
||||||
|
@ -106,9 +104,8 @@ impl<'a> Context<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let safe_nodes = lazy_nodes(&ctx);
|
let safe_nodes = lazy_nodes(&ctx);
|
||||||
let unsafe_nodes = unsafe { std::mem::transmute::<VNode<'a>, VNode<'static>>(safe_nodes) };
|
let root: VNode<'static> = unsafe { std::mem::transmute(safe_nodes) };
|
||||||
self.final_nodes.deref().borrow_mut().replace(unsafe_nodes);
|
DomTree { root }
|
||||||
DomTree {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,13 +48,13 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ensure_creation() -> Result<(), ()> {
|
fn ensure_creation() -> Result<(), ()> {
|
||||||
static Example: FC<()> = |ctx, props| {
|
// static Example: FC<()> = |ctx, props| {
|
||||||
//
|
// //
|
||||||
ctx.render(html! { <div> "hello world" </div> })
|
// ctx.render(html! { <div> "hello world" </div> })
|
||||||
};
|
// };
|
||||||
|
|
||||||
let mut dom = VirtualDom::new(Example);
|
// let mut dom = VirtualDom::new(Example);
|
||||||
let machine = DiffMachine::new();
|
// let machine = DiffMachine::new();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,6 +102,7 @@ pub(crate) mod innerlude {
|
||||||
|
|
||||||
pub(crate) use nodes::*;
|
pub(crate) use nodes::*;
|
||||||
|
|
||||||
|
pub use crate::context::NodeCtx;
|
||||||
pub use crate::diff::DiffMachine;
|
pub use crate::diff::DiffMachine;
|
||||||
pub use crate::patch::{EditList, EditMachine};
|
pub use crate::patch::{EditList, EditMachine};
|
||||||
// pub use crate::patchdx;
|
// pub use crate::patchdx;
|
||||||
|
@ -137,6 +138,7 @@ pub mod prelude {
|
||||||
use crate::nodes;
|
use crate::nodes;
|
||||||
pub use nodes::*;
|
pub use nodes::*;
|
||||||
|
|
||||||
|
pub use crate::context::NodeCtx;
|
||||||
// pub use nodes::iterables::IterableNodes;
|
// pub use nodes::iterables::IterableNodes;
|
||||||
/// This type alias is an internal way of abstracting over the static functions that represent components.
|
/// This type alias is an internal way of abstracting over the static functions that represent components.
|
||||||
pub use crate::innerlude::FC;
|
pub use crate::innerlude::FC;
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::{any::Any, borrow::BorrowMut, intrinsics::transmute, u128};
|
||||||
use crate::{
|
use crate::{
|
||||||
context::NodeCtx,
|
context::NodeCtx,
|
||||||
events::VirtualEvent,
|
events::VirtualEvent,
|
||||||
innerlude::{Properties, VComponent, FC},
|
innerlude::{DomTree, Properties, VComponent, FC},
|
||||||
nodes::{Attribute, Listener, NodeKey, VNode},
|
nodes::{Attribute, Listener, NodeKey, VNode},
|
||||||
prelude::VElement,
|
prelude::VElement,
|
||||||
};
|
};
|
||||||
|
@ -16,13 +16,14 @@ use crate::{
|
||||||
/// function for building `<div>` elements or the `button` function for building
|
/// function for building `<div>` elements or the `button` function for building
|
||||||
/// `<button>` elements.
|
/// `<button>` elements.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ElementBuilder<'a, 'b, Listeners, Attributes, Children>
|
pub struct ElementBuilder<'a, Listeners, Attributes, Children>
|
||||||
where
|
where
|
||||||
Listeners: 'a + AsRef<[Listener<'a>]>,
|
Listeners: 'a + AsRef<[Listener<'a>]>,
|
||||||
Attributes: 'a + AsRef<[Attribute<'a>]>,
|
Attributes: 'a + AsRef<[Attribute<'a>]>,
|
||||||
Children: 'a + AsRef<[VNode<'a>]>,
|
Children: 'a + AsRef<[VNode<'a>]>,
|
||||||
{
|
{
|
||||||
ctx: &'b NodeCtx<'a>,
|
ctx: NodeCtx<'a>,
|
||||||
|
// ctx: &'b NodeCtx<'a>,
|
||||||
key: NodeKey,
|
key: NodeKey,
|
||||||
tag_name: &'a str,
|
tag_name: &'a str,
|
||||||
listeners: Listeners,
|
listeners: Listeners,
|
||||||
|
@ -31,10 +32,9 @@ where
|
||||||
namespace: Option<&'a str>,
|
namespace: Option<&'a str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b>
|
impl<'a>
|
||||||
ElementBuilder<
|
ElementBuilder<
|
||||||
'a,
|
'a,
|
||||||
'b,
|
|
||||||
bumpalo::collections::Vec<'a, Listener<'a>>,
|
bumpalo::collections::Vec<'a, Listener<'a>>,
|
||||||
bumpalo::collections::Vec<'a, Attribute<'a>>,
|
bumpalo::collections::Vec<'a, Attribute<'a>>,
|
||||||
bumpalo::collections::Vec<'a, VNode<'a>>,
|
bumpalo::collections::Vec<'a, VNode<'a>>,
|
||||||
|
@ -63,23 +63,24 @@ impl<'a, 'b>
|
||||||
/// let my_element_builder = ElementBuilder::new(&b, tag_name);
|
/// let my_element_builder = ElementBuilder::new(&b, tag_name);
|
||||||
/// # fn flip_coin() -> bool { true }
|
/// # fn flip_coin() -> bool { true }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn new(ctx: &'b NodeCtx<'a>, tag_name: &'static str) -> Self {
|
pub fn new(ctx: &NodeCtx<'a>, tag_name: &'static str) -> Self {
|
||||||
|
// pub fn new(ctx: &'b NodeCtx<'a>, tag_name: &'static str) -> Self {
|
||||||
// pub fn new<B>(ctx: &'a mut NodeCtx<'a>, tag_name: &'a str) -> Self {
|
// pub fn new<B>(ctx: &'a mut NodeCtx<'a>, tag_name: &'a str) -> Self {
|
||||||
let bump = ctx.bump;
|
let bump = ctx.bump;
|
||||||
ElementBuilder {
|
todo!()
|
||||||
ctx,
|
// ElementBuilder {
|
||||||
key: NodeKey::NONE,
|
// ctx,
|
||||||
tag_name,
|
// key: NodeKey::NONE,
|
||||||
listeners: bumpalo::collections::Vec::new_in(bump),
|
// tag_name,
|
||||||
attributes: bumpalo::collections::Vec::new_in(bump),
|
// listeners: bumpalo::collections::Vec::new_in(bump),
|
||||||
children: bumpalo::collections::Vec::new_in(bump),
|
// attributes: bumpalo::collections::Vec::new_in(bump),
|
||||||
namespace: None,
|
// children: bumpalo::collections::Vec::new_in(bump),
|
||||||
}
|
// namespace: None,
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, Listeners, Attributes, Children>
|
impl<'a, Listeners, Attributes, Children> ElementBuilder<'a, Listeners, Attributes, Children>
|
||||||
ElementBuilder<'a, 'b, Listeners, Attributes, Children>
|
|
||||||
where
|
where
|
||||||
Listeners: 'a + AsRef<[Listener<'a>]>,
|
Listeners: 'a + AsRef<[Listener<'a>]>,
|
||||||
Attributes: 'a + AsRef<[Attribute<'a>]>,
|
Attributes: 'a + AsRef<[Attribute<'a>]>,
|
||||||
|
@ -113,7 +114,7 @@ where
|
||||||
/// .finish();
|
/// .finish();
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn listeners<L>(self, listeners: L) -> ElementBuilder<'a, 'b, L, Attributes, Children>
|
pub fn listeners<L>(self, listeners: L) -> ElementBuilder<'a, L, Attributes, Children>
|
||||||
where
|
where
|
||||||
L: 'a + AsRef<[Listener<'a>]>,
|
L: 'a + AsRef<[Listener<'a>]>,
|
||||||
{
|
{
|
||||||
|
@ -152,7 +153,7 @@ where
|
||||||
/// .finish();
|
/// .finish();
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn attributes<A>(self, attributes: A) -> ElementBuilder<'a, 'b, Listeners, A, Children>
|
pub fn attributes<A>(self, attributes: A) -> ElementBuilder<'a, Listeners, A, Children>
|
||||||
where
|
where
|
||||||
A: 'a + AsRef<[Attribute<'a>]>,
|
A: 'a + AsRef<[Attribute<'a>]>,
|
||||||
{
|
{
|
||||||
|
@ -191,7 +192,7 @@ where
|
||||||
/// .finish();
|
/// .finish();
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn children<C>(self, children: C) -> ElementBuilder<'a, 'b, Listeners, Attributes, C>
|
pub fn children<C>(self, children: C) -> ElementBuilder<'a, Listeners, Attributes, C>
|
||||||
where
|
where
|
||||||
C: 'a + AsRef<[VNode<'a>]>,
|
C: 'a + AsRef<[VNode<'a>]>,
|
||||||
{
|
{
|
||||||
|
@ -310,8 +311,8 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, Attributes, Children>
|
impl<'a, Attributes, Children>
|
||||||
ElementBuilder<'a, 'b, bumpalo::collections::Vec<'a, Listener<'a>>, Attributes, Children>
|
ElementBuilder<'a, bumpalo::collections::Vec<'a, Listener<'a>>, Attributes, Children>
|
||||||
where
|
where
|
||||||
Attributes: 'a + AsRef<[Attribute<'a>]>,
|
Attributes: 'a + AsRef<[Attribute<'a>]>,
|
||||||
Children: 'a + AsRef<[VNode<'a>]>,
|
Children: 'a + AsRef<[VNode<'a>]>,
|
||||||
|
@ -364,8 +365,8 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, Listeners, Children>
|
impl<'a, Listeners, Children>
|
||||||
ElementBuilder<'a, 'b, Listeners, bumpalo::collections::Vec<'a, Attribute<'a>>, Children>
|
ElementBuilder<'a, Listeners, bumpalo::collections::Vec<'a, Attribute<'a>>, Children>
|
||||||
where
|
where
|
||||||
Listeners: 'a + AsRef<[Listener<'a>]>,
|
Listeners: 'a + AsRef<[Listener<'a>]>,
|
||||||
Children: 'a + AsRef<[VNode<'a>]>,
|
Children: 'a + AsRef<[VNode<'a>]>,
|
||||||
|
@ -423,8 +424,8 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, Listeners, Attributes>
|
impl<'a, Listeners, Attributes>
|
||||||
ElementBuilder<'a, 'b, Listeners, Attributes, bumpalo::collections::Vec<'a, VNode<'a>>>
|
ElementBuilder<'a, Listeners, Attributes, bumpalo::collections::Vec<'a, VNode<'a>>>
|
||||||
where
|
where
|
||||||
Listeners: 'a + AsRef<[Listener<'a>]>,
|
Listeners: 'a + AsRef<[Listener<'a>]>,
|
||||||
Attributes: 'a + AsRef<[Attribute<'a>]>,
|
Attributes: 'a + AsRef<[Attribute<'a>]>,
|
||||||
|
@ -450,7 +451,190 @@ where
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn virtual_child(mut self)
|
pub fn iter_child(mut self, nodes: impl IntoIterator<Item = DomTree>) -> Self {
|
||||||
|
for item in nodes.into_iter() {
|
||||||
|
self.children.push(item.root);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_tomdtree(mut self, nodes: impl IntoDomTree<'a>) -> Self {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoIterator for DomTree {
|
||||||
|
type Item = DomTree;
|
||||||
|
type IntoIter = std::iter::Once<Self::Item>;
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
std::iter::once(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait IntoDomTree<'a> {
|
||||||
|
type NodeIter: IntoIterator<Item = DomTree>;
|
||||||
|
fn into_domtree(self, ctx: &NodeCtx<'a>) -> Self::NodeIter;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoDomTree<'_> for DomTree {
|
||||||
|
type NodeIter = std::iter::Once<DomTree>;
|
||||||
|
fn into_domtree(self, ctx: &NodeCtx) -> Self::NodeIter {
|
||||||
|
std::iter::once(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, G> IntoDomTree<'a> for NodeWrapper<'a, G>
|
||||||
|
where
|
||||||
|
G: for<'b, 'c> FnOnce(&'b NodeCtx<'c>) -> VNode<'c> + 'a,
|
||||||
|
{
|
||||||
|
type NodeIter = std::iter::Once<DomTree>;
|
||||||
|
|
||||||
|
fn into_domtree(self, ctx: &NodeCtx) -> Self::NodeIter {
|
||||||
|
let p: VNode<'_> = (self.inner)(ctx);
|
||||||
|
let root: VNode<'static> = unsafe { std::mem::transmute(p) };
|
||||||
|
std::iter::once(DomTree { root })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, G, I> IntoDomTree<'a> for I
|
||||||
|
where
|
||||||
|
G: for<'b, 'c> FnOnce(&'b NodeCtx<'c>) -> VNode<'c> + 'a,
|
||||||
|
I: Iterator<Item = NodeWrapper<'a, G>>,
|
||||||
|
// O: Iterator<Item = DomTree>,
|
||||||
|
{
|
||||||
|
type NodeIter = std::iter::Map<I, O>;
|
||||||
|
|
||||||
|
fn into_domtree(self, ctx: &NodeCtx) -> Self::NodeIter {
|
||||||
|
self.map(|f| {
|
||||||
|
//
|
||||||
|
let caller = (f.inner);
|
||||||
|
let r = caller(ctx);
|
||||||
|
})
|
||||||
|
// todo!()
|
||||||
|
// let p: VNode<'_> = (self.inner)(ctx);
|
||||||
|
// let root: VNode<'static> = unsafe { std::mem::transmute(p) };
|
||||||
|
// std::iter::once(DomTree { root })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
all possible impls
|
||||||
|
|
||||||
|
rsx!{ }
|
||||||
|
ctx.render(rsx!)
|
||||||
|
|
||||||
|
map(rsx!)
|
||||||
|
map(ctx.render(rsx!))
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub struct NodeWrapper<'a, G>
|
||||||
|
where
|
||||||
|
G: for<'b, 'c> FnOnce(&'b NodeCtx<'c>) -> VNode<'c> + 'a,
|
||||||
|
{
|
||||||
|
inner: G,
|
||||||
|
_p: std::marker::PhantomData<&'a ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_wrapper<'a, G>(f: G) -> NodeWrapper<'a, G>
|
||||||
|
where
|
||||||
|
G: for<'b, 'c> FnOnce(&'b NodeCtx<'c>) -> VNode<'c> + 'a,
|
||||||
|
{
|
||||||
|
NodeWrapper {
|
||||||
|
inner: f,
|
||||||
|
_p: std::default::Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_iterator_of_nodes<'b>() {
|
||||||
|
let p = (0..10).map(|f| {
|
||||||
|
//
|
||||||
|
new_wrapper(rsx! {
|
||||||
|
div {
|
||||||
|
"aaa {f}"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let g = p.into_iter();
|
||||||
|
for f in g {}
|
||||||
|
|
||||||
|
static Example: FC<()> = |ctx, props| {
|
||||||
|
ctx.render(|c| {
|
||||||
|
//
|
||||||
|
ElementBuilder::new(c, "div")
|
||||||
|
.into_tomdtree({
|
||||||
|
// rsx!
|
||||||
|
new_wrapper(move |n: &NodeCtx| -> VNode {
|
||||||
|
//
|
||||||
|
ElementBuilder::new(n, "div").finish()
|
||||||
|
})
|
||||||
|
// use the macro to be "blind" to the type
|
||||||
|
// everything gets interpreted as
|
||||||
|
/*
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for node in {expr} {
|
||||||
|
ctx.push_alloc_node(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
so.... just make sure whatever enters {} is iterable (domtree and nodewrapper need impls, )
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
})
|
||||||
|
.into_tomdtree({
|
||||||
|
// render to wrapper -> tree
|
||||||
|
ctx.render(rsx! {
|
||||||
|
div {}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.into_tomdtree({
|
||||||
|
// map rsx!
|
||||||
|
(0..10).map(|f| {
|
||||||
|
new_wrapper(move |n: &NodeCtx| -> VNode {
|
||||||
|
//
|
||||||
|
ElementBuilder::new(n, "div").finish()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.finish()
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
// static Example: FC<()> = |ctx, props| {
|
||||||
|
// //
|
||||||
|
// let list = (0..10).map(|f| {
|
||||||
|
// ctx.render(rsx! {
|
||||||
|
// div {}
|
||||||
|
// })
|
||||||
|
// });
|
||||||
|
|
||||||
|
// ctx.render(|c| {
|
||||||
|
// ElementBuilder::new(c, "div")
|
||||||
|
// .iter_child({
|
||||||
|
// //
|
||||||
|
// ctx.render(rsx! {
|
||||||
|
// div {}
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// .iter_child({
|
||||||
|
// //
|
||||||
|
// (0..10).map(|f| {
|
||||||
|
// ctx.render(rsx! {
|
||||||
|
// div {}
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// .iter_child(list)
|
||||||
|
// .finish()
|
||||||
|
// })
|
||||||
|
// };
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a text VNode.
|
/// Construct a text VNode.
|
||||||
|
@ -510,7 +694,7 @@ pub fn attr<'a>(name: &'static str, value: &'a str) -> Attribute<'a> {
|
||||||
// /// });
|
// /// });
|
||||||
// /// ```
|
// /// ```
|
||||||
// pub fn on<'a, 'b>(
|
// pub fn on<'a, 'b>(
|
||||||
// // pub fn on<'a, 'b, F: 'static>(
|
// // pub fn on<'a, F: 'static>(
|
||||||
// bump: &'a Bump,
|
// bump: &'a Bump,
|
||||||
// event: &'static str,
|
// event: &'static str,
|
||||||
// callback: impl Fn(VirtualEvent) + 'a,
|
// callback: impl Fn(VirtualEvent) + 'a,
|
||||||
|
@ -525,27 +709,3 @@ pub fn virtual_child<'a, T: Properties + 'a>(ctx: &NodeCtx<'a>, f: FC<T>, p: T)
|
||||||
let propsd: &'a mut _ = ctx.bump.alloc(p);
|
let propsd: &'a mut _ = ctx.bump.alloc(p);
|
||||||
VNode::Component(crate::nodes::VComponent::new(f, propsd))
|
VNode::Component(crate::nodes::VComponent::new(f, propsd))
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Bany {
|
|
||||||
// fn compare_to<P: Properties>(other: &P) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn test_vchild<T: Properties>(p: &T) {
|
|
||||||
// let r = p as *const dyn Bany;
|
|
||||||
// let r = p as *const dyn Bany;
|
|
||||||
|
|
||||||
// std::any::Any
|
|
||||||
// let r = p as &dyn Any;
|
|
||||||
// let g = p as *const u128;
|
|
||||||
// let l = unsafe { std::mem::transmute::<&T, &dyn Any>(p) };
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
Problem:
|
|
||||||
compare two props that we know are the same type without transmute
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
|
@ -14,7 +14,10 @@ use std::{any::Any, cell::RefCell, marker::PhantomData, rc::Rc};
|
||||||
|
|
||||||
/// A domtree represents the result of "Viewing" the context
|
/// A domtree represents the result of "Viewing" the context
|
||||||
/// It's a placeholder over vnodes, to make working with lifetimes easier
|
/// It's a placeholder over vnodes, to make working with lifetimes easier
|
||||||
pub struct DomTree;
|
pub struct DomTree {
|
||||||
|
// this should *never* be publicly accessible to external
|
||||||
|
pub(crate) root: VNode<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
// ==============================
|
// ==============================
|
||||||
// VNODES
|
// VNODES
|
||||||
|
@ -88,9 +91,7 @@ impl<'a> VNode<'a> {
|
||||||
VNode::Suspended => {
|
VNode::Suspended => {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
VNode::Component(c) => {
|
VNode::Component(c) => c.key,
|
||||||
c.key
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,7 +254,7 @@ pub struct VComponent<'src> {
|
||||||
pub ass_scope: Rc<VCompAssociatedScope>,
|
pub ass_scope: Rc<VCompAssociatedScope>,
|
||||||
|
|
||||||
pub comparator: Rc<dyn Fn(&VComponent) -> bool + 'src>,
|
pub comparator: Rc<dyn Fn(&VComponent) -> bool + 'src>,
|
||||||
pub caller: Rc<dyn for<'r> Fn(Context<'r>) -> DomTree + 'src>,
|
pub caller: Rc<dyn Fn(Context) -> DomTree + 'src>,
|
||||||
|
|
||||||
// a pointer into the bump arena (given by the 'src lifetime)
|
// a pointer into the bump arena (given by the 'src lifetime)
|
||||||
raw_props: *const (),
|
raw_props: *const (),
|
||||||
|
@ -296,11 +297,7 @@ impl<'a> VComponent<'a> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let caller = move |ctx: Context| -> DomTree {
|
let caller = Rc::new(create_closure(component, raw_props));
|
||||||
// cast back into the right lifetime
|
|
||||||
let safe_props: &P = unsafe { &*(raw_props as *const P) };
|
|
||||||
component(ctx, props)
|
|
||||||
};
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
key: NodeKey::NONE,
|
key: NodeKey::NONE,
|
||||||
|
@ -308,9 +305,20 @@ impl<'a> VComponent<'a> {
|
||||||
user_fc: caller_ref,
|
user_fc: caller_ref,
|
||||||
raw_props: props as *const P as *const _,
|
raw_props: props as *const P as *const _,
|
||||||
_p: PhantomData,
|
_p: PhantomData,
|
||||||
caller: Rc::new(caller),
|
caller,
|
||||||
comparator: Rc::new(props_comparator),
|
comparator: Rc::new(props_comparator),
|
||||||
stable_addr: Rc::new(RefCell::new(None)),
|
stable_addr: Rc::new(RefCell::new(None)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_closure<'a, P: Properties + 'a>(
|
||||||
|
component: FC<P>,
|
||||||
|
raw_props: *const (),
|
||||||
|
) -> impl for<'r> Fn(Context<'r>) -> DomTree + 'a {
|
||||||
|
move |ctx: Context| -> DomTree {
|
||||||
|
// cast back into the right lifetime
|
||||||
|
let safe_props: &'a P = unsafe { &*(raw_props as *const P) };
|
||||||
|
component(ctx, safe_props)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -83,7 +83,7 @@ impl Scope {
|
||||||
/// This function downcasts the function pointer based on the stored props_type
|
/// This function downcasts the function pointer based on the stored props_type
|
||||||
///
|
///
|
||||||
/// Props is ?Sized because we borrow the props and don't need to know the size. P (sized) is used as a marker (unsized)
|
/// Props is ?Sized because we borrow the props and don't need to know the size. P (sized) is used as a marker (unsized)
|
||||||
pub fn run_scope(&mut self) -> Result<()> {
|
pub fn run_scope<'b>(&'b mut self) -> Result<()> {
|
||||||
// pub fn run_scope<'bump>(&'bump mut self) -> Result<()> {
|
// pub fn run_scope<'bump>(&'bump mut self) -> Result<()> {
|
||||||
let frame = {
|
let frame = {
|
||||||
let frame = self.frames.next();
|
let frame = self.frames.next();
|
||||||
|
@ -91,24 +91,17 @@ impl Scope {
|
||||||
frame
|
frame
|
||||||
};
|
};
|
||||||
|
|
||||||
let node_slot = std::rc::Rc::new(RefCell::new(None));
|
let ctx: Context<'b> = Context {
|
||||||
|
|
||||||
let ctx = Context {
|
|
||||||
arena: &self.hook_arena,
|
arena: &self.hook_arena,
|
||||||
hooks: &self.hooks,
|
hooks: &self.hooks,
|
||||||
bump: &frame.bump,
|
bump: &frame.bump,
|
||||||
idx: 0.into(),
|
idx: 0.into(),
|
||||||
_p: PhantomData {},
|
_p: PhantomData {},
|
||||||
final_nodes: node_slot.clone(),
|
|
||||||
scope: self.myidx,
|
scope: self.myidx,
|
||||||
listeners: &self.listeners,
|
listeners: &self.listeners,
|
||||||
};
|
};
|
||||||
let caller = self.caller.upgrade().expect("Failed to get caller");
|
let caller = self.caller.upgrade().expect("Failed to get caller");
|
||||||
|
|
||||||
// todo!()
|
|
||||||
// Note that the actual modification of the vnode head element occurs during this call
|
|
||||||
let _: DomTree = (caller.as_ref())(ctx);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
SAFETY ALERT
|
SAFETY ALERT
|
||||||
|
|
||||||
|
@ -121,11 +114,11 @@ impl Scope {
|
||||||
- Public API cannot drop or destructure VNode
|
- Public API cannot drop or destructure VNode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
frame.head_node = node_slot
|
frame.head_node = unsafe {
|
||||||
.as_ref()
|
let caller2: Rc<OpaqueComponent<'b>> = std::mem::transmute(caller);
|
||||||
.borrow_mut()
|
let tree = (caller2.as_ref())(ctx);
|
||||||
.take()
|
tree.root
|
||||||
.expect("Viewing did not happen");
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,16 @@
|
||||||
use crate::{error::Error, innerlude::*};
|
use crate::{error::Error, innerlude::*};
|
||||||
use crate::{patch::Edit, scope::Scope};
|
use crate::{patch::Edit, scope::Scope};
|
||||||
use generational_arena::Arena;
|
use generational_arena::Arena;
|
||||||
use std::{any::TypeId, borrow::{Borrow, BorrowMut}, rc::{Rc, Weak}};
|
use std::{
|
||||||
|
any::TypeId,
|
||||||
|
borrow::{Borrow, BorrowMut},
|
||||||
|
rc::{Rc, Weak},
|
||||||
|
};
|
||||||
use thiserror::private::AsDynError;
|
use thiserror::private::AsDynError;
|
||||||
|
|
||||||
// We actually allocate the properties for components in their parent's properties
|
// We actually allocate the properties for components in their parent's properties
|
||||||
// We then expose a handle to use those props for render in the form of "OpaqueComponent"
|
// We then expose a handle to use those props for render in the form of "OpaqueComponent"
|
||||||
pub(crate) type OpaqueComponent<'a> = dyn Fn(Context) -> DomTree + 'a;
|
pub(crate) type OpaqueComponent<'a> = dyn for<'b> Fn(Context<'b>) -> DomTree + 'a;
|
||||||
|
|
||||||
/// An integrated virtual node system that progresses events and diffs UI trees.
|
/// An integrated virtual node system that progresses events and diffs UI trees.
|
||||||
/// Differences are converted into patches which a renderer can use to draw the UI.
|
/// Differences are converted into patches which a renderer can use to draw the UI.
|
||||||
|
@ -47,8 +51,15 @@ impl VirtualDom {
|
||||||
pub fn new_with_props<P: Properties + 'static>(root: FC<P>, root_props: P) -> Self {
|
pub fn new_with_props<P: Properties + 'static>(root: FC<P>, root_props: P) -> Self {
|
||||||
let mut components = Arena::new();
|
let mut components = Arena::new();
|
||||||
|
|
||||||
|
// let prr = Rc::new(root_props);
|
||||||
|
|
||||||
// the root is kept around with a "hard" allocation
|
// the root is kept around with a "hard" allocation
|
||||||
let root_caller: Rc<OpaqueComponent> = Rc::new(move |ctx| root(ctx, &root_props));
|
let root_caller: Rc<OpaqueComponent> = Rc::new(move |ctx| {
|
||||||
|
//
|
||||||
|
// let p2 = &root_props;
|
||||||
|
// let p2 = prr.clone();
|
||||||
|
root(ctx, &root_props)
|
||||||
|
});
|
||||||
|
|
||||||
// we then expose this to the component with a weak allocation
|
// we then expose this to the component with a weak allocation
|
||||||
let weak_caller: Weak<OpaqueComponent> = Rc::downgrade(&root_caller);
|
let weak_caller: Weak<OpaqueComponent> = Rc::downgrade(&root_caller);
|
||||||
|
@ -110,9 +121,8 @@ impl VirtualDom {
|
||||||
LifeCycleEvent::PropsChanged { caller, id, scope } => {
|
LifeCycleEvent::PropsChanged { caller, id, scope } => {
|
||||||
let idx = scope.upgrade().unwrap().as_ref().borrow().unwrap();
|
let idx = scope.upgrade().unwrap().as_ref().borrow().unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
||||||
let p = &mut *(very_unsafe_components);
|
let p = &mut *(very_unsafe_components);
|
||||||
let c = p.get_mut(idx).unwrap();
|
let c = p.get_mut(idx).unwrap();
|
||||||
c.update_caller(caller);
|
c.update_caller(caller);
|
||||||
c.run_scope()?;
|
c.run_scope()?;
|
||||||
diff_machine.change_list.load_known_root(id);
|
diff_machine.change_list.load_known_root(id);
|
||||||
|
|
131
packages/liveview/examples/simpletide.rs
Normal file
131
packages/liveview/examples/simpletide.rs
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
pub fn main() {
|
||||||
|
#[cfg(feature = "client")]
|
||||||
|
wasm_bindgen_futures::spawn_local(async { client::app().await.unwrap() });
|
||||||
|
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
async_std::task::block_on(async { server::app().await.expect("") });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ===============================
|
||||||
|
/// Common code (shared types)
|
||||||
|
/// ===============================
|
||||||
|
#[derive(PartialEq, strum::EnumIter, strum::Display, strum::AsRefStr, strum::EnumString)]
|
||||||
|
pub enum SelectedStream {
|
||||||
|
Football,
|
||||||
|
Hockey,
|
||||||
|
Socker,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Client-specific code
|
||||||
|
#[cfg(feature = "client")]
|
||||||
|
mod client {
|
||||||
|
use super::*;
|
||||||
|
use dioxus_core::prelude::*;
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
pub async fn app() -> anyhow::Result<()> {
|
||||||
|
Ok(dioxus_web::WebsysRenderer::start(APP).await)
|
||||||
|
}
|
||||||
|
|
||||||
|
static APP: FC<()> = |ctx, props| {
|
||||||
|
todo!()
|
||||||
|
// let (selected_stream, set_stream) = use_state(&ctx, || SelectedStream::Football);
|
||||||
|
|
||||||
|
// let opts = SelectedStream::iter().map(|name| rsx! { option { "{name}", value: "{name}" } });
|
||||||
|
|
||||||
|
// ctx.render(rsx! {
|
||||||
|
// div {
|
||||||
|
// h1 { "Tide basic CRUD app" }
|
||||||
|
// h2 { "Chosen stream: {selected_stream}" }
|
||||||
|
// select {
|
||||||
|
// value: {selected_stream.as_ref()}
|
||||||
|
// "{selected_stream}"
|
||||||
|
// {opts}
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Server-specific code
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
mod server {
|
||||||
|
use async_std::sync::RwLock;
|
||||||
|
pub use log::info;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tide::Request;
|
||||||
|
use tide_websockets::{Message, WebSocket, WebSocketConnection};
|
||||||
|
|
||||||
|
use crate::SelectedStream;
|
||||||
|
|
||||||
|
// type ServerRequest = Request<Arc<RwLock<()>>>;
|
||||||
|
type ServerRequest = Request<()>;
|
||||||
|
// type ServerRequest = Request<Arc<RwLock<ServerState>>>;
|
||||||
|
|
||||||
|
static CLIENT_PATH: &'static str = "";
|
||||||
|
|
||||||
|
pub async fn app() -> anyhow::Result<()> {
|
||||||
|
let mut app = tide::new();
|
||||||
|
|
||||||
|
app.at("")
|
||||||
|
.serve_dir(format!("{}/pkg", CLIENT_PATH))
|
||||||
|
.expect("Cannot serve directory");
|
||||||
|
|
||||||
|
app.at("/updates").get(WebSocket::new(socket_handler));
|
||||||
|
|
||||||
|
let addr = "0.0.0.0:9001";
|
||||||
|
log::info!("Congrats! Server is up and running at http://{}", addr);
|
||||||
|
app.listen(addr).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn socket_handler(
|
||||||
|
request: ServerRequest,
|
||||||
|
stream: WebSocketConnection,
|
||||||
|
) -> tide::Result<()> {
|
||||||
|
// clone the receiver channel
|
||||||
|
// subscribe to any updates
|
||||||
|
// let receiver = request.state().read().await.receiver.clone();
|
||||||
|
// while let Ok(evt) = receiver.recv().await {
|
||||||
|
// let response_msg = serde_json::to_string(&evt)?;
|
||||||
|
// stream.send_string(response_msg).await?;
|
||||||
|
// }
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
use dioxus_core::prelude::*;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Props)]
|
||||||
|
struct SreamListProps {
|
||||||
|
selected_stream: SelectedStream,
|
||||||
|
}
|
||||||
|
|
||||||
|
static STREAM_LIST: FC<SreamListProps> = |ctx, props| {
|
||||||
|
//
|
||||||
|
let g = match props.selected_stream {
|
||||||
|
SelectedStream::Football => ctx.render(rsx! {
|
||||||
|
li {
|
||||||
|
"watch football!"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
SelectedStream::Hockey => ctx.render(rsx! {
|
||||||
|
li {
|
||||||
|
"watch football!"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
SelectedStream::Socker => ctx.render(rsx! {
|
||||||
|
li {
|
||||||
|
"watch football!"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
ctx.render(rsx! {
|
||||||
|
div {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
|
@ -6,18 +6,21 @@ pub fn main() {
|
||||||
async_std::task::block_on(async { server::app().await.expect("") });
|
async_std::task::block_on(async { server::app().await.expect("") });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(strum::EnumIter, strum::Display, strum::AsRefStr)]
|
/// ===============================
|
||||||
|
/// Common code (shared types)
|
||||||
|
/// ===============================
|
||||||
|
#[derive(PartialEq, strum::EnumIter, strum::Display, strum::AsRefStr, strum::EnumString)]
|
||||||
pub enum SelectedStream {
|
pub enum SelectedStream {
|
||||||
Football,
|
Football,
|
||||||
Hockey,
|
Hockey,
|
||||||
Socker,
|
Socker,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Client-specific code
|
||||||
#[cfg(feature = "client")]
|
#[cfg(feature = "client")]
|
||||||
mod client {
|
mod client {
|
||||||
use super::*;
|
use super::*;
|
||||||
use dioxus_core::prelude::*;
|
use dioxus_core::prelude::*;
|
||||||
use dioxus_web::WebsysRenderer;
|
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
pub async fn app() -> anyhow::Result<()> {
|
pub async fn app() -> anyhow::Result<()> {
|
||||||
|
@ -25,26 +28,26 @@ mod client {
|
||||||
}
|
}
|
||||||
|
|
||||||
static APP: FC<()> = |ctx, props| {
|
static APP: FC<()> = |ctx, props| {
|
||||||
let (selected_stream, set_stream) = use_state(&ctx, || SelectedStream::Football);
|
todo!()
|
||||||
|
// let (selected_stream, set_stream) = use_state(&ctx, || SelectedStream::Football);
|
||||||
|
|
||||||
let options = SelectedStream::iter().map(|name| {
|
// let opts = SelectedStream::iter().map(|name| rsx! { option { "{name}", value: "{name}" } });
|
||||||
rsx! { option { "{name}", value: "{name}" } }
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.render(rsx! {
|
// ctx.render(rsx! {
|
||||||
div {
|
// div {
|
||||||
h1 { "Tide basic CRUD app" }
|
// h1 { "Tide basic CRUD app" }
|
||||||
h2 { "Chosen stream: {selected_stream}" }
|
// h2 { "Chosen stream: {selected_stream}" }
|
||||||
select {
|
// select {
|
||||||
value: {selected_stream.as_ref()}
|
// value: {selected_stream.as_ref()}
|
||||||
"{selected_stream}"
|
// "{selected_stream}"
|
||||||
{options}
|
// {opts}
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Server-specific code
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
mod server {
|
mod server {
|
||||||
use async_std::sync::RwLock;
|
use async_std::sync::RwLock;
|
||||||
|
@ -53,6 +56,8 @@ mod server {
|
||||||
use tide::Request;
|
use tide::Request;
|
||||||
use tide_websockets::{Message, WebSocket, WebSocketConnection};
|
use tide_websockets::{Message, WebSocket, WebSocketConnection};
|
||||||
|
|
||||||
|
use crate::SelectedStream;
|
||||||
|
|
||||||
// type ServerRequest = Request<Arc<RwLock<()>>>;
|
// type ServerRequest = Request<Arc<RwLock<()>>>;
|
||||||
type ServerRequest = Request<()>;
|
type ServerRequest = Request<()>;
|
||||||
// type ServerRequest = Request<Arc<RwLock<ServerState>>>;
|
// type ServerRequest = Request<Arc<RwLock<ServerState>>>;
|
||||||
|
@ -61,11 +66,6 @@ mod server {
|
||||||
|
|
||||||
pub async fn app() -> anyhow::Result<()> {
|
pub async fn app() -> anyhow::Result<()> {
|
||||||
let mut app = tide::new();
|
let mut app = tide::new();
|
||||||
// let mut app = tide::with_state(Arc::new(RwLock::new(())));
|
|
||||||
// let mut app = tide::with_state(ServerState::new());
|
|
||||||
|
|
||||||
// for all examples:
|
|
||||||
// assume the bundle exists at ../public
|
|
||||||
|
|
||||||
app.at("")
|
app.at("")
|
||||||
.serve_dir(format!("{}/pkg", CLIENT_PATH))
|
.serve_dir(format!("{}/pkg", CLIENT_PATH))
|
||||||
|
@ -94,4 +94,89 @@ mod server {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use dioxus_core::prelude::*;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Props)]
|
||||||
|
struct SreamListProps {
|
||||||
|
selected_stream: SelectedStream,
|
||||||
|
}
|
||||||
|
|
||||||
|
static STREAM_LIST: FC<SreamListProps> = |ctx, props| {
|
||||||
|
//
|
||||||
|
match props.selected_stream {
|
||||||
|
SelectedStream::Football => ctx.render(rsx! {
|
||||||
|
li {
|
||||||
|
"watch football!"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
_ => unimplemented!()
|
||||||
|
// .render(ctx),
|
||||||
|
// SelectedStream::Hockey => rsx! {
|
||||||
|
// li {
|
||||||
|
// "watch football!"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// .render(ctx),
|
||||||
|
// SelectedStream::Socker => rsx! {
|
||||||
|
// li {
|
||||||
|
// "watch football!"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// .render(ctx),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
mod ergorsx {
|
||||||
|
|
||||||
|
// struct Ncx {}
|
||||||
|
|
||||||
|
// struct VVNode {}
|
||||||
|
// struct DTree {
|
||||||
|
// // struct DTree<F: Fn(&Ncx) -> VVNode> {
|
||||||
|
// caller: F,
|
||||||
|
// }
|
||||||
|
// impl<F: Fn(&Ncx) -> VVNode> DTree<F> {
|
||||||
|
// fn new(f: F) -> Self {
|
||||||
|
// Self { caller: f }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// trait Renderable {
|
||||||
|
// fn render(self, nodectx: &Ncx) -> VVNode;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl<F: Fn(&Ncx) -> VVNode> Renderable for DTree<F> {
|
||||||
|
// fn render(self, nodectx: &Ncx) -> VVNode {
|
||||||
|
// (self.caller)(nodectx)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn test() {
|
||||||
|
// let t = 123;
|
||||||
|
// let r = match t {
|
||||||
|
// 123 => DTree::new(|f| VVNode {}).render(ctx),
|
||||||
|
// 456 => DTree::new(|f| VVNode {}).render(ctx),
|
||||||
|
// 789 => DTree::new(|f| VVNode {}).render(ctx),
|
||||||
|
// _ => unreachable!(),
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn example() {
|
||||||
|
// rsx! {
|
||||||
|
// div {
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }.render(ctx)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn example() {
|
||||||
|
// ctx.render(rsx!{
|
||||||
|
// div {
|
||||||
|
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue