Pārlūkot izejas kodu

wip: more refactor for async

Jonathan Kelley 4 gadi atpakaļ
vecāks
revīzija
975fa566f9

+ 1 - 1
Cargo.toml

@@ -40,7 +40,7 @@ rand = "0.8.4"
 separator = "0.4.1"
 serde = { version="1.0.126", features=["derive"] }
 surf = "2.2.0"
-
+env_logger = "*"
 
 [workspace]
 members = [

+ 13 - 38
examples/async.rs

@@ -7,7 +7,9 @@ use std::pin::Pin;
 use dioxus::prelude::*;
 use futures::Future;
 fn main() {
-    dioxus::web::launch(App)
+    env_logger::init();
+    log::info!("hello world");
+    dioxus::desktop::launch(App, |c| c).expect("faield to launch");
 }
 
 #[derive(serde::Deserialize)]
@@ -17,58 +19,31 @@ struct DogApi {
 
 const ENDPOINT: &str = "https://dog.ceo/api/breeds/image/random";
 
+struct Ex(Pin<Box<dyn Future<Output = ()> + 'static>>);
 static App: FC<()> = |cx| {
     // let mut count = use_state(cx, || 0);
     let mut fut = cx.use_hook(
         move || {
-            Box::pin(async {
+            Ex(Box::pin(async {
                 //
                 loop {
-                    // repeatadly get new doggos
                     match surf::get(ENDPOINT).recv_json::<DogApi>().await {
                         Ok(_) => (),
                         Err(_) => (),
-                        // Ok(res) => rsx!(in cx, img { src: "{res.message}" }),
-                        // Err(_) => rsx!(in cx, div { "No doggos for you :(" }),
                     }
-                    // wait one seconds
                 }
-            }) as Pin<Box<dyn Future<Output = ()> + 'static>>
+            })
+                as Pin<Box<dyn Future<Output = ()> + 'static>>)
         },
-        |h| h,
+        |h| &mut h.0,
         |_| {},
     );
 
     cx.submit_task(fut);
 
-    todo!()
-    // cx.render(rsx! {
-    //     div {
-    //         h1 { "Hifive counter: {count}" }
-    //         button { onclick: move |_| count += 1, "Up high!" }
-    //         button { onclick: move |_| count -= 1, "Down low!" }
-    //     }
-    // })
-};
-
-// #[derive(serde::Deserialize)]
-// struct DogApi {
-//     message: String,
-// }
-// const ENDPOINT: &str = "https://dog.ceo/api/breeds/image/random";
+    cx.render(rsx! {
+        div {
 
-// pub static App: FC<()> = |cx| {
-//     let doggo = use_future_effect(&cx, move || async move {
-//         match surf::get(ENDPOINT).recv_json::<DogApi>().await {
-//             Ok(res) => rsx!(in cx, img { src: "{res.message}" }),
-//             Err(_) => rsx!(in cx, div { "No doggos for you :(" }),
-//         }
-//     });
-
-//     cx.render(rsx!(
-//         div {
-//             h1 {"Waiting for a doggo..."}
-//             {doggo}
-//         }
-//     ))
-// };
+        }
+    })
+};

+ 11 - 12
examples/calculator.rs

@@ -26,19 +26,18 @@ static App: FC<()> = |cx| {
     let clear_display = display_value.eq("0");
     let clear_text = if clear_display { "C" } else { "AC" };
 
-    let input_digit =
-        move |num: u8| display_value.modify(move |f| f.push_str(num.to_string().as_str()));
+    let input_digit = move |num: u8| display_value.get_mut().push_str(num.to_string().as_str());
 
-    let input_dot = move || display_value.modify(move |f| f.push_str("."));
+    let input_dot = move || display_value.get_mut().push_str(".");
 
     let perform_operation = move || {
         if let Some(op) = operator.as_ref() {
             let rhs = display_value.parse::<f64>().unwrap();
             let new_val = match op {
-                Operator::Add => **cur_val + rhs,
-                Operator::Sub => **cur_val - rhs,
-                Operator::Mul => **cur_val * rhs,
-                Operator::Div => **cur_val / rhs,
+                Operator::Add => *cur_val + rhs,
+                Operator::Sub => *cur_val - rhs,
+                Operator::Mul => *cur_val * rhs,
+                Operator::Div => *cur_val / rhs,
             };
             cur_val.set(new_val);
             display_value.set(new_val.to_string());
@@ -50,7 +49,7 @@ static App: FC<()> = |cx| {
         if display_value.starts_with("-") {
             display_value.set(display_value.trim_start_matches("-").to_string())
         } else {
-            display_value.set(format!("-{}", **display_value))
+            display_value.set(format!("-{}", *display_value))
         }
     };
     let toggle_percent = move |_| todo!();
@@ -64,11 +63,11 @@ static App: FC<()> = |cx| {
     };
 
     let keydownhandler = move |evt: KeyboardEvent| match evt.key_code() {
-        KeyCode::Backspace => display_value.modify(|f| {
-            if !f.as_str().eq("0") {
-                f.pop();
+        KeyCode::Backspace => {
+            if !display_value.as_str().eq("0") {
+                display_value.get_mut().pop();
             }
-        }),
+        }
         KeyCode::_0 => input_digit(0),
         KeyCode::_1 => input_digit(1),
         KeyCode::_2 => input_digit(2),

+ 1 - 1
examples/doggo.rs

@@ -2,7 +2,7 @@ use dioxus::prelude::*;
 fn main() {}
 
 static Example: FC<()> = |cx| {
-    let (g, set_g) = use_state_classic(cx, || 0);
+    let (g, set_g) = use_state(cx, || 0).classic();
     let v = (0..10).map(move |f| {
         rsx!(li {
             onclick: move |_| set_g(10)

+ 3 - 3
examples/model.rs

@@ -36,9 +36,9 @@ enum Operator {
 }
 
 static App: FC<()> = |cx| {
-    let (cur_val, set_cur_val) = use_state_classic(cx, || 0.0_f64);
-    let (operator, set_operator) = use_state_classic(cx, || None as Option<Operator>);
-    let (display_value, set_display_value) = use_state_classic(cx, || "0".to_string());
+    let (cur_val, set_cur_val) = use_state(cx, || 0.0_f64).classic();
+    let (operator, set_operator) = use_state(cx, || None as Option<Operator>).classic();
+    let (display_value, set_display_value) = use_state(cx, || "0".to_string()).classic();
 
     let clear_display = display_value.eq("0");
     let clear_text = if clear_display { "C" } else { "AC" };

+ 5 - 3
examples/reducer.rs

@@ -1,5 +1,6 @@
 //! Example: Reducer Pattern
 //! -----------------
+//!
 //! This example shows how to encapsulate sate in dioxus components with the reducer pattern.
 //! This pattern is very useful when a single component can handle many types of input that can
 //! be represented by an enum.
@@ -10,7 +11,7 @@ fn main() {
 }
 
 pub static App: FC<()> = |cx| {
-    let (state, reduce) = use_reducer(cx, PlayerState::new, PlayerState::reduce);
+    let state = use_state(cx, PlayerState::new);
 
     let is_playing = state.is_playing();
 
@@ -20,11 +21,11 @@ pub static App: FC<()> = |cx| {
             h3 {"The radio is... {is_playing}!"}
             button {
                 "Pause"
-                onclick: move |_| reduce(PlayerAction::Pause)
+                onclick: move |_| state.get_mut().reduce(PlayerAction::Pause)
             }
             button {
                 "Play"
-                onclick: move |_| reduce(PlayerAction::Play)
+                onclick: move |_| state.get_mut().reduce(PlayerAction::Play)
             }
         }
     })
@@ -35,6 +36,7 @@ enum PlayerAction {
     Play,
 }
 
+#[derive(Clone)]
 struct PlayerState {
     is_playing: bool,
 }

+ 1 - 1
packages/atoms/src/lib.rs

@@ -368,7 +368,7 @@ mod root {
 
 mod hooks {
     use super::*;
-    use dioxus_core::{hooks::use_ref, prelude::Context};
+    use dioxus_core::prelude::Context;
 
     pub fn use_init_recoil_root<P>(cx: Context<P>, cfg: impl Fn(())) {
         cx.use_create_context(move || RefCell::new(RecoilRoot::new()))

+ 8 - 16
packages/core/src/context.rs

@@ -147,18 +147,18 @@ impl<'src, P> Context<'src, P> {
         cleanup: impl FnOnce(InternalHookState),
     ) -> Output {
         // If the idx is the same as the hook length, then we need to add the current hook
-        if self.scope.hooks.is_finished() {
+        if self.scope.hooks.at_end() {
             let new_state = initializer();
-            self.scope.hooks.push(Box::new(new_state));
+            self.scope.hooks.push(new_state);
         }
 
         let state = self.scope.hooks.next::<InternalHookState>().expect(
             r###"
-Unable to retrive the hook that was initialized in this index.
-Consult the `rules of hooks` to understand how to use hooks properly.
-
-You likely used the hook in a conditional. Hooks rely on consistent ordering between renders.
-Any function prefixed with "use" should not be called conditionally.
+            Unable to retrive the hook that was initialized in this index.
+            Consult the `rules of hooks` to understand how to use hooks properly.
+            
+            You likely used the hook in a conditional. Hooks rely on consistent ordering between renders.
+            Any function prefixed with "use" should not be called conditionally.
             "###,
         );
 
@@ -299,16 +299,8 @@ Any function prefixed with "use" should not be called conditionally.
     ///
     ///
     ///
-    pub fn submit_task(
-        &self,
-        mut task: &'src mut DTask<'src>,
-        // mut task: &'src mut Pin<Box<dyn Future<Output = ()> + 'static>>,
-    ) -> TaskHandle {
+    pub fn submit_task(&self, mut task: &'src mut DTask<'src>) -> TaskHandle {
         self.tasks.push(task);
-        // let mut g = self.task.borrow_mut();
-        // *g = Some(task);
-        // the pointer to the task is stable - we guarantee stability of all &'src references
-        // let task_ptr = task as *mut _;
 
         TaskHandle { _p: PhantomData {} }
     }

+ 4 - 1
packages/core/src/diff.rs

@@ -22,7 +22,7 @@
 //! More info on how to improve this diffing algorithm:
 //!  - https://hacks.mozilla.org/2019/03/fast-bump-allocated-virtual-doms-with-rust-and-wasm/
 
-use crate::{arena::SharedArena, innerlude::*};
+use crate::{arena::SharedArena, innerlude::*, tasks::TaskQueue};
 use fxhash::{FxHashMap, FxHashSet};
 
 use std::{
@@ -94,6 +94,7 @@ pub trait RealDom<'a> {
 pub struct DiffMachine<'real, 'bump, Dom: RealDom<'bump>> {
     pub dom: &'real mut Dom,
     pub components: &'bump SharedArena,
+    pub task_queue: &'bump TaskQueue,
     pub cur_idx: ScopeIdx,
     pub diffed: FxHashSet<ScopeIdx>,
     pub event_queue: EventQueue,
@@ -106,12 +107,14 @@ impl<'real, 'bump, Dom: RealDom<'bump>> DiffMachine<'real, 'bump, Dom> {
         components: &'bump SharedArena,
         cur_idx: ScopeIdx,
         event_queue: EventQueue,
+        task_queue: &'bump TaskQueue,
     ) -> Self {
         Self {
             components,
             dom,
             cur_idx,
             event_queue,
+            task_queue,
             diffed: FxHashSet::default(),
             seen_nodes: FxHashSet::default(),
         }

+ 2 - 2
packages/core/src/hooklist.rs

@@ -59,7 +59,7 @@ impl HookList {
     }
 
     #[inline]
-    pub(crate) fn is_finished(&self) -> bool {
-        self.idx.get() == self.vals.len()
+    pub(crate) fn at_end(&self) -> bool {
+        self.cur_idx() >= self.len()
     }
 }

+ 1 - 0
packages/core/src/lib.rs

@@ -61,6 +61,7 @@ pub mod prelude {
     use crate::nodes;
     pub use crate::styles::{AsAttr, StyleBuilder};
 
+    pub use crate::util::RealDomNode;
     pub use nodes::*;
 
     pub use crate::nodebuilder::LazyNodes;

+ 10 - 3
packages/core/src/nodes.rs

@@ -9,6 +9,7 @@ use crate::{
     innerlude::{Context, Properties, RealDom, RealDomNode, Scope, ScopeIdx, FC},
     nodebuilder::{text3, NodeFactory},
 };
+use appendlist::AppendList;
 use bumpalo::Bump;
 use std::{
     cell::{Cell, RefCell},
@@ -417,19 +418,25 @@ impl<'a> VComponent<'a> {
 type Captured<'a> = Rc<dyn for<'r> Fn(&'r Scope) -> VNode<'r> + 'a>;
 
 fn create_closure<'a, P: 'a>(
-    component: FC<P>,
+    user_component: FC<P>,
     raw_props: *const (),
 ) -> Rc<dyn for<'r> Fn(&'r Scope) -> VNode<'r>> {
     let g: Captured = Rc::new(move |scp: &Scope| -> VNode {
         // cast back into the right lifetime
         let safe_props: &'_ P = unsafe { &*(raw_props as *const P) };
+        let tasks = AppendList::new();
         let cx: Context<P> = Context {
             props: safe_props,
             scope: scp,
-            tasks: todo!(),
+            tasks: &tasks,
         };
 
-        let g = component(cx);
+        let g = user_component(cx);
+
+        // collect the submitted tasks
+        println!("tasks submittted: {:#?}", tasks.len());
+        // log::debug!("tasks submittted: {:#?}", tasks.len());
+
         let g2 = unsafe { std::mem::transmute(g) };
         g2
     });

+ 11 - 9
packages/core/src/tasks.rs

@@ -39,15 +39,15 @@ impl TaskQueue {
         Self { slots, submitter }
     }
 
-    fn push_task(&mut self, task: DTask) -> TaskHandle {
+    pub fn submit_task(&mut self, task: DTask) -> TaskHandle {
         let key = self.slots.write().unwrap().insert(task);
-        TaskHandle {}
+        TaskHandle { key }
     }
 
-    fn is_empty(&self) -> bool {
+    pub fn is_empty(&self) -> bool {
         self.slots.read().unwrap().is_empty()
     }
-    fn len(&self) -> usize {
+    pub fn len(&self) -> usize {
         self.slots.read().unwrap().len()
     }
 }
@@ -99,7 +99,9 @@ impl Stream for TaskQueue {
     }
 }
 
-struct TaskHandle {}
+pub struct TaskHandle {
+    key: DefaultKey,
+}
 
 pub struct DTask {
     fut: *mut Pin<Box<dyn Future<Output = ()>>>,
@@ -114,7 +116,7 @@ impl DTask {
             dead: Cell::new(false),
         }
     }
-    fn debug_new(fut: &mut Pin<Box<dyn Future<Output = ()>>>) -> Self {
+    pub fn debug_new(fut: &mut Pin<Box<dyn Future<Output = ()>>>) -> Self {
         let originator = ScopeIdx::default();
         Self {
             fut,
@@ -154,9 +156,9 @@ mod tests {
         }) as RawTask);
 
         let mut queue = TaskQueue::new();
-        queue.push_task(DTask::debug_new(f1));
-        queue.push_task(DTask::debug_new(f2));
-        queue.push_task(DTask::debug_new(f3));
+        queue.submit_task(DTask::debug_new(f1));
+        queue.submit_task(DTask::debug_new(f2));
+        queue.submit_task(DTask::debug_new(f3));
 
         while !queue.is_empty() {
             let next = queue.next().await;

+ 26 - 6
packages/core/src/virtual_dom.rs

@@ -21,6 +21,7 @@
 
 use crate::tasks::TaskQueue;
 use crate::{arena::SharedArena, innerlude::*};
+use appendlist::AppendList;
 use slotmap::DefaultKey;
 use slotmap::SlotMap;
 use std::{any::TypeId, fmt::Debug, rc::Rc};
@@ -130,16 +131,29 @@ impl VirtualDom {
 
         // Normally, a component would be passed as a child in the RSX macro which automatically produces OpaqueComponents
         // Here, we need to make it manually, using an RC to force the Weak reference to stick around for the main scope.
-        let _root_caller: Rc<WrappedCaller> = Rc::new(move |scope| {
+        let _root_caller: Rc<WrappedCaller> = Rc::new(move |scope: &Scope| {
             // let _root_caller: Rc<OpaqueComponent<'static>> = Rc::new(move |scope| {
             // the lifetime of this closure is just as long as the lifetime on the scope reference
             // this closure moves root props (which is static) into this closure
             let props = unsafe { &*(&root_props as *const _) };
-            root(Context {
+            let tasks = AppendList::new();
+            let t2 = &tasks;
+
+            let cx = Context {
                 props,
                 scope,
-                tasks: todo!(),
-            })
+                tasks: t2,
+            };
+            let nodes = root(cx);
+
+            log::debug!("There were {:?} tasks submitted", tasks.len());
+            // cast a weird lifetime to shake the appendlist thing
+            // TODO: move all of this into the same logic that governs other components
+            // we want to wrap everything in a dioxus root component
+            unsafe { std::mem::transmute(nodes) }
+            // std::mem::drop(tasks);
+            //
+            // nodes
         });
 
         // Create a weak reference to the OpaqueComponent for the root scope to use as its render function
@@ -185,6 +199,7 @@ impl VirtualDom {
             &self.components,
             self.base_scope,
             self.event_queue.clone(),
+            &self.tasks,
         );
 
         // Schedule an update and then immediately call it on the root component
@@ -251,8 +266,13 @@ impl VirtualDom {
 
         self.components.try_get_mut(id)?.call_listener(trigger)?;
 
-        let mut diff_machine =
-            DiffMachine::new(realdom, &self.components, id, self.event_queue.clone());
+        let mut diff_machine = DiffMachine::new(
+            realdom,
+            &self.components,
+            id,
+            self.event_queue.clone(),
+            &self.tasks,
+        );
 
         self.progress_completely(&mut diff_machine)?;
 

+ 1 - 2
packages/hooks/src/usestate.rs

@@ -69,7 +69,6 @@ struct UseStateInner<T: 'static> {
     update_scheuled: Cell<bool>,
     callback: Rc<dyn Fn()>,
     wip: RefCell<Option<T>>,
-    updater: 
 }
 
 pub struct UseState<'a, T: 'static> {
@@ -109,7 +108,7 @@ impl<'a, T: 'static> UseState<'a, T> {
     }
 
     pub fn classic(self) -> (&'a T, &'a Rc<dyn Fn(T)>) {
-        (&self.inner.current_val)
+        todo!()
     }
 }
 impl<'a, T: 'static + ToOwned<Owned = T>> UseState<'a, T> {

+ 5 - 10
packages/web/src/new.rs

@@ -2,8 +2,7 @@ use std::{collections::HashMap, rc::Rc, sync::Arc};
 
 use dioxus_core::{
     events::{EventTrigger, VirtualEvent},
-    prelude::ScopeIdx,
-    virtual_dom::RealDomNode,
+    prelude::{RealDomNode, ScopeIdx},
 };
 use fxhash::FxHashMap;
 use slotmap::{DefaultKey, Key, KeyData};
@@ -72,7 +71,7 @@ impl WebsysDom {
 }
 
 impl<'a> dioxus_core::diff::RealDom<'a> for WebsysDom {
-    fn push_root(&mut self, root: dioxus_core::virtual_dom::RealDomNode) {
+    fn push_root(&mut self, root: RealDomNode) {
         log::debug!("Called [push_root] {:?}", root);
         let key: DefaultKey = KeyData::from_ffi(root.0).into();
         let domnode = self.nodes.get(key).expect("Failed to pop know root");
@@ -150,7 +149,7 @@ impl<'a> dioxus_core::diff::RealDom<'a> for WebsysDom {
     fn create_placeholder(&mut self) -> RealDomNode {
         self.create_element("pre", None)
     }
-    fn create_text_node(&mut self, text: &str) -> dioxus_core::virtual_dom::RealDomNode {
+    fn create_text_node(&mut self, text: &str) -> RealDomNode {
         // let nid = self.node_counter.next();
         let textnode = self
             .document
@@ -166,11 +165,7 @@ impl<'a> dioxus_core::diff::RealDom<'a> for WebsysDom {
         RealDomNode::new(nid)
     }
 
-    fn create_element(
-        &mut self,
-        tag: &str,
-        ns: Option<&'static str>,
-    ) -> dioxus_core::virtual_dom::RealDomNode {
+    fn create_element(&mut self, tag: &str, ns: Option<&'static str>) -> RealDomNode {
         let tag = wasm_bindgen::intern(tag);
         let el = match ns {
             Some(ns) => self
@@ -587,7 +582,7 @@ fn decode_trigger(event: &web_sys::Event) -> anyhow::Result<EventTrigger> {
     Ok(EventTrigger::new(
         virtual_event_from_websys_event(event),
         triggered_scope,
-        real_id,
+        Some(real_id),
         dioxus_core::events::EventPriority::High,
     ))
 }

+ 6 - 14
packages/webview/src/dom.rs

@@ -2,11 +2,7 @@
 
 use dioxus_core as dioxus;
 use dioxus_core::prelude::*;
-use dioxus_core::{
-    diff::RealDom,
-    serialize::DomEdit,
-    virtual_dom::{RealDomNode, VirtualDom},
-};
+use dioxus_core::{diff::RealDom, serialize::DomEdit, virtual_dom::VirtualDom};
 use DomEdit::*;
 
 pub struct WebviewRegistry {}
@@ -37,7 +33,7 @@ impl WebviewDom<'_> {
     }
 }
 impl<'bump> RealDom<'bump> for WebviewDom<'bump> {
-    fn push_root(&mut self, root: dioxus_core::virtual_dom::RealDomNode) {
+    fn push_root(&mut self, root: RealDomNode) {
         self.edits.push(PushRoot { root: root.0 });
     }
 
@@ -57,18 +53,14 @@ impl<'bump> RealDom<'bump> for WebviewDom<'bump> {
         self.edits.push(RemoveAllChildren);
     }
 
-    fn create_text_node(&mut self, text: &'bump str) -> dioxus_core::virtual_dom::RealDomNode {
+    fn create_text_node(&mut self, text: &'bump str) -> RealDomNode {
         self.node_counter += 1;
         let id = RealDomNode::new(self.node_counter);
         self.edits.push(CreateTextNode { text, id: id.0 });
         id
     }
 
-    fn create_element(
-        &mut self,
-        tag: &'bump str,
-        ns: Option<&'bump str>,
-    ) -> dioxus_core::virtual_dom::RealDomNode {
+    fn create_element(&mut self, tag: &'bump str, ns: Option<&'bump str>) -> RealDomNode {
         self.node_counter += 1;
         let id = RealDomNode::new(self.node_counter);
         match ns {
@@ -78,7 +70,7 @@ impl<'bump> RealDom<'bump> for WebviewDom<'bump> {
         id
     }
 
-    fn create_placeholder(&mut self) -> dioxus_core::virtual_dom::RealDomNode {
+    fn create_placeholder(&mut self) -> RealDomNode {
         self.node_counter += 1;
         let id = RealDomNode::new(self.node_counter);
         self.edits.push(CreatePlaceholder { id: id.0 });
@@ -90,7 +82,7 @@ impl<'bump> RealDom<'bump> for WebviewDom<'bump> {
         event: &'static str,
         scope: dioxus_core::prelude::ScopeIdx,
         element_id: usize,
-        realnode: dioxus_core::virtual_dom::RealDomNode,
+        realnode: RealDomNode,
     ) {
         self.edits.push(NewEventListener {
             scope,

+ 1 - 0
src/lib.rs

@@ -169,6 +169,7 @@ pub mod prelude {
     //! A glob import that includes helper types like FC, rsx!, html!, and required traits
     pub use dioxus_core::prelude::*;
     pub use dioxus_core_macro::fc;
+    pub use dioxus_hooks::*;
     pub use dioxus_html as dioxus_elements;
 }
 // pub mod builder {