fix: make miri pass on context api
This commit is contained in:
1 parent
b50f38c675
commit
faf94c7b4e
6 files changed
+65
-68
No files matched your search
@@ -1,9 +1,9 @@
|
|||||||
use crate::nodes::RenderReturn;
|
use crate::nodes::RenderReturn;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use std::cell::Cell;
|
use std::cell::{Cell, UnsafeCell};
|
||||||
|
|
||||||
pub(crate) struct BumpFrame {
|
pub(crate) struct BumpFrame {
|
||||||
pub bump: Bump,
|
pub bump: UnsafeCell<Bump>,
|
||||||
pub node: Cell<*const RenderReturn<'static>>,
|
pub node: Cell<*const RenderReturn<'static>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ impl BumpFrame {
|
|||||||
pub(crate) fn new(capacity: usize) -> Self {
|
pub(crate) fn new(capacity: usize) -> Self {
|
||||||
let bump = Bump::with_capacity(capacity);
|
let bump = Bump::with_capacity(capacity);
|
||||||
Self {
|
Self {
|
||||||
bump,
|
bump: UnsafeCell::new(bump),
|
||||||
node: Cell::new(std::ptr::null()),
|
node: Cell::new(std::ptr::null()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -26,4 +26,11 @@ impl BumpFrame {
|
|||||||
|
|
||||||
unsafe { std::mem::transmute(&*node) }
|
unsafe { std::mem::transmute(&*node) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn bump(&self) -> &Bump {
|
||||||
|
unsafe { &*self.bump.get() }
|
||||||
|
}
|
||||||
|
pub(crate) unsafe fn bump_mut(&self) -> &mut Bump {
|
||||||
|
unsafe { &mut *self.bump.get() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,8 @@ impl VirtualDom {
|
|||||||
// If the task completes...
|
// If the task completes...
|
||||||
if task.task.borrow_mut().as_mut().poll(&mut cx).is_ready() {
|
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
|
// 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
|
// Remove it from the scheduler
|
||||||
tasks.try_remove(id.0);
|
tasks.try_remove(id.0);
|
||||||
@@ -63,10 +64,10 @@ impl VirtualDom {
|
|||||||
if let Poll::Ready(new_nodes) = as_pinned_mut.poll_unpin(&mut cx) {
|
if let Poll::Ready(new_nodes) = as_pinned_mut.poll_unpin(&mut cx) {
|
||||||
let fiber = self.acquire_suspense_boundary(leaf.scope_id);
|
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 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),
|
Some(new) => RenderReturn::Ready(new),
|
||||||
None => RenderReturn::default(),
|
None => RenderReturn::default(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use crate::{
|
|||||||
scopes::{ScopeId, ScopeState},
|
scopes::{ScopeId, ScopeState},
|
||||||
virtual_dom::VirtualDom,
|
virtual_dom::VirtualDom,
|
||||||
};
|
};
|
||||||
use bumpalo::Bump;
|
|
||||||
use futures_util::FutureExt;
|
use futures_util::FutureExt;
|
||||||
use std::{
|
use std::{
|
||||||
mem,
|
mem,
|
||||||
@@ -48,11 +47,10 @@ impl VirtualDom {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn acquire_current_scope_raw(&mut self) -> Option<*mut ScopeState> {
|
fn acquire_current_scope_raw(&self) -> Option<*const ScopeState> {
|
||||||
self.scope_stack
|
let id = self.scope_stack.last().copied()?;
|
||||||
.last()
|
let scope = self.scopes.get(id.0)?;
|
||||||
.copied()
|
Some(scope.as_ref())
|
||||||
.and_then(|id| self.scopes.get_mut(id.0).map(|f| f.as_mut() as *mut _))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn run_scope(&mut self, scope_id: ScopeId) -> &RenderReturn {
|
pub(crate) fn run_scope(&mut self, scope_id: ScopeId) -> &RenderReturn {
|
||||||
@@ -62,17 +60,10 @@ impl VirtualDom {
|
|||||||
self.ensure_drop_safety(scope_id);
|
self.ensure_drop_safety(scope_id);
|
||||||
|
|
||||||
let mut new_nodes = unsafe {
|
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
|
let scope = &self.scopes[scope_id.0];
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure to reset the hook counter so we give out hooks in the right order
|
|
||||||
scope.hook_idx.set(0);
|
scope.hook_idx.set(0);
|
||||||
|
|
||||||
// safety: due to how we traverse the tree, we know that the scope is not currently aliased
|
// 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();
|
let frame = scope.previous_frame();
|
||||||
|
|
||||||
// set the new head of the bump 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);
|
frame.node.set(allocated);
|
||||||
|
|
||||||
// And move the render generation forward by one
|
// And move the render generation forward by one
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ pub struct ScopeState {
|
|||||||
pub(crate) node_arena_1: BumpFrame,
|
pub(crate) node_arena_1: BumpFrame,
|
||||||
pub(crate) node_arena_2: 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) id: ScopeId,
|
||||||
|
|
||||||
pub(crate) height: u32,
|
pub(crate) height: u32,
|
||||||
@@ -85,7 +85,7 @@ pub struct ScopeState {
|
|||||||
pub(crate) shared_contexts: RefCell<FxHashMap<TypeId, Box<dyn Any>>>,
|
pub(crate) shared_contexts: RefCell<FxHashMap<TypeId, Box<dyn Any>>>,
|
||||||
|
|
||||||
pub(crate) tasks: Rc<Scheduler>,
|
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) borrowed_props: RefCell<Vec<*const VComponent<'static>>>,
|
||||||
pub(crate) attributes_to_drop: RefCell<Vec<*const Attribute<'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
|
/// Get the name of this component
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
self.name
|
self.name
|
||||||
@@ -139,7 +131,7 @@ impl<'src> ScopeState {
|
|||||||
/// If you need to allocate items that need to be dropped, use bumpalo's box.
|
/// If you need to allocate items that need to be dropped, use bumpalo's box.
|
||||||
pub fn bump(&self) -> &Bump {
|
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
|
// 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
|
/// Get a handle to the currently active head node arena for this Scope
|
||||||
|
|||||||
@@ -549,7 +549,7 @@ impl VirtualDom {
|
|||||||
loop {
|
loop {
|
||||||
// first, unload any complete suspense trees
|
// first, unload any complete suspense trees
|
||||||
for finished_fiber in self.finished_fibers.drain(..) {
|
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();
|
let context = scope.has_context::<Rc<SuspenseContext>>().unwrap();
|
||||||
|
|
||||||
self.mutations
|
self.mutations
|
||||||
|
|||||||
@@ -5,42 +5,48 @@ use std::future::IntoFuture;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
#[tokio::test]
|
#[test]
|
||||||
async fn it_works() {
|
fn it_works() {
|
||||||
let mut dom = VirtualDom::new(app);
|
|
||||||
|
|
||||||
{
|
|
||||||
let mutations = dom.rebuild().santize();
|
|
||||||
|
|
||||||
// We should at least get the top-level template in before pausing for the children
|
|
||||||
// note: we dont test template edits anymore
|
|
||||||
// assert_eq!(
|
|
||||||
// mutations.templates,
|
|
||||||
// [
|
|
||||||
// CreateElement { name: "div" },
|
|
||||||
// CreateStaticText { value: "Waiting for child..." },
|
|
||||||
// CreateStaticPlaceholder,
|
|
||||||
// AppendChildren { m: 2 },
|
|
||||||
// SaveTemplate { name: "template", m: 1 }
|
|
||||||
// ]
|
|
||||||
// );
|
|
||||||
|
|
||||||
// And we should load it in and assign the placeholder properly
|
|
||||||
assert_eq!(
|
|
||||||
mutations.edits,
|
|
||||||
[
|
|
||||||
LoadTemplate { name: "template", index: 0, id: ElementId(1) },
|
|
||||||
// hmmmmmmmmm.... with suspense how do we guarantee that IDs increase linearly?
|
|
||||||
// can we even?
|
|
||||||
AssignId { path: &[1], id: ElementId(3) },
|
|
||||||
AppendChildren { m: 1, id: ElementId(0) },
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait just a moment, not enough time for the boundary to resolve
|
// wait just a moment, not enough time for the boundary to resolve
|
||||||
|
|
||||||
dom.wait_for_work().await;
|
tokio::runtime::Builder::new_current_thread()
|
||||||
|
.enable_time()
|
||||||
|
.build()
|
||||||
|
.unwrap()
|
||||||
|
.block_on(async {
|
||||||
|
let mut dom = VirtualDom::new(app);
|
||||||
|
|
||||||
|
{
|
||||||
|
let mutations = dom.rebuild().santize();
|
||||||
|
|
||||||
|
// We should at least get the top-level template in before pausing for the children
|
||||||
|
// note: we dont test template edits anymore
|
||||||
|
// assert_eq!(
|
||||||
|
// mutations.templates,
|
||||||
|
// [
|
||||||
|
// CreateElement { name: "div" },
|
||||||
|
// CreateStaticText { value: "Waiting for child..." },
|
||||||
|
// CreateStaticPlaceholder,
|
||||||
|
// AppendChildren { m: 2 },
|
||||||
|
// SaveTemplate { name: "template", m: 1 }
|
||||||
|
// ]
|
||||||
|
// );
|
||||||
|
|
||||||
|
// And we should load it in and assign the placeholder properly
|
||||||
|
assert_eq!(
|
||||||
|
mutations.edits,
|
||||||
|
[
|
||||||
|
LoadTemplate { name: "template", index: 0, id: ElementId(1) },
|
||||||
|
// hmmmmmmmmm.... with suspense how do we guarantee that IDs increase linearly?
|
||||||
|
// can we even?
|
||||||
|
AssignId { path: &[1], id: ElementId(3) },
|
||||||
|
AppendChildren { m: 1, id: ElementId(0) },
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
dom.wait_for_work().await;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn app(cx: Scope) -> Element {
|
fn app(cx: Scope) -> Element {
|
||||||
|
|||||||
Reference in new issue
Block a user