Merge branch 'upstream' into handle-aborting-renders

This commit is contained in:
Evan Almloff committed 2023-01-12 13:30:15 -06:00
commit 733ff40bd0
72 files changed
+1221 -1045

No files matched your search

+12 -3
View File
@@ -1,9 +1,9 @@
use crate::nodes::RenderReturn;
use bumpalo::Bump;
use std::cell::Cell;
use std::cell::{Cell, UnsafeCell};
pub(crate) struct BumpFrame {
pub bump: Bump,
pub bump: UnsafeCell<Bump>,
pub node: Cell<*const RenderReturn<'static>>,
}
@@ -11,7 +11,7 @@ impl BumpFrame {
pub(crate) fn new(capacity: usize) -> Self {
let bump = Bump::with_capacity(capacity);
Self {
bump,
bump: UnsafeCell::new(bump),
node: Cell::new(std::ptr::null()),
}
}
@@ -26,4 +26,13 @@ impl BumpFrame {
unsafe { std::mem::transmute(&*node) }
}
pub(crate) fn bump(&self) -> &Bump {
unsafe { &*self.bump.get() }
}
#[allow(clippy::mut_from_ref)]
pub(crate) unsafe fn bump_mut(&self) -> &mut Bump {
unsafe { &mut *self.bump.get() }
}
}
+1
View File
@@ -11,6 +11,7 @@
//! The logic for this was borrowed from <https://docs.rs/stack_dst/0.6.1/stack_dst/>. Unfortunately, this crate does not
//! support non-static closures, so we've implemented the core logic of `ValueA` in this module.
#[allow(unused_imports)]
use smallbox::{smallbox, space::S16, SmallBox};
use crate::{innerlude::VNode, ScopeState};
+4 -3
View File
@@ -31,7 +31,8 @@ impl VirtualDom {
// If the task completes...
if task.task.borrow_mut().as_mut().poll(&mut cx).is_ready() {
// Remove it from the scope so we dont try to double drop it when the scope dropes
self.scopes[task.scope.0].spawned_tasks.remove(&id);
let scope = &self.scopes[task.scope.0];
scope.spawned_tasks.borrow_mut().remove(&id);
// Remove it from the scheduler
tasks.try_remove(id.0);
@@ -63,10 +64,10 @@ impl VirtualDom {
if let Poll::Ready(new_nodes) = as_pinned_mut.poll_unpin(&mut cx) {
let fiber = self.acquire_suspense_boundary(leaf.scope_id);
let scope = &mut self.scopes[scope_id.0];
let scope = &self.scopes[scope_id.0];
let arena = scope.current_frame();
let ret = arena.bump.alloc(match new_nodes {
let ret = arena.bump().alloc(match new_nodes {
Some(new) => RenderReturn::Ready(new),
None => RenderReturn::default(),
});
+7 -16
View File
@@ -7,7 +7,6 @@ use crate::{
scopes::{ScopeId, ScopeState},
virtual_dom::VirtualDom,
};
use bumpalo::Bump;
use futures_util::FutureExt;
use std::{
mem,
@@ -48,11 +47,10 @@ impl VirtualDom {
}))
}
fn acquire_current_scope_raw(&mut self) -> Option<*mut ScopeState> {
self.scope_stack
.last()
.copied()
.and_then(|id| self.scopes.get_mut(id.0).map(|f| f.as_mut() as *mut _))
fn acquire_current_scope_raw(&self) -> Option<*const ScopeState> {
let id = self.scope_stack.last().copied()?;
let scope = self.scopes.get(id.0)?;
Some(scope.as_ref())
}
pub(crate) fn run_scope(&mut self, scope_id: ScopeId) -> &RenderReturn {
@@ -62,17 +60,10 @@ impl VirtualDom {
self.ensure_drop_safety(scope_id);
let mut new_nodes = unsafe {
let scope = self.scopes[scope_id.0].as_mut();
self.scopes[scope_id.0].previous_frame().bump_mut().reset();
// if this frame hasn't been intialized yet, we can guess the size of the next frame to be more efficient
if scope.previous_frame().bump.allocated_bytes() == 0 {
scope.previous_frame_mut().bump =
Bump::with_capacity(scope.current_frame().bump.allocated_bytes());
} else {
scope.previous_frame_mut().bump.reset();
}
let scope = &self.scopes[scope_id.0];
// Make sure to reset the hook counter so we give out hooks in the right order
scope.hook_idx.set(0);
// safety: due to how we traverse the tree, we know that the scope is not currently aliased
@@ -142,7 +133,7 @@ impl VirtualDom {
let frame = scope.previous_frame();
// set the new head of the bump frame
let allocated = &*frame.bump.alloc(new_nodes);
let allocated = &*frame.bump().alloc(new_nodes);
frame.node.set(allocated);
// And move the render generation forward by one
+3 -11
View File
@@ -73,7 +73,7 @@ pub struct ScopeState {
pub(crate) node_arena_1: BumpFrame,
pub(crate) node_arena_2: BumpFrame,
pub(crate) parent: Option<*mut ScopeState>,
pub(crate) parent: Option<*const ScopeState>,
pub(crate) id: ScopeId,
pub(crate) height: u32,
@@ -85,7 +85,7 @@ pub struct ScopeState {
pub(crate) shared_contexts: RefCell<FxHashMap<TypeId, Box<dyn Any>>>,
pub(crate) tasks: Rc<Scheduler>,
pub(crate) spawned_tasks: FxHashSet<TaskId>,
pub(crate) spawned_tasks: RefCell<FxHashSet<TaskId>>,
pub(crate) borrowed_props: RefCell<Vec<*const VComponent<'static>>>,
pub(crate) attributes_to_drop: RefCell<Vec<*const Attribute<'static>>>,
@@ -111,14 +111,6 @@ impl<'src> ScopeState {
}
}
pub(crate) fn previous_frame_mut(&mut self) -> &mut BumpFrame {
match self.render_cnt.get() % 2 {
1 => &mut self.node_arena_1,
0 => &mut self.node_arena_2,
_ => unreachable!(),
}
}
/// Get the name of this component
pub fn name(&self) -> &str {
self.name
@@ -139,7 +131,7 @@ impl<'src> ScopeState {
/// If you need to allocate items that need to be dropped, use bumpalo's box.
pub fn bump(&self) -> &Bump {
// note that this is actually the previous frame since we use that as scratch space while the component is rendering
&self.previous_frame().bump
self.previous_frame().bump()
}
/// Get a handle to the currently active head node arena for this Scope
+37 -4
View File
@@ -24,7 +24,9 @@ use std::{any::Any, borrow::BorrowMut, cell::Cell, collections::BTreeSet, future
///
/// Components are defined as simple functions that take [`Scope`] and return an [`Element`].
///
/// ```rust, ignore
/// ```rust
/// # use dioxus::prelude::*;
///
/// #[derive(Props, PartialEq)]
/// struct AppProps {
/// title: String
@@ -39,7 +41,17 @@ use std::{any::Any, borrow::BorrowMut, cell::Cell, collections::BTreeSet, future
///
/// Components may be composed to make complex apps.
///
/// ```rust, ignore
/// ```rust
/// # #![allow(unused)]
/// # use dioxus::prelude::*;
///
/// # #[derive(Props, PartialEq)]
/// # struct AppProps {
/// # title: String
/// # }
///
/// static ROUTES: &str = "";
///
/// fn App(cx: Scope<AppProps>) -> Element {
/// cx.render(rsx!(
/// NavBar { routes: ROUTES }
@@ -47,12 +59,33 @@ use std::{any::Any, borrow::BorrowMut, cell::Cell, collections::BTreeSet, future
/// Footer {}
/// ))
/// }
///
/// #[inline_props]
/// fn NavBar(cx: Scope, routes: &'static str) -> Element {
/// cx.render(rsx! {
/// div { "Routes: {routes}" }
/// })
/// }
///
/// fn Footer(cx: Scope) -> Element {
/// cx.render(rsx! { div { "Footer" } })
/// }
///
/// #[inline_props]
/// fn Title<'a>(cx: Scope<'a>, children: Element<'a>) -> Element {
/// cx.render(rsx! {
/// div { id: "title", children }
/// })
/// }
/// ```
///
/// To start an app, create a [`VirtualDom`] and call [`VirtualDom::rebuild`] to get the list of edits required to
/// draw the UI.
///
/// ```rust, ignore
/// ```rust
/// # use dioxus::prelude::*;
/// # fn App(cx: Scope) -> Element { cx.render(rsx! { div {} }) }
///
/// let mut vdom = VirtualDom::new(App);
/// let edits = vdom.rebuild();
/// ```
@@ -549,7 +582,7 @@ impl VirtualDom {
loop {
// first, unload any complete suspense trees
for finished_fiber in self.finished_fibers.drain(..) {
let scope = &mut self.scopes[finished_fiber.0];
let scope = &self.scopes[finished_fiber.0];
let context = scope.has_context::<Rc<SuspenseContext>>().unwrap();
self.mutations