wip: fill out the snippets
This commit is contained in:
1 parent
4a72b3140b
commit
6051b0ec86
14 files changed
+185
-66
No files matched your search
@@ -1,13 +1,13 @@
|
||||
use std::{cell::UnsafeCell, rc::Rc};
|
||||
|
||||
use crate::innerlude::*;
|
||||
use slotmap::{DefaultKey, SlotMap};
|
||||
use slotmap::SlotMap;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SharedArena {
|
||||
pub components: Rc<UnsafeCell<ScopeMap>>,
|
||||
}
|
||||
pub type ScopeMap = SlotMap<DefaultKey, Scope>;
|
||||
pub type ScopeMap = SlotMap<ScopeId, Scope>;
|
||||
|
||||
enum MutStatus {
|
||||
Immut,
|
||||
|
||||
@@ -77,13 +77,14 @@ impl ActiveFrame {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next(&mut self) -> &mut BumpFrame {
|
||||
*self.generation.borrow_mut() += 1;
|
||||
|
||||
if *self.generation.borrow() % 2 == 0 {
|
||||
&mut self.frames[0]
|
||||
} else {
|
||||
&mut self.frames[1]
|
||||
pub fn old_frame_mut(&mut self) -> &mut BumpFrame {
|
||||
match *self.generation.borrow() & 1 == 0 {
|
||||
true => &mut self.frames[1],
|
||||
false => &mut self.frames[0],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cycle_frame(&mut self) {
|
||||
*self.generation.borrow_mut() += 1;
|
||||
}
|
||||
}
|
||||
@@ -115,6 +115,11 @@ impl<'src, P> Context<'src, P> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Get's this context's ScopeId
|
||||
pub fn get_scope_id(&self) -> ScopeId {
|
||||
self.scope.our_arena_idx.clone()
|
||||
}
|
||||
|
||||
/// Take a lazy VNode structure and actually build it with the context of the VDom's efficient VNode allocator.
|
||||
///
|
||||
/// This function consumes the context and absorb the lifetime, so these VNodes *must* be returned.
|
||||
@@ -200,7 +205,11 @@ Any function prefixed with "use" should not be called conditionally.
|
||||
///
|
||||
///
|
||||
///
|
||||
pub fn use_create_context<T: 'static>(&self, init: impl Fn() -> T) {
|
||||
pub fn use_context_provider<T, F>(self, init: F) -> &'src Rc<T>
|
||||
where
|
||||
T: 'static,
|
||||
F: FnOnce() -> T,
|
||||
{
|
||||
let mut cxs = self.scope.shared_contexts.borrow_mut();
|
||||
let ty = TypeId::of::<T>();
|
||||
|
||||
@@ -225,7 +234,8 @@ Any function prefixed with "use" should not be called conditionally.
|
||||
}
|
||||
|
||||
_ => debug_assert!(false, "Cannot initialize two contexts of the same type"),
|
||||
}
|
||||
};
|
||||
self.use_context::<T>()
|
||||
}
|
||||
|
||||
/// There are hooks going on here!
|
||||
@@ -234,26 +244,19 @@ Any function prefixed with "use" should not be called conditionally.
|
||||
}
|
||||
|
||||
/// Uses a context, storing the cached value around
|
||||
pub fn try_use_context<T: 'static>(self) -> Result<&'src Rc<T>> {
|
||||
///
|
||||
/// If a context is not found on the first search, then this call will be "dud", always returning "None" even if a
|
||||
/// context was added later. This allows using another hook as a fallback
|
||||
///
|
||||
pub fn try_use_context<T: 'static>(self) -> Option<&'src Rc<T>> {
|
||||
struct UseContextHook<C> {
|
||||
par: Option<Rc<C>>,
|
||||
we: Option<Weak<C>>,
|
||||
}
|
||||
|
||||
self.use_hook(
|
||||
move |_| UseContextHook {
|
||||
par: None as Option<Rc<T>>,
|
||||
we: None as Option<Weak<T>>,
|
||||
},
|
||||
move |hook| {
|
||||
move |_| {
|
||||
let mut scope = Some(self.scope);
|
||||
|
||||
if let Some(we) = &hook.we {
|
||||
if let Some(re) = we.upgrade() {
|
||||
hook.par = Some(re);
|
||||
return Ok(hook.par.as_ref().unwrap());
|
||||
}
|
||||
}
|
||||
let mut par = None;
|
||||
|
||||
let ty = TypeId::of::<T>();
|
||||
while let Some(inner) = scope {
|
||||
@@ -270,26 +273,21 @@ Any function prefixed with "use" should not be called conditionally.
|
||||
.downcast::<T>()
|
||||
.expect("Should not fail, already validated the type from the hashmap");
|
||||
|
||||
hook.we = Some(Rc::downgrade(&rc));
|
||||
hook.par = Some(rc);
|
||||
return Ok(hook.par.as_ref().unwrap());
|
||||
par = Some(rc);
|
||||
break;
|
||||
} else {
|
||||
match inner.parent_idx {
|
||||
Some(parent_id) => {
|
||||
let parent = inner
|
||||
.arena_link
|
||||
.get(parent_id)
|
||||
.ok_or_else(|| Error::FatalInternal("Failed to find parent"))?;
|
||||
|
||||
scope = Some(parent);
|
||||
scope = inner.arena_link.get(parent_id);
|
||||
}
|
||||
None => return Err(Error::MissingSharedContext),
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::MissingSharedContext)
|
||||
//
|
||||
UseContextHook { par }
|
||||
},
|
||||
move |hook| hook.par.as_ref(),
|
||||
|_| {},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ pub enum Error {
|
||||
#[error("Wrong Properties Type")]
|
||||
WrongProps,
|
||||
|
||||
#[error("The component failed to return VNodes")]
|
||||
ComponentFailed,
|
||||
|
||||
#[error("Base scope has not been mounted yet")]
|
||||
NotMounted,
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
//!
|
||||
|
||||
pub use crate::innerlude::{
|
||||
format_args_f, html, rsx, Context, DioxusElement, DomEdit, EventTrigger, LazyNodes,
|
||||
format_args_f, html, rsx, Context, DioxusElement, DomEdit, DomTree, EventTrigger, LazyNodes,
|
||||
NodeFactory, Properties, RealDom, RealDomNode, ScopeId, VNode, VNodeKind, VirtualDom,
|
||||
VirtualEvent, FC,
|
||||
};
|
||||
|
||||
@@ -267,6 +267,22 @@ impl<'a> NodeFactory<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn attr_with_alloc_val(
|
||||
&self,
|
||||
name: &'static str,
|
||||
val: &'a str,
|
||||
namespace: Option<&'static str>,
|
||||
is_volatile: bool,
|
||||
) -> Attribute<'a> {
|
||||
Attribute {
|
||||
name,
|
||||
value: val,
|
||||
is_static: false,
|
||||
namespace,
|
||||
is_volatile,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn component<P>(
|
||||
&self,
|
||||
component: FC<P>,
|
||||
@@ -508,6 +524,14 @@ impl IntoVNode<'_> for Option<()> {
|
||||
cx.fragment_from_iter(None as Option<VNode>)
|
||||
}
|
||||
}
|
||||
impl<'a> IntoVNode<'a> for Option<VNode<'a>> {
|
||||
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
||||
match self {
|
||||
Some(n) => n,
|
||||
None => cx.fragment_from_iter(None as Option<VNode>),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for NodeFactory<'_> {
|
||||
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
|
||||
+15
-11
@@ -113,7 +113,8 @@ impl Scope {
|
||||
// Remove all the outdated listeners
|
||||
|
||||
// This is a very dangerous operation
|
||||
self.frames.next().bump.reset();
|
||||
let next_frame = self.frames.old_frame_mut();
|
||||
next_frame.bump.reset();
|
||||
|
||||
self.listeners.borrow_mut().clear();
|
||||
|
||||
@@ -123,16 +124,19 @@ impl Scope {
|
||||
// Cast the caller ptr from static to one with our own reference
|
||||
let c3: &WrappedCaller = self.caller.as_ref();
|
||||
|
||||
self.frames.cur_frame_mut().head_node = unsafe { self.call_user_component(c3) };
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// this is its own function so we can preciesly control how lifetimes flow
|
||||
unsafe fn call_user_component<'a>(&'a self, caller: &WrappedCaller) -> VNode<'static> {
|
||||
let new_head: Option<VNode<'a>> = caller(self);
|
||||
let new_head = new_head.unwrap_or(errored_fragment());
|
||||
std::mem::transmute(new_head)
|
||||
match c3(self) {
|
||||
None => {
|
||||
// the user's component failed. We avoid cycling to the next frame
|
||||
log::error!("Running your component failed! It will no longer receive events.");
|
||||
Err(Error::ComponentFailed)
|
||||
}
|
||||
Some(new_head) => {
|
||||
// the user's component succeeded. We can safely cycle to the next frame
|
||||
self.frames.old_frame_mut().head_node = unsafe { std::mem::transmute(new_head) };
|
||||
self.frames.cycle_frame();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A safe wrapper around calling listeners
|
||||
|
||||
@@ -30,7 +30,9 @@ use std::any::TypeId;
|
||||
use std::cell::RefCell;
|
||||
use std::pin::Pin;
|
||||
|
||||
pub type ScopeId = DefaultKey;
|
||||
slotmap::new_key_type! {
|
||||
pub struct ScopeId;
|
||||
}
|
||||
|
||||
/// An integrated virtual node system that progresses events and diffs UI trees.
|
||||
/// Differences are converted into patches which a renderer can use to draw the UI.
|
||||
@@ -140,7 +142,7 @@ impl VirtualDom {
|
||||
/// let dom = VirtualDom::new(Example);
|
||||
/// ```
|
||||
pub fn new_with_props<P: Properties + 'static>(root: FC<P>, root_props: P) -> Self {
|
||||
let components = SharedArena::new(SlotMap::new());
|
||||
let components = SharedArena::new(SlotMap::<ScopeId, Scope>::with_key());
|
||||
|
||||
let root_props: Pin<Box<dyn Any>> = Box::pin(root_props);
|
||||
let props_ptr = root_props.as_ref().downcast_ref::<P>().unwrap() as *const P;
|
||||
@@ -225,11 +227,12 @@ impl VirtualDom {
|
||||
);
|
||||
|
||||
let cur_component = self.components.get_mut(self.base_scope).unwrap();
|
||||
cur_component.run_scope()?;
|
||||
|
||||
let meta = diff_machine.create(cur_component.next_frame());
|
||||
|
||||
diff_machine.edits.append_children(meta.added_to_stack);
|
||||
// We run the component. If it succeeds, then we can diff it and add the changes to the dom.
|
||||
if cur_component.run_scope().is_ok() {
|
||||
let meta = diff_machine.create(cur_component.next_frame());
|
||||
diff_machine.edits.append_children(meta.added_to_stack);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -370,10 +373,10 @@ impl VirtualDom {
|
||||
// We are guaranteeed that this scope is unique because we are tracking which nodes have modified
|
||||
let cur_component = self.components.get_mut(update.idx).unwrap();
|
||||
|
||||
cur_component.run_scope()?;
|
||||
|
||||
let (old, new) = (cur_component.old_frame(), cur_component.next_frame());
|
||||
diff_machine.diff_node(old, new);
|
||||
if cur_component.run_scope().is_ok() {
|
||||
let (old, new) = (cur_component.old_frame(), cur_component.next_frame());
|
||||
diff_machine.diff_node(old, new);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user