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

This commit is contained in:
Evan Almloff 2022-06-04 12:20:56 -05:00
parent 0079f7d18b
commit 2bcaa2e43e
5 changed files with 64 additions and 51 deletions

View file

@ -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(),
}
}

View file

@ -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 {

View file

@ -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" }

View file

@ -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);
}

View file

@ -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,
};
}