mirror of
https://github.com/DioxusLabs/dioxus
synced 2025-02-16 21:58:25 +00:00
WIP: moving to CbIdx as serializable event system
This commit is contained in:
parent
e4b1f6ea0d
commit
e840f472fa
9 changed files with 160 additions and 200 deletions
|
@ -16,11 +16,9 @@ static Example: FC<()> = |ctx| {
|
||||||
|
|
||||||
ctx.view(html! {
|
ctx.view(html! {
|
||||||
<div>
|
<div>
|
||||||
|
<h1> "Hello, {value}" </h1>
|
||||||
<button onclick={move |_| set_value("world!")}> "?" </button>
|
<button onclick={move |_| set_value("world!")}> "?" </button>
|
||||||
<button onclick={move |_| set_value("Dioxus 🎉")}> "?" </button>
|
<button onclick={move |_| set_value("Dioxus 🎉")}> "?" </button>
|
||||||
<div>
|
|
||||||
<h1> "Hello, {value}" </h1>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
# Project: Web-View 🤲 🍨
|
|
||||||
> Proof of concept: stream render edits from server to client
|
|
||||||
- [x] Prove that the diffing and patching framework can support patch streaming
|
|
||||||
|
|
||||||
|
|
||||||
# Project: Live-View 🤲 🍨
|
# Project: Live-View 🤲 🍨
|
||||||
|
@ -8,6 +6,7 @@
|
||||||
|
|
||||||
|
|
||||||
# Project: Sanitization (TBD)
|
# Project: Sanitization (TBD)
|
||||||
|
> Improve code health
|
||||||
- [ ] (Macro) Clippy sanity for html macro
|
- [ ] (Macro) Clippy sanity for html macro
|
||||||
- [ ] (Macro) Error sanitization
|
- [ ] (Macro) Error sanitization
|
||||||
|
|
||||||
|
@ -22,13 +21,19 @@
|
||||||
# Project: Concurrency (TBD)
|
# Project: Concurrency (TBD)
|
||||||
> Ensure the concurrency model works well, play with lifetimes to check if it can be multithreaded + halted
|
> Ensure the concurrency model works well, play with lifetimes to check if it can be multithreaded + halted
|
||||||
|
|
||||||
|
|
||||||
|
# Project: Web-View 🤲 🍨
|
||||||
|
> Proof of concept: stream render edits from server to client
|
||||||
|
- [x] Prove that the diffing and patching framework can support patch streaming
|
||||||
|
|
||||||
# Project: Web_sys renderer (TBD)
|
# Project: Web_sys renderer (TBD)
|
||||||
- [ ] (Web) Web-sys renderer and web tests
|
- [x] WebSys edit interpreter
|
||||||
|
- [ ] Event system using async channels
|
||||||
|
|
||||||
# Project: String Render (TBD)
|
# Project: String Render (TBD)
|
||||||
> Implement a light-weight string renderer with basic caching
|
> Implement a light-weight string renderer with basic caching
|
||||||
- [ ] (SSR) Implement stateful 3rd party string renderer
|
- [ ] (SSR) Implement stateful 3rd party string renderer
|
||||||
- [ ] (Macro) Make VText nodes automatically capture and format IE allow "Text is {blah}" in place of {format!("Text is {}",blah)}
|
- [x] (Macro) Make VText nodes automatically capture and format IE allow "Text is {blah}"
|
||||||
|
|
||||||
# Project: Hooks + Context + Subscriptions (TBD)
|
# Project: Hooks + Context + Subscriptions (TBD)
|
||||||
> Implement the foundations for state management
|
> Implement the foundations for state management
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
|
||||||
use crate::innerlude::Listener;
|
use crate::innerlude::Listener;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
/// The `Edit` represents a single modifcation of the renderer tree.
|
/// The `Edit` represents a single modifcation of the renderer tree.
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
|
@ -33,7 +33,7 @@ use crate::innerlude::Listener;
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// todo@ jon: allow serde to be optional
|
/// todo@ jon: allow serde to be optional
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(tag = "type")]
|
#[serde(tag = "type")]
|
||||||
pub enum Edit<'d> {
|
pub enum Edit<'d> {
|
||||||
SetText { text: &'d str },
|
SetText { text: &'d str },
|
||||||
|
@ -47,8 +47,8 @@ pub enum Edit<'d> {
|
||||||
AppendChild,
|
AppendChild,
|
||||||
CreateTextNode { text: &'d str },
|
CreateTextNode { text: &'d str },
|
||||||
CreateElement { tag_name: &'d str },
|
CreateElement { tag_name: &'d str },
|
||||||
NewEventListener { event_type: &'d str, a: u32, b: u32 },
|
NewEventListener { event_type: &'d str, idx: CbIdx },
|
||||||
UpdateEventListener { event_type: &'d str, a: u32, b: u32 },
|
UpdateEventListener { event_type: &'d str, idx: CbIdx },
|
||||||
RemoveEventListener { event_type: &'d str },
|
RemoveEventListener { event_type: &'d str },
|
||||||
CreateElementNs { tag_name: &'d str, ns: &'d str },
|
CreateElementNs { tag_name: &'d str, ns: &'d str },
|
||||||
SaveChildrenToTemporaries { temp: u32, start: u32, end: u32 },
|
SaveChildrenToTemporaries { temp: u32, start: u32, end: u32 },
|
||||||
|
@ -60,6 +60,26 @@ pub enum Edit<'d> {
|
||||||
SetClass { class_name: &'d str },
|
SetClass { class_name: &'d str },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Re-export a cover over generational ID for libraries that don't need it
|
||||||
|
/// We can go back and forth between the two via methods on GI
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
|
pub struct CbIdx {
|
||||||
|
gi_id: usize,
|
||||||
|
gi_gen: u64,
|
||||||
|
listener_idx: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CbIdx {
|
||||||
|
pub fn from_gi_index(index: generational_arena::Index, listener_idx: usize) -> Self {
|
||||||
|
let (gi_id, gi_gen) = index.into_raw_parts();
|
||||||
|
Self {
|
||||||
|
gi_id,
|
||||||
|
gi_gen,
|
||||||
|
listener_idx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type EditList<'src> = Vec<Edit<'src>>;
|
pub type EditList<'src> = Vec<Edit<'src>>;
|
||||||
|
|
||||||
pub struct EditMachine<'src> {
|
pub struct EditMachine<'src> {
|
||||||
|
@ -306,38 +326,41 @@ impl<'a> EditMachine<'a> {
|
||||||
self.forcing_new_listeners = previous;
|
self.forcing_new_listeners = previous;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_event_listener(&mut self, listener: &Listener) {
|
pub fn new_event_listener(&mut self, event: &'a str, idx: CbIdx) {
|
||||||
debug_assert!(self.traversal_is_committed());
|
debug_assert!(self.traversal_is_committed());
|
||||||
// todo!("Event listener not wired up yet");
|
|
||||||
log::debug!("emit: new_event_listener({:?})", listener);
|
|
||||||
let (a, b) = listener.get_callback_parts();
|
|
||||||
debug_assert!(a != 0);
|
|
||||||
// let event_id = self.ensure_string(listener.event);
|
|
||||||
self.emitter.push(Edit::NewEventListener {
|
self.emitter.push(Edit::NewEventListener {
|
||||||
event_type: listener.event.into(),
|
event_type: event,
|
||||||
a,
|
idx,
|
||||||
b,
|
|
||||||
});
|
});
|
||||||
|
// todo!("Event listener not wired up yet");
|
||||||
|
// log::debug!("emit: new_event_listener({:?})", listener);
|
||||||
|
// let (a, b) = listener.get_callback_parts();
|
||||||
|
// debug_assert!(a != 0);
|
||||||
|
// // let event_id = self.ensure_string(listener.event);
|
||||||
// self.emitter.new_event_listener(listener.event.into(), a, b);
|
// self.emitter.new_event_listener(listener.event.into(), a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_event_listener(&mut self, listener: &Listener) {
|
pub fn update_event_listener(&mut self, event: &'a str, idx: CbIdx) {
|
||||||
debug_assert!(self.traversal_is_committed());
|
debug_assert!(self.traversal_is_committed());
|
||||||
|
|
||||||
if self.forcing_new_listeners {
|
if self.forcing_new_listeners {
|
||||||
self.new_event_listener(listener);
|
self.new_event_listener(event, idx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log::debug!("emit: update_event_listener({:?})", listener);
|
self.emitter.push(Edit::NewEventListener {
|
||||||
// todo!("Event listener not wired up yet");
|
event_type: event,
|
||||||
let (a, b) = listener.get_callback_parts();
|
idx,
|
||||||
debug_assert!(a != 0);
|
|
||||||
self.emitter.push(Edit::UpdateEventListener {
|
|
||||||
event_type: listener.event.into(),
|
|
||||||
a,
|
|
||||||
b,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// log::debug!("emit: update_event_listener({:?})", listener);
|
||||||
|
// // todo!("Event listener not wired up yet");
|
||||||
|
// let (a, b) = listener.get_callback_parts();
|
||||||
|
// debug_assert!(a != 0);
|
||||||
|
// self.emitter.push(Edit::UpdateEventListener {
|
||||||
|
// event_type: listener.event.into(),
|
||||||
|
// a,
|
||||||
|
// b,
|
||||||
|
// });
|
||||||
// self.emitter.update_event_listener(event_id.into(), a, b);
|
// self.emitter.update_event_listener(event_id.into(), a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,9 +44,9 @@ pub struct Context<'src> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Context<'a> {
|
impl<'a> Context<'a> {
|
||||||
pub fn props<P>() -> &'a P {
|
// pub fn props<P>() -> &'a P {
|
||||||
todo!()
|
// todo!()
|
||||||
}
|
// }
|
||||||
|
|
||||||
// impl<'a, PropType> Context<'a, PropType> {
|
// impl<'a, PropType> Context<'a, PropType> {
|
||||||
/// Access the children elements passed into the component
|
/// Access the children elements passed into the component
|
||||||
|
@ -56,7 +56,8 @@ impl<'a> Context<'a> {
|
||||||
|
|
||||||
/// Create a subscription that schedules a future render for the reference component
|
/// Create a subscription that schedules a future render for the reference component
|
||||||
pub fn schedule_update(&self) -> impl Fn() -> () {
|
pub fn schedule_update(&self) -> impl Fn() -> () {
|
||||||
todo!("Subscription API is not ready yet");
|
// log::debug!()
|
||||||
|
// todo!("Subscription API is not ready yet");
|
||||||
|| {}
|
|| {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ use fxhash::{FxHashMap, FxHashSet};
|
||||||
use generational_arena::Index;
|
use generational_arena::Index;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
changelist::{Edit, EditList, EditMachine},
|
changelist::{CbIdx, Edit, EditList, EditMachine},
|
||||||
innerlude::{Attribute, Listener, Scope, VElement, VNode, VText},
|
innerlude::{Attribute, Listener, Scope, VElement, VNode, VText},
|
||||||
virtual_dom::LifecycleEvent,
|
virtual_dom::LifecycleEvent,
|
||||||
};
|
};
|
||||||
|
@ -61,16 +61,20 @@ pub struct DiffMachine<'a> {
|
||||||
immediate_queue: Vec<Index>,
|
immediate_queue: Vec<Index>,
|
||||||
diffed: FxHashSet<Index>,
|
diffed: FxHashSet<Index>,
|
||||||
need_to_diff: FxHashSet<Index>,
|
need_to_diff: FxHashSet<Index>,
|
||||||
|
|
||||||
|
// Current scopes we're comparing
|
||||||
|
current_idx: Option<generational_arena::Index>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DiffMachine<'a> {
|
impl<'a> DiffMachine<'a> {
|
||||||
pub fn new(bump: &'a Bump) -> Self {
|
pub fn new(bump: &'a Bump) -> Self {
|
||||||
log::debug!("starsting diff machine");
|
log::debug!("starting diff machine");
|
||||||
Self {
|
Self {
|
||||||
change_list: EditMachine::new(bump),
|
change_list: EditMachine::new(bump),
|
||||||
immediate_queue: Vec::new(),
|
immediate_queue: Vec::new(),
|
||||||
diffed: FxHashSet::default(),
|
diffed: FxHashSet::default(),
|
||||||
need_to_diff: FxHashSet::default(),
|
need_to_diff: FxHashSet::default(),
|
||||||
|
current_idx: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,8 +82,17 @@ impl<'a> DiffMachine<'a> {
|
||||||
self.change_list.emitter
|
self.change_list.emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn diff_node(&mut self, old: &VNode<'a>, new: &VNode<'a>) {
|
pub fn diff_node(
|
||||||
|
&mut self,
|
||||||
|
old: &VNode<'a>,
|
||||||
|
new: &VNode<'a>,
|
||||||
|
scope: Option<generational_arena::Index>,
|
||||||
|
) {
|
||||||
log::debug!("Diffing nodes");
|
log::debug!("Diffing nodes");
|
||||||
|
|
||||||
|
// Set it while diffing
|
||||||
|
// Reset it when finished diffing
|
||||||
|
self.current_idx = scope;
|
||||||
/*
|
/*
|
||||||
For each valid case, we "commit traversal", meaning we save this current position in the tree.
|
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.
|
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.
|
||||||
|
@ -222,6 +235,7 @@ impl<'a> DiffMachine<'a> {
|
||||||
todo!("Suspended components not currently available")
|
todo!("Suspended components not currently available")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.current_idx = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Diff event listeners between `old` and `new`.
|
// Diff event listeners between `old` and `new`.
|
||||||
|
@ -237,16 +251,20 @@ impl<'a> DiffMachine<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
'outer1: for new_l in new {
|
'outer1: for new_l in new {
|
||||||
unsafe {
|
// unsafe {
|
||||||
// Safety relies on removing `new_l` from the registry manually at
|
// Safety relies on removing `new_l` from the registry manually at
|
||||||
// the end of its lifetime. This happens below in the `'outer2`
|
// the end of its lifetime. This happens below in the `'outer2`
|
||||||
// loop, and elsewhere in diffing when removing old dom trees.
|
// loop, and elsewhere in diffing when removing old dom trees.
|
||||||
// registry.add(new_l);
|
// registry.add(new_l);
|
||||||
}
|
// }
|
||||||
|
|
||||||
for old_l in old {
|
for (l_idx, old_l) in old.iter().enumerate() {
|
||||||
if new_l.event == old_l.event {
|
if new_l.event == old_l.event {
|
||||||
self.change_list.update_event_listener(new_l);
|
let event_type = new_l.event;
|
||||||
|
if let Some(scope) = self.current_idx {
|
||||||
|
let cb = CbIdx::from_gi_index(scope, l_idx);
|
||||||
|
self.change_list.update_event_listener(event_type, cb);
|
||||||
|
}
|
||||||
continue 'outer1;
|
continue 'outer1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -507,7 +525,7 @@ impl<'a> DiffMachine<'a> {
|
||||||
|
|
||||||
self.change_list.go_to_sibling(i);
|
self.change_list.go_to_sibling(i);
|
||||||
|
|
||||||
self.diff_node(old, new);
|
self.diff_node(old, new, self.current_idx);
|
||||||
|
|
||||||
shared_prefix_count += 1;
|
shared_prefix_count += 1;
|
||||||
}
|
}
|
||||||
|
@ -705,7 +723,7 @@ impl<'a> DiffMachine<'a> {
|
||||||
// [... parent]
|
// [... parent]
|
||||||
self.change_list.go_down_to_temp_child(temp);
|
self.change_list.go_down_to_temp_child(temp);
|
||||||
// [... parent last]
|
// [... parent last]
|
||||||
self.diff_node(&old[old_index], last);
|
self.diff_node(&old[old_index], last, self.current_idx);
|
||||||
|
|
||||||
if new_index_is_in_lis.contains(&last_index) {
|
if new_index_is_in_lis.contains(&last_index) {
|
||||||
// Don't move it, since it is already where it needs to be.
|
// Don't move it, since it is already where it needs to be.
|
||||||
|
@ -758,7 +776,7 @@ impl<'a> DiffMachine<'a> {
|
||||||
// [... parent new_child]
|
// [... parent new_child]
|
||||||
}
|
}
|
||||||
|
|
||||||
self.diff_node(&old[old_index], new_child);
|
self.diff_node(&old[old_index], new_child, self.current_idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -789,8 +807,7 @@ impl<'a> DiffMachine<'a> {
|
||||||
|
|
||||||
for (i, (old_child, new_child)) in old.iter().zip(new.iter()).enumerate() {
|
for (i, (old_child, new_child)) in old.iter().zip(new.iter()).enumerate() {
|
||||||
self.change_list.go_to_sibling(new_shared_suffix_start + i);
|
self.change_list.go_to_sibling(new_shared_suffix_start + i);
|
||||||
|
self.diff_node(old_child, new_child, self.current_idx);
|
||||||
self.diff_node(old_child, new_child);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// [... parent]
|
// [... parent]
|
||||||
|
@ -818,7 +835,7 @@ impl<'a> DiffMachine<'a> {
|
||||||
// [... parent prev_child]
|
// [... parent prev_child]
|
||||||
self.change_list.go_to_sibling(i);
|
self.change_list.go_to_sibling(i);
|
||||||
// [... parent this_child]
|
// [... parent this_child]
|
||||||
self.diff_node(old_child, new_child);
|
self.diff_node(old_child, new_child, self.current_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
match old.len().cmp(&new.len()) {
|
match old.len().cmp(&new.len()) {
|
||||||
|
@ -880,12 +897,21 @@ impl<'a> DiffMachine<'a> {
|
||||||
self.change_list.create_element(tag_name);
|
self.change_list.create_element(tag_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
for l in listeners {
|
listeners.iter().enumerate().for_each(|(id, listener)| {
|
||||||
// unsafe {
|
if let Some(index) = self.current_idx {
|
||||||
// registry.add(l);
|
self.change_list
|
||||||
// }
|
.new_event_listener(listener.event, CbIdx::from_gi_index(index, id));
|
||||||
self.change_list.new_event_listener(l);
|
} else {
|
||||||
}
|
// Don't panic
|
||||||
|
// Used for testing
|
||||||
|
log::trace!("Failed to set listener, create was not called in the context of the virtual dom");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// for l in listeners {
|
||||||
|
// unsafe {
|
||||||
|
// registry.add(l);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
for attr in attributes {
|
for attr in attributes {
|
||||||
self.change_list
|
self.change_list
|
||||||
|
|
|
@ -96,6 +96,7 @@ pub(crate) mod innerlude {
|
||||||
pub(crate) use crate::virtual_dom::VirtualDom;
|
pub(crate) use crate::virtual_dom::VirtualDom;
|
||||||
pub(crate) use nodes::*;
|
pub(crate) use nodes::*;
|
||||||
|
|
||||||
|
pub use crate::changelist::CbIdx;
|
||||||
// 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.
|
||||||
|
|
||||||
|
@ -151,119 +152,3 @@ pub mod prelude {
|
||||||
|
|
||||||
pub use crate::hooks::*;
|
pub use crate::hooks::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[macro_use]
|
|
||||||
// extern crate dioxus_core_macro;
|
|
||||||
|
|
||||||
// #[macro_use]
|
|
||||||
// extern crate fstrings;
|
|
||||||
// pub use dioxus_core_macro::format_args_f;
|
|
||||||
// macro_rules! mk_macros {( @with_dollar![$dol:tt]=>
|
|
||||||
// $(
|
|
||||||
// #[doc = $doc_string:literal]
|
|
||||||
// $printlnf:ident
|
|
||||||
// => $println:ident!($($stream:ident,)? ...)
|
|
||||||
// ,
|
|
||||||
// )*
|
|
||||||
// ) => (
|
|
||||||
// $(
|
|
||||||
// #[doc = $doc_string]
|
|
||||||
// #[macro_export]
|
|
||||||
// macro_rules! $printlnf {(
|
|
||||||
// $($dol $stream : expr,)? $dol($dol args:tt)*
|
|
||||||
// ) => (
|
|
||||||
// $println!($($dol $stream,)? "{}", format_args_f!($dol($dol args)*))
|
|
||||||
// )}
|
|
||||||
// )*
|
|
||||||
// )}
|
|
||||||
|
|
||||||
// mk_macros! { @with_dollar![$]=>
|
|
||||||
// #[doc = "Like [`print!`](https://doc.rust-lang.org/std/macro.print.html), but with basic f-string interpolation."]
|
|
||||||
// print_f
|
|
||||||
// => print!(...)
|
|
||||||
// ,
|
|
||||||
// #[doc = "Like [`println!`](https://doc.rust-lang.org/std/macro.println.html), but with basic f-string interpolation."]
|
|
||||||
// println_f
|
|
||||||
// => println!(...)
|
|
||||||
// ,
|
|
||||||
// #[doc = "Like [`eprint!`](https://doc.rust-lang.org/std/macro.eprint.html), but with basic f-string interpolation."]
|
|
||||||
// eprint_f
|
|
||||||
// => eprint!(...)
|
|
||||||
// ,
|
|
||||||
// #[doc = "Like [`eprintln!`](https://doc.rust-lang.org/std/macro.eprintln.html), but with basic f-string interpolation."]
|
|
||||||
// eprintln_f
|
|
||||||
// => eprintln!(...)
|
|
||||||
// ,
|
|
||||||
// #[doc = "Like [`format!`](https://doc.rust-lang.org/std/macro.format.html), but with basic f-string interpolation."]
|
|
||||||
// format_f
|
|
||||||
// => format!(...)
|
|
||||||
// ,
|
|
||||||
// #[doc = "Shorthand for [`format_f`]."]
|
|
||||||
// f
|
|
||||||
// => format!(...)
|
|
||||||
// ,
|
|
||||||
// #[doc = "Like [`panic!`](https://doc.rust-lang.org/std/macro.panic.html), but with basic f-string interpolation."]
|
|
||||||
// panic_f
|
|
||||||
// => panic!(...)
|
|
||||||
// ,
|
|
||||||
// #[doc = "Like [`unreachable!`](https://doc.rust-lang.org/std/macro.unreachable.html), but with basic f-string interpolation."]
|
|
||||||
// unreachable_f
|
|
||||||
// => unreachable!(...)
|
|
||||||
// ,
|
|
||||||
// #[doc = "Like [`unimplemented!`](https://doc.rust-lang.org/std/macro.unimplemented.html), but with basic f-string interpolation."]
|
|
||||||
// unimplemented_f
|
|
||||||
// => unimplemented!(...)
|
|
||||||
// ,
|
|
||||||
// #[doc = "Like [`write!`](https://doc.rust-lang.org/std/macro.write.html), but with basic f-string interpolation."]
|
|
||||||
// write_f
|
|
||||||
// => write!(stream, ...)
|
|
||||||
// ,
|
|
||||||
// #[doc = "Like [`writeln!`](https://doc.rust-lang.org/std/macro.writeln.html), but with basic f-string interpolation."]
|
|
||||||
// writeln_f
|
|
||||||
// => writeln!(stream, ...)
|
|
||||||
// ,
|
|
||||||
// }
|
|
||||||
/// Like the `format!` macro for creating `std::string::String`s but for
|
|
||||||
/// `bumpalo::collections::String`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use bumpalo::Bump;
|
|
||||||
///
|
|
||||||
/// let b = Bump::new();
|
|
||||||
///
|
|
||||||
/// let who = "World";
|
|
||||||
/// let s = bumpalo::format!(in &b, "Hello, {}!", who);
|
|
||||||
/// assert_eq!(s, "Hello, World!")
|
|
||||||
/// ```
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! ifmt {
|
|
||||||
( in $bump:expr; $fmt:literal;) => {{
|
|
||||||
use bumpalo::core_alloc::fmt::Write;
|
|
||||||
use $crate::prelude::bumpalo;
|
|
||||||
let bump = $bump;
|
|
||||||
let mut s = bumpalo::collections::String::new_in(bump);
|
|
||||||
let args = $crate::prelude::format_args_f!($fmt);
|
|
||||||
s.write_fmt(args);
|
|
||||||
s
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
// ( in $bump:expr; $fmt:expr; ) => {
|
|
||||||
// $println!("{}", format_args_f!($dol($dol args)*))
|
|
||||||
|
|
||||||
// write!(&mut s, println!("{}", args));
|
|
||||||
// let _ = $crate::write_f!(&mut s, $fmt);
|
|
||||||
// s
|
|
||||||
// use fstrings::*;
|
|
||||||
// $crate::ifmt!(in $bump, $fmt)
|
|
||||||
// };
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn macro_test() {
|
|
||||||
let w = 123;
|
|
||||||
let world = &w;
|
|
||||||
// let g = format_args_f!("Hello {world}");
|
|
||||||
|
|
||||||
// dbg!(g);
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ log = "0.4.14"
|
||||||
fxhash = "0.2.1"
|
fxhash = "0.2.1"
|
||||||
pretty_env_logger = "0.4.0"
|
pretty_env_logger = "0.4.0"
|
||||||
console_error_panic_hook = "0.1.6"
|
console_error_panic_hook = "0.1.6"
|
||||||
|
generational-arena = "0.2.8"
|
||||||
# html-validation = { path = "../html-validation", version = "0.1.1" }
|
# html-validation = { path = "../html-validation", version = "0.1.1" }
|
||||||
|
|
||||||
[dependencies.web-sys]
|
[dependencies.web-sys]
|
||||||
|
|
|
@ -23,16 +23,3 @@ static Example: FC<()> = |ctx, props| {
|
||||||
</div>
|
</div>
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ItemProps {
|
|
||||||
name: String,
|
|
||||||
birthdate: String,
|
|
||||||
}
|
|
||||||
static Item: FC<ItemProps> = |ctx, ItemProps { name, birthdate }| {
|
|
||||||
ctx.view(html! {
|
|
||||||
<div>
|
|
||||||
<p>"{name}"</p>
|
|
||||||
<p>"{birthdate}"</p>
|
|
||||||
</div>
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
|
@ -20,22 +20,50 @@ impl std::fmt::Debug for RootCallback {
|
||||||
pub(crate) struct PatchMachine {
|
pub(crate) struct PatchMachine {
|
||||||
pub(crate) stack: Stack,
|
pub(crate) stack: Stack,
|
||||||
|
|
||||||
|
pub(crate) root: Element,
|
||||||
|
|
||||||
|
pub(crate) temporaries: FxHashMap<u32, Node>,
|
||||||
|
|
||||||
|
pub(crate) document: Document,
|
||||||
|
|
||||||
|
pub(crate) events: EventDelegater,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct EventDelegater {
|
||||||
root: Element,
|
root: Element,
|
||||||
|
|
||||||
temporaries: FxHashMap<u32, Node>,
|
|
||||||
|
|
||||||
// callback: RootCallback,
|
|
||||||
// callback: Option<Closure<dyn Fn(EventTrigger)>>,
|
|
||||||
document: Document,
|
|
||||||
|
|
||||||
// every callback gets a monotomically increasing callback ID
|
// every callback gets a monotomically increasing callback ID
|
||||||
callback_id: usize,
|
callback_id: usize,
|
||||||
|
|
||||||
|
// map of listener types to number of those listeners
|
||||||
|
listeners: FxHashMap<&'static str, (usize, Closure<dyn Fn()>)>,
|
||||||
|
|
||||||
// Map of callback_id to component index and listener id
|
// Map of callback_id to component index and listener id
|
||||||
callback_map: FxHashMap<usize, (usize, usize)>,
|
callback_map: FxHashMap<usize, (usize, usize)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// templates: FxHashMap<CacheId, Node>,
|
impl EventDelegater {
|
||||||
|
pub fn new(root: Element) -> Self {
|
||||||
|
Self {
|
||||||
|
root,
|
||||||
|
callback_id: 0,
|
||||||
|
listeners: FxHashMap::default(),
|
||||||
|
callback_map: FxHashMap::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_listener(
|
||||||
|
&mut self,
|
||||||
|
event: &'static str,
|
||||||
|
gi: generational_arena::Index,
|
||||||
|
listener_id: usize,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// callback: RootCallback,
|
||||||
|
// callback: Option<Closure<dyn Fn(EventTrigger)>>,
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Stack {
|
pub struct Stack {
|
||||||
|
@ -85,16 +113,14 @@ impl PatchMachine {
|
||||||
.expect("must have access to the Document");
|
.expect("must have access to the Document");
|
||||||
|
|
||||||
// attach all listeners to the container element
|
// attach all listeners to the container element
|
||||||
|
let events = EventDelegater::new(root.clone());
|
||||||
|
|
||||||
// templates: Default::default(),
|
|
||||||
Self {
|
Self {
|
||||||
root,
|
root,
|
||||||
|
events,
|
||||||
stack: Stack::with_capacity(20),
|
stack: Stack::with_capacity(20),
|
||||||
temporaries: Default::default(),
|
temporaries: Default::default(),
|
||||||
// callback: None,
|
|
||||||
document,
|
document,
|
||||||
callback_id: 0,
|
|
||||||
callback_map: FxHashMap::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,7 +319,11 @@ impl PatchMachine {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 11
|
// 11
|
||||||
Edit::NewEventListener { event_type, a, b } => {
|
Edit::NewEventListener {
|
||||||
|
event_type,
|
||||||
|
idx: a,
|
||||||
|
b,
|
||||||
|
} => {
|
||||||
// attach the correct attributes to the element
|
// attach the correct attributes to the element
|
||||||
// these will be used by accessing the event's target
|
// these will be used by accessing the event's target
|
||||||
// This ensures we only ever have one handler attached to the root, but decide
|
// This ensures we only ever have one handler attached to the root, but decide
|
||||||
|
@ -304,16 +334,20 @@ impl PatchMachine {
|
||||||
let el = el
|
let el = el
|
||||||
.dyn_ref::<Element>()
|
.dyn_ref::<Element>()
|
||||||
.expect(&format!("not an element: {:?}", el));
|
.expect(&format!("not an element: {:?}", el));
|
||||||
|
|
||||||
// el.add_event_listener_with_callback(
|
// el.add_event_listener_with_callback(
|
||||||
// event_type,
|
// event_type,
|
||||||
// self.callback.as_ref().unwrap().as_ref().unchecked_ref(),
|
// self.callback.as_ref().unwrap().as_ref().unchecked_ref(),
|
||||||
// )
|
// )
|
||||||
// .unwrap();
|
// .unwrap();
|
||||||
|
|
||||||
debug!("adding attributes: {}, {}", a, b);
|
debug!("adding attributes: {}, {}", a, b);
|
||||||
el.set_attribute(&format!("dioxus-a-{}", event_type), &a.to_string())
|
el.set_attribute(&format!("dioxus-a-{}", event_type), &a.to_string())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
el.set_attribute(&format!("dioxus-b-{}", event_type), &b.to_string())
|
el.set_attribute(&format!("dioxus-b-{}", event_type), &b.to_string())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
self.events.add_listener(event_type, gi, listener_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 12
|
// 12
|
||||||
|
|
Loading…
Add table
Reference in a new issue