wip: begint to accept iterator types

This commit is contained in:
Jonathan Kelley 2021-03-18 18:54:26 -04:00
parent f24d29130a
commit 742f150eb3
11 changed files with 528 additions and 143 deletions

View file

@ -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",

View file

@ -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
} }

View file

@ -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 {}
} }
} }

View file

@ -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(())
} }

View file

@ -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;

View file

@ -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
*/

View file

@ -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)
}
}

View file

@ -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(())
} }

View file

@ -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);

View 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 {
}
})
};
}

View file

@ -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 {
// }
// })
// }
} }