Browse Source

refactor interperting macro into function and don't rely on cx being in scope

Evan Almloff 3 years ago
parent
commit
2bcaa2e43e

+ 10 - 36
packages/core-macro/src/lib.rs

@@ -189,44 +189,18 @@ pub fn rsx(s: TokenStream) -> TokenStream {
                 use dioxus_rsx_interpreter::captuered_context::CapturedContextBuilder;
 
                 match CapturedContextBuilder::from_call_body(body) {
-                    Ok(captured) => {
-                        quote::quote! {
-                            {
-                                let __line_num = get_line_num();
-                                let __rsx_text_index: RsxContext = cx.consume_context().expect("Hot reload is not avalable on this platform");
-                                // only the insert the rsx text once
-                                if !__rsx_text_index.read().hm.contains_key(&__line_num){
-                                    __rsx_text_index.insert(
-                                        __line_num.clone(),
-                                        #rsx_text.to_string(),
-                                    );
-                                }
-                                LazyNodes::new(move |__cx|{
-                                    if let Some(__text) = {
-                                        let read = __rsx_text_index.read();
-                                        // clone prevents deadlock on nested rsx calls
-                                        read.hm.get(&__line_num).cloned()
-                                    } {
-                                        match interpert_rsx(
-                                            __cx,
-                                            &__text,
-                                            #captured
-                                        ){
-                                            Ok(vnode) => vnode,
-                                            Err(err) => {
-                                                __rsx_text_index.report_error(err);
-                                                __cx.text(format_args!(""))
-                                            }
-                                        }
-                                    }
-                                    else {
-                                        panic!("rsx: line number {:?} not found in rsx index", __line_num);
-                                    }
-                                })
-                            }
+                    Ok(captured) => quote::quote! {
+                        {
+                            LazyNodes::new(|__cx|{
+                                let captured = #captured;
+                                let line_num = get_line_num();
+                                let text = #rsx_text;
+
+                                resolve_scope(line_num, text, captured, __cx)
+                            })
                         }
-                        .into()
                     }
+                    .into(),
                     Err(err) => err.into_compile_error().into(),
                 }
             }

+ 5 - 10
packages/desktop/src/controller.rs

@@ -54,7 +54,7 @@ impl DesktopController {
                 #[cfg(feature = "hot_reload")]
                 {
                     use dioxus_rsx_interpreter::{
-                        error::Error, ErrorHandler, RsxContext, RsxData, SetRsxMessage,
+                        error::Error, ErrorHandler, RsxContext, RsxData, SetRsxMessage, RSX_CONTEXT,
                     };
                     use interprocess::local_socket::{LocalSocketListener, LocalSocketStream};
                     use std::io::{BufRead, BufReader, Write};
@@ -93,14 +93,9 @@ impl DesktopController {
                         }
                     }
 
-                    let context = dom
-                        .base_scope()
-                        .provide_root_context(RsxContext::new(RsxData {
-                            hm: HashMap::new(),
-                            error_handler: Box::new(DesktopErrorHandler {
-                                latest_connection: latest_connection_handle,
-                            }),
-                        }));
+                    RSX_CONTEXT.set_error_handler(DesktopErrorHandler {
+                        latest_connection: latest_connection_handle,
+                    });
 
                     std::thread::spawn(move || {
                         if let Ok(listener) = LocalSocketListener::bind("@dioxus") {
@@ -124,7 +119,7 @@ impl DesktopController {
                                         let message: SetRsxMessage =
                                             serde_json::from_str(&buf).unwrap();
                                         println!("{:?}", message.location);
-                                        context.insert(message.location, message.new_text);
+                                        RSX_CONTEXT.insert(message.location, message.new_text);
                                     }
                                     Err(err) => {
                                         if err.kind() != std::io::ErrorKind::WouldBlock {

+ 1 - 0
packages/rsx_interpreter/Cargo.toml

@@ -9,6 +9,7 @@ syn = { version = "1.0", features = ["extra-traits"] }
 quote = "1.0"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = { vesion = "1.0" }
+lazy_static = "1.4.0"
 
 dioxus-rsx = { path = "../rsx", default-features = false }
 dioxus-ssr = { path = "../ssr" }

+ 47 - 4
packages/rsx_interpreter/src/lib.rs

@@ -1,6 +1,8 @@
-use dioxus_core::{Component, Element, LazyNodes, Scope, VNode};
+use captuered_context::CapturedContext;
+use dioxus_core::{Component, Element, LazyNodes, NodeFactory, Scope, ScopeState, VNode};
 use error::Error;
 use interperter::build;
+use lazy_static::lazy_static;
 use serde::{Deserialize, Serialize};
 use std::collections::HashMap;
 use std::panic::Location;
@@ -13,6 +15,12 @@ mod elements;
 pub mod error;
 mod interperter;
 
+lazy_static! {
+    /// This a a global store of the current
+    // Global mutable data is genrally not great, but it allows users to not worry about passing down the text RsxContex every time they switch to hot reloading.
+    pub static ref RSX_CONTEXT: RsxContext = RsxContext::new(RsxData::default());
+}
+
 #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
 pub struct CodeLocation {
     pub file: String,
@@ -20,6 +28,34 @@ pub struct CodeLocation {
     pub column: u32,
 }
 
+pub fn resolve_scope<'a>(
+    location: CodeLocation,
+    rsx: &'static str,
+    captured: CapturedContext<'a>,
+    factory: NodeFactory<'a>,
+) -> VNode<'a> {
+    let rsx_text_index = &*RSX_CONTEXT;
+    // only the insert the rsx text once
+    if !rsx_text_index.read().hm.contains_key(&location) {
+        rsx_text_index.insert(location.clone(), rsx.to_string());
+    }
+    if let Some(text) = {
+        let read = rsx_text_index.read();
+        // clone prevents deadlock on nested rsx calls
+        read.hm.get(&location).cloned()
+    } {
+        match interpert_rsx(factory, &text, captured) {
+            Ok(vnode) => vnode,
+            Err(err) => {
+                rsx_text_index.report_error(err);
+                factory.text(format_args!(""))
+            }
+        }
+    } else {
+        panic!("rsx: line number {:?} not found in rsx index", location);
+    }
+}
+
 pub fn interpert_rsx<'a, 'b>(
     factory: dioxus_core::NodeFactory<'a>,
     text: &str,
@@ -47,9 +83,10 @@ pub struct RsxContext {
     data: Arc<RwLock<RsxData>>,
 }
 
+#[derive(Default)]
 pub struct RsxData {
     pub hm: HashMap<CodeLocation, String>,
-    pub error_handler: Box<dyn ErrorHandler + Send + Sync>,
+    pub error_handler: Option<Box<dyn ErrorHandler>>,
 }
 
 impl std::fmt::Debug for RsxData {
@@ -74,11 +111,17 @@ impl RsxContext {
     }
 
     pub fn report_error(&self, error: Error) {
-        self.data.write().unwrap().error_handler.handle_error(error)
+        if let Some(handler) = &self.data.write().unwrap().error_handler {
+            handler.handle_error(error)
+        }
+    }
+
+    pub fn set_error_handler(&self, handler: impl ErrorHandler + 'static) {
+        self.data.write().unwrap().error_handler = Some(Box::new(handler));
     }
 }
 
-pub trait ErrorHandler {
+pub trait ErrorHandler: Send + Sync {
     fn handle_error(&self, err: Error);
 }
 

+ 1 - 1
src/lib.rs

@@ -65,6 +65,6 @@ pub mod prelude {
     #[cfg(feature = "hot_reload")]
     pub use dioxus_rsx_interpreter::{
         captuered_context::{CapturedContext, FormattedArg, IfmtArgs},
-        get_line_num, interpert_rsx, CodeLocation, RsxContext,
+        get_line_num, interpert_rsx, resolve_scope, CodeLocation, RsxContext,
     };
 }