Feat: major overhaul, wire up event system

This commit is contained in:
Jonathan Kelley committed 2021-02-12 03:07:35 -05:00
1 parent f47651b32a
commit 8295ac4b3d
20 files changed
+1418 -188

No files matched your search

+96 -59
View File
@@ -40,7 +40,7 @@ use std::{
pub struct VirtualDom<P: Properties> {
/// All mounted components are arena allocated to make additions, removals, and references easy to work with
/// A generational arean is used to re-use slots of deleted scopes without having to resize the underlying arena.
components: Arena<Scope>,
pub(crate) components: Arena<Scope>,
/// The index of the root component.
base_scope: Index,
@@ -48,7 +48,8 @@ pub struct VirtualDom<P: Properties> {
/// Components generate lifecycle events
event_queue: Vec<LifecycleEvent>,
root_props: P,
// mark the root props with P, even though they're held by the root component
_p: PhantomData<P>,
}
/// Implement VirtualDom with no props for components that initialize their state internal to the VDom rather than externally.
@@ -83,7 +84,7 @@ impl<P: Properties + 'static> VirtualDom<P> {
let base_scope = components.insert(Scope::new(root, None));
// Create a new mount event with no root container
let first_event = LifecycleEvent::mount(base_scope, None, 0);
let first_event = LifecycleEvent::mount(base_scope, None, 0, root_props);
// Create an event queue with a mount for the base scope
let event_queue = vec![first_event];
@@ -92,83 +93,119 @@ impl<P: Properties + 'static> VirtualDom<P> {
components,
base_scope,
event_queue,
root_props,
_p: PhantomData {},
}
}
/// Pop an event off the even queue and process it
pub fn progress(&mut self) -> Result<(), ()> {
let LifecycleEvent { index, event_type } = self.event_queue.pop().ok_or(())?;
/// Pop an event off the event queue and process it
pub fn progress(&mut self) -> Result<()> {
let event = self.event_queue.pop().ok_or(Error::NoEvent)?;
let scope = self.components.get(index).ok_or(())?;
match event_type {
// Component needs to be mounted to the virtual dom
LifecycleType::Mount { to, under } => {
// todo! run the FC with the bump allocator
// Run it with its properties
if let Some(other) = to {
// mount to another component
let p = ();
} else {
// mount to the root
}
}
// The parent for this component generated new props and the component needs update
LifecycleType::PropsChanged {} => {}
// Component was successfully mounted to the dom
LifecycleType::Mounted {} => {}
// Component was removed from the DOM
// Run any destructors and cleanup for the hooks and the dump the component
LifecycleType::Removed {} => {
let f = self.components.remove(index);
}
// Component was messaged via the internal subscription service
LifecycleType::Messaged => {}
}
Ok(())
process_event(self, event)
}
/// Update the root props, causing a full event cycle
pub fn update_props(&mut self, new_props: P) {}
}
/// Run through every event in the event queue until the events are empty.
/// Function is asynchronous to allow for async components to finish their work.
pub async fn progess_completely() {}
/// Using mutable access to the Virtual Dom, progress a given lifecycle event
///
///
///
///
///
///
fn process_event<P: Properties>(
dom: &mut VirtualDom<P>,
LifecycleEvent { index, event_type }: LifecycleEvent,
) -> Result<()> {
let scope = dom.components.get(index).ok_or(Error::NoEvent)?;
/// Create a new context object for a given component and scope
fn new_context<T: Properties>(&self) -> Context {
// fn new_context<T: Properties>(&self) -> Context<T> {
todo!()
match event_type {
// Component needs to be mounted to the virtual dom
LifecycleType::Mount { to, under, props } => {
if let Some(other) = to {
// mount to another component
} else {
// mount to the root
}
let g = props.as_ref();
scope.run(g);
// scope.run(runner, props, dom);
}
// The parent for this component generated new props and the component needs update
LifecycleType::PropsChanged { props } => {
//
}
// Component was successfully mounted to the dom
LifecycleType::Mounted {} => {
//
}
// Component was removed from the DOM
// Run any destructors and cleanup for the hooks and the dump the component
LifecycleType::Removed {} => {
let f = dom.components.remove(index);
}
// Component was messaged via the internal subscription service
LifecycleType::Messaged => {
//
}
// Event from renderer was fired with a given listener ID
//
LifecycleType::Callback { listener_id } => {}
}
/// Stop writing to the current buffer and start writing to the new one.
/// This should be done inbetween CallbackEvent handling, but not between lifecycle events.
pub fn swap_buffers(&mut self) {}
Ok(())
}
pub struct LifecycleEvent {
pub index: Index,
pub event_type: LifecycleType,
}
impl LifecycleEvent {
fn mount(which: Index, to: Option<Index>, under: usize) -> Self {
Self {
index: which,
event_type: LifecycleType::Mount { to, under },
}
}
}
/// The internal lifecycle event system is managed by these
/// Right now, we box the properties and but them in the enum
/// Later, we could directly call the chain of children without boxing
/// We could try to reuse the boxes somehow
pub enum LifecycleType {
Mount { to: Option<Index>, under: usize },
PropsChanged,
Mount {
to: Option<Index>,
under: usize,
props: Box<dyn Properties>,
},
PropsChanged {
props: Box<dyn Properties>,
},
Mounted,
Removed,
Messaged,
Callback {
listener_id: i32,
},
}
impl LifecycleEvent {
// helper method for shortcutting to the enum type
// probably not necessary
fn mount<P: Properties + 'static>(
which: Index,
to: Option<Index>,
under: usize,
props: P,
) -> Self {
Self {
index: which,
event_type: LifecycleType::Mount {
to,
under,
props: Box::new(props),
},
}
}
}