Feat: abstraction lifetimes work out nicely
This commit is contained in:
1 parent
a99147c85b
commit
2284b35782
2 files changed
+46
-42
No files matched your search
@@ -22,11 +22,11 @@ impl ScopeArena {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, idx: ScopeIdx) -> Result<&Scope> {
|
pub fn try_get(&self, idx: ScopeIdx) -> Result<&Scope> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut(&self, idx: ScopeIdx) -> Result<&Scope> {
|
pub fn try_get_mut(&self, idx: ScopeIdx) -> Result<&mut Scope> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ impl ScopeArena {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with<T>(&mut self, f: impl FnOnce(&mut Arena<Scope>) -> T) -> T {
|
pub fn with<T>(&self, f: impl FnOnce(&mut Arena<Scope>) -> T) -> Result<T> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
//! This module includes just the barebones for a complete VirtualDOM API.
|
//! This module includes just the barebones for a complete VirtualDOM API.
|
||||||
//! Additional functionality is defined in the respective files.
|
//! Additional functionality is defined in the respective files.
|
||||||
|
|
||||||
use crate::innerlude::*;
|
use crate::{arena::ScopeArena, innerlude::*};
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use generational_arena::Arena;
|
use generational_arena::Arena;
|
||||||
use std::{
|
use std::{
|
||||||
@@ -41,7 +41,7 @@ pub struct VirtualDom {
|
|||||||
///
|
///
|
||||||
/// This is wrapped in an UnsafeCell because we will need to get mutable access to unique values in unique bump arenas
|
/// This is wrapped in an UnsafeCell because we will need to get mutable access to unique values in unique bump arenas
|
||||||
/// and rusts's guartnees cannot prove that this is safe. We will need to maintain the safety guarantees manually.
|
/// and rusts's guartnees cannot prove that this is safe. We will need to maintain the safety guarantees manually.
|
||||||
components: UnsafeCell<Arena<Scope>>,
|
components: ScopeArena,
|
||||||
|
|
||||||
/// The index of the root component
|
/// The index of the root component
|
||||||
/// Should always be the first (gen0, id0)
|
/// Should always be the first (gen0, id0)
|
||||||
@@ -152,7 +152,7 @@ impl VirtualDom {
|
|||||||
_root_caller,
|
_root_caller,
|
||||||
base_scope,
|
base_scope,
|
||||||
event_queue,
|
event_queue,
|
||||||
components: UnsafeCell::new(components),
|
components: ScopeArena::new(components),
|
||||||
_root_prop_type: TypeId::of::<P>(),
|
_root_prop_type: TypeId::of::<P>(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -164,17 +164,19 @@ impl VirtualDom {
|
|||||||
// Schedule an update and then immediately call it on the root component
|
// Schedule an update and then immediately call it on the root component
|
||||||
// This is akin to a hook being called from a listener and requring a re-render
|
// This is akin to a hook being called from a listener and requring a re-render
|
||||||
// Instead, this is done on top-level component
|
// Instead, this is done on top-level component
|
||||||
unsafe {
|
|
||||||
let components = &*self.components.get();
|
let base = self.components.try_get(self.base_scope)?;
|
||||||
let base = components.get(self.base_scope).unwrap();
|
let update = self.event_queue.schedule_update(base);
|
||||||
let update = self.event_queue.schedule_update(base);
|
update();
|
||||||
update();
|
|
||||||
};
|
|
||||||
|
|
||||||
self.progress_completely(&mut diff_machine)?;
|
self.progress_completely(&mut diff_machine)?;
|
||||||
|
|
||||||
Ok(diff_machine.consume())
|
Ok(diff_machine.consume())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn base_scope(&self) -> &Scope {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================================
|
// ======================================
|
||||||
@@ -223,16 +225,11 @@ impl VirtualDom {
|
|||||||
// in crafting a 100% safe solution with traditional lifetimes. Consider this method to be internally unsafe
|
// in crafting a 100% safe solution with traditional lifetimes. Consider this method to be internally unsafe
|
||||||
// but the guarantees provide a safe, fast, and efficient abstraction for the VirtualDOM updating framework.
|
// but the guarantees provide a safe, fast, and efficient abstraction for the VirtualDOM updating framework.
|
||||||
//
|
//
|
||||||
// A good project would be to remove all unsafe from this crate and move the unsafety into abstractions.
|
// A good project would be to remove all unsafe from this crate and move the unsafety into safer abstractions.
|
||||||
pub fn progress_with_event(&mut self, event: EventTrigger) -> Result<EditList> {
|
pub fn progress_with_event(&mut self, event: EventTrigger) -> Result<EditList> {
|
||||||
let id = event.component_id.clone();
|
let id = event.component_id.clone();
|
||||||
|
|
||||||
unsafe {
|
self.components.try_get_mut(id)?.call_listener(event)?;
|
||||||
(&mut *self.components.get())
|
|
||||||
.get_mut(id)
|
|
||||||
.ok_or(Error::FatalInternal("Borrowing should not fail"))?
|
|
||||||
.call_listener(event)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut diff_machine = DiffMachine::new();
|
let mut diff_machine = DiffMachine::new();
|
||||||
self.progress_completely(&mut diff_machine)?;
|
self.progress_completely(&mut diff_machine)?;
|
||||||
@@ -240,8 +237,16 @@ impl VirtualDom {
|
|||||||
Ok(diff_machine.consume())
|
Ok(diff_machine.consume())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn progress_completely(&mut self, diff_machine: &mut DiffMachine) -> Result<()> {
|
/// Consume the event queue, descending depth-first.
|
||||||
|
/// Only ever run each component once.
|
||||||
|
///
|
||||||
|
/// The DiffMachine logs its progress as it goes which might be useful for certain types of renderers.
|
||||||
|
pub(crate) fn progress_completely<'s>(
|
||||||
|
&'s mut self,
|
||||||
|
diff_machine: &'_ mut DiffMachine<'s>,
|
||||||
|
) -> Result<()> {
|
||||||
// Add this component to the list of components that need to be difed
|
// Add this component to the list of components that need to be difed
|
||||||
|
#[allow(unused_assignments)]
|
||||||
let mut cur_height: u32 = 0;
|
let mut cur_height: u32 = 0;
|
||||||
|
|
||||||
// Now, there are events in the queue
|
// Now, there are events in the queue
|
||||||
@@ -263,20 +268,16 @@ impl VirtualDom {
|
|||||||
// Now, all the "seen nodes" are nodes that got notified by running this listener
|
// Now, all the "seen nodes" are nodes that got notified by running this listener
|
||||||
seen_nodes.insert(update.idx.clone());
|
seen_nodes.insert(update.idx.clone());
|
||||||
|
|
||||||
unsafe {
|
// Start a new mutable borrow to components
|
||||||
// Start a new mutable borrow to components
|
// We are guaranteeed that this scope is unique because we are tracking which nodes have modified
|
||||||
|
|
||||||
// We are guaranteeed that this scope is unique because we are tracking which nodes have modified
|
let component = self.components.try_get_mut(update.idx).unwrap();
|
||||||
let component = (&mut *self.components.get())
|
|
||||||
.get_mut(update.idx)
|
|
||||||
.expect("msg");
|
|
||||||
|
|
||||||
component.run_scope()?;
|
component.run_scope()?;
|
||||||
|
|
||||||
diff_machine.diff_node(component.old_frame(), component.next_frame());
|
diff_machine.diff_node(component.old_frame(), component.next_frame());
|
||||||
|
|
||||||
cur_height = component.height;
|
cur_height = component.height;
|
||||||
}
|
|
||||||
|
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"Processing update: {:#?} with height {}",
|
"Processing update: {:#?} with height {}",
|
||||||
@@ -301,15 +302,22 @@ impl VirtualDom {
|
|||||||
// We're modifying the component arena while holding onto references into the assoiated bump arenas of its children
|
// We're modifying the component arena while holding onto references into the assoiated bump arenas of its children
|
||||||
// those references are stable, even if the component arena moves around in memory, thanks to the bump arenas.
|
// those references are stable, even if the component arena moves around in memory, thanks to the bump arenas.
|
||||||
// However, there is no way to convey this to rust, so we need to use unsafe to pierce through the lifetime.
|
// However, there is no way to convey this to rust, so we need to use unsafe to pierce through the lifetime.
|
||||||
let components: &mut _ = unsafe { &mut *self.components.get() };
|
|
||||||
|
|
||||||
// Insert a new scope into our component list
|
// Insert a new scope into our component list
|
||||||
let idx = components.insert_with(|f| {
|
let idx = self.components.with(|components| {
|
||||||
Scope::new(caller, f, None, cur_height + 1, self.event_queue.clone())
|
components.insert_with(|f| {
|
||||||
});
|
Scope::new(
|
||||||
|
caller,
|
||||||
|
f,
|
||||||
|
None,
|
||||||
|
cur_height + 1,
|
||||||
|
self.event_queue.clone(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
// Grab out that component
|
// Grab out that component
|
||||||
let component = components.get_mut(idx).unwrap();
|
let component = self.components.try_get_mut(idx).unwrap();
|
||||||
|
|
||||||
// Actually initialize the caller's slot with the right address
|
// Actually initialize the caller's slot with the right address
|
||||||
*stable_scope_addr.upgrade().unwrap().as_ref().borrow_mut() = Some(idx);
|
*stable_scope_addr.upgrade().unwrap().as_ref().borrow_mut() = Some(idx);
|
||||||
@@ -336,8 +344,6 @@ impl VirtualDom {
|
|||||||
} => {
|
} => {
|
||||||
log::debug!("Updating a component after its props have changed");
|
log::debug!("Updating a component after its props have changed");
|
||||||
|
|
||||||
let components: &mut _ = unsafe { &mut *self.components.get() };
|
|
||||||
|
|
||||||
// Get the stable index to the target component
|
// Get the stable index to the target component
|
||||||
// This *should* exist due to guarantees in the diff algorithm
|
// This *should* exist due to guarantees in the diff algorithm
|
||||||
let idx = stable_scope_addr
|
let idx = stable_scope_addr
|
||||||
@@ -348,7 +354,7 @@ impl VirtualDom {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Grab out that component
|
// Grab out that component
|
||||||
let component = components.get_mut(idx).unwrap();
|
let component = self.components.try_get_mut(idx).unwrap();
|
||||||
|
|
||||||
// We have to move the caller over or running the scope will fail
|
// We have to move the caller over or running the scope will fail
|
||||||
component.update_caller(caller);
|
component.update_caller(caller);
|
||||||
@@ -377,8 +383,6 @@ impl VirtualDom {
|
|||||||
// However, since our caller is located in a Bump frame, we need to update the caller pointer (which is now invalid)
|
// However, since our caller is located in a Bump frame, we need to update the caller pointer (which is now invalid)
|
||||||
log::debug!("Received the same props");
|
log::debug!("Received the same props");
|
||||||
|
|
||||||
let components: &mut _ = unsafe { &mut *self.components.get() };
|
|
||||||
|
|
||||||
// Get the stable index to the target component
|
// Get the stable index to the target component
|
||||||
// This *should* exist due to guarantees in the diff algorithm
|
// This *should* exist due to guarantees in the diff algorithm
|
||||||
let idx = stable_scope_addr
|
let idx = stable_scope_addr
|
||||||
@@ -389,7 +393,7 @@ impl VirtualDom {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Grab out that component
|
// Grab out that component
|
||||||
let component = components.get_mut(idx).unwrap();
|
let component = self.components.try_get_mut(idx).unwrap();
|
||||||
|
|
||||||
// We have to move the caller over or running the scope will fail
|
// We have to move the caller over or running the scope will fail
|
||||||
component.update_caller(caller);
|
component.update_caller(caller);
|
||||||
@@ -445,7 +449,7 @@ pub struct Scope {
|
|||||||
// slightly unsafe stuff
|
// slightly unsafe stuff
|
||||||
// ==========================
|
// ==========================
|
||||||
// an internal, highly efficient storage of vnodes
|
// an internal, highly efficient storage of vnodes
|
||||||
pub(crate) frames: ActiveFrame,
|
pub frames: ActiveFrame,
|
||||||
|
|
||||||
// These hooks are actually references into the hook arena
|
// These hooks are actually references into the hook arena
|
||||||
// These two could be combined with "OwningRef" to remove unsafe usage
|
// These two could be combined with "OwningRef" to remove unsafe usage
|
||||||
|
|||||||
Reference in new issue
Block a user