wip: some work

This commit is contained in:
Jonathan Kelley 2021-07-09 03:39:45 -04:00
parent 58ab51a4e4
commit feab50f24a
8 changed files with 171 additions and 108 deletions

View file

@ -1,3 +1,3 @@
{
"rust-analyzer.inlayHints.enable": false
"rust-analyzer.inlayHints.enable": true
}

View file

@ -17,5 +17,7 @@ const App: FC<()> = |cx| {
cx.submit_task(fut);
cx.submit_task(fut);
todo!()
};

View file

@ -21,75 +21,6 @@ enum MutStatus {
Mut,
}
// impl ScopeArenaInner {
// pub fn new(arena: Arena<Scope>) -> Self {
// ScopeArenaInner {
// arena: UnsafeCell::new(arena),
// locks: Default::default(),
// }
// }
// /// THIS METHOD IS CURRENTLY UNSAFE
// /// THERE ARE NO CHECKS TO VERIFY THAT WE ARE ALLOWED TO DO THIS
// pub fn try_get(&self, idx: ScopeIdx) -> Result<&Scope> {
// let inner = unsafe { &*self.arena.get() };
// let scope = inner.get(idx);
// scope.ok_or_else(|| Error::FatalInternal("Scope not found"))
// }
// /// THIS METHOD IS CURRENTLY UNSAFE
// /// THERE ARE NO CHECKS TO VERIFY THAT WE ARE ALLOWED TO DO THIS
// pub fn try_get_mut(&self, idx: ScopeIdx) -> Result<&mut Scope> {
// let inner = unsafe { &mut *self.arena.get() };
// let scope = inner.get_mut(idx);
// scope.ok_or_else(|| Error::FatalInternal("Scope not found"))
// }
// fn inner(&self) -> &Arena<Scope> {
// todo!()
// }
// fn inner_mut(&mut self) -> &mut Arena<Scope> {
// todo!()
// }
// /// THIS METHOD IS CURRENTLY UNSAFE
// /// THERE ARE NO CHECKS TO VERIFY THAT WE ARE ALLOWED TO DO THIS
// pub fn with<T>(&self, f: impl FnOnce(&mut Arena<Scope>) -> T) -> Result<T> {
// let inner = unsafe { &mut *self.arena.get() };
// Ok(f(inner))
// // todo!()
// }
// pub fn with_scope<'b, O: 'static>(
// &'b self,
// id: ScopeIdx,
// f: impl FnOnce(&'b mut Scope) -> O,
// ) -> Result<O> {
// todo!()
// }
// // return a bumpframe with a lifetime attached to the arena borrow
// // this is useful for merging lifetimes
// pub fn with_scope_vnode<'b>(
// &self,
// id: ScopeIdx,
// f: impl FnOnce(&mut Scope) -> &VNode<'b>,
// ) -> Result<&VNode<'b>> {
// todo!()
// }
// pub fn try_remove(&mut self, id: ScopeIdx) -> Result<Scope> {
// let inner = unsafe { &mut *self.arena.get() };
// inner
// .remove(id)
// .ok_or_else(|| Error::FatalInternal("Scope not found"))
// }
// unsafe fn inner_unchecked<'s>() -> &'s mut Arena<Scope> {
// todo!()
// }
// }
impl ScopeArena {
pub fn new(arena: ScopeMap) -> Self {
ScopeArena(Rc::new(RefCell::new(ScopeArenaInner {

View file

@ -10,19 +10,30 @@ use crate::{innerlude::ScopeIdx, virtual_dom::RealDomNode};
#[derive(Debug)]
pub struct EventTrigger {
///
pub component_id: ScopeIdx,
/// The originator of the event trigger
pub originator: ScopeIdx,
///
pub real_node_id: RealDomNode,
/// The optional real node associated with the trigger
pub real_node_id: Option<RealDomNode>,
///
/// The type of event
pub event: VirtualEvent,
///
/// The priority of the event
pub priority: EventPriority,
}
impl EventTrigger {
pub fn new_from_task(originator: ScopeIdx) -> Self {
Self {
originator,
event: VirtualEvent::FiberEvent,
priority: EventPriority::Low,
real_node_id: None,
}
}
}
/// Priority of Event Triggers.
///
/// Internally, Dioxus will abort work that's taking too long if new, more important, work arrives. Unlike React, Dioxus
@ -61,12 +72,12 @@ impl EventTrigger {
pub fn new(
event: VirtualEvent,
scope: ScopeIdx,
mounted_dom_id: RealDomNode,
mounted_dom_id: Option<RealDomNode>,
priority: EventPriority,
) -> Self {
Self {
priority,
component_id: scope,
originator: scope,
real_node_id: mounted_dom_id,
event,
}
@ -93,7 +104,7 @@ pub enum VirtualEvent {
PointerEvent(on::PointerEvent),
// Whenever a task is ready (complete) Dioxus produces this "FiberEvent"
FiberEvent { task_id: u16 },
FiberEvent,
// image event has conflicting method types
// ImageEvent(event_data::ImageEvent),

View file

@ -216,7 +216,7 @@ impl Scope {
.iter()
.find(|(domptr, _)| {
let p = unsafe { &**domptr };
p.get() == real_node_id
p.get() == real_node_id.expect("realdomnode not found, propery handling of true virtual events not managed")
})
.expect(&format!(
"Failed to find real node with ID {:?}",

View file

@ -9,30 +9,158 @@
//! This is all pretty unsafe stuff.
//! The major invariant here is that tasks that enter the queue may be invalidated during transitions.
use std::pin::Pin;
use std::{
cell::Cell,
pin::Pin,
sync::{Arc, RwLock},
task::{Context, Poll},
};
use futures::{Future, Stream, StreamExt};
use slotmap::{DefaultKey, SlotMap};
use crate::events::EventTrigger;
use crate::{events::EventTrigger, prelude::ScopeIdx};
pub struct TaskQueue {
slots: SlotMap<DefaultKey, Task>,
slots: Arc<RwLock<SlotMap<DefaultKey, DTask>>>,
submitter: Arc<dyn Fn(DTask)>,
}
impl TaskQueue {
unsafe fn push_task(&mut self, task: Task) -> TaskHandle {
todo!()
pub fn new() -> Self {
let slots = Arc::new(RwLock::new(SlotMap::new()));
let slots2 = slots.clone();
let submitter = Arc::new(move |task| {
let mut slots = slots2.write().unwrap();
slots.insert(task);
});
Self { slots, submitter }
}
async fn next(&mut self) -> EventTrigger {
for (key, task) in self.slots.iter_mut() {
let ptr = task.0;
}
todo!()
fn push_task(&mut self, task: DTask) -> TaskHandle {
let key = self.slots.write().unwrap().insert(task);
TaskHandle {}
}
fn is_empty(&self) -> bool {
self.slots.read().unwrap().is_empty()
}
fn len(&self) -> usize {
self.slots.read().unwrap().len()
}
}
struct Task(*mut Pin<Box<dyn Future<Output = ()>>>);
impl Stream for TaskQueue {
type Item = EventTrigger;
/// We can never be finished polling
fn poll_next(
mut self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Option<Self::Item>> {
// let yield_every = self.len();
// let mut polled = 0;
let mut slots = self.slots.write().unwrap();
for (key, slot) in slots.iter_mut() {
if slot.dead.get() {
continue;
}
let r = slot.fut;
let mut fut = unsafe { &mut *r };
// use futures::{future::Future, poll, FutureExt};
let f2 = fut.as_mut();
let w = cx.waker();
let mut cx = Context::from_waker(&w);
// Pin::new_unchecked(pointer)
// use std::future::Future;
match f2.poll(&mut cx) {
Poll::Ready(_) => {
let trigger = EventTrigger::new_from_task(slot.originator);
slot.dead.set(true);
return Poll::Ready(Some(trigger));
}
Poll::Pending => continue,
}
}
// we tried polling every active task.
// give up and relinquish controlto the parent
// We have polled a large number of futures in a row without yielding.
// To ensure we do not starve other tasks waiting on the executor,
// we yield here, but immediately wake ourselves up to continue.
// cx.waker().wake_by_ref();
return Poll::Pending;
}
}
struct TaskHandle {}
pub struct DTask {
fut: *mut Pin<Box<dyn Future<Output = ()>>>,
originator: ScopeIdx,
dead: Cell<bool>,
}
impl DTask {
pub fn new(fut: &mut Pin<Box<dyn Future<Output = ()>>>, originator: ScopeIdx) -> Self {
Self {
fut,
originator,
dead: Cell::new(false),
}
}
fn debug_new(fut: &mut Pin<Box<dyn Future<Output = ()>>>) -> Self {
let originator = ScopeIdx::default();
Self {
fut,
originator,
dead: Cell::new(false),
}
}
}
mod tests {
use std::time::Duration;
use super::*;
use bumpalo::Bump;
#[async_std::test]
async fn example() {
let bump = Bump::new();
type RawTask = Pin<Box<dyn Future<Output = ()>>>;
// build the three
let f1 = bump.alloc(Box::pin(async {
//
async_std::task::sleep(Duration::from_secs(3)).await;
println!("3 sec")
}) as RawTask);
let f2 = bump.alloc(Box::pin(async {
//
async_std::task::sleep(Duration::from_secs(2)).await;
println!("2 sec")
}) as RawTask);
let f3 = bump.alloc(Box::pin(async {
//
async_std::task::sleep(Duration::from_secs(1)).await;
println!("1 sec");
}) as RawTask);
let mut queue = TaskQueue::new();
queue.push_task(DTask::debug_new(f1));
queue.push_task(DTask::debug_new(f2));
queue.push_task(DTask::debug_new(f3));
while !queue.is_empty() {
let next = queue.next().await;
println!("Event received {:#?}", next);
}
}
}

View file

@ -81,6 +81,7 @@ impl<'a> RealDom<'a> for DebugDom {
realnode: RealDomNode,
) {
}
fn remove_event_listener(&mut self, event: &str) {}
fn set_text(&mut self, text: &str) {}

View file

@ -19,24 +19,11 @@
//! This module includes just the barebones for a complete VirtualDOM API.
//! Additional functionality is defined in the respective files.
use crate::hooklist::HookList;
use crate::tasks::TaskQueue;
use crate::{arena::ScopeArena, innerlude::*};
use appendlist::AppendList;
use bumpalo::Bump;
use futures::FutureExt;
use slotmap::DefaultKey;
use slotmap::SlotMap;
use std::marker::PhantomData;
use std::{
any::{Any, TypeId},
cell::{Cell, RefCell},
collections::{HashMap, HashSet, VecDeque},
fmt::Debug,
future::Future,
ops::Deref,
pin::Pin,
rc::{Rc, Weak},
};
use std::{any::TypeId, fmt::Debug, rc::Rc};
pub type ScopeIdx = DefaultKey;
@ -57,10 +44,12 @@ pub struct VirtualDom {
/// All components dump their updates into a queue to be processed
pub(crate) event_queue: EventQueue,
pub(crate) tasks: TaskQueue,
/// a strong allocation to the "caller" for the original component and its props
#[doc(hidden)]
_root_caller: Rc<OpaqueComponent>,
// _root_caller: Rc<OpaqueComponent<'static>>,
/// Type of the original cx. This is stored as TypeId so VirtualDom does not need to be generic.
///
/// Whenver props need to be updated, an Error will be thrown if the new props do not
@ -194,6 +183,7 @@ impl VirtualDom {
base_scope,
event_queue,
components,
tasks: TaskQueue::new(),
_root_prop_type: TypeId::of::<P>(),
}
}
@ -273,7 +263,7 @@ impl VirtualDom {
realdom: &'_ mut Dom,
trigger: EventTrigger,
) -> Result<()> {
let id = trigger.component_id.clone();
let id = trigger.originator.clone();
self.components.try_get_mut(id)?.call_listener(trigger)?;