Merge branch 'upstream' into fix-hot-reloading
This commit is contained in:
commit
555b192436
6 files changed
+77
-99
No files matched your search
@@ -1,5 +1,6 @@
|
||||
use proc_macro::TokenStream;
|
||||
use quote::ToTokens;
|
||||
use rsx::RenderCallBody;
|
||||
use syn::parse_macro_input;
|
||||
|
||||
mod inlineprops;
|
||||
@@ -41,10 +42,7 @@ pub fn rsx(s: TokenStream) -> TokenStream {
|
||||
pub fn render(s: TokenStream) -> TokenStream {
|
||||
match syn::parse::<rsx::CallBody>(s) {
|
||||
Err(err) => err.to_compile_error().into(),
|
||||
Ok(mut body) => {
|
||||
body.inline_cx = true;
|
||||
body.into_token_stream().into()
|
||||
}
|
||||
Ok(body) => RenderCallBody(body).into_token_stream().into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ use serde_json::Value;
|
||||
use std::future::Future;
|
||||
use std::future::IntoFuture;
|
||||
use std::pin::Pin;
|
||||
use wry::application::dpi::LogicalSize;
|
||||
use wry::application::event_loop::ControlFlow;
|
||||
use wry::application::event_loop::EventLoopProxy;
|
||||
#[cfg(target_os = "ios")]
|
||||
@@ -136,6 +137,11 @@ impl DesktopContext {
|
||||
let _ = self.proxy.send_event(SetZoomLevel(scale_factor));
|
||||
}
|
||||
|
||||
/// modifies the inner size of the window
|
||||
pub fn set_inner_size(&self, logical_size: LogicalSize<f64>) {
|
||||
let _ = self.proxy.send_event(SetInnerSize(logical_size));
|
||||
}
|
||||
|
||||
/// launch print modal
|
||||
pub fn print(&self) {
|
||||
let _ = self.proxy.send_event(Print);
|
||||
@@ -188,6 +194,7 @@ pub enum UserWindowEvent {
|
||||
SetDecorations(bool),
|
||||
|
||||
SetZoomLevel(f64),
|
||||
SetInnerSize(LogicalSize<f64>),
|
||||
|
||||
Print,
|
||||
DevTool,
|
||||
@@ -259,6 +266,7 @@ impl DesktopController {
|
||||
SetDecorations(state) => window.set_decorations(state),
|
||||
|
||||
SetZoomLevel(scale_factor) => webview.zoom(scale_factor),
|
||||
SetInnerSize(logical_size) => window.set_inner_size(logical_size),
|
||||
|
||||
Print => {
|
||||
if let Err(e) = webview.print() {
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
//! - [ ] Keys
|
||||
//! - [ ] Properties spreading with with `..` syntax
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use super::*;
|
||||
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
@@ -169,7 +167,6 @@ impl ToTokens for Component {
|
||||
if !self.children.is_empty() {
|
||||
let renderer: TemplateRenderer = TemplateRenderer {
|
||||
roots: &self.children,
|
||||
phantom: PhantomData,
|
||||
};
|
||||
|
||||
toks.append_all(quote! {
|
||||
|
||||
@@ -69,8 +69,8 @@ impl<Ctx: HotReloadingContext> FileMap<Ctx> {
|
||||
let old_start = old.span().start();
|
||||
|
||||
if let (Ok(old_call_body), Ok(new_call_body)) = (
|
||||
syn::parse2::<CallBody<Ctx>>(old.tokens),
|
||||
syn::parse2::<CallBody<Ctx>>(new),
|
||||
syn::parse2::<CallBody>(old.tokens),
|
||||
syn::parse2::<CallBody>(new),
|
||||
) {
|
||||
if let Ok(file) = file_path.strip_prefix(crate_dir) {
|
||||
let line = old_start.line;
|
||||
@@ -83,10 +83,12 @@ impl<Ctx: HotReloadingContext> FileMap<Ctx> {
|
||||
// the byte index doesn't matter, but dioxus needs it
|
||||
+ ":0";
|
||||
|
||||
if let Some(template) = new_call_body.update_template(
|
||||
Some(old_call_body),
|
||||
Box::leak(location.into_boxed_str()),
|
||||
) {
|
||||
if let Some(template) = new_call_body
|
||||
.update_template::<Ctx>(
|
||||
Some(old_call_body),
|
||||
Box::leak(location.into_boxed_str()),
|
||||
)
|
||||
{
|
||||
// dioxus cannot handle empty templates
|
||||
if template.roots.is_empty() {
|
||||
return UpdateResult::NeedsRebuild;
|
||||
|
||||
+58
-81
@@ -25,7 +25,6 @@ use std::{collections::HashMap, fmt::Debug, hash::Hash};
|
||||
pub use component::*;
|
||||
use dioxus_core::{Template, TemplateAttribute, TemplateNode};
|
||||
pub use element::*;
|
||||
use hot_reload::Empty;
|
||||
pub use hot_reload::HotReloadingContext;
|
||||
pub use ifmt::*;
|
||||
use internment::Intern;
|
||||
@@ -46,34 +45,26 @@ fn intern<T: Eq + Hash + Send + Sync + ?Sized + 'static>(s: impl Into<Intern<T>>
|
||||
|
||||
/// Fundametnally, every CallBody is a template
|
||||
#[derive(Default, Debug)]
|
||||
pub struct CallBody<Ctx: HotReloadingContext = Empty> {
|
||||
pub struct CallBody {
|
||||
pub roots: Vec<BodyNode>,
|
||||
|
||||
// set this after
|
||||
pub inline_cx: bool,
|
||||
|
||||
phantom: std::marker::PhantomData<Ctx>,
|
||||
}
|
||||
|
||||
impl<Ctx: HotReloadingContext> CallBody<Ctx> {
|
||||
impl CallBody {
|
||||
/// This will try to create a new template from the current body and the previous body. This will return None if the rsx has some dynamic part that has changed.
|
||||
/// This function intentionally leaks memory to create a static template.
|
||||
/// Keeping the template static allows us to simplify the core of dioxus and leaking memory in dev mode is less of an issue.
|
||||
/// the previous_location is the location of the previous template at the time the template was originally compiled.
|
||||
pub fn update_template(
|
||||
pub fn update_template<Ctx: HotReloadingContext>(
|
||||
&self,
|
||||
template: Option<CallBody<Ctx>>,
|
||||
template: Option<CallBody>,
|
||||
location: &'static str,
|
||||
) -> Option<Template<'static>> {
|
||||
let mut renderer: TemplateRenderer<Ctx> = TemplateRenderer {
|
||||
roots: &self.roots,
|
||||
phantom: std::marker::PhantomData,
|
||||
};
|
||||
renderer.update_template(template, location)
|
||||
let mut renderer: TemplateRenderer = TemplateRenderer { roots: &self.roots };
|
||||
renderer.update_template::<Ctx>(template, location)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: HotReloadingContext> Parse for CallBody<Ctx> {
|
||||
impl Parse for CallBody {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let mut roots = Vec::new();
|
||||
|
||||
@@ -87,58 +78,59 @@ impl<Ctx: HotReloadingContext> Parse for CallBody<Ctx> {
|
||||
roots.push(node);
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
roots,
|
||||
inline_cx: false,
|
||||
phantom: std::marker::PhantomData,
|
||||
})
|
||||
Ok(Self { roots })
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialize the same way, regardless of flavor
|
||||
impl<Ctx: HotReloadingContext> ToTokens for CallBody<Ctx> {
|
||||
impl ToTokens for CallBody {
|
||||
fn to_tokens(&self, out_tokens: &mut TokenStream2) {
|
||||
let body: TemplateRenderer<Ctx> = TemplateRenderer {
|
||||
roots: &self.roots,
|
||||
phantom: std::marker::PhantomData,
|
||||
};
|
||||
let body = TemplateRenderer { roots: &self.roots };
|
||||
|
||||
if self.inline_cx {
|
||||
out_tokens.append_all(quote! {
|
||||
Some({
|
||||
let __cx = cx;
|
||||
#body
|
||||
})
|
||||
out_tokens.append_all(quote! {
|
||||
::dioxus::core::LazyNodes::new( move | __cx: &::dioxus::core::ScopeState| -> ::dioxus::core::VNode {
|
||||
#body
|
||||
})
|
||||
} else {
|
||||
out_tokens.append_all(quote! {
|
||||
::dioxus::core::LazyNodes::new( move | __cx: &::dioxus::core::ScopeState| -> ::dioxus::core::VNode {
|
||||
#body
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TemplateRenderer<'a, Ctx: HotReloadingContext = Empty> {
|
||||
pub roots: &'a [BodyNode],
|
||||
phantom: std::marker::PhantomData<Ctx>,
|
||||
#[derive(Default, Debug)]
|
||||
pub struct RenderCallBody(pub CallBody);
|
||||
|
||||
impl ToTokens for RenderCallBody {
|
||||
fn to_tokens(&self, out_tokens: &mut TokenStream2) {
|
||||
let body: TemplateRenderer = TemplateRenderer {
|
||||
roots: &self.0.roots,
|
||||
};
|
||||
|
||||
out_tokens.append_all(quote! {
|
||||
Some({
|
||||
let __cx = cx;
|
||||
#body
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Ctx: HotReloadingContext> TemplateRenderer<'a, Ctx> {
|
||||
fn update_template(
|
||||
pub struct TemplateRenderer<'a> {
|
||||
pub roots: &'a [BodyNode],
|
||||
}
|
||||
|
||||
impl<'a> TemplateRenderer<'a> {
|
||||
fn update_template<Ctx: HotReloadingContext>(
|
||||
&mut self,
|
||||
previous_call: Option<CallBody<Ctx>>,
|
||||
previous_call: Option<CallBody>,
|
||||
location: &'static str,
|
||||
) -> Option<Template<'static>> {
|
||||
let mut mapping = previous_call.map(|call| DynamicMapping::from(call.roots));
|
||||
|
||||
let mut context: DynamicContext<Ctx> = DynamicContext::default();
|
||||
let mut context = DynamicContext::default();
|
||||
|
||||
let mut roots = Vec::new();
|
||||
for (idx, root) in self.roots.iter().enumerate() {
|
||||
context.current_path.push(idx as u8);
|
||||
roots.push(context.update_node(root, &mut mapping)?);
|
||||
roots.push(context.update_node::<Ctx>(root, &mut mapping)?);
|
||||
context.current_path.pop();
|
||||
}
|
||||
|
||||
@@ -165,9 +157,9 @@ impl<'a, Ctx: HotReloadingContext> TemplateRenderer<'a, Ctx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Ctx: HotReloadingContext> ToTokens for TemplateRenderer<'a, Ctx> {
|
||||
impl<'a> ToTokens for TemplateRenderer<'a> {
|
||||
fn to_tokens(&self, out_tokens: &mut TokenStream2) {
|
||||
let mut context: DynamicContext<Ctx> = DynamicContext::default();
|
||||
let mut context = DynamicContext::default();
|
||||
|
||||
let key = match self.roots.get(0) {
|
||||
Some(BodyNode::Element(el)) if self.roots.len() == 1 => el.key.clone(),
|
||||
@@ -180,6 +172,12 @@ impl<'a, Ctx: HotReloadingContext> ToTokens for TemplateRenderer<'a, Ctx> {
|
||||
None => quote! { None },
|
||||
};
|
||||
|
||||
let spndbg = format!("{:?}", self.roots[0].span());
|
||||
let root_col = spndbg
|
||||
.rsplit_once("..")
|
||||
.and_then(|(_, after)| after.split_once(')').map(|(before, _)| before))
|
||||
.unwrap_or_default();
|
||||
|
||||
let root_printer = self.roots.iter().enumerate().map(|(idx, root)| {
|
||||
context.current_path.push(idx as u8);
|
||||
let out = context.render_static_node(root);
|
||||
@@ -187,12 +185,6 @@ impl<'a, Ctx: HotReloadingContext> ToTokens for TemplateRenderer<'a, Ctx> {
|
||||
out
|
||||
});
|
||||
|
||||
let spndbg = format!("{:?}", self.roots[0].span());
|
||||
let root_col = spndbg
|
||||
.rsplit_once("..")
|
||||
.and_then(|(_, after)| after.split_once(')').map(|(before, _)| before))
|
||||
.unwrap_or_default();
|
||||
|
||||
// Render and release the mutable borrow on context
|
||||
let roots = quote! { #( #root_printer ),* };
|
||||
let node_printer = &context.dynamic_nodes;
|
||||
@@ -220,7 +212,6 @@ impl<'a, Ctx: HotReloadingContext> ToTokens for TemplateRenderer<'a, Ctx> {
|
||||
key: #key_tokens,
|
||||
template: std::cell::Cell::new(TEMPLATE),
|
||||
root_ids: Default::default(),
|
||||
// root_ids: std::cell::Cell::from_mut( __cx.bump().alloc([None; #num_roots]) as &mut [::dioxus::core::ElementId]).as_slice_of_cells(),
|
||||
dynamic_nodes: __cx.bump().alloc([ #( #node_printer ),* ]),
|
||||
dynamic_attrs: __cx.bump().alloc([ #( #dyn_attr_printer ),* ]),
|
||||
}
|
||||
@@ -318,32 +309,18 @@ impl DynamicMapping {
|
||||
|
||||
// As we create the dynamic nodes, we want to keep track of them in a linear fashion
|
||||
// We'll use the size of the vecs to determine the index of the dynamic node in the final output
|
||||
pub struct DynamicContext<'a, Ctx: HotReloadingContext> {
|
||||
#[derive(Default, Debug)]
|
||||
pub struct DynamicContext<'a> {
|
||||
dynamic_nodes: Vec<&'a BodyNode>,
|
||||
dynamic_attributes: Vec<&'a ElementAttrNamed>,
|
||||
current_path: Vec<u8>,
|
||||
|
||||
node_paths: Vec<Vec<u8>>,
|
||||
attr_paths: Vec<Vec<u8>>,
|
||||
|
||||
phantom: std::marker::PhantomData<Ctx>,
|
||||
}
|
||||
|
||||
impl<'a, Ctx: HotReloadingContext> Default for DynamicContext<'a, Ctx> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
dynamic_nodes: Vec::new(),
|
||||
dynamic_attributes: Vec::new(),
|
||||
current_path: Vec::new(),
|
||||
node_paths: Vec::new(),
|
||||
attr_paths: Vec::new(),
|
||||
phantom: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Ctx: HotReloadingContext> DynamicContext<'a, Ctx> {
|
||||
fn update_node(
|
||||
impl<'a> DynamicContext<'a> {
|
||||
fn update_node<Ctx: HotReloadingContext>(
|
||||
&mut self,
|
||||
root: &'a BodyNode,
|
||||
mapping: &mut Option<DynamicMapping>,
|
||||
@@ -400,7 +377,7 @@ impl<'a, Ctx: HotReloadingContext> DynamicContext<'a, Ctx> {
|
||||
let mut children = Vec::new();
|
||||
for (idx, root) in el.children.iter().enumerate() {
|
||||
self.current_path.push(idx as u8);
|
||||
children.push(self.update_node(root, mapping)?);
|
||||
children.push(self.update_node::<Ctx>(root, mapping)?);
|
||||
self.current_path.pop();
|
||||
}
|
||||
|
||||
@@ -577,9 +554,9 @@ fn create_template() {
|
||||
}
|
||||
}
|
||||
|
||||
let call_body: CallBody<Mock> = syn::parse2(input).unwrap();
|
||||
let call_body: CallBody = syn::parse2(input).unwrap();
|
||||
|
||||
let template = call_body.update_template(None, "testing").unwrap();
|
||||
let template = call_body.update_template::<Mock>(None, "testing").unwrap();
|
||||
|
||||
dbg!(template);
|
||||
|
||||
@@ -672,9 +649,9 @@ fn diff_template() {
|
||||
}
|
||||
}
|
||||
|
||||
let call_body1: CallBody<Mock> = syn::parse2(input).unwrap();
|
||||
let call_body1: CallBody = syn::parse2(input).unwrap();
|
||||
|
||||
let template = call_body1.update_template(None, "testing").unwrap();
|
||||
let template = call_body1.update_template::<Mock>(None, "testing").unwrap();
|
||||
dbg!(template);
|
||||
|
||||
// scrambling the attributes should not cause a full rebuild
|
||||
@@ -694,10 +671,10 @@ fn diff_template() {
|
||||
}
|
||||
};
|
||||
|
||||
let call_body2: CallBody<Mock> = syn::parse2(input).unwrap();
|
||||
let call_body2: CallBody = syn::parse2(input).unwrap();
|
||||
|
||||
let template = call_body2
|
||||
.update_template(Some(call_body1), "testing")
|
||||
.update_template::<Mock>(Some(call_body1), "testing")
|
||||
.unwrap();
|
||||
dbg!(template);
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -143,10 +142,7 @@ impl ToTokens for BodyNode {
|
||||
pat, expr, body, ..
|
||||
} = exp;
|
||||
|
||||
let renderer: TemplateRenderer = TemplateRenderer {
|
||||
roots: body,
|
||||
phantom: PhantomData,
|
||||
};
|
||||
let renderer: TemplateRenderer = TemplateRenderer { roots: body };
|
||||
|
||||
tokens.append_all(quote! {
|
||||
__cx.make_node(
|
||||
|
||||
Reference in new issue
Block a user