Merge branch 'upstream' into fix-hot-reloading

This commit is contained in:
Evan Almloff committed 2022-12-23 18:06:47 -06:00
commit 555b192436
6 files changed
+77 -99

No files matched your search

+2 -4
View File
@@ -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(),
}
}
+8
View File
@@ -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() {
-3
View File
@@ -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
View File
@@ -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 -5
View File
@@ -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(