restore liveview renderer
This commit is contained in:
1 parent
41d10075e3
commit
9a38331826
4 files changed
+32
-158
No files matched your search
@@ -27,6 +27,11 @@ impl MutationState {
|
|||||||
bytes
|
bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write_memory_into(&mut self, buffer: &mut Vec<u8>) {
|
||||||
|
buffer.extend(self.channel.export_memory());
|
||||||
|
self.channel.reset();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn channel(&mut self) -> &mut Channel {
|
pub fn channel(&mut self) -> &mut Channel {
|
||||||
&mut self.channel
|
&mut self.channel
|
||||||
}
|
}
|
||||||
@@ -167,7 +172,7 @@ impl WriteMutations for MutationState {
|
|||||||
self.channel
|
self.channel
|
||||||
.remove_attribute(id.0 as u32, name, ns.unwrap_or_default())
|
.remove_attribute(id.0 as u32, name, ns.unwrap_or_default())
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!("Any attributes are not supported by the current renderer"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#![allow(clippy::await_holding_refcell_ref)]
|
#![allow(clippy::await_holding_refcell_ref)]
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use dioxus_core::prelude::{consume_context, provide_context};
|
use dioxus_core::ScopeId;
|
||||||
use dioxus_html::prelude::{EvalError, EvalProvider, Evaluator};
|
use dioxus_html::prelude::{EvalError, EvalProvider, Evaluator};
|
||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
@@ -9,9 +9,9 @@ use crate::query::{Query, QueryEngine};
|
|||||||
|
|
||||||
/// Provides the DesktopEvalProvider through [`cx.provide_context`].
|
/// Provides the DesktopEvalProvider through [`cx.provide_context`].
|
||||||
pub fn init_eval() {
|
pub fn init_eval() {
|
||||||
let query = consume_context::<QueryEngine>().unwrap();
|
let query = ScopeId::ROOT.consume_context::<QueryEngine>().unwrap();
|
||||||
let provider: Rc<dyn EvalProvider> = Rc::new(DesktopEvalProvider { query });
|
let provider: Rc<dyn EvalProvider> = Rc::new(DesktopEvalProvider { query });
|
||||||
provide_context(provider);
|
ScopeId::ROOT.provide_context(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reprents the desktop-target's provider of evaluators.
|
/// Reprents the desktop-target's provider of evaluators.
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ pub mod adapters {
|
|||||||
pub use rocket_adapter::*;
|
pub use rocket_adapter::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused_imports)]
|
||||||
pub use adapters::*;
|
pub use adapters::*;
|
||||||
|
|
||||||
mod element;
|
mod element;
|
||||||
|
|||||||
+22
-154
@@ -5,11 +5,10 @@ use crate::{
|
|||||||
query::{QueryEngine, QueryResult},
|
query::{QueryEngine, QueryResult},
|
||||||
LiveViewError,
|
LiveViewError,
|
||||||
};
|
};
|
||||||
use dioxus_core::{prelude::*, Attribute, AttributeValue, Mutations};
|
use dioxus_core::prelude::*;
|
||||||
use dioxus_html::{event_bubbles, EventData, HtmlEvent, MountedData, PlatformEventData};
|
use dioxus_html::{EventData, HtmlEvent, MountedData, PlatformEventData};
|
||||||
use dioxus_interpreter_js::binary_protocol::Channel;
|
use dioxus_interpreter_js::MutationState;
|
||||||
use futures_util::{pin_mut, SinkExt, StreamExt};
|
use futures_util::{pin_mut, SinkExt, StreamExt};
|
||||||
use rustc_hash::FxHashMap;
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::{rc::Rc, time::Duration};
|
use std::{rc::Rc, time::Duration};
|
||||||
use tokio_util::task::LocalPoolHandle;
|
use tokio_util::task::LocalPoolHandle;
|
||||||
@@ -38,12 +37,12 @@ impl LiveViewPool {
|
|||||||
pub async fn launch(
|
pub async fn launch(
|
||||||
&self,
|
&self,
|
||||||
ws: impl LiveViewSocket,
|
ws: impl LiveViewSocket,
|
||||||
app: fn(()) -> Element,
|
app: fn() -> Element,
|
||||||
) -> Result<(), LiveViewError> {
|
) -> Result<(), LiveViewError> {
|
||||||
self.launch_with_props(ws, app, ()).await
|
self.launch_with_props(ws, |app| app(), app).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn launch_with_props<T: Send + 'static>(
|
pub async fn launch_with_props<T: Clone + Send + 'static>(
|
||||||
&self,
|
&self,
|
||||||
ws: impl LiveViewSocket,
|
ws: impl LiveViewSocket,
|
||||||
app: fn(T) -> Element,
|
app: fn(T) -> Element,
|
||||||
@@ -126,27 +125,22 @@ pub async fn run(mut vdom: VirtualDom, ws: impl LiveViewSocket) -> Result<(), Li
|
|||||||
rx
|
rx
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut templates: FxHashMap<String, u16> = Default::default();
|
let mut mutations = MutationState::default();
|
||||||
let mut max_template_count = 0;
|
|
||||||
|
|
||||||
// Create the a proxy for query engine
|
// Create the a proxy for query engine
|
||||||
let (query_tx, mut query_rx) = tokio::sync::mpsc::unbounded_channel();
|
let (query_tx, mut query_rx) = tokio::sync::mpsc::unbounded_channel();
|
||||||
let query_engine = QueryEngine::new(query_tx);
|
let query_engine = QueryEngine::new(query_tx);
|
||||||
vdom.base_scope().provide_context(query_engine.clone());
|
vdom.in_runtime(|| {
|
||||||
init_eval();
|
ScopeId::ROOT.provide_context(query_engine.clone());
|
||||||
|
init_eval();
|
||||||
|
});
|
||||||
|
|
||||||
// pin the futures so we can use select!
|
// pin the futures so we can use select!
|
||||||
pin_mut!(ws);
|
pin_mut!(ws);
|
||||||
|
|
||||||
let mut edit_channel = Channel::default();
|
|
||||||
if let Some(edits) = {
|
if let Some(edits) = {
|
||||||
let mutations = vdom.rebuild();
|
vdom.rebuild(&mut mutations);
|
||||||
apply_edits(
|
take_edits(&mut mutations)
|
||||||
mutations,
|
|
||||||
&mut edit_channel,
|
|
||||||
&mut templates,
|
|
||||||
&mut max_template_count,
|
|
||||||
)
|
|
||||||
} {
|
} {
|
||||||
// send the initial render to the client
|
// send the initial render to the client
|
||||||
ws.send(edits).await?;
|
ws.send(edits).await?;
|
||||||
@@ -233,18 +227,13 @@ pub async fn run(mut vdom: VirtualDom, ws: impl LiveViewSocket) -> Result<(), Li
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let edits = vdom
|
vdom.render_with_deadline(
|
||||||
.render_with_deadline(tokio::time::sleep(Duration::from_millis(10)))
|
tokio::time::sleep(Duration::from_millis(10)),
|
||||||
.await;
|
&mut mutations,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
if let Some(edits) = {
|
if let Some(edits) = take_edits(&mut mutations) {
|
||||||
apply_edits(
|
|
||||||
edits,
|
|
||||||
&mut edit_channel,
|
|
||||||
&mut templates,
|
|
||||||
&mut max_template_count,
|
|
||||||
)
|
|
||||||
} {
|
|
||||||
ws.send(edits).await?;
|
ws.send(edits).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -256,132 +245,11 @@ fn text_frame(text: &str) -> Vec<u8> {
|
|||||||
bytes
|
bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_template(
|
fn take_edits(mutations: &mut MutationState) -> Option<Vec<u8>> {
|
||||||
template: &Template,
|
|
||||||
channel: &mut Channel,
|
|
||||||
templates: &mut FxHashMap<String, u16>,
|
|
||||||
max_template_count: &mut u16,
|
|
||||||
) {
|
|
||||||
for root in template.roots.iter() {
|
|
||||||
create_template_node(channel, root);
|
|
||||||
templates.insert(template.name.to_owned(), *max_template_count);
|
|
||||||
}
|
|
||||||
channel.add_templates(*max_template_count, template.roots.len() as u16);
|
|
||||||
|
|
||||||
*max_template_count += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_template_node(channel: &mut Channel, v: &'static TemplateNode) {
|
|
||||||
use TemplateNode::*;
|
|
||||||
match v {
|
|
||||||
Element {
|
|
||||||
tag,
|
|
||||||
namespace,
|
|
||||||
attrs,
|
|
||||||
children,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
// Push the current node onto the stack
|
|
||||||
match namespace {
|
|
||||||
Some(ns) => channel.create_element_ns(tag, ns),
|
|
||||||
None => channel.create_element(tag),
|
|
||||||
}
|
|
||||||
// Set attributes on the current node
|
|
||||||
for attr in *attrs {
|
|
||||||
if let TemplateAttribute::Static {
|
|
||||||
name,
|
|
||||||
value,
|
|
||||||
namespace,
|
|
||||||
} = attr
|
|
||||||
{
|
|
||||||
channel.set_top_attribute(name, value, namespace.unwrap_or_default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Add each child to the stack
|
|
||||||
for child in *children {
|
|
||||||
create_template_node(channel, child);
|
|
||||||
}
|
|
||||||
// Add all children to the parent
|
|
||||||
channel.append_children_to_top(children.len() as u16);
|
|
||||||
}
|
|
||||||
Text { text } => channel.create_raw_text(text),
|
|
||||||
DynamicText { .. } => channel.create_raw_text("p"),
|
|
||||||
Dynamic { .. } => channel.add_placeholder(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn apply_edits(
|
|
||||||
mutations: Mutations,
|
|
||||||
channel: &mut Channel,
|
|
||||||
templates: &mut FxHashMap<String, u16>,
|
|
||||||
max_template_count: &mut u16,
|
|
||||||
) -> Option<Vec<u8>> {
|
|
||||||
use dioxus_core::Mutation::*;
|
|
||||||
if mutations.templates.is_empty() && mutations.edits.is_empty() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
for template in mutations.templates {
|
|
||||||
add_template(&template, channel, templates, max_template_count);
|
|
||||||
}
|
|
||||||
for edit in mutations.edits {
|
|
||||||
match edit {
|
|
||||||
AppendChildren { id, m } => channel.append_children(id.0 as u32, m as u16),
|
|
||||||
AssignId { path, id } => channel.assign_id(path, id.0 as u32),
|
|
||||||
CreatePlaceholder { id } => channel.create_placeholder(id.0 as u32),
|
|
||||||
CreateTextNode { value, id } => channel.create_text_node(value, id.0 as u32),
|
|
||||||
HydrateText { path, value, id } => channel.hydrate_text(path, value, id.0 as u32),
|
|
||||||
LoadTemplate { name, index, id } => {
|
|
||||||
if let Some(tmpl_id) = templates.get(name) {
|
|
||||||
channel.load_template(*tmpl_id, index as u16, id.0 as u32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ReplaceWith { id, m } => channel.replace_with(id.0 as u32, m as u16),
|
|
||||||
ReplacePlaceholder { path, m } => channel.replace_placeholder(path, m as u16),
|
|
||||||
InsertAfter { id, m } => channel.insert_after(id.0 as u32, m as u16),
|
|
||||||
InsertBefore { id, m } => channel.insert_before(id.0 as u32, m as u16),
|
|
||||||
SetAttribute {
|
|
||||||
name,
|
|
||||||
value,
|
|
||||||
id,
|
|
||||||
ns,
|
|
||||||
} => match value {
|
|
||||||
BorrowedAttributeValue::Text(txt) => {
|
|
||||||
channel.set_attribute(id.0 as u32, name, txt, ns.unwrap_or_default())
|
|
||||||
}
|
|
||||||
BorrowedAttributeValue::Float(f) => {
|
|
||||||
channel.set_attribute(id.0 as u32, name, &f.to_string(), ns.unwrap_or_default())
|
|
||||||
}
|
|
||||||
BorrowedAttributeValue::Int(n) => {
|
|
||||||
channel.set_attribute(id.0 as u32, name, &n.to_string(), ns.unwrap_or_default())
|
|
||||||
}
|
|
||||||
BorrowedAttributeValue::Bool(b) => channel.set_attribute(
|
|
||||||
id.0 as u32,
|
|
||||||
name,
|
|
||||||
if b { "true" } else { "false" },
|
|
||||||
ns.unwrap_or_default(),
|
|
||||||
),
|
|
||||||
BorrowedAttributeValue::None => {
|
|
||||||
channel.remove_attribute(id.0 as u32, name, ns.unwrap_or_default())
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
},
|
|
||||||
SetText { value, id } => channel.set_text(id.0 as u32, value),
|
|
||||||
NewEventListener { name, id, .. } => {
|
|
||||||
channel.new_event_listener(name, id.0 as u32, event_bubbles(name) as u8)
|
|
||||||
}
|
|
||||||
RemoveEventListener { name, id } => {
|
|
||||||
channel.remove_event_listener(name, id.0 as u32, event_bubbles(name) as u8)
|
|
||||||
}
|
|
||||||
Remove { id } => channel.remove(id.0 as u32),
|
|
||||||
PushRoot { id } => channel.push_root(id.0 as u32),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add an extra one at the beginning to tell the shim this is a binary frame
|
// Add an extra one at the beginning to tell the shim this is a binary frame
|
||||||
let mut bytes = vec![1];
|
let mut bytes = vec![1];
|
||||||
bytes.extend(channel.export_memory());
|
mutations.write_memory_into(&mut bytes);
|
||||||
channel.reset();
|
(bytes.len() > 1).then_some(bytes)
|
||||||
Some(bytes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
|
|||||||
Reference in new issue
Block a user