From 2bcaa2e43e10551364f165961bbfc8381bdd7db0 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sat, 4 Jun 2022 12:20:56 -0500 Subject: [PATCH] refactor interperting macro into function and don't rely on cx being in scope --- packages/core-macro/src/lib.rs | 46 ++++++-------------------- packages/desktop/src/controller.rs | 15 +++------ packages/rsx_interpreter/Cargo.toml | 1 + packages/rsx_interpreter/src/lib.rs | 51 ++++++++++++++++++++++++++--- src/lib.rs | 2 +- 5 files changed, 64 insertions(+), 51 deletions(-) diff --git a/packages/core-macro/src/lib.rs b/packages/core-macro/src/lib.rs index 6cba99ace..c7bf5485c 100644 --- a/packages/core-macro/src/lib.rs +++ b/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(), } } diff --git a/packages/desktop/src/controller.rs b/packages/desktop/src/controller.rs index 9329e25f7..f6521f397 100644 --- a/packages/desktop/src/controller.rs +++ b/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 { diff --git a/packages/rsx_interpreter/Cargo.toml b/packages/rsx_interpreter/Cargo.toml index 890773ad4..172ce4975 100644 --- a/packages/rsx_interpreter/Cargo.toml +++ b/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" } diff --git a/packages/rsx_interpreter/src/lib.rs b/packages/rsx_interpreter/src/lib.rs index 7150b888e..79420cebb 100644 --- a/packages/rsx_interpreter/src/lib.rs +++ b/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>, } +#[derive(Default)] pub struct RsxData { pub hm: HashMap, - pub error_handler: Box, + pub error_handler: Option>, } 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); } diff --git a/src/lib.rs b/src/lib.rs index d9e723f3b..22144f87c 100644 --- a/src/lib.rs +++ b/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, }; }