mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-23 12:43:08 +00:00
wip: some work
This commit is contained in:
parent
58ab51a4e4
commit
feab50f24a
8 changed files with 171 additions and 108 deletions
2
packages/core/.vscode/settings.json
vendored
2
packages/core/.vscode/settings.json
vendored
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"rust-analyzer.inlayHints.enable": false
|
||||
"rust-analyzer.inlayHints.enable": true
|
||||
}
|
||||
|
|
|
@ -17,5 +17,7 @@ const App: FC<()> = |cx| {
|
|||
|
||||
cx.submit_task(fut);
|
||||
|
||||
cx.submit_task(fut);
|
||||
|
||||
todo!()
|
||||
};
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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 {:?}",
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -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)?;
|
||||
|
||||
|
|
Loading…
Reference in a new issue