소스 검색

Feat: desktop app wired up

Jonathan Kelley 4 년 전
부모
커밋
b3e6886351

+ 13 - 7
packages/core/src/changelist.rs

@@ -19,6 +19,8 @@
 //!
 //!
 
+use std::ops::{Deref, DerefMut};
+
 use bumpalo::Bump;
 
 use crate::innerlude::{Listener, VirtualDom};
@@ -32,8 +34,9 @@ use crate::innerlude::{Listener, VirtualDom};
 ///
 ///
 ///
-///
-#[derive(Debug)]
+/// todo@ jon: allow serde to be optional
+#[derive(Debug, serde::Serialize, serde::Deserialize)]
+#[serde(tag = "type")]
 pub enum Edit<'d> {
     SetText { text: &'d str },
     RemoveSelfAndNextSiblings {},
@@ -59,20 +62,23 @@ pub enum Edit<'d> {
     SetClass { class_name: &'d str },
 }
 
-pub struct EditList<'src> {
+pub type EditList<'src> = Vec<Edit<'src>>;
+
+pub struct EditMachine<'src> {
     pub traversal: Traversal,
     next_temporary: u32,
     forcing_new_listeners: bool,
-    pub emitter: Vec<Edit<'src>>,
+
+    pub emitter: EditList<'src>,
 }
 
-impl<'b> EditList<'b> {
+impl<'b> EditMachine<'b> {
     pub fn new(bump: &'b Bump) -> Self {
         Self {
             traversal: Traversal::new(),
             next_temporary: 0,
             forcing_new_listeners: false,
-            emitter: Vec::new(),
+            emitter: EditList::default(),
         }
     }
 
@@ -153,7 +159,7 @@ impl<'b> EditList<'b> {
     }
 }
 
-impl<'a> EditList<'a> {
+impl<'a> EditMachine<'a> {
     pub fn next_temporary(&self) -> u32 {
         self.next_temporary
     }

+ 4 - 4
packages/core/src/dodriodiff.rs

@@ -37,7 +37,7 @@ use fxhash::{FxHashMap, FxHashSet};
 use generational_arena::Index;
 
 use crate::{
-    changelist::{Edit, EditList},
+    changelist::{Edit, EditList, EditMachine},
     innerlude::{Attribute, Listener, Scope, VElement, VNode, VText},
     virtual_dom::LifecycleEvent,
 };
@@ -57,7 +57,7 @@ use std::cmp::Ordering;
 /// that were modified by the eventtrigger. This prevents doubly evaluating components if they wereboth updated via
 /// subscriptions and props changes.
 pub struct DiffMachine<'a> {
-    pub change_list: EditList<'a>,
+    pub change_list: EditMachine<'a>,
     immediate_queue: Vec<Index>,
     diffed: FxHashSet<Index>,
     need_to_diff: FxHashSet<Index>,
@@ -71,14 +71,14 @@ enum NeedToDiff {
 impl<'a> DiffMachine<'a> {
     pub fn new(bump: &'a Bump) -> Self {
         Self {
-            change_list: EditList::new(bump),
+            change_list: EditMachine::new(bump),
             immediate_queue: Vec::new(),
             diffed: FxHashSet::default(),
             need_to_diff: FxHashSet::default(),
         }
     }
 
-    pub fn consume(self) -> Vec<Edit<'a>> {
+    pub fn consume(self) -> EditList<'a> {
         self.change_list.emitter
     }
 

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

@@ -19,6 +19,11 @@ impl EventTrigger {
 }
 
 pub enum VirtualEvent {
+    // the event to drain the current lifecycle queue
+    // Used to initate the dom
+    InitiateEvent,
+
+    // Real events
     ClipboardEvent,
     CompositionEvent,
     KeyboardEvent,

+ 16 - 20
packages/core/src/scope.rs

@@ -21,7 +21,8 @@ use std::{
 ///
 /// Scopes are allocated in a generational arena. As components are mounted/unmounted, they will replace slots of dead components.
 /// The actual contents of the hooks, though, will be allocated with the standard allocator. These should not allocate as frequently.
-pub(crate) struct Scope {
+pub struct Scope {
+    // pub(crate) struct Scope {
     // TODO @Jon
     // These hooks are actually references into the hook arena
     // These two could be combined with "OwningRef" to remove unsafe usage
@@ -50,23 +51,10 @@ pub(crate) struct Scope {
     pub caller: *const i32,
 }
 
-// pub enum ActiveFrame {
-//     First,
-//     Second,
-// }
-
-// impl ActiveFrame {
-//     fn next(&mut self) {
-//         match self {
-//             ActiveFrame::First => *self = ActiveFrame::Second,
-//             ActiveFrame::Second => *self = ActiveFrame::First,
-//         }
-//     }
-// }
-
 impl Scope {
     // create a new scope from a function
-    pub(crate) fn new<T: 'static>(
+    pub fn new<T: 'static>(
+        // pub(crate) fn new<T: 'static>(
         f: FC<T>,
         props: impl Properties + 'static,
         parent: Option<Index>,
@@ -120,7 +108,7 @@ impl Scope {
     /// This function downcasts the function pointer based on the stored props_type
     ///
     /// Props is ?Sized because we borrow the props and don't need to know the size. P (sized) is used as a marker (unsized)
-    pub(crate) fn run<'bump, P: Properties + Sized + 'static>(&'bump mut self) {
+    pub fn run<'bump, P: Properties + Sized + 'static>(&'bump mut self) {
         let frame = {
             let frame = self.frames.next();
             frame.bump.reset();
@@ -164,14 +152,12 @@ impl Scope {
 
         let unsafe_node = unsafe { std::mem::transmute::<VNode<'bump>, VNode<'static>>(nodes) };
         frame.head_node = unsafe_node;
-
-        todo!()
     }
 
     /// Accessor to get the root node and its children (safely)\
     /// Scope is self-referntial, so we are forced to use the 'static lifetime to cheat
     pub fn current_root_node<'bump>(&'bump self) -> &'bump VNode<'bump> {
-        todo!()
+        self.frames.current_head_node()
     }
     pub fn prev_root_node<'bump>(&'bump self) -> &'bump VNode<'bump> {
         todo!()
@@ -196,6 +182,16 @@ impl ActiveFrame {
         }
     }
 
+    fn current_head_node<'b>(&'b self) -> &'b VNode<'b> {
+        let cur_idx = self.idx.borrow().load(std::sync::atomic::Ordering::Relaxed);
+        let raw_node = &self.frames[cur_idx];
+        unsafe {
+            let unsafe_head = &raw_node.head_node;
+            let safe_node = std::mem::transmute::<&VNode<'static>, &VNode<'b>>(unsafe_head);
+            safe_node
+        }
+    }
+
     fn next(&mut self) -> &mut BumpFrame {
         self.idx.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
         let cur = self.idx.borrow().load(std::sync::atomic::Ordering::Relaxed);

+ 9 - 7
packages/core/src/virtual_dom.rs

@@ -1,8 +1,9 @@
 // use crate::{changelist::EditList, nodes::VNode};
-use crate::{dodriodiff::DiffMachine, nodes::VNode};
+use crate::{changelist::{self, EditList}, dodriodiff::DiffMachine, nodes::VNode};
 use crate::{events::EventTrigger, innerlude::*};
 use any::Any;
 use bumpalo::Bump;
+use changelist::EditMachine;
 use generational_arena::{Arena, Index};
 use std::{
     any::{self, TypeId},
@@ -105,6 +106,10 @@ impl VirtualDom {
     /// This lets services external to the virtual dom interact directly with the component and event system.
     pub fn queue_update() {}
 
+    pub fn start(&mut self) -> Result<EditList> {
+        todo!()
+    }
+
     /// Pop an event off the event queue and process it
     /// Update the root props, and progress
     /// Takes a bump arena to allocate into, making the diff phase as fast as possible
@@ -115,7 +120,7 @@ impl VirtualDom {
             .borrow_mut()
             .pop_front()
             .ok_or(Error::NoEvent)?;
-        self.process_event(event)
+        self.process_lifecycle(event)
     }
 
     /// This method is the most sophisticated way of updating the virtual dom after an external event has been triggered.
@@ -171,7 +176,7 @@ impl VirtualDom {
             new_evt
         } {
             affected_components.push(event.component_index);
-            self.process_event(event)?;
+            self.process_lifecycle(event)?;
         }
 
         let diff_bump = Bump::new();
@@ -180,9 +185,6 @@ impl VirtualDom {
         Ok(())
     }
 
-    pub async fn progress_completely(&mut self) -> Result<()> {
-        Ok(())
-    }
     /// Using mutable access to the Virtual Dom, progress a given lifecycle event
     ///
     ///
@@ -190,7 +192,7 @@ impl VirtualDom {
     ///
     ///
     ///
-    fn process_event(
+    fn process_lifecycle(
         &mut self,
         LifecycleEvent {
             component_index: index,

+ 251 - 251
packages/web/src/interpreter.rs

@@ -380,257 +380,257 @@ impl PatchMachine {
         }
     }
 
-    // 0
-    pub fn set_text(&mut self, text: &str) {
-        self.stack.top().set_text_content(Some(text));
-    }
-
-    // 1
-    pub fn remove_self_and_next_siblings(&mut self) {
-        let node = self.stack.pop();
-        let mut sibling = node.next_sibling();
-
-        while let Some(inner) = sibling {
-            let temp = inner.next_sibling();
-            if let Some(sibling) = inner.dyn_ref::<Element>() {
-                sibling.remove();
-            }
-            sibling = temp;
-        }
-        if let Some(node) = node.dyn_ref::<Element>() {
-            node.remove();
-        }
-    }
-
-    // 2
-    pub fn replace_with(&mut self) {
-        let new_node = self.stack.pop();
-        let old_node = self.stack.pop();
-
-        if old_node.has_type::<Element>() {
-            old_node
-                .dyn_ref::<Element>()
-                .unwrap()
-                .replace_with_with_node_1(&new_node)
-                .unwrap();
-        } else if old_node.has_type::<web_sys::CharacterData>() {
-            old_node
-                .dyn_ref::<web_sys::CharacterData>()
-                .unwrap()
-                .replace_with_with_node_1(&new_node)
-                .unwrap();
-        } else if old_node.has_type::<web_sys::DocumentType>() {
-            old_node
-                .dyn_ref::<web_sys::DocumentType>()
-                .unwrap()
-                .replace_with_with_node_1(&new_node)
-                .unwrap();
-        } else {
-            panic!("Cannot replace node: {:?}", old_node);
-        }
-
-        self.stack.push(new_node);
-    }
-
-    // 3
-    pub fn set_attribute(&mut self, name: &str, value: &str) {
-        let node = self.stack.top();
-
-        if let Some(node) = node.dyn_ref::<Element>() {
-            node.set_attribute(name, value).unwrap();
-
-            // Some attributes are "volatile" and don't work through `setAttribute`.
-            // TODO:
-            // if name == "value" {
-            //     node.set_value(value);
-            // }
-            // if name == "checked" {
-            //     node.set_checked(true);
-            // }
-            // if name == "selected" {
-            //     node.set_selected(true);
-            // }
-        }
-    }
-
-    // 4
-    pub fn remove_attribute(&mut self, name: &str) {
-        let node = self.stack.top();
-        if let Some(node) = node.dyn_ref::<Element>() {
-            node.remove_attribute(name).unwrap();
-
-            // Some attributes are "volatile" and don't work through `removeAttribute`.
-            // TODO:
-            // if name == "value" {
-            //     node.set_value("");
-            // }
-            // if name == "checked" {
-            //     node.set_checked(false);
-            // }
-            // if name == "selected" {
-            //     node.set_selected(false);
-            // }
-        }
-    }
-
-    // 5
-    pub fn push_reverse_child(&mut self, n: u32) {
-        let parent = self.stack.top();
-        let children = parent.child_nodes();
-        let child = children.get(children.length() - n - 1).unwrap();
-        self.stack.push(child);
-    }
-
-    // 6
-    pub fn pop_push_child(&mut self, n: u32) {
-        self.stack.pop();
-        let parent = self.stack.top();
-        let children = parent.child_nodes();
-        let child = children.get(n).unwrap();
-        self.stack.push(child);
-    }
-
-    // 7
-    pub fn pop(&mut self) {
-        self.stack.pop();
-    }
-
-    // 8
-    pub fn append_child(&mut self) {
-        let child = self.stack.pop();
-        self.stack.top().append_child(&child).unwrap();
-    }
-
-    // 9
-    pub fn create_text_node(&mut self, text: &str) {
-        self.stack.push(
-            self.document
-                .create_text_node(text)
-                .dyn_into::<Node>()
-                .unwrap(),
-        );
-    }
-
-    // 10
-    pub fn create_element(&mut self, tag_name: &str) {
-        let el = self
-            .document
-            .create_element(tag_name)
-            .unwrap()
-            .dyn_into::<Node>()
-            .unwrap();
-        self.stack.push(el);
-    }
-
-    // 11
-    pub fn new_event_listener(&mut self, event_type: &str, a: u32, b: u32) {
-        let el = self.stack.top();
-
-        let el = el
-            .dyn_ref::<Element>()
-            .expect(&format!("not an element: {:?}", el));
-        el.add_event_listener_with_callback(
-            event_type,
-            self.callback.as_ref().unwrap().as_ref().unchecked_ref(),
-        )
-        .unwrap();
-        debug!("adding attributes: {}, {}", a, b);
-        el.set_attribute(&format!("dodrio-a-{}", event_type), &a.to_string())
-            .unwrap();
-        el.set_attribute(&format!("dodrio-b-{}", event_type), &b.to_string())
-            .unwrap();
-    }
-
-    // 12
-    pub fn update_event_listener(&mut self, event_type: &str, a: u32, b: u32) {
-        if let Some(el) = self.stack.top().dyn_ref::<Element>() {
-            el.set_attribute(&format!("dodrio-a-{}", event_type), &a.to_string())
-                .unwrap();
-            el.set_attribute(&format!("dodrio-b-{}", event_type), &b.to_string())
-                .unwrap();
-        }
-    }
-
-    // 13
-    pub fn remove_event_listener(&mut self, event_type: &str) {
-        if let Some(el) = self.stack.top().dyn_ref::<Element>() {
-            el.remove_event_listener_with_callback(
-                event_type,
-                self.callback.as_ref().unwrap().as_ref().unchecked_ref(),
-            )
-            .unwrap();
-        }
-    }
-
-    // 16
-    pub fn create_element_ns(&mut self, tag_name: &str, ns: &str) {
-        let el = self
-            .document
-            .create_element_ns(Some(ns), tag_name)
-            .unwrap()
-            .dyn_into::<Node>()
-            .unwrap();
-        self.stack.push(el);
-    }
-
-    // 17
-    pub fn save_children_to_temporaries(&mut self, mut temp: u32, start: u32, end: u32) {
-        let parent = self.stack.top();
-        let children = parent.child_nodes();
-        for i in start..end {
-            self.temporaries.insert(temp, children.get(i).unwrap());
-            temp += 1;
-        }
-    }
-
-    // 18
-    pub fn push_child(&mut self, n: u32) {
-        let parent = self.stack.top();
-        let child = parent.child_nodes().get(n).unwrap();
-        self.stack.push(child);
-    }
-
-    // 19
-    pub fn push_temporary(&mut self, temp: u32) {
-        let t = self.temporaries.get(&temp).unwrap().clone();
-        self.stack.push(t);
-    }
-
-    // 20
-    pub fn insert_before(&mut self) {
-        let before = self.stack.pop();
-        let after = self.stack.pop();
-        after
-            .parent_node()
-            .unwrap()
-            .insert_before(&before, Some(&after))
-            .unwrap();
-        self.stack.push(before);
-    }
-
-    // 21
-    pub fn pop_push_reverse_child(&mut self, n: u32) {
-        self.stack.pop();
-        let parent = self.stack.top();
-        let children = parent.child_nodes();
-        let child = children.get(children.length() - n - 1).unwrap();
-        self.stack.push(child);
-    }
-
-    // 22
-    pub fn remove_child(&mut self, n: u32) {
-        let parent = self.stack.top();
-        if let Some(child) = parent.child_nodes().get(n).unwrap().dyn_ref::<Element>() {
-            child.remove();
-        }
-    }
-
-    // 23
-    pub fn set_class(&mut self, class_name: &str) {
-        if let Some(el) = self.stack.top().dyn_ref::<Element>() {
-            el.set_class_name(class_name);
-        }
-    }
+    // // 0
+    // pub fn set_text(&mut self, text: &str) {
+    //     self.stack.top().set_text_content(Some(text));
+    // }
+
+    // // 1
+    // pub fn remove_self_and_next_siblings(&mut self) {
+    //     let node = self.stack.pop();
+    //     let mut sibling = node.next_sibling();
+
+    //     while let Some(inner) = sibling {
+    //         let temp = inner.next_sibling();
+    //         if let Some(sibling) = inner.dyn_ref::<Element>() {
+    //             sibling.remove();
+    //         }
+    //         sibling = temp;
+    //     }
+    //     if let Some(node) = node.dyn_ref::<Element>() {
+    //         node.remove();
+    //     }
+    // }
+
+    // // 2
+    // pub fn replace_with(&mut self) {
+    //     let new_node = self.stack.pop();
+    //     let old_node = self.stack.pop();
+
+    //     if old_node.has_type::<Element>() {
+    //         old_node
+    //             .dyn_ref::<Element>()
+    //             .unwrap()
+    //             .replace_with_with_node_1(&new_node)
+    //             .unwrap();
+    //     } else if old_node.has_type::<web_sys::CharacterData>() {
+    //         old_node
+    //             .dyn_ref::<web_sys::CharacterData>()
+    //             .unwrap()
+    //             .replace_with_with_node_1(&new_node)
+    //             .unwrap();
+    //     } else if old_node.has_type::<web_sys::DocumentType>() {
+    //         old_node
+    //             .dyn_ref::<web_sys::DocumentType>()
+    //             .unwrap()
+    //             .replace_with_with_node_1(&new_node)
+    //             .unwrap();
+    //     } else {
+    //         panic!("Cannot replace node: {:?}", old_node);
+    //     }
+
+    //     self.stack.push(new_node);
+    // }
+
+    // // 3
+    // pub fn set_attribute(&mut self, name: &str, value: &str) {
+    //     let node = self.stack.top();
+
+    //     if let Some(node) = node.dyn_ref::<Element>() {
+    //         node.set_attribute(name, value).unwrap();
+
+    //         // Some attributes are "volatile" and don't work through `setAttribute`.
+    //         // TODO:
+    //         // if name == "value" {
+    //         //     node.set_value(value);
+    //         // }
+    //         // if name == "checked" {
+    //         //     node.set_checked(true);
+    //         // }
+    //         // if name == "selected" {
+    //         //     node.set_selected(true);
+    //         // }
+    //     }
+    // }
+
+    // // 4
+    // pub fn remove_attribute(&mut self, name: &str) {
+    //     let node = self.stack.top();
+    //     if let Some(node) = node.dyn_ref::<Element>() {
+    //         node.remove_attribute(name).unwrap();
+
+    //         // Some attributes are "volatile" and don't work through `removeAttribute`.
+    //         // TODO:
+    //         // if name == "value" {
+    //         //     node.set_value("");
+    //         // }
+    //         // if name == "checked" {
+    //         //     node.set_checked(false);
+    //         // }
+    //         // if name == "selected" {
+    //         //     node.set_selected(false);
+    //         // }
+    //     }
+    // }
+
+    // // 5
+    // pub fn push_reverse_child(&mut self, n: u32) {
+    //     let parent = self.stack.top();
+    //     let children = parent.child_nodes();
+    //     let child = children.get(children.length() - n - 1).unwrap();
+    //     self.stack.push(child);
+    // }
+
+    // // 6
+    // pub fn pop_push_child(&mut self, n: u32) {
+    //     self.stack.pop();
+    //     let parent = self.stack.top();
+    //     let children = parent.child_nodes();
+    //     let child = children.get(n).unwrap();
+    //     self.stack.push(child);
+    // }
+
+    // // 7
+    // pub fn pop(&mut self) {
+    //     self.stack.pop();
+    // }
+
+    // // 8
+    // pub fn append_child(&mut self) {
+    //     let child = self.stack.pop();
+    //     self.stack.top().append_child(&child).unwrap();
+    // }
+
+    // // 9
+    // pub fn create_text_node(&mut self, text: &str) {
+    //     self.stack.push(
+    //         self.document
+    //             .create_text_node(text)
+    //             .dyn_into::<Node>()
+    //             .unwrap(),
+    //     );
+    // }
+
+    // // 10
+    // pub fn create_element(&mut self, tag_name: &str) {
+    //     let el = self
+    //         .document
+    //         .create_element(tag_name)
+    //         .unwrap()
+    //         .dyn_into::<Node>()
+    //         .unwrap();
+    //     self.stack.push(el);
+    // }
+
+    // // 11
+    // pub fn new_event_listener(&mut self, event_type: &str, a: u32, b: u32) {
+    //     let el = self.stack.top();
+
+    //     let el = el
+    //         .dyn_ref::<Element>()
+    //         .expect(&format!("not an element: {:?}", el));
+    //     el.add_event_listener_with_callback(
+    //         event_type,
+    //         self.callback.as_ref().unwrap().as_ref().unchecked_ref(),
+    //     )
+    //     .unwrap();
+    //     debug!("adding attributes: {}, {}", a, b);
+    //     el.set_attribute(&format!("dodrio-a-{}", event_type), &a.to_string())
+    //         .unwrap();
+    //     el.set_attribute(&format!("dodrio-b-{}", event_type), &b.to_string())
+    //         .unwrap();
+    // }
+
+    // // 12
+    // pub fn update_event_listener(&mut self, event_type: &str, a: u32, b: u32) {
+    //     if let Some(el) = self.stack.top().dyn_ref::<Element>() {
+    //         el.set_attribute(&format!("dodrio-a-{}", event_type), &a.to_string())
+    //             .unwrap();
+    //         el.set_attribute(&format!("dodrio-b-{}", event_type), &b.to_string())
+    //             .unwrap();
+    //     }
+    // }
+
+    // // 13
+    // pub fn remove_event_listener(&mut self, event_type: &str) {
+    //     if let Some(el) = self.stack.top().dyn_ref::<Element>() {
+    //         el.remove_event_listener_with_callback(
+    //             event_type,
+    //             self.callback.as_ref().unwrap().as_ref().unchecked_ref(),
+    //         )
+    //         .unwrap();
+    //     }
+    // }
+
+    // // 16
+    // pub fn create_element_ns(&mut self, tag_name: &str, ns: &str) {
+    //     let el = self
+    //         .document
+    //         .create_element_ns(Some(ns), tag_name)
+    //         .unwrap()
+    //         .dyn_into::<Node>()
+    //         .unwrap();
+    //     self.stack.push(el);
+    // }
+
+    // // 17
+    // pub fn save_children_to_temporaries(&mut self, mut temp: u32, start: u32, end: u32) {
+    //     let parent = self.stack.top();
+    //     let children = parent.child_nodes();
+    //     for i in start..end {
+    //         self.temporaries.insert(temp, children.get(i).unwrap());
+    //         temp += 1;
+    //     }
+    // }
+
+    // // 18
+    // pub fn push_child(&mut self, n: u32) {
+    //     let parent = self.stack.top();
+    //     let child = parent.child_nodes().get(n).unwrap();
+    //     self.stack.push(child);
+    // }
+
+    // // 19
+    // pub fn push_temporary(&mut self, temp: u32) {
+    //     let t = self.temporaries.get(&temp).unwrap().clone();
+    //     self.stack.push(t);
+    // }
+
+    // // 20
+    // pub fn insert_before(&mut self) {
+    //     let before = self.stack.pop();
+    //     let after = self.stack.pop();
+    //     after
+    //         .parent_node()
+    //         .unwrap()
+    //         .insert_before(&before, Some(&after))
+    //         .unwrap();
+    //     self.stack.push(before);
+    // }
+
+    // // 21
+    // pub fn pop_push_reverse_child(&mut self, n: u32) {
+    //     self.stack.pop();
+    //     let parent = self.stack.top();
+    //     let children = parent.child_nodes();
+    //     let child = children.get(children.length() - n - 1).unwrap();
+    //     self.stack.push(child);
+    // }
+
+    // // 22
+    // pub fn remove_child(&mut self, n: u32) {
+    //     let parent = self.stack.top();
+    //     if let Some(child) = parent.child_nodes().get(n).unwrap().dyn_ref::<Element>() {
+    //         child.remove();
+    //     }
+    // }
+
+    // // 23
+    // pub fn set_class(&mut self, class_name: &str) {
+    //     if let Some(el) = self.stack.top().dyn_ref::<Element>() {
+    //         el.set_class_name(class_name);
+    //     }
+    // }
 
     // 24
     pub fn save_template(&mut self, id: CacheId) {

+ 8 - 1
packages/webview/Cargo.toml

@@ -9,6 +9,13 @@ edition = "2018"
 [dependencies]
 web-view = "0.7.2"
 dioxus-core = { path = "../core" }
-
+anyhow = "1.0.38"
+argh = "0.1.4"
+serde = "1.0.120"
+serde_json = "1.0.61"
+async-std = { version = "1.9.0", features = ["attributes"] }
+thiserror = "1.0.23"
+log = "0.4.13"
+fern = { version = "0.6.0", features = ["colored"] }
 
 [build-dependencies]

+ 3 - 0
packages/webview/examples/demo.js

@@ -0,0 +1,3 @@
+// This file interperets incoming edit messages into the page and renders them.
+// This is written in javascript to be slightly easier to work with (instead of having to pre-compile the wasm)
+// One day, we'll probably using wasmbindgen for the inner, but a javascripty one is fine too.

+ 139 - 7
packages/webview/examples/demo.rs

@@ -1,20 +1,152 @@
 //! An example where the dioxus vdom is running in a native thread, interacting with webview
 
-fn main() {
-    let html_content = "<div>Hello world!</div>";
+use std::{
+    borrow::BorrowMut,
+    rc::Rc,
+    sync::{mpsc::channel, Arc},
+};
 
-    web_view::builder()
+// use async_std::{channel, task::block_on};
+
+use dioxus_core::{dodriodiff::DiffMachine, prelude::bumpalo::Bump, prelude::*, scope};
+use scope::Scope;
+use web_view::Handle;
+static HTML_CONTENT: &'static str = include_str!("./index.html");
+
+enum InnerEvent {
+    Initiate(Handle<()>),
+}
+
+// async_std::task::spawn(async {
+// #[async_std::main]
+fn main() -> anyhow::Result<()> {
+    let (sender, receiver) = channel::<InnerEvent>();
+    // let (sender, receiver) = channel::unbounded::<InnerEvent>();
+
+    // let task = async_std::task::spawn(async move {
+    let mut view = web_view::builder()
         .title("My Project")
-        .content(web_view::Content::Html(html_content))
+        .content(web_view::Content::Html(HTML_CONTENT))
         .size(320, 480)
         .resizable(true)
         .debug(true)
         .user_data(())
         .invoke_handler(|view, arg| {
-            //
-
+            // todo: handle events here
+            println!("handling invoker");
+            let handle = view.handle();
+            sender.send(InnerEvent::Initiate(handle));
             Ok(())
         })
-        .run()
+        .build()
         .unwrap();
+
+    println!("building the diff");
+    let bump = Bump::new();
+    let mut diff_machine = DiffMachine::new(&bump);
+    let old = html! {<div> </div>}(&bump);
+
+    // let mut scope = Scope::new(TEST, (), None);
+    // scope.run::<()>();
+    let new = html! {
+        <div>
+            <div class="flex items-center justify-center flex-col">
+                <div class="flex items-center justify-center">
+                    <div class="flex flex-col bg-white rounded p-4 w-full max-w-xs">
+                        // Title
+                        <div class="font-bold text-xl">
+                            "Jon's awesome site!!11"
+                        </div>
+
+                        // Subtext / description
+                        <div class="text-sm text-gray-500">
+                            "He worked so hard on it :)"
+                        </div>
+
+                        <div class="flex flex-row items-center justify-center mt-6">
+                            // Main number
+                            <div class="font-medium text-6xl">
+                                "1337"
+                            </div>
+                        </div>
+
+                        // Try another
+                        <div class="flex flex-row justify-between mt-6">
+                            // <a href=format!("http://localhost:8080/fib/{}", other_fib_to_try) class="underline">
+                                "Legit made my own React"
+                            // </a>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    }(&bump);
+
+    diff_machine.diff_node(&old, &new);
+
+    let edits = diff_machine.consume();
+    let ready_edits = serde_json::to_string(&edits)?;
+    let ref_edits = Arc::new(ready_edits);
+
+    loop {
+        view.step().expect("should not fail");
+        // if let Some(evt) = receiver.try_recv() {}
+        if let Ok(event) = receiver.try_recv() {
+            match event {
+                InnerEvent::Initiate(handle) => {
+                    // println!("awesome, things worked");
+                    let ediits = ref_edits.clone();
+                    // println!("{}", ediits);
+                    handle
+                        .dispatch(move |view| {
+                            view.eval(format!("EditListReceived(`{}`);", ediits).as_str())?;
+
+                            Ok(())
+                        })
+                        .expect("Dispatch failed");
+                    // let g = handle.();
+                }
+            }
+        }
+        // let event = receiver.try_recv();
+
+        // view.eval("alert('omg');")?;
+        // view.step().expect("webview should not fail")?;
+    }
 }
+
+// static TEST: FC<()> = |ctx, props| {
+// ctx.view(html! {
+//     <div>
+//         <div class="flex items-center justify-center flex-col">
+//             <div class="flex items-center justify-center">
+//                 <div class="flex flex-col bg-white rounded p-4 w-full max-w-xs">
+//                     // Title
+//                     <div class="font-bold text-xl">
+//                         "Jon's awesome site!!11"
+//                     </div>
+
+//                     // Subtext / description
+//                     <div class="text-sm text-gray-500">
+//                         "He worked so hard on it :)"
+//                     </div>
+
+//                     <div class="flex flex-row items-center justify-center mt-6">
+//                         // Main number
+//                         <div class="font-medium text-6xl">
+//                             "1337"
+//                         </div>
+//                     </div>
+
+//                     // Try another
+//                     <div class="flex flex-row justify-between mt-6">
+//                         // <a href=format!("http://localhost:8080/fib/{}", other_fib_to_try) class="underline">
+//                             "Legit made my own React"
+//                         // </a>
+//                     </div>
+//                 </div>
+//             </div>
+//         </div>
+//     </div>
+// })
+// };

+ 324 - 0
packages/webview/examples/index.html

@@ -0,0 +1,324 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
+    <meta charset="UTF-8" />
+    <link
+      href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css"
+      rel="stylesheet"
+    />
+  </head>
+  <body>
+    <div></div>
+  </body>
+  <script>
+    // #[derive(Debug, serde::Serialize, serde::Deserialize)]
+    // pub enum Edit<'d> {
+    //     SetText { text: &'d str },
+    //     RemoveSelfAndNextSiblings {},
+    //     ReplaceWith,
+    //     SetAttribute { name: &'d str, value: &'d str },
+    //     RemoveAttribute { name: &'d str },
+    //     PushReverseChild { n: u32 },
+    //     PopPushChild { n: u32 },
+    //     Pop,
+    //     AppendChild,
+    //     CreateTextNode { text: &'d str },
+    //     CreateElement { tag_name: &'d str },
+    //     NewEventListener { event_type: &'d str, a: u32, b: u32 },
+    //     UpdateEventListener { event_type: &'d str, a: u32, b: u32 },
+    //     RemoveEventListener { event_type: &'d str },
+    //     CreateElementNs { tag_name: &'d str, ns: &'d str },
+    //     SaveChildrenToTemporaries { temp: u32, start: u32, end: u32 },
+    //     PushChild { n: u32 },
+    //     PushTemporary { temp: u32 },
+    //     InsertBefore,
+    //     PopPushReverseChild { n: u32 },
+    //     RemoveChild { n: u32 },
+    //     SetClass { class_name: &'d str },
+    // }
+
+    //   const interpreter = new Interpreter();
+
+    class Interpreter {
+      constructor(root) {
+        this.stack = [root];
+      }
+
+      top() {
+        return this.stack[this.stack.length - 1];
+      }
+
+      pop() {
+        return this.stack.pop();
+      }
+    }
+
+    class OPTABLE {
+      // 0
+      SetText(edit, interp) {
+        interp.top(interp.stack).textContent = edit.text;
+      }
+      // 1
+      RemoveSelfAndNextSiblings(edit) {
+        const node = interp.pop();
+        let sibling = node.nextSibling;
+        while (sibling) {
+          const temp = sibling.nextSibling;
+          sibling.remove();
+          sibling = temp;
+        }
+        node.remove();
+      }
+
+      // 2
+      ReplaceWith(edit, interp) {
+        const newNode = interp.pop();
+        const oldNode = interp.pop();
+        oldNode.replaceWith(newNode);
+        interp.stack.push(newNode);
+      }
+
+      // 3
+      SetAttribute(edit, interp) {
+        const name = edit.name;
+        const value = edit.value;
+        const node = interp.top(interp.stack);
+        node.setAttribute(name, value);
+
+        // Some attributes are "volatile" and don't work through `setAttribute`.
+        if ((name === "value", interp)) {
+          node.value = value;
+        }
+        if ((name === "checked", interp)) {
+          node.checked = true;
+        }
+        if ((name === "selected", interp)) {
+          node.selected = true;
+        }
+      }
+
+      // 4
+      RemoveAttribute(edit, interp) {
+        const name = edit.name;
+        const node = interp.top(interp.stack);
+        node.removeAttribute(name);
+
+        // Some attributes are "volatile" and don't work through `removeAttribute`.
+        if ((name === "value", interp)) {
+          node.value = null;
+        }
+        if ((name === "checked", interp)) {
+          node.checked = false;
+        }
+        if ((name === "selected", interp)) {
+          node.selected = false;
+        }
+      }
+
+      // 5
+      PushReverseChild(edit, interp) {
+        const n = edit.n;
+        const parent = interp.top(interp.stack);
+        const children = parent.childNodes;
+        const child = children[children.length - n - 1];
+        interp.stack.push(child);
+      }
+
+      // 6
+      PopPushChild(edit, interp) {
+        const n = edit.n;
+        interp.pop();
+        const parent = interp.top(interp.stack);
+        const children = parent.childNodes;
+        const child = children[n];
+        interp.stack.push(child);
+      }
+
+      // 7
+      Pop(edit, interp) {
+        interp.pop();
+      }
+
+      // 8
+      AppendChild(edit, interp) {
+        console.log(interp.stack);
+        const child = interp.pop();
+        console.log(interp.stack);
+        interp.top().appendChild(child);
+      }
+
+      // 9
+      CreateTextNode(edit, interp) {
+        // interp.stack.push(document.createTextNode("asd"));
+        console.log(interp.stack);
+
+        interp.stack.push(document.createTextNode(edit.text));
+        console.log(interp.stack);
+      }
+
+      // 10
+      CreateElement(edit, interp) {
+        const tagName = edit.tag_name;
+        interp.stack.push(document.createElement(tagName));
+      }
+
+      // 11
+      NewEventListener(edit, interp) {
+        // todo!
+        const eventId = mem32[i++];
+        const eventType = interp.getCachedString(eventId);
+        const a = mem32[i++];
+        const b = mem32[i++];
+        const el = interp.top(interp.stack);
+        el.addEventListener(eventType, interp.eventHandler);
+        el[`dodrio-a-${eventType}`] = a;
+        el[`dodrio-b-${eventType}`] = b;
+      }
+
+      // 12
+      UpdateEventListener(edit, interp) {
+        // todo!
+        const eventId = mem32[i++];
+        const eventType = interp.getCachedString(eventId);
+        const el = interp.top(interp.stack);
+        el[`dodrio-a-${eventType}`] = mem32[i++];
+        el[`dodrio-b-${eventType}`] = mem32[i++];
+      }
+
+      // 13
+      RemoveEventListener(edit, interp) {
+        // todo!
+        const eventId = mem32[i++];
+        const eventType = interp.getCachedString(eventId);
+        const el = interp.top(interp.stack);
+        el.removeEventListener(eventType, interp.eventHandler);
+      }
+
+      // 14
+      AddCachedString(edit, interp) {
+        // todo!
+        const pointer = mem32[i++];
+        const length = mem32[i++];
+        const id = mem32[i++];
+        const str = string(mem8, pointer, length);
+        interp.addCachedString(str, id);
+      }
+
+      // 15
+      DropCachedString(edit, interp) {
+        // todo!
+        const id = mem32[i++];
+        interp.dropCachedString(id);
+      }
+
+      // 16
+      CreateElementNS(edit, interp) {
+        //   const tagNameId = mem32[i++];
+        //   const tagName = interp.getCachedString(tagNameId);
+        //   const nsId = mem32[i++];
+        //   const ns = interp.getCachedString(nsId);
+        interp.stack.push(document.createElementNS(edit.ns, edit.tag_name));
+      }
+
+      // 17
+      SaveChildrenToTemporaries(edit, interp) {
+        //   let temp = mem32[i++];
+        //   const start = mem32[i++];
+        //   const end = mem32[i++];
+        let temp = edit.temp;
+        const start = edit.start;
+        const end = edit.end;
+        const parent = interp.top(interp.stack);
+        const children = parent.childNodes;
+        for (let i = start; i < end; i++, interp) {
+          interp.temporaries[temp++] = children[i];
+        }
+      }
+
+      // 18
+      PushChild(edit, interp) {
+        const parent = interp.top(interp.stack);
+        //   const n = mem32[i++];
+        const n = edit.n;
+        const child = parent.childNodes[n];
+        interp.stack.push(child);
+      }
+
+      // 19
+      PushTemporary(edit, interp) {
+        //   const temp = mem32[i++];
+        const temp = edit.temp;
+        interp.stack.push(interp.temporaries[temp]);
+      }
+
+      // 20
+      InsertBefore(edit, interp) {
+        const before = interp.pop();
+        const after = interp.pop();
+        after.parentNode.insertBefore(before, after);
+        interp.stack.push(before);
+      }
+
+      // 21
+      PopPushReverseChild(edit, interp) {
+        //   const n = mem32[i++];
+        const n = edit.n;
+        interp.pop();
+        const parent = interp.top(interp.stack);
+        const children = parent.childNodes;
+        const child = children[children.length - n - 1];
+        interp.stack.push(child);
+      }
+
+      // 22
+      RemoveChild(edit, interp) {
+        //   const n = mem32[i++];
+        const n = edit.n;
+        const parent = interp.top(interp.stack);
+        const child = parent.childNodes[n];
+        child.remove();
+      }
+
+      // 23
+      SetClass(edit, interp) {
+        //   const classId = mem32[i++];
+        const className = edit.class_name;
+        interp.top(interp.stack).className = className;
+      }
+
+      // 24
+      SaveTemplate(edit, interp) {
+        const id = mem32[i++];
+        const template = interp.top(interp.stack);
+        interp.saveTemplate(id, template.cloneNode(true));
+      }
+
+      // 25
+      PushTemplate(edit, interp) {
+        const id = mem32[i++];
+        const template = interp.getTemplate(id);
+        interp.stack.push(template.cloneNode(true));
+      }
+    }
+
+    let op = new OPTABLE();
+    const c = window.document.body.firstChild;
+    console.log("First child");
+    console.log(c);
+    const interpreter = new Interpreter(window.document.body);
+    function EditListReceived(rawEditList) {
+      let editList = JSON.parse(rawEditList);
+      console.log(editList);
+      editList.forEach(function (edit, index) {
+        // console.log("processing edit");
+        const name = edit.type;
+        console.log(name);
+        const f = op[name];
+        f(edit, interpreter);
+      });
+    }
+
+    external.invoke("initiate");
+  </script>
+</html>