dioxus/packages/core/src/virtual_dom.rs

111 lines
3.5 KiB
Rust
Raw Normal View History

2022-11-02 01:42:29 +00:00
use crate::any_props::VComponentProps;
use crate::arena::ElementPath;
2022-11-03 08:38:18 +00:00
use crate::component::Component;
2022-11-02 01:42:29 +00:00
use crate::diff::DirtyScope;
2022-11-04 03:56:31 +00:00
use crate::factory::RenderReturn;
2022-11-09 03:39:37 +00:00
use crate::innerlude::{Renderer, Scheduler, SchedulerMsg};
2022-11-02 01:42:29 +00:00
use crate::mutations::Mutation;
use crate::nodes::{Template, TemplateId};
2022-11-06 08:48:34 +00:00
2022-11-02 01:42:29 +00:00
use crate::{
arena::ElementId,
scopes::{ScopeId, ScopeState},
};
2022-11-06 08:48:34 +00:00
use crate::{scheduler, Element, Scope};
2022-11-02 01:42:29 +00:00
use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
2022-11-09 03:39:37 +00:00
use futures_util::Future;
use scheduler::{SuspenseBoundary, SuspenseContext, SuspenseId};
2022-11-02 01:42:29 +00:00
use slab::Slab;
use std::collections::{BTreeSet, HashMap};
pub struct VirtualDom {
2022-11-02 08:00:37 +00:00
pub(crate) templates: HashMap<TemplateId, Template<'static>>,
2022-11-02 01:42:29 +00:00
pub(crate) elements: Slab<ElementPath>,
pub(crate) scopes: Slab<ScopeState>,
pub(crate) element_stack: Vec<ElementId>,
pub(crate) dirty_scopes: BTreeSet<DirtyScope>,
2022-11-06 08:48:34 +00:00
pub(crate) scheduler: Scheduler,
2022-11-09 03:39:37 +00:00
// While diffing we need some sort of way of breaking off a stream of suspended mutations.
pub(crate) scope_stack: Vec<ScopeId>,
pub(crate) waiting_on: Vec<SuspenseId>,
2022-11-02 01:42:29 +00:00
}
impl VirtualDom {
2022-11-04 00:34:42 +00:00
pub fn new(app: fn(Scope) -> Element) -> Self {
2022-11-06 08:48:34 +00:00
let scheduler = Scheduler::new();
2022-11-02 01:42:29 +00:00
let mut res = Self {
templates: Default::default(),
scopes: Slab::default(),
elements: Default::default(),
scope_stack: Vec::new(),
element_stack: vec![ElementId(0)],
dirty_scopes: BTreeSet::new(),
2022-11-09 03:39:37 +00:00
waiting_on: Vec::new(),
2022-11-06 08:48:34 +00:00
scheduler,
2022-11-02 01:42:29 +00:00
};
let props = Box::into_raw(Box::new(VComponentProps::new_empty(app)));
2022-11-04 00:34:42 +00:00
let props: *mut VComponentProps<(), ()> = unsafe { std::mem::transmute(props) };
2022-11-02 01:42:29 +00:00
let root = res.new_scope(props);
2022-11-04 05:30:26 +00:00
// the root component is always a suspense boundary for any async children
2022-11-09 03:39:37 +00:00
res.scopes[root.0].provide_context(SuspenseBoundary::new(root));
2022-11-02 01:42:29 +00:00
assert_eq!(root, ScopeId(0));
res
}
/// Render the virtualdom, without processing any suspense.
2022-11-09 03:39:37 +00:00
///
/// This does register futures with wakers, but does not process any of them.
pub fn rebuild<'a>(&'a mut self) -> Renderer<'a> {
let mut mutations = Renderer::new(0);
2022-11-04 03:56:31 +00:00
let root_node: &RenderReturn = self.run_scope(ScopeId(0));
let root_node: &RenderReturn = unsafe { std::mem::transmute(root_node) };
2022-11-09 03:39:37 +00:00
let mut created = 0;
2022-11-04 03:56:31 +00:00
match root_node {
RenderReturn::Sync(Some(node)) => {
self.scope_stack.push(ScopeId(0));
2022-11-09 03:39:37 +00:00
created = self.create(&mut mutations, node);
2022-11-04 03:56:31 +00:00
self.scope_stack.pop();
}
2022-11-06 08:48:34 +00:00
RenderReturn::Sync(None) => {
//
}
RenderReturn::Async(_) => unreachable!("Root scope cannot be an async component"),
2022-11-04 03:56:31 +00:00
}
2022-11-09 03:39:37 +00:00
mutations.push(Mutation::AppendChildren { m: created });
mutations
2022-11-02 01:42:29 +00:00
}
/// Render what you can given the timeline and then move on
2022-11-09 03:39:37 +00:00
///
/// It's generally a good idea to put some sort of limit on the suspense process in case a future is having issues.
pub async fn render_with_deadline(
&mut self,
deadline: impl Future<Output = ()>,
) -> Vec<Mutation> {
2022-11-02 01:42:29 +00:00
todo!()
}
2022-11-02 08:00:37 +00:00
pub fn get_scope(&self, id: ScopeId) -> Option<&ScopeState> {
self.scopes.get(id.0)
}
pub fn base_scope(&self) -> &ScopeState {
self.scopes.get(0).unwrap()
}
2022-11-02 01:42:29 +00:00
}
impl Drop for VirtualDom {
fn drop(&mut self) {
// self.drop_scope(ScopeId(0));
}
}