Jonathan Kelley 3 rokov pred
rodič
commit
8b0eb87

+ 1 - 1
examples/hydration.rs

@@ -13,7 +13,7 @@ use dioxus::prelude::*;
 use dioxus::ssr;
 
 fn main() {
-    let mut vdom = VirtualDom::launch_in_place(App);
+    let vdom = VirtualDom::new(App);
     let content = ssr::render_vdom(&vdom, |f| f.pre_render(true));
 
     dioxus::desktop::launch(App, |c| c.with_prerendered(content)).unwrap();

+ 1 - 1
examples/reference/tostring.rs

@@ -6,7 +6,7 @@ pub static Example: FC<()> = |cx| {
         // Currently, SSR is only supported for whole VirtualDOMs
         // This is an easy/low hanging fruit to improve upon
         let mut dom = VirtualDom::new(SomeApp);
-        dom.rebuild_in_place().unwrap();
+        dom.rebuild();
         ssr::render_vdom(&dom, |c| c)
     });
 

+ 23 - 30
examples/web_tick.rs

@@ -13,32 +13,13 @@
 use dioxus::prelude::*;
 
 fn main() {
-    // Setup logging
-    // wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
-    // console_error_panic_hook::set_once();
-    for adj in ADJECTIVES {
-        wasm_bindgen::intern(adj);
-    }
-    for col in COLOURS {
-        wasm_bindgen::intern(col);
-    }
-    for no in NOUNS {
-        wasm_bindgen::intern(no);
-    }
-    wasm_bindgen::intern("col-md-1");
-    wasm_bindgen::intern("col-md-6");
-    wasm_bindgen::intern("glyphicon glyphicon-remove remove");
-    wasm_bindgen::intern("remove");
-    wasm_bindgen::intern("dioxus");
-    wasm_bindgen::intern("lbl");
-    wasm_bindgen::intern("true");
+    #[cfg(target_arch = "wasm32")]
+    intern_strings();
 
     dioxus::web::launch(App, |c| c);
 }
 
 static App: FC<()> = |cx| {
-    // let mut count = use_state(cx, || 0);
-
     let mut rng = SmallRng::from_entropy();
     let rows = (0..1_000).map(|f| {
         let label = Label::new(&mut rng);
@@ -49,6 +30,7 @@ static App: FC<()> = |cx| {
             }
         }
     });
+
     cx.render(rsx! {
         table {
             tbody {
@@ -56,15 +38,6 @@ static App: FC<()> = |cx| {
             }
         }
     })
-    // cx.render(rsx! {
-    //     div {
-    //         // h1 { "Hifive counter: {count}" }
-    //         // {cx.children()}
-    //         // button { onclick: move |_| count += 1, "Up high!" }
-    //         // button { onclick: move |_| count -= 1, "Down low!" }
-    //         {(0..1000).map(|i| rsx!{ div { "Count: {count}" } })}
-    //     }
-    // })
 };
 
 #[derive(PartialEq, Props)]
@@ -141,3 +114,23 @@ static NOUNS: &[&str] = &[
     "table", "chair", "house", "bbq", "desk", "car", "pony", "cookie", "sandwich", "burger",
     "pizza", "mouse", "keyboard",
 ];
+
+#[cfg(target_arch = "wasm32")]
+fn intern_strings() {
+    for adj in ADJECTIVES {
+        wasm_bindgen::intern(adj);
+    }
+    for col in COLOURS {
+        wasm_bindgen::intern(col);
+    }
+    for no in NOUNS {
+        wasm_bindgen::intern(no);
+    }
+    wasm_bindgen::intern("col-md-1");
+    wasm_bindgen::intern("col-md-6");
+    wasm_bindgen::intern("glyphicon glyphicon-remove remove");
+    wasm_bindgen::intern("remove");
+    wasm_bindgen::intern("dioxus");
+    wasm_bindgen::intern("lbl");
+    wasm_bindgen::intern("true");
+}

+ 0 - 4
packages/core/examples/vdom_usage.rs

@@ -12,8 +12,4 @@ async fn main() {
 
     let mut deadline = async_std::task::sleep(Duration::from_millis(50));
     let fut = dom.run_with_deadline(deadline);
-
-    if let Some(mutations) = fut.await {
-        //
-    }
 }

+ 11 - 23
packages/core/src/diff.rs

@@ -106,7 +106,6 @@ use DomEdit::*;
 /// Funnily enough, this stack machine's entire job is to create instructions for another stack machine to execute. It's
 /// stack machines all the way down!
 pub struct DiffMachine<'bump> {
-    pub channel: EventChannel,
     pub vdom: &'bump ResourcePool,
     pub mutations: Mutations<'bump>,
     pub stack: DiffStack<'bump>,
@@ -117,7 +116,6 @@ pub struct DiffMachine<'bump> {
 /// in regular diff machine, the &'bump reference is a stack borrow, but the
 /// bump lifetimes are heap borrows.
 pub struct SavedDiffWork<'bump> {
-    pub channel: EventChannel,
     pub mutations: Mutations<'bump>,
     pub stack: DiffStack<'bump>,
     pub seen_scopes: FxHashSet<ScopeId>,
@@ -131,7 +129,6 @@ impl<'a> SavedDiffWork<'a> {
         let extended: SavedDiffWork<'b> = std::mem::transmute(self);
         DiffMachine {
             vdom,
-            channel: extended.channel,
             mutations: extended.mutations,
             stack: extended.stack,
             seen_scopes: extended.seen_scopes,
@@ -140,13 +137,8 @@ impl<'a> SavedDiffWork<'a> {
 }
 
 impl<'bump> DiffMachine<'bump> {
-    pub(crate) fn new(
-        edits: Mutations<'bump>,
-        shared: &'bump mut ResourcePool,
-        channel: EventChannel,
-    ) -> Self {
+    pub(crate) fn new(edits: Mutations<'bump>, shared: &'bump mut ResourcePool) -> Self {
         Self {
-            channel,
             stack: DiffStack::new(),
             mutations: edits,
             vdom: shared,
@@ -156,7 +148,6 @@ impl<'bump> DiffMachine<'bump> {
 
     pub fn save(self) -> SavedDiffWork<'bump> {
         SavedDiffWork {
-            channel: self.channel,
             mutations: self.mutations,
             stack: self.stack,
             seen_scopes: self.seen_scopes,
@@ -208,12 +199,10 @@ impl<'bump> DiffMachine<'bump> {
                 }
 
                 DiffInstruction::PrepareMoveNode { node } => {
-                    log::debug!("Preparing to move node: {:?}", node);
-                    todo!();
-                    // for el in RealChildIterator::new(node, self.vdom) {
-                    //     self.mutations.push_root(el.direct_id());
-                    //     self.stack.add_child_count(1);
-                    // }
+                    for el in RealChildIterator::new(node, self.vdom) {
+                        self.mutations.push_root(el.direct_id());
+                        self.stack.add_child_count(1);
+                    }
                 }
             };
 
@@ -237,12 +226,11 @@ impl<'bump> DiffMachine<'bump> {
             }
 
             MountType::Replace { old } => {
-                todo!()
-                // let mut iter = RealChildIterator::new(old, self.vdom);
-                // let first = iter.next().unwrap();
-                // self.mutations
-                //     .replace_with(first.direct_id(), nodes_created as u32);
-                // self.remove_nodes(iter);
+                let mut iter = RealChildIterator::new(old, self.vdom);
+                let first = iter.next().unwrap();
+                self.mutations
+                    .replace_with(first.direct_id(), nodes_created as u32);
+                self.remove_nodes(iter);
             }
 
             MountType::ReplaceByElementId { el: old } => {
@@ -343,7 +331,7 @@ impl<'bump> DiffMachine<'bump> {
 
         let parent_idx = self.stack.current_scope().unwrap();
 
-        let shared = self.channel.clone();
+        let shared = self.vdom.channel.clone();
         // Insert a new scope into our component list
         let parent_scope = self.vdom.get_scope(parent_idx).unwrap();
         let new_idx = self.vdom.insert_scope_with_key(|new_idx| {

+ 0 - 5
packages/core/src/events.rs

@@ -15,11 +15,6 @@ pub struct EventTrigger {
 
     /// The type of event
     pub event: SyntheticEvent,
-
-    /// Is consistency important for this event?
-    /// UI events are the only events where consistency is important.
-    /// All else may be batched.
-    pub discrete: bool,
 }
 
 pub enum SyntheticEvent {

+ 15 - 22
packages/core/src/scheduler.rs

@@ -133,8 +133,6 @@ pub struct Scheduler {
 
     pub heuristics: HeuristicsEngine,
 
-    pub channel: EventChannel,
-
     pub receiver: UnboundedReceiver<SchedulerMsg>,
 
     // Garbage stored
@@ -166,11 +164,6 @@ impl Scheduler {
         let components = Rc::new(UnsafeCell::new(Slab::with_capacity(100)));
         let raw_elements = Rc::new(UnsafeCell::new(Slab::with_capacity(2000)));
 
-        let pool = ResourcePool {
-            components: components.clone(),
-            raw_elements,
-        };
-
         let heuristics = HeuristicsEngine::new();
 
         let (sender, receiver) = futures_channel::mpsc::unbounded::<SchedulerMsg>();
@@ -214,9 +207,14 @@ impl Scheduler {
             },
         };
 
+        let pool = ResourcePool {
+            components: components.clone(),
+            raw_elements,
+            channel,
+        };
+
         Self {
             pool,
-            channel,
             receiver,
 
             async_tasks: FuturesUnordered::new(),
@@ -253,7 +251,7 @@ impl Scheduler {
     }
 
     // Converts UI events into dirty scopes with various priorities
-    pub fn consume_pending_events(&mut self) -> Result<()> {
+    pub fn consume_pending_events(&mut self) {
         // while let Some(trigger) = self.ui_events.pop_back() {
         //     match &trigger.event {
         //         SyntheticEvent::ClipboardEvent(_)
@@ -287,8 +285,6 @@ impl Scheduler {
         //         }
         //     }
         // }
-
-        Ok(())
     }
 
     // nothing to do, no events on channels, no work
@@ -363,8 +359,6 @@ impl Scheduler {
     /// Uses some fairly complex logic to schedule what work should be produced.
     ///
     /// Returns a list of successful mutations.
-    ///
-    ///
     pub async fn work_with_deadline<'a>(
         &'a mut self,
         mut deadline: Pin<Box<impl FusedFuture<Output = ()>>>,
@@ -392,10 +386,6 @@ impl Scheduler {
         */
         let mut committed_mutations = Vec::<Mutations<'static>>::new();
 
-        // TODO:
-        // the scheduler uses a bunch of different receivers to mimic a "topic" queue system. The futures-channel implementation
-        // doesn't really have a concept of a "topic" queue, so there's a lot of noise in the hand-rolled scheduler. We should
-        // explore abstracting the scheduler into a topic-queue channel system - similar to Kafka or something similar.
         loop {
             // Internalize any pending work since the last time we ran
             self.manually_poll_events();
@@ -411,7 +401,7 @@ impl Scheduler {
             }
 
             // Create work from the pending event queue
-            self.consume_pending_events().unwrap();
+            self.consume_pending_events();
 
             // Work through the current subtree, and commit the results when it finishes
             // When the deadline expires, give back the work
@@ -443,8 +433,8 @@ impl Scheduler {
                 pin_mut!(fut);
                 use futures_util::future::{select, Either};
                 match select(fut, &mut deadline).await {
-                    Either::Left((work, _other)) => true,
-                    Either::Right((deadline, _other)) => false,
+                    Either::Left((_, _other)) => true,
+                    Either::Right((_, _other)) => false,
                 }
             };
 
@@ -461,6 +451,7 @@ impl Scheduler {
 
                 committed_mutations.push(new_mutations);
             }
+
             self.save_work(saved);
 
             if !completed {
@@ -670,6 +661,8 @@ pub struct ResourcePool {
     In the future, we could actually store a pointer to the VNode instead of nil to provide O(1) lookup for VNodes...
     */
     pub raw_elements: Rc<UnsafeCell<Slab<()>>>,
+
+    pub channel: EventChannel,
 }
 
 impl ResourcePool {
@@ -711,8 +704,8 @@ impl ResourcePool {
     }
 
     pub fn reserve_node(&self) -> ElementId {
-        todo!("reserving wip until it's fast enough again")
-        // ElementId(self.raw_elements.insert(()))
+        let els = unsafe { &mut *self.raw_elements.get() };
+        ElementId(els.insert(()))
     }
 
     /// return the id, freeing the space of the original node

+ 1 - 1
packages/core/src/scope.rs

@@ -164,7 +164,7 @@ impl Scope {
             "clean up your garabge please"
         );
 
-        todo!("arch changes");
+        // todo!("arch changes");
 
         // // make sure we drop all borrowed props manually to guarantee that their drop implementation is called before we
         // // run the hooks (which hold an &mut Referrence)

+ 25 - 23
packages/core/src/virtual_dom.rs

@@ -116,7 +116,7 @@ impl VirtualDom {
                 None,
                 0,
                 ScopeChildren(&[]),
-                scheduler.channel.clone(),
+                scheduler.pool.channel.clone(),
             )
         });
 
@@ -158,29 +158,31 @@ impl VirtualDom {
     /// the diff and creating nodes can be expensive, so we provide this method to avoid blocking the main thread. This
     /// method can be useful when needing to perform some crucial periodic tasks.
     pub async fn rebuild_async<'s>(&'s mut self) -> Mutations<'s> {
-        todo!()
-        // let mut diff_machine = DiffMachine::new(Mutations::new(), self.base_scope, &self.scheduler);
+        let mut shared = self.scheduler.pool.clone();
+        let mut diff_machine = DiffMachine::new(Mutations::new(), &mut shared);
 
-        // let cur_component = self
-        //     .scheduler
-        //     .get_scope_mut(self.base_scope)
-        //     .expect("The base scope should never be moved");
+        let cur_component = self
+            .scheduler
+            .pool
+            .get_scope_mut(self.base_scope)
+            .expect("The base scope should never be moved");
 
-        // // // We run the component. If it succeeds, then we can diff it and add the changes to the dom.
-        // if cur_component.run_scope().is_ok() {
-        //     diff_machine
-        //         .stack
-        //         .create_node(cur_component.frames.fin_head(), MountType::Append);
-        //     diff_machine.work().await;
-        // } else {
-        //     // todo: should this be a hard error?
-        //     log::warn!(
-        //         "Component failed to run succesfully during rebuild.
-        //         This does not result in a failed rebuild, but indicates a logic failure within your app."
-        //     );
-        // }
+        // // We run the component. If it succeeds, then we can diff it and add the changes to the dom.
+        if cur_component.run_scope().is_ok() {
+            diff_machine
+                .stack
+                .create_node(cur_component.frames.fin_head(), MountType::Append);
+            diff_machine.stack.scope_stack.push(self.base_scope);
+            diff_machine.work().await;
+        } else {
+            // todo: should this be a hard error?
+            log::warn!(
+                "Component failed to run succesfully during rebuild.
+                This does not result in a failed rebuild, but indicates a logic failure within your app."
+            );
+        }
 
-        // diff_machine.mutations
+        unsafe { std::mem::transmute(diff_machine.mutations) }
     }
 
     pub fn diff_sync<'s>(&'s mut self) -> Mutations<'s> {
@@ -194,7 +196,7 @@ impl VirtualDom {
     }
 
     pub async fn diff_async<'s>(&'s mut self) -> Mutations<'s> {
-        let mut diff_machine = DiffMachine::new(Mutations::new(), todo!(), todo!());
+        let mut diff_machine = DiffMachine::new(Mutations::new(), todo!());
 
         let cur_component = self
             .scheduler
@@ -273,7 +275,7 @@ impl VirtualDom {
     }
 
     pub fn get_event_sender(&self) -> futures_channel::mpsc::UnboundedSender<SchedulerMsg> {
-        self.scheduler.channel.sender.clone()
+        self.scheduler.pool.channel.sender.clone()
     }
 
     pub fn has_work(&self) -> bool {

+ 1 - 1
packages/core/tests/eventsystem.rs

@@ -17,6 +17,6 @@ async fn event_queue_works() {
     let edits = dom.rebuild();
 
     async_std::task::spawn_local(async move {
-        let mutations = dom.run_unbounded().await;
+        // let mutations = dom.run_unbounded().await;
     });
 }

+ 5 - 2
packages/desktop/src/events.rs

@@ -24,8 +24,11 @@ pub fn trigger_from_serialized(val: serde_json::Value) -> EventTrigger {
     let event = SyntheticEvent::MouseEvent(MouseEvent(Rc::new(WebviewMouseEvent)));
     let scope = ScopeId(data.scope as usize);
     let mounted_dom_id = Some(ElementId(data.mounted_dom_id as usize));
-    let priority = EventPriority::High;
-    EventTrigger::new(event, scope, mounted_dom_id, priority)
+    EventTrigger {
+        event,
+        scope,
+        mounted_dom_id,
+    }
 }
 
 #[derive(Debug)]

+ 9 - 9
packages/web/src/dom.rs

@@ -3,6 +3,7 @@ use std::{collections::HashMap, fmt::Debug, rc::Rc, sync::Arc};
 use dioxus_core::{
     events::{on::GenericEventInner, EventTrigger, SyntheticEvent},
     mutations::NodeRefMutation,
+    scheduler::SchedulerMsg,
     DomEdit, ElementId, ScopeId,
 };
 use fxhash::FxHashMap;
@@ -24,7 +25,7 @@ pub struct WebsysDom {
 
     root: Element,
 
-    sender_callback: Rc<dyn Fn(EventTrigger)>,
+    sender_callback: Rc<dyn Fn(SchedulerMsg)>,
 
     // map of listener types to number of those listeners
     // This is roughly a delegater
@@ -39,7 +40,7 @@ pub struct WebsysDom {
     last_node_was_text: bool,
 }
 impl WebsysDom {
-    pub fn new(root: Element, cfg: WebConfig, sender_callback: Rc<dyn Fn(EventTrigger)>) -> Self {
+    pub fn new(root: Element, cfg: WebConfig, sender_callback: Rc<dyn Fn(SchedulerMsg)>) -> Self {
         let document = load_document();
 
         let mut nodes = NodeSlab::new(2000);
@@ -277,7 +278,7 @@ impl WebsysDom {
                 // "Result" cannot be received from JS
                 // Instead, we just build and immediately execute a closure that returns result
                 match decode_trigger(event) {
-                    Ok(synthetic_event) => trigger.as_ref()(synthetic_event),
+                    Ok(synthetic_event) => trigger.as_ref()(SchedulerMsg::UiEvent(synthetic_event)),
                     Err(e) => log::error!("Error decoding Dioxus event attribute. {:#?}", e),
                 };
             }) as Box<dyn FnMut(&Event)>);
@@ -560,12 +561,11 @@ fn decode_trigger(event: &web_sys::Event) -> anyhow::Result<EventTrigger> {
     let triggered_scope = gi_id;
     // let triggered_scope: ScopeId = KeyData::from_ffi(gi_id).into();
     log::debug!("Triggered scope is {:#?}", triggered_scope);
-    Ok(EventTrigger::new(
-        virtual_event_from_websys_event(event.clone()),
-        ScopeId(triggered_scope as usize),
-        Some(ElementId(real_id as usize)),
-        dioxus_core::events::EventPriority::High,
-    ))
+    Ok(EventTrigger {
+        event: virtual_event_from_websys_event(event.clone()),
+        mounted_dom_id: Some(ElementId(real_id as usize)),
+        scope: ScopeId(triggered_scope as usize),
+    })
 }
 
 pub fn prepare_websys_dom() -> Element {

+ 4 - 6
packages/web/src/lib.rs

@@ -97,8 +97,7 @@ where
     F: FnOnce(WebConfig) -> WebConfig,
 {
     let config = config(WebConfig::default());
-    let fut = run_with_props(root, root_props, config);
-    wasm_bindgen_futures::spawn_local(fut);
+    wasm_bindgen_futures::spawn_local(run_with_props(root, root_props, config));
 }
 /// This method is the primary entrypoint for Websys Dioxus apps. Will panic if an error occurs while rendering.
 /// See DioxusErrors for more information on how these errors could occour.
@@ -143,9 +142,8 @@ pub async fn run_with_props<T: Properties + 'static>(root: FC<T>, root_props: T,
 
         let deadline = work_loop.wait_for_idle_time().await;
 
-        if let Some(mut mutations) = dom.run_with_deadline(deadline).await {
-            work_loop.wait_for_raf().await;
-            websys_dom.process_edits(&mut mutations.edits);
-        }
+        let mut mutations = dom.run_with_deadline(deadline).await;
+        work_loop.wait_for_raf().await;
+        websys_dom.process_edits(&mut mutations[0].edits);
     }
 }