wip: basic support for scheduled rendering

This commit is contained in:
Jonathan Kelley 2021-07-14 18:19:51 -04:00
parent 80e6c25698
commit c52af221f7
8 changed files with 93 additions and 80 deletions

View file

@ -13,7 +13,6 @@ proc-macro = true
[dependencies]
once_cell = "1.7.2"
proc-macro-hack = "0.5.19"
proc-macro2 = { version = "1.0.6" }
quote = "1.0"
syn = { version = "1.0.11", features = ["full", "extra-traits"] }

View file

@ -66,6 +66,11 @@ impl RealDomNode {
let key: DefaultKey = data.into();
Self(key)
}
pub fn from_u64(id: u64) -> Self {
let data = KeyData::from_ffi(id);
let key: DefaultKey = data.into();
Self(key)
}
pub fn empty_cell() -> Cell<Self> {
Cell::new(Self::empty())
}
@ -102,7 +107,8 @@ impl<'a> RealDom<'a> for DebugDom {
async fn launch_demo(app: FC<()>) {
let mut dom = VirtualDom::new(app);
let mut real_dom = DebugDom::new();
dom.rebuild(&mut real_dom).unwrap();
let mut edits = Vec::new();
dom.rebuild(&mut real_dom, &mut edits).unwrap();
while let Some(evt) = dom.tasks.next().await {
//

View file

@ -191,7 +191,8 @@ impl VirtualDom {
/// SSR takes advantage of this by using Dioxus itself as the source of truth, and rendering from the tree directly.
pub fn rebuild_in_place(&mut self) -> Result<()> {
let mut realdom = DebugDom::new();
self.rebuild(&mut realdom)
let mut edits = Vec::new();
self.rebuild(&mut realdom, &mut edits)
}
/// Performs a *full* rebuild of the virtual dom, returning every edit required to generate the actual dom rom scratch
@ -199,10 +200,13 @@ impl VirtualDom {
/// Currently this doesn't do what we want it to do
///
/// The diff machine expects the RealDom's stack to be the root of the application
pub fn rebuild<'s, Dom: RealDom<'s>>(&'s mut self, realdom: &mut Dom) -> Result<()> {
let mut edits = Vec::new();
pub fn rebuild<'s, Dom: RealDom<'s>>(
&'s mut self,
realdom: &mut Dom,
edits: &mut Vec<DomEdit<'s>>,
) -> Result<()> {
let mut diff_machine = DiffMachine::new(
&mut edits,
edits,
realdom,
&self.components,
self.base_scope,
@ -211,7 +215,6 @@ impl VirtualDom {
);
let cur_component = self.components.try_get_mut(self.base_scope).unwrap();
cur_component.run_scope()?;
let meta = diff_machine.create(cur_component.next_frame());
@ -278,12 +281,12 @@ impl VirtualDom {
pub async fn progress_with_event<'s, Dom: RealDom<'s>>(
&'s mut self,
realdom: &'_ mut Dom,
edits: &mut Vec<DomEdit<'s>>,
) -> Result<()> {
let trigger = self.triggers.borrow_mut().pop().expect("failed");
let mut edits = Vec::new();
let mut diff_machine = DiffMachine::new(
&mut edits,
edits,
realdom,
&self.components,
trigger.originator,
@ -295,9 +298,9 @@ impl VirtualDom {
VirtualEvent::OtherEvent => todo!(),
// Fiber events
VirtualEvent::FiberEvent => {
//
}
// VirtualEvent::FiberEvent => {
// //
// }
// This is the "meat" of our cooperative scheduler
// As updates flow in, we re-evalute the event queue and decide if we should be switching the type of work

View file

@ -17,7 +17,7 @@ use dioxus_web::*;
fn main() {
// Setup logging
// wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
console_error_panic_hook::set_once();
// Run the app
@ -37,17 +37,6 @@ static App: FC<()> = |cx| {
let set_val = state.setter();
let (tas, g) = cx.use_task(|| async move {
let mut tick: i32 = 0;
log::debug!("yeet!");
// loop {
// gloo_timers::future::TimeoutFuture::new(250).await;
// log::debug!("ticking forward... {}", tick);
// tick += 1;
// if tick > 10 {
// break;
// }
// }
// String::from("Huzza!")
set_val(10);
surf::get(ENDPOINT).recv_json::<DogApi>().await
});

View file

@ -72,53 +72,57 @@ impl WebsysRenderer {
websys_dom.stack.push(root_node.clone());
websys_dom.stack.push(root_node);
self.internal_dom.rebuild(&mut websys_dom)?;
let mut edits = Vec::new();
self.internal_dom.rebuild(&mut websys_dom, &mut edits)?;
websys_dom.process_edits(&mut edits);
log::info!("Going into event loop");
// loop {
let trigger = {
let real_queue = websys_dom.wait_for_event();
if self.internal_dom.tasks.is_empty() {
log::info!("tasks is empty, waiting for dom event to trigger soemthing");
real_queue.await
} else {
log::info!("tasks is not empty, waiting for either tasks or event system");
let task_queue = (&mut self.internal_dom.tasks).next();
loop {
let trigger = {
let real_queue = websys_dom.wait_for_event();
if self.internal_dom.tasks.is_empty() {
log::info!("tasks is empty, waiting for dom event to trigger soemthing");
real_queue.await
} else {
log::info!("tasks is not empty, waiting for either tasks or event system");
let task_queue = (&mut self.internal_dom.tasks).next();
pin_mut!(real_queue);
pin_mut!(task_queue);
pin_mut!(real_queue);
pin_mut!(task_queue);
match futures_util::future::select(real_queue, task_queue).await {
futures_util::future::Either::Left((trigger, _)) => trigger,
futures_util::future::Either::Right((trigger, _)) => trigger,
match futures_util::future::select(real_queue, task_queue).await {
futures_util::future::Either::Left((trigger, _)) => trigger,
futures_util::future::Either::Right((trigger, _)) => trigger,
}
}
};
if let Some(real_trigger) = trigger {
log::info!("event received");
// let root_node = body_element.first_child().unwrap();
// websys_dom.stack.push(root_node.clone());
self.internal_dom.queue_event(real_trigger)?;
let mut edits = Vec::new();
self.internal_dom
.progress_with_event(&mut websys_dom, &mut edits)
.await?;
websys_dom.process_edits(&mut edits);
}
};
if let Some(real_trigger) = trigger {
log::info!("event received");
// let root_node = body_element.first_child().unwrap();
// websys_dom.stack.push(root_node.clone());
self.internal_dom.queue_event(real_trigger)?;
self.internal_dom
.progress_with_event(&mut websys_dom)
.await?;
// let t2 = self.internal_dom.tasks.next();
// futures::select! {
// trigger = t1 => {
// log::info!("event received");
// let root_node = body_element.first_child().unwrap();
// websys_dom.stack.push(root_node.clone());
// self.internal_dom
// .progress_with_event(&mut websys_dom, trigger)?;
// },
// () = t2 => {}
// };
}
// let t2 = self.internal_dom.tasks.next();
// futures::select! {
// trigger = t1 => {
// log::info!("event received");
// let root_node = body_element.first_child().unwrap();
// websys_dom.stack.push(root_node.clone());
// self.internal_dom
// .progress_with_event(&mut websys_dom, trigger)?;
// },
// () = t2 => {}
// };
// }
// while let Some(trigger) = websys_dom.wait_for_event().await {
// }

View file

@ -13,7 +13,7 @@ use web_sys::{
pub struct WebsysDom {
pub stack: Stack,
nodes: slotmap::SlotMap<DefaultKey, Node>,
nodes: slotmap::SlotMap<DefaultKey, Option<Node>>,
document: Document,
root: Element,
@ -51,7 +51,7 @@ impl WebsysDom {
let mut nodes = slotmap::SlotMap::with_capacity(1000);
let root_id = nodes.insert(root.clone().dyn_into::<Node>().unwrap());
let root_id = nodes.insert(Some(root.clone().dyn_into::<Node>().unwrap()));
Self {
stack: Stack::with_capacity(10),
@ -72,6 +72,7 @@ impl WebsysDom {
pub fn process_edits(&mut self, edits: &mut Vec<DomEdit>) {
for edit in edits.drain(..) {
log::info!("Handling edit: {:#?}", edit);
match edit {
DomEdit::PushRoot { root } => self.push(root),
DomEdit::PopRoot => self.pop(),
@ -90,18 +91,19 @@ impl WebsysDom {
idx,
} => self.new_event_listener(event, scope, idx, node),
DomEdit::RemoveEventListener { event } => todo!(),
DomEdit::SetText { text } => todo!(),
DomEdit::SetAttribute { field, value, ns } => todo!(),
DomEdit::RemoveAttribute { name } => todo!(),
DomEdit::SetText { text } => self.set_text(text),
DomEdit::SetAttribute { field, value, ns } => self.set_attribute(field, value, ns),
DomEdit::RemoveAttribute { name } => self.remove_attribute(name),
}
}
}
fn push(&mut self, root: RealDomNode) {
let key = root.0;
let domnode = self
.nodes
.get(key)
.expect(&format!("Failed to pop know root: {:#?}", key));
let domnode = self.nodes.get_mut(key);
let domnode = domnode.unwrap().as_mut().unwrap();
// .expect(&format!("Failed to pop know root: {:#?}", key))
// .unwrap();
self.stack.push(domnode.clone());
}
@ -189,14 +191,17 @@ impl WebsysDom {
}
fn create_text_node(&mut self, text: &str, id: RealDomNode) {
// let nid = self.node_counter.next();
let textnode = self
.document
.create_text_node(text)
.dyn_into::<Node>()
.unwrap();
self.stack.push(textnode.clone());
todo!();
self.stack.push(textnode.clone());
let mut slot = self.nodes.get_mut(id.0).unwrap();
*slot = Some(textnode);
// let nid = self.nodes.insert(textnode);
// let nid = nid.data().as_ffi();
@ -223,6 +228,8 @@ impl WebsysDom {
};
self.stack.push(el.clone());
let mut slot = self.nodes.get_mut(id.0).unwrap();
*slot = Some(el);
// let nid = self.node_counter.?next();
// let nid = self.nodes.insert(el).data().as_ffi();
// log::debug!("Called [`create_element`]: {}, {:?}", tag, nid);
@ -331,7 +338,9 @@ impl WebsysDom {
impl<'a> dioxus_core::diff::RealDom<'a> for WebsysDom {
fn request_available_node(&mut self) -> RealDomNode {
todo!()
let key = self.nodes.insert(None);
log::debug!("making new key: {:#?}", key);
RealDomNode(key)
}
fn raw_node_as_any(&self) -> &mut dyn std::any::Any {

View file

@ -37,6 +37,7 @@ impl<'bump> RealDom<'bump> for WebviewDom<'bump> {
}
fn request_available_node(&mut self) -> RealDomNode {
todo!()
self.node_counter += 1;
RealDomNode::from_u64(self.node_counter)
}
}

View file

@ -87,8 +87,9 @@ impl<T: Properties + 'static> WebviewRenderer<T> {
// Serialize the edit stream
let edits = {
lock.rebuild(&mut real).unwrap();
serde_json::to_value(&real.edits).unwrap()
let mut edits = Vec::new();
lock.rebuild(&mut real, &mut edits).unwrap();
serde_json::to_value(edits).unwrap()
};
// Give back the registry into its slot
@ -108,8 +109,9 @@ impl<T: Properties + 'static> WebviewRenderer<T> {
// Serialize the edit stream
let edits = {
lock.rebuild(&mut real).unwrap();
serde_json::to_value(&real.edits).unwrap()
let mut edits = Vec::new();
lock.rebuild(&mut real, &mut edits).unwrap();
serde_json::to_value(edits).unwrap()
};
// Give back the registry into its slot