diff --git a/packages/rsx_interpreter/src/attributes.rs b/packages/rsx_interpreter/src/attributes.rs index c0b2c9980..f8d19fddb 100644 --- a/packages/rsx_interpreter/src/attributes.rs +++ b/packages/rsx_interpreter/src/attributes.rs @@ -1,6 +1,6 @@ use crate::elements::*; -// find the mapped attribute name +// map the rsx name of the attribute to the html name of the attribute and the namespace that contains it pub fn attrbute_to_static_str(attr: &str) -> Option<(&'static str, Option<&'static str>)> { NO_NAMESPACE_ATTRIBUTES .iter() diff --git a/packages/rsx_interpreter/src/captuered_context.rs b/packages/rsx_interpreter/src/captuered_context.rs index 052cceabc..40c471112 100644 --- a/packages/rsx_interpreter/src/captuered_context.rs +++ b/packages/rsx_interpreter/src/captuered_context.rs @@ -4,7 +4,6 @@ use dioxus_rsx::{ }; use quote::{quote, ToTokens, TokenStreamExt}; use syn::{Expr, Ident, Result}; - #[derive(Default)] pub struct CapturedContextBuilder { pub ifmted: Vec, @@ -146,7 +145,7 @@ impl ToTokens for CapturedContextBuilder { pub struct CapturedContext<'a> { // map of the variable name to the formated value pub captured: IfmtArgs, - // // map of the attribute name and element path to the formated value + // map of the attribute name and element path to the formated value // pub captured_attribute_values: IfmtArgs, // the only thing we can update in component is the children pub components: Vec<(&'static str, VNode<'a>)>, @@ -159,10 +158,11 @@ pub struct CapturedContext<'a> { } pub struct IfmtArgs { - // map expressions to the value string they produced + // All expressions that have been resolved pub named_args: Vec, } +/// A formated segment that has been resolved pub struct FormattedArg { pub expr: &'static str, pub format_args: &'static str, diff --git a/packages/rsx_interpreter/src/elements.rs b/packages/rsx_interpreter/src/elements.rs index 032c8f98e..7be3f2804 100644 --- a/packages/rsx_interpreter/src/elements.rs +++ b/packages/rsx_interpreter/src/elements.rs @@ -1,4 +1,4 @@ -// find the mapped attribute name +// map the rsx name of the element to the html name of the element and the namespace that contains it pub fn element_to_static_str(element: &str) -> Option<(&'static str, Option<&'static str>)> { ELEMENTS_WITH_MAPPED_ATTRIBUTES .iter() diff --git a/packages/rsx_interpreter/src/error.rs b/packages/rsx_interpreter/src/error.rs index 6235c10b3..24ad86e20 100644 --- a/packages/rsx_interpreter/src/error.rs +++ b/packages/rsx_interpreter/src/error.rs @@ -1,5 +1,6 @@ use serde::{Deserialize, Serialize}; +/// An error produced when interperting the rsx #[derive(Debug)] pub enum Error { ParseError(syn::Error), diff --git a/packages/rsx_interpreter/src/interperter.rs b/packages/rsx_interpreter/src/interperter.rs index b3439b3e9..53b1a9196 100644 --- a/packages/rsx_interpreter/src/interperter.rs +++ b/packages/rsx_interpreter/src/interperter.rs @@ -8,43 +8,39 @@ use crate::captuered_context::{CapturedContext, IfmtArgs}; use crate::elements::element_to_static_str; use crate::error::{Error, RecompileReason}; -struct InterpertedIfmt(IfmtInput); - -impl InterpertedIfmt { - fn resolve(&self, captured: &IfmtArgs) -> Result { - let mut result = String::new(); - for seg in &self.0.segments { - match seg { - Segment::Formatted { - segment, - format_args, - } => { - let expr = segment.to_token_stream(); - let expr: Expr = parse2(expr).unwrap(); - let search = captured.named_args.iter().find(|fmted| { - parse_str::(fmted.expr).unwrap() == expr - && fmted.format_args == format_args - }); - match search { - Some(formatted) => { - result.push_str(&formatted.result); - } - None => { - let expr_str = segment.to_token_stream().to_string(); - return Err(Error::RecompileRequiredError( - RecompileReason::CapturedExpression(format!( - "could not resolve {{{}:{}}}", - expr_str, format_args - )), - )); - } +fn resolve_ifmt(ifmt: &IfmtInput, captured: &IfmtArgs) -> Result { + let mut result = String::new(); + for seg in &ifmt.segments { + match seg { + Segment::Formatted { + segment, + format_args, + } => { + let expr = segment.to_token_stream(); + let expr: Expr = parse2(expr).unwrap(); + let search = captured.named_args.iter().find(|fmted| { + parse_str::(fmted.expr).unwrap() == expr + && fmted.format_args == format_args + }); + match search { + Some(formatted) => { + result.push_str(&formatted.result); + } + None => { + let expr_str = segment.to_token_stream().to_string(); + return Err(Error::RecompileRequiredError( + RecompileReason::CapturedExpression(format!( + "could not resolve {{{}:{}}}", + expr_str, format_args + )), + )); } } - Segment::Literal(lit) => result.push_str(lit), } + Segment::Literal(lit) => result.push_str(lit), } - Ok(result) } + Ok(result) } pub fn build<'a>( @@ -67,10 +63,8 @@ fn build_node<'a>( let bump = factory.bump(); match node { BodyNode::Text(text) => { - let ifmt = InterpertedIfmt( - IfmtInput::from_str(&text.value()).map_err(|err| Error::ParseError(err))?, - ); - let text = bump.alloc(ifmt.resolve(&ctx.captured)?); + let ifmt = IfmtInput::from_str(&text.value()).map_err(|err| Error::ParseError(err))?; + let text = bump.alloc(resolve_ifmt(&ifmt, &ctx.captured)?); Ok(factory.text(format_args!("{}", text))) } BodyNode::Element(el) => { @@ -78,26 +72,22 @@ fn build_node<'a>( for attr in &el.attributes { match &attr.attr { ElementAttr::AttrText { .. } | ElementAttr::CustomAttrText { .. } => { - let (name, value): (String, InterpertedIfmt) = match &attr.attr { + let (name, value): (String, IfmtInput) = match &attr.attr { ElementAttr::AttrText { name, value } => ( name.to_string(), - InterpertedIfmt( - IfmtInput::from_str(&value.value()) - .map_err(|err| Error::ParseError(err))?, - ), + IfmtInput::from_str(&value.value()) + .map_err(|err| Error::ParseError(err))?, ), ElementAttr::CustomAttrText { name, value } => ( name.value(), - InterpertedIfmt( - IfmtInput::from_str(&value.value()) - .map_err(|err| Error::ParseError(err))?, - ), + IfmtInput::from_str(&value.value()) + .map_err(|err| Error::ParseError(err))?, ), _ => unreachable!(), }; if let Some((name, namespace)) = attrbute_to_static_str(&name) { - let value = bump.alloc(value.resolve(&ctx.captured)?); + let value = bump.alloc(resolve_ifmt(&value, &ctx.captured)?); attributes.push(Attribute { name, value: AttributeValue::Text(value), @@ -188,10 +178,9 @@ fn build_node<'a>( None, )), Some(lit) => { - let ifmt: InterpertedIfmt = InterpertedIfmt( - parse_str(&lit.value()).map_err(|err| Error::ParseError(err))?, - ); - let key = bump.alloc(ifmt.resolve(&ctx.captured)?); + let ifmt: IfmtInput = + parse_str(&lit.value()).map_err(|err| Error::ParseError(err))?; + let key = bump.alloc(resolve_ifmt(&ifmt, &ctx.captured)?); Ok(factory.raw_element( tag, diff --git a/packages/rsx_interpreter/src/lib.rs b/packages/rsx_interpreter/src/lib.rs index 922ab3acd..75297abe4 100644 --- a/packages/rsx_interpreter/src/lib.rs +++ b/packages/rsx_interpreter/src/lib.rs @@ -22,6 +22,7 @@ lazy_static! { pub static ref RSX_CONTEXT: RsxContext = RsxContext::new(RsxData::default()); } +// the location of the code relative to the current crate based on [std::panic::Location] #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] pub struct CodeLocation { pub file: String, @@ -29,6 +30,7 @@ pub struct CodeLocation { pub column: u32, } +/// Get the resolved rsx given the origional rsx, a captured context of dynamic components, and a factory to build the resulting node pub fn resolve_scope<'a>( location: CodeLocation, rsx: &'static str, @@ -57,7 +59,7 @@ pub fn resolve_scope<'a>( } } -pub fn interpert_rsx<'a, 'b>( +fn interpert_rsx<'a, 'b>( factory: dioxus_core::NodeFactory<'a>, text: &str, context: captuered_context::CapturedContext<'a>, @@ -69,6 +71,7 @@ pub fn interpert_rsx<'a, 'b>( ) } +/// get the code location of the code that called this function #[track_caller] pub fn get_line_num() -> CodeLocation { let location = Location::caller(); @@ -79,11 +82,13 @@ pub fn get_line_num() -> CodeLocation { } } +/// A handle to the rsx context with interior mutability #[derive(Debug)] pub struct RsxContext { data: RwLock, } +/// A store of the text for the rsx macro for each call to rsx #[derive(Default)] pub struct RsxData { pub hm: HashMap, @@ -104,6 +109,7 @@ impl RsxContext { } } + /// Set the text for an rsx call at some location pub fn insert(&self, loc: CodeLocation, text: String) { let mut write = self.data.write().unwrap(); write.hm.insert(loc, text); @@ -112,25 +118,29 @@ impl RsxContext { } } - pub fn read(&self) -> RwLockReadGuard { + fn read(&self) -> RwLockReadGuard { self.data.read().unwrap() } - pub fn report_error(&self, error: Error) { + fn report_error(&self, error: Error) { if let Some(handler) = &self.data.write().unwrap().error_handler { handler.handle_error(error) } } + /// Set the handler for errors interperting the rsx pub fn set_error_handler(&self, handler: impl ErrorHandler + 'static) { self.data.write().unwrap().error_handler = Some(Box::new(handler)); } + /// Provide the scduler channel from [dioxus_code::VirtualDom::get_scheduler_channel]. + /// The channel allows the interpreter to force re-rendering of the dom when the rsx is changed. pub fn provide_scheduler_channel(&self, channel: UnboundedSender) { self.data.write().unwrap().scheduler_channel = Some(channel) } } +/// A error handler for errors reported by the rsx interperter pub trait ErrorHandler: Send + Sync { fn handle_error(&self, err: Error); } diff --git a/src/lib.rs b/src/lib.rs index 22144f87c..a28d6c7f5 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, resolve_scope, CodeLocation, RsxContext, + get_line_num, resolve_scope, CodeLocation, RsxContext, }; }