Feat: more cleanup
This commit is contained in:
1 parent
cf16090838
commit
5a9155b059
17 files changed
+156
-259
No files matched your search
@@ -62,6 +62,8 @@ pub fn build(config: &Config, _build_config: &BuildConfig) -> Result<()> {
|
||||
let mut child = cmd.spawn()?;
|
||||
let _err_code = child.wait()?;
|
||||
|
||||
info!("Build complete!");
|
||||
|
||||
// [2] Establish the output directory structure
|
||||
let bindgen_outdir = out_dir.join("wasm");
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
use argh::FromArgs;
|
||||
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
@@ -43,6 +42,10 @@ pub struct BuildOptions {
|
||||
/// an example in the crate
|
||||
#[argh(option)]
|
||||
pub example: Option<String>,
|
||||
|
||||
/// develop in release mode
|
||||
#[argh(switch, short = 'r')]
|
||||
pub release: bool,
|
||||
}
|
||||
|
||||
/// 🛠 Start a development server
|
||||
@@ -52,4 +55,8 @@ pub struct DevelopOptions {
|
||||
/// an example in the crate
|
||||
#[argh(option)]
|
||||
pub example: Option<String>,
|
||||
|
||||
/// develop in release mode
|
||||
#[argh(switch, short = 'r')]
|
||||
pub release: bool,
|
||||
}
|
||||
@@ -2,7 +2,6 @@ use crate::{
|
||||
cli::{BuildOptions, DevelopOptions},
|
||||
error::Result,
|
||||
};
|
||||
// use log::{info, warn};
|
||||
use std::{io::Write, path::PathBuf, process::Command};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -70,10 +69,16 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_release(&mut self, release: bool) -> &mut Self {
|
||||
self.release = release;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_build_options(&mut self, options: &BuildOptions) {
|
||||
if let Some(name) = &options.example {
|
||||
self.as_example(name.clone());
|
||||
}
|
||||
self.release = options.release;
|
||||
self.out_dir = options.outdir.clone().into();
|
||||
}
|
||||
|
||||
@@ -81,7 +86,7 @@ impl Config {
|
||||
if let Some(name) = &options.example {
|
||||
self.as_example(name.clone());
|
||||
}
|
||||
let outdir = tempfile::Builder::new().tempdir().expect("").into_path();
|
||||
self.out_dir = outdir;
|
||||
self.release = options.release;
|
||||
self.out_dir = tempfile::Builder::new().tempdir().expect("").into_path();
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,7 @@ async fn watch_directory(config: Config) -> Result<()> {
|
||||
.watch(src_dir.join("examples"), RecursiveMode::Recursive)
|
||||
.expect("Failed to watch dir");
|
||||
|
||||
let build_config = BuildConfig::default();
|
||||
let mut build_config = BuildConfig::default();
|
||||
|
||||
'run: loop {
|
||||
crate::builder::build(&config, &build_config)?;
|
||||
|
||||
@@ -1,41 +1,30 @@
|
||||
use proc_macro::TokenStream;
|
||||
use quote::{quote, quote_spanned, ToTokens};
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{
|
||||
parse::{Parse, ParseStream},
|
||||
Signature,
|
||||
};
|
||||
use syn::{
|
||||
parse_macro_input, Attribute, Block, FnArg, Ident, Item, ItemFn, ReturnType, Type, Visibility,
|
||||
};
|
||||
use quote::ToTokens;
|
||||
use syn::parse_macro_input;
|
||||
|
||||
mod fc;
|
||||
mod htm;
|
||||
mod ifmt;
|
||||
mod rsxt;
|
||||
// mod styles;
|
||||
|
||||
/// The html! macro makes it easy for developers to write jsx-style markup in their components.
|
||||
/// We aim to keep functional parity with html templates.
|
||||
#[proc_macro]
|
||||
pub fn html(s: TokenStream) -> TokenStream {
|
||||
let html: htm::HtmlRender = match syn::parse(s) {
|
||||
Ok(s) => s,
|
||||
Err(e) => return e.to_compile_error().into(),
|
||||
};
|
||||
html.to_token_stream().into()
|
||||
match syn::parse::<htm::HtmlRender>(s) {
|
||||
Err(e) => e.to_compile_error().into(),
|
||||
Ok(s) => s.to_token_stream().into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// The html! macro makes it easy for developers to write jsx-style markup in their components.
|
||||
/// We aim to keep functional parity with html templates.
|
||||
#[proc_macro]
|
||||
pub fn rsx(s: TokenStream) -> TokenStream {
|
||||
let template: rsxt::RsxRender = match syn::parse(s) {
|
||||
Ok(s) => s,
|
||||
Err(e) => return e.to_compile_error().into(),
|
||||
};
|
||||
|
||||
template.to_token_stream().into()
|
||||
match syn::parse::<rsxt::RsxRender>(s) {
|
||||
Err(e) => e.to_compile_error().into(),
|
||||
Ok(s) => s.to_token_stream().into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Label a function or static closure as a functional component.
|
||||
@@ -49,9 +38,6 @@ pub fn fc(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
function_component_impl(item)
|
||||
.unwrap_or_else(|err| err.to_compile_error())
|
||||
.into()
|
||||
|
||||
// function_component_impl(attr, item)
|
||||
// let attr = parse_macro_input!(attr as FunctionComponentName);
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
|
||||
@@ -144,9 +144,9 @@ impl ToTokens for ToToksCtx<&Element> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||
// todo!()
|
||||
// // let ctx = self.ctx;
|
||||
let name = &self.inner.name;
|
||||
let name = &self.inner.name.to_string();
|
||||
tokens.append_all(quote! {
|
||||
dioxus::builder::ElementBuilder::new(ctx, "#name")
|
||||
dioxus::builder::ElementBuilder::new(ctx, #name)
|
||||
});
|
||||
for attr in self.inner.attrs.iter() {
|
||||
self.recurse(attr).to_tokens(tokens);
|
||||
|
||||
@@ -2,7 +2,6 @@ use crate::nodes::VNode;
|
||||
use crate::prelude::*;
|
||||
use bumpalo::Bump;
|
||||
use hooks::Hook;
|
||||
use log::info;
|
||||
use std::{
|
||||
any::TypeId, borrow::Borrow, cell::RefCell, future::Future, marker::PhantomData, ops::Deref,
|
||||
rc::Rc, sync::atomic::AtomicUsize,
|
||||
@@ -56,6 +55,8 @@ impl<'a> Context<'a> {
|
||||
todo!("Children API not yet implemented for component Context")
|
||||
}
|
||||
|
||||
pub fn callback(&self, _f: impl Fn(()) + 'a) {}
|
||||
|
||||
/// Create a subscription that schedules a future render for the reference component
|
||||
pub fn schedule_update(&self) -> impl Fn() -> () {
|
||||
// log::debug!()
|
||||
@@ -63,6 +64,16 @@ impl<'a> Context<'a> {
|
||||
|| {}
|
||||
}
|
||||
|
||||
/// Create a suspended component from a future.
|
||||
///
|
||||
/// When the future completes, the component will be renderered
|
||||
pub fn suspend(
|
||||
&self,
|
||||
_fut: impl Future<Output = impl FnOnce(&'a NodeCtx<'a>) -> VNode<'a>>,
|
||||
) -> VNode<'a> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Take a lazy VNode structure and actually build it with the context of the VDom's efficient VNode allocator.
|
||||
///
|
||||
/// This function consumes the context and absorb the lifetime, so these VNodes *must* be returned.
|
||||
@@ -84,25 +95,12 @@ impl<'a> Context<'a> {
|
||||
idx: 0.into(),
|
||||
scope: self.scope,
|
||||
};
|
||||
// todo!();
|
||||
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) };
|
||||
self.final_nodes.deref().borrow_mut().replace(unsafe_nodes);
|
||||
DomTree {}
|
||||
}
|
||||
|
||||
pub fn callback(&self, _f: impl Fn(()) + 'a) {}
|
||||
|
||||
/// Create a suspended component from a future.
|
||||
///
|
||||
/// When the future completes, the component will be renderered
|
||||
pub fn suspend(
|
||||
&self,
|
||||
_fut: impl Future<Output = impl FnOnce(&'a NodeCtx<'a>) -> VNode<'a>>,
|
||||
) -> VNode<'a> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
// NodeCtx is used to build VNodes in the component's memory space.
|
||||
|
||||
+10
-27
@@ -58,13 +58,11 @@ pub struct DiffMachine<'a> {
|
||||
|
||||
impl<'a> DiffMachine<'a> {
|
||||
pub fn new(bump: &'a Bump) -> Self {
|
||||
// log::debug!("starting diff machine");
|
||||
Self {
|
||||
change_list: EditMachine::new(bump),
|
||||
immediate_queue: Vec::new(),
|
||||
diffed: FxHashSet::default(),
|
||||
need_to_diff: FxHashSet::default(),
|
||||
// current_idx: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,19 +70,13 @@ impl<'a> DiffMachine<'a> {
|
||||
self.change_list.emitter
|
||||
}
|
||||
|
||||
pub fn diff_node(
|
||||
&mut self,
|
||||
old: &VNode<'a>,
|
||||
new: &VNode<'a>,
|
||||
// scope: Option<generational_arena::Index>,
|
||||
) {
|
||||
pub fn diff_node(&mut self, old: &VNode<'a>, new: &VNode<'a>) {
|
||||
/*
|
||||
For each valid case, we "commit traversal", meaning we save this current position in the tree.
|
||||
Then, we diff and queue an edit event (via chagelist). s single trees - when components show up, we save that traversal and then re-enter later.
|
||||
When re-entering, we reuse the EditList in DiffState
|
||||
*/
|
||||
match (old, new) {
|
||||
// This case occurs when two text nodes are generation
|
||||
(VNode::Text(VText { text: old_text }), VNode::Text(VText { text: new_text })) => {
|
||||
if old_text != new_text {
|
||||
self.change_list.commit_traversal();
|
||||
@@ -93,12 +85,8 @@ impl<'a> DiffMachine<'a> {
|
||||
}
|
||||
|
||||
(VNode::Text(_), VNode::Element(_)) => {
|
||||
// TODO: Hook up the events properly
|
||||
// todo!("Hook up events registry");
|
||||
self.change_list.commit_traversal();
|
||||
// diff_support::create(cached_set, self.change_list, registry, new, cached_roots);
|
||||
self.create(new);
|
||||
// registry.remove_subtree(&old);
|
||||
self.change_list.replace_with();
|
||||
}
|
||||
|
||||
@@ -121,30 +109,25 @@ impl<'a> DiffMachine<'a> {
|
||||
self.diff_children(eold.children, enew.children);
|
||||
}
|
||||
|
||||
(VNode::Component(_), VNode::Component(_)) => {
|
||||
(VNode::Component(cold), VNode::Component(cnew)) => {
|
||||
if cold.comp != cnew.comp {
|
||||
// queue an event to mount this new component
|
||||
return;
|
||||
}
|
||||
|
||||
// compare props.... somehow.....
|
||||
|
||||
todo!("Usage of component VNode not currently supported");
|
||||
}
|
||||
|
||||
(_, VNode::Component(_)) => {
|
||||
todo!("Usage of component VNode not currently supported");
|
||||
}
|
||||
|
||||
(VNode::Component(_), _) => {
|
||||
(_, VNode::Component(_)) | (VNode::Component(_), _) => {
|
||||
todo!("Usage of component VNode not currently supported");
|
||||
}
|
||||
|
||||
(VNode::Suspended, _) | (_, VNode::Suspended) => {
|
||||
// (VNode::Element(_), VNode::Suspended) => {}
|
||||
// (VNode::Text(_), VNode::Suspended) => {}
|
||||
// (VNode::Component(_), VNode::Suspended) => {}
|
||||
// (VNode::Suspended, VNode::Element(_)) => {}
|
||||
// (VNode::Suspended, VNode::Text(_)) => {}
|
||||
// (VNode::Suspended, VNode::Suspended) => {}
|
||||
// (VNode::Suspended, VNode::Component(_)) => {}
|
||||
todo!("Suspended components not currently available")
|
||||
}
|
||||
}
|
||||
// self.current_idx = None;
|
||||
}
|
||||
|
||||
// Diff event listeners between `old` and `new`.
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
@@ -13,37 +12,6 @@ pub enum Error {
|
||||
#[error("Base scope has not been mounted yet")]
|
||||
NotMounted,
|
||||
|
||||
// #[error("Out of compute credits")]
|
||||
// OutOfCredits,
|
||||
|
||||
// /// Used when errors need to propogate but are too unique to be typed
|
||||
// #[error("{0}")]
|
||||
// Unique(String),
|
||||
|
||||
// #[error("GraphQL error: {0}")]
|
||||
// GraphQL(String),
|
||||
|
||||
// // TODO(haze): Remove, or make a better error. This is pretty much useless
|
||||
// #[error("GraphQL response mismatch. Got {found} but expected {expected}")]
|
||||
// GraphQLMisMatch {
|
||||
// expected: &'static str,
|
||||
// found: String,
|
||||
// },
|
||||
|
||||
// #[error("Difference detected in SystemTime! {0}")]
|
||||
// SystemTime(#[from] std::time::SystemTimeError),
|
||||
|
||||
// #[error("Failed to parse Integer")]
|
||||
// ParseInt(#[from] std::num::ParseIntError),
|
||||
|
||||
// #[error("")]
|
||||
// MissingAuthentication,
|
||||
|
||||
// #[error("Failed to create experiment run: {0}")]
|
||||
// FailedToCreateExperimentRun(String),
|
||||
|
||||
// #[error("Could not find shared behavior with ID {0}")]
|
||||
// MissingSharedBehavior(String),
|
||||
#[error("I/O Error: {0}")]
|
||||
IO(#[from] std::io::Error),
|
||||
}
|
||||
@@ -28,8 +28,8 @@ mod use_state_def {
|
||||
/// ```ignore
|
||||
/// static Example: FC<()> = |ctx| {
|
||||
/// let (counter, set_counter) = use_state(ctx, || 0);
|
||||
/// let increment = || set_couter(counter + 1);
|
||||
/// let decrement = || set_couter(counter + 1);
|
||||
/// let increment = |_| set_couter(counter + 1);
|
||||
/// let decrement = |_| set_couter(counter + 1);
|
||||
///
|
||||
/// html! {
|
||||
/// <div>
|
||||
|
||||
@@ -442,6 +442,8 @@ where
|
||||
self.children.push(child);
|
||||
self
|
||||
}
|
||||
|
||||
// pub fn virtual_child(mut self)
|
||||
}
|
||||
|
||||
/// Construct a text VNode.
|
||||
|
||||
@@ -296,21 +296,57 @@ mod vtext {
|
||||
/// Virtual Components for custom user-defined components
|
||||
/// Only supports the functional syntax
|
||||
mod vcomponent {
|
||||
use crate::innerlude::FC;
|
||||
use std::marker::PhantomData;
|
||||
use crate::innerlude::{Context, FC};
|
||||
use std::{any::TypeId, marker::PhantomData};
|
||||
|
||||
use super::DomTree;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VComponent<'src> {
|
||||
_p: PhantomData<&'src ()>,
|
||||
props: Box<dyn std::any::Any>,
|
||||
// props: Box<dyn Properties + 'src>,
|
||||
caller: *const (),
|
||||
pub(crate) props: Box<dyn std::any::Any>,
|
||||
pub(crate) props_type: TypeId,
|
||||
pub(crate) comp: *const (),
|
||||
pub(crate) caller: Caller,
|
||||
}
|
||||
|
||||
pub struct Caller(Box<dyn Fn(Context) -> DomTree>);
|
||||
impl std::fmt::Debug for Caller {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> VComponent<'a> {
|
||||
pub fn new<P>(caller: FC<P>, props: P) -> Self {
|
||||
let _caller = caller as *const ();
|
||||
let _props = Box::new(props);
|
||||
// use the type parameter on props creation and move it into a portable context
|
||||
// this lets us keep scope generic *and* downcast its props when we need to:
|
||||
// - perform comparisons when diffing (memoization)
|
||||
// -
|
||||
pub fn new<P>(comp: FC<P>, props: P) -> Self {
|
||||
let caller = move |ctx: Context| {
|
||||
let t = comp(ctx, &props);
|
||||
t
|
||||
};
|
||||
// let _caller = comp as *const ();
|
||||
// let _props = Box::new(props);
|
||||
|
||||
// cast to static?
|
||||
// how do we save the type of props ?
|
||||
// do it in the caller function?
|
||||
// something like
|
||||
|
||||
// the "true" entrpypoint
|
||||
//
|
||||
// |caller| caller.call(fn, Props {})
|
||||
// fn call<P>(f, new_props) {
|
||||
// let old_props = old.downcast_ref::<P>();
|
||||
// if new_props == old_props {
|
||||
// return;
|
||||
// } else {
|
||||
// // set the new props
|
||||
// // call the fn
|
||||
// }
|
||||
// }
|
||||
|
||||
todo!()
|
||||
// Self {
|
||||
|
||||
@@ -107,7 +107,6 @@ pub enum Edit<'d> {
|
||||
RemoveListener {
|
||||
event: &'d str,
|
||||
},
|
||||
// NewListener { event: &'d str, id: usize, s: ScopeIdx },
|
||||
}
|
||||
|
||||
pub type EditList<'src> = Vec<Edit<'src>>;
|
||||
@@ -167,40 +166,17 @@ impl<'b> EditMachine<'b> {
|
||||
|
||||
pub fn commit_traversal(&mut self) {
|
||||
if self.traversal.is_committed() {
|
||||
log::debug!("Traversal already committed");
|
||||
return;
|
||||
}
|
||||
|
||||
for mv in self.traversal.commit() {
|
||||
match mv {
|
||||
MoveTo::Parent => {
|
||||
log::debug!("emit: pop");
|
||||
self.emitter.push(Edit::Pop {});
|
||||
// self.emitter.pop();
|
||||
}
|
||||
MoveTo::Child(n) => {
|
||||
log::debug!("emit: push_child({})", n);
|
||||
self.emitter.push(Edit::PushChild { n });
|
||||
}
|
||||
MoveTo::ReverseChild(n) => {
|
||||
log::debug!("emit: push_reverse_child({})", n);
|
||||
self.emitter.push(Edit::PushReverseChild { n });
|
||||
// self.emitter.push_reverse_child(n);
|
||||
}
|
||||
MoveTo::Sibling(n) => {
|
||||
log::debug!("emit: pop_push_child({})", n);
|
||||
self.emitter.push(Edit::PopPushChild { n });
|
||||
// self.emitter.pop_push_child(n);
|
||||
}
|
||||
MoveTo::ReverseSibling(n) => {
|
||||
log::debug!("emit: pop_push_reverse_child({})", n);
|
||||
self.emitter.push(Edit::PopPushReverseChild { n });
|
||||
}
|
||||
MoveTo::TempChild(temp) => {
|
||||
log::debug!("emit: push_temporary({})", temp);
|
||||
self.emitter.push(Edit::PushTemporary { temp });
|
||||
// self.emitter.push_temporary(temp);
|
||||
}
|
||||
MoveTo::Parent => self.emitter.push(Edit::Pop {}),
|
||||
MoveTo::Child(n) => self.emitter.push(Edit::PushChild { n }),
|
||||
MoveTo::ReverseChild(n) => self.emitter.push(Edit::PushReverseChild { n }),
|
||||
MoveTo::Sibling(n) => self.emitter.push(Edit::PopPushChild { n }),
|
||||
MoveTo::ReverseSibling(n) => self.emitter.push(Edit::PopPushReverseChild { n }),
|
||||
MoveTo::TempChild(temp) => self.emitter.push(Edit::PushTemporary { temp }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+31
-99
@@ -227,6 +227,8 @@ impl ActiveFrame {
|
||||
true => &self.frames[0],
|
||||
false => &self.frames[1],
|
||||
};
|
||||
|
||||
// Give out our self-referential item with our own borrowed lifetime
|
||||
unsafe {
|
||||
let unsafe_head = &raw_node.head_node;
|
||||
let safe_node = std::mem::transmute::<&VNode<'static>, &VNode<'b>>(unsafe_head);
|
||||
@@ -240,6 +242,7 @@ impl ActiveFrame {
|
||||
false => &self.frames[1],
|
||||
};
|
||||
|
||||
// Give out our self-referential item with our own borrowed lifetime
|
||||
unsafe {
|
||||
let unsafe_head = &raw_node.head_node;
|
||||
let safe_node = std::mem::transmute::<&VNode<'static>, &VNode<'b>>(unsafe_head);
|
||||
@@ -250,56 +253,28 @@ impl ActiveFrame {
|
||||
fn next(&mut self) -> &mut BumpFrame {
|
||||
self.idx.fetch_add(1, Ordering::Relaxed);
|
||||
let cur = self.idx.borrow().load(Ordering::Relaxed);
|
||||
log::debug!("Next frame! {}", cur);
|
||||
|
||||
if cur % 2 == 0 {
|
||||
log::debug!("Chosing frame 0");
|
||||
&mut self.frames[0]
|
||||
} else {
|
||||
log::debug!("Chosing frame 1");
|
||||
&mut self.frames[1]
|
||||
}
|
||||
// match cur % 1 {
|
||||
// 0 => {
|
||||
// }
|
||||
// 1 => {
|
||||
// }
|
||||
// _ => unreachable!("mod cannot by non-zero"),
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::prelude::bumpalo;
|
||||
// use crate::prelude::bumpalo::collections::string::String;
|
||||
use crate::prelude::format_args_f;
|
||||
use crate::prelude::*;
|
||||
|
||||
static ListenerTest: FC<()> = |ctx, props| {
|
||||
ctx.render(move |c| {
|
||||
//
|
||||
builder::ElementBuilder::new(c, "div").finish()
|
||||
ctx.render(html! {
|
||||
<div onclick={|_| println!("Hell owlrld")}>
|
||||
"hello"
|
||||
</div>
|
||||
})
|
||||
// ctx.render(html! {
|
||||
// <div onclick={|_| println!("Hell owlrld")}>
|
||||
// "hello"
|
||||
// </div>
|
||||
// })
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn check_listeners() -> Result<()> {
|
||||
todo!()
|
||||
// let mut scope = Scope::new::<(), ()>(ListenerTest, (), None);
|
||||
// scope.run::<()>();
|
||||
|
||||
// let nodes = scope.new_frame();
|
||||
// dbg!(nodes);
|
||||
|
||||
// Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scope() {
|
||||
let example: FC<()> = |ctx, props| {
|
||||
@@ -316,7 +291,6 @@ mod tests {
|
||||
let mut nodes = generational_arena::Arena::new();
|
||||
nodes.insert_with(|f| {
|
||||
let scope = Scope::new::<(), ()>(example, props, f, parent);
|
||||
//
|
||||
});
|
||||
}
|
||||
|
||||
@@ -324,103 +298,61 @@ mod tests {
|
||||
struct ExampleProps<'src> {
|
||||
name: &'src String,
|
||||
}
|
||||
// impl<'src> Properties<'src> for ExampleProps<'src> {}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct EmptyProps<'src> {
|
||||
name: &'src String,
|
||||
}
|
||||
// impl<'src> Properties<'src> for EmptyProps<'src> {}
|
||||
|
||||
use crate::{builder::*, hooks::use_ref};
|
||||
|
||||
fn example_fc<'a>(ctx: Context<'a>, props: &'a EmptyProps) -> DomTree {
|
||||
// fn example_fc<'a>(ctx: Context<'a>, props: &'a EmptyProps<'a>) -> DomTree {
|
||||
let (content, _): (&'a String, _) = crate::hooks::use_state(&ctx, || "abcd".to_string());
|
||||
// let (content, _): (&'a String, _) = crate::hooks::use_state(&ctx, || "abcd".to_string());
|
||||
// let (text, set_val) = crate::hooks::use_state(&ctx, || "abcd".to_string());
|
||||
|
||||
let childprops: ExampleProps<'a> = ExampleProps { name: content };
|
||||
// let childprops: ExampleProps<'a> = ExampleProps { name: content };
|
||||
ctx.render(move |ctx| {
|
||||
todo!()
|
||||
// let b = ctx.bump();
|
||||
// div(b)
|
||||
// .child(text(props.name))
|
||||
// // .child(text(props.name))
|
||||
// .child(virtual_child::<ExampleProps>(b, childprops, child_example))
|
||||
// // .child(virtual_child::<ExampleProps<'a>>(b, childprops, CHILD))
|
||||
// // as for<'scope> fn(Context<'_>, &'scope ExampleProps<'scope>) -> DomTree
|
||||
// // |ctx, pops| todo!(),
|
||||
// // .child(virtual_child::<'a>(
|
||||
// // b,
|
||||
// // child_example,
|
||||
// // ExampleProps { name: text },
|
||||
// // ))
|
||||
// .finish()
|
||||
ctx.render(move |c| {
|
||||
builder::ElementBuilder::new(c, "div")
|
||||
.child(text(props.name))
|
||||
.child(virtual_child::<ExampleProps>(
|
||||
c.bump,
|
||||
childprops,
|
||||
child_example,
|
||||
))
|
||||
.finish()
|
||||
})
|
||||
}
|
||||
|
||||
fn child_example<'b>(ctx: Context<'b>, props: &'b ExampleProps) -> DomTree {
|
||||
ctx.render(move |ctx| {
|
||||
todo!()
|
||||
// div(ctx.bump())
|
||||
// .child(text(props.name))
|
||||
// //
|
||||
// .finish()
|
||||
builder::ElementBuilder::new(ctx, "div")
|
||||
.child(text(props.name))
|
||||
.finish()
|
||||
})
|
||||
}
|
||||
|
||||
static CHILD: FC<ExampleProps> = |ctx, props: &'_ ExampleProps| {
|
||||
// todo!()
|
||||
ctx.render(move |ctx| {
|
||||
todo!()
|
||||
// div(ctx.bump())
|
||||
// .child(text(props.name))
|
||||
// //
|
||||
// .finish()
|
||||
builder::ElementBuilder::new(ctx, "div")
|
||||
.child(text(props.name))
|
||||
.finish()
|
||||
})
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_borrowed_scope() {
|
||||
// use crate::builder::*;
|
||||
|
||||
let example: FC<EmptyProps> = |ctx, props| {
|
||||
// render counter
|
||||
// let mut val = crate::hooks::use_ref(&ctx, || 0);
|
||||
// val.modify(|f| {
|
||||
// *f += 1;
|
||||
// });
|
||||
// dbg!(val.current());
|
||||
// only needs to be valid when ran?
|
||||
// can only borrow from parent?
|
||||
// props are boxed in parent's scope?
|
||||
// passing complex structures down to child?
|
||||
// stored value
|
||||
// let (text, set_val) = crate::hooks::use_state(&ctx, || "abcd".to_string());
|
||||
|
||||
ctx.render(move |b| {
|
||||
todo!()
|
||||
// div(b)
|
||||
// // .child(text(props.name))
|
||||
// // .child(virtual_child(b, CHILD, ExampleProps { name: val.as_str() }))
|
||||
// .child(virtual_child(b, CHILD, ExampleProps { name: }))
|
||||
// .finish()
|
||||
builder::ElementBuilder::new(b, "div")
|
||||
.child(virtual_child(
|
||||
b.bump,
|
||||
ExampleProps { name: props.name },
|
||||
CHILD,
|
||||
))
|
||||
.finish()
|
||||
})
|
||||
};
|
||||
|
||||
let source_text = "abcd123".to_string();
|
||||
let props = ExampleProps { name: &source_text };
|
||||
|
||||
// let parent = None;
|
||||
// let mut scope =
|
||||
// Scope::new::<EmptyProps, EmptyProps>(example, EmptyProps { name: &() }, parent);
|
||||
// scope.run::<ExampleProps>();
|
||||
// scope.run::<ExampleProps>();
|
||||
// scope.run::<ExampleProps>();
|
||||
// scope.run::<ExampleProps>();
|
||||
// scope.run::<ExampleProps>();
|
||||
// let nodes = scope.current_root_node();
|
||||
// dbg!(nodes);
|
||||
}
|
||||
}
|
||||
@@ -25,11 +25,12 @@ pub struct VirtualDom {
|
||||
/// Will not be ready if the dom is fresh
|
||||
base_scope: ScopeIdx,
|
||||
|
||||
event_queue: Rc<RefCell<VecDeque<LifecycleEvent>>>,
|
||||
event_queue: RefCell<VecDeque<LifecycleEvent>>,
|
||||
|
||||
// todo: encapsulate more state into this so we can better reuse it
|
||||
diff_bump: Bump,
|
||||
|
||||
// Type of the original props. This is done so VirtualDom does not need to be generic.
|
||||
#[doc(hidden)]
|
||||
_root_prop_type: std::any::TypeId,
|
||||
}
|
||||
@@ -51,7 +52,7 @@ impl VirtualDom {
|
||||
pub fn new_with_props<P: 'static>(root: FC<P>, root_props: P) -> Self {
|
||||
let mut components = Arena::new();
|
||||
|
||||
let event_queue = Rc::new(RefCell::new(VecDeque::new()));
|
||||
let event_queue = RefCell::new(VecDeque::new());
|
||||
|
||||
// Create a reference to the component in the arena
|
||||
// Note: we are essentially running the "Mount" lifecycle event manually while the vdom doesnt yet exist
|
||||
@@ -212,7 +213,7 @@ impl VirtualDom {
|
||||
|
||||
/// Pop the top event of the internal lifecycle event queu
|
||||
pub fn pop_event(&self) -> Option<LifecycleEvent> {
|
||||
self.event_queue.as_ref().borrow_mut().pop_front()
|
||||
self.event_queue.borrow_mut().pop_front()
|
||||
}
|
||||
|
||||
/// With access to the virtual dom, schedule an update to the Root component's props.
|
||||
|
||||
@@ -8,15 +8,14 @@ use dioxus_web::WebsysRenderer;
|
||||
// static IMG: ImgAsset = dioxus_asset!("");
|
||||
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
console_error_panic_hook::set_once();
|
||||
// wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
// console_error_panic_hook::set_once();
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example))
|
||||
}
|
||||
|
||||
static Example: FC<()> = |ctx, props| {
|
||||
let (name, set_name) = use_state(&ctx, || "...?");
|
||||
|
||||
let handler = move |_| set_name("jill");
|
||||
|
||||
ctx.render(rsx! {
|
||||
div {
|
||||
@@ -36,12 +35,14 @@ static Example: FC<()> = |ctx, props| {
|
||||
}
|
||||
button {
|
||||
class: "inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
|
||||
onfocus: {handler}
|
||||
onmouseover: move |_| {
|
||||
set_name("jill");
|
||||
}
|
||||
onmouseover: move |_| set_name("jill")
|
||||
"Jill!"
|
||||
}
|
||||
button {
|
||||
class: "inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
|
||||
onmouseover: move |e| set_name("....")
|
||||
"Reset!"
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
@@ -76,27 +76,27 @@ impl WebsysRenderer {
|
||||
// todo: initialize the event registry properly on the root
|
||||
|
||||
self.internal_dom.rebuild()?.iter().for_each(|edit| {
|
||||
log::debug!("patching with {:?}", edit);
|
||||
// log::debug!("patching with {:?}", edit);
|
||||
patch_machine.handle_edit(edit);
|
||||
});
|
||||
log::debug!("patch stack size {:?}", patch_machine.stack);
|
||||
// log::debug!("patch stack size {:?}", patch_machine.stack);
|
||||
|
||||
// Event loop waits for the receiver to finish up
|
||||
// TODO! Connect the sender to the virtual dom's suspense system
|
||||
// Suspense is basically an external event that can force renders to specific nodes
|
||||
while let Some(event) = receiver.next().await {
|
||||
log::debug!("patch stack size before {:#?}", patch_machine.stack);
|
||||
// log::debug!("patch stack size before {:#?}", patch_machine.stack);
|
||||
// patch_machine.reset();
|
||||
// patch_machine.stack.push(root_node.clone());
|
||||
self.internal_dom
|
||||
.progress_with_event(event)?
|
||||
.iter()
|
||||
.for_each(|edit| {
|
||||
log::debug!("edit stream {:?}", edit);
|
||||
// log::debug!("edit stream {:?}", edit);
|
||||
patch_machine.handle_edit(edit);
|
||||
});
|
||||
|
||||
log::debug!("patch stack size after {:#?}", patch_machine.stack);
|
||||
// log::debug!("patch stack size after {:#?}", patch_machine.stack);
|
||||
patch_machine.reset();
|
||||
// our root node reference gets invalidated
|
||||
// not sure why
|
||||
|
||||
Reference in new issue
Block a user