wip: fix issues with lifetimes

this commit fixes some lifetime issues regarding having to "move" data into the IntoVNode closure.
This commit is contained in:
Jonathan Kelley committed 2021-07-07 13:51:55 -04:00
1 parent 22e659c2bd
commit a38a81e129
39 files changed
+566 -255

No files matched your search

+19 -6
View File
@@ -49,10 +49,23 @@ pub fn fc_to_builder<T: Properties>(_: FC<T>) -> T::Builder {
///
/// Fragments are incredibly useful when necessary, but *do* add cost in the diffing phase.
/// Try to avoid nesting fragments if you can. Infinitely nested Fragments *will* cause diffing to crash.
#[allow(non_upper_case_globals)]
pub const Fragment: FC<()> = |cx| {
use crate::prelude::*;
cx.render(LazyNodes::new(move |c| {
crate::nodebuilder::vfragment(c, None, cx.children())
use crate::prelude::*;
pub fn Fragment<'a>(cx: Context<'a, ()>) -> VNode<'a> {
let childs: &'a [VNode<'a>] = cx.children();
cx.render(LazyNodes::new({
move |f| {
//
f.fragment_from_iter(childs)
}
}))
};
}
// #[allow(non_upper_case_globals)]
// pub const Fragment: FC<()> = |cx| {
// use crate::prelude::*;
// let childs = cx.children();
// cx.render(LazyNodes::new(move |c| {
// c.fragment_from_iter(childs)
// // c.text(format_args!(""))
// // crate::nodebuilder::vfragment(c, None, cx.children())
// }))
// };
+6 -6
View File
@@ -49,18 +49,18 @@ impl DebugRenderer {
// If you have a list or "nth" child, you do need to list those children, but you don't need to
// fill in their children/attrs/etc
// Does not handle children or lifecycles and will always fail the test if they show up in the rhs
pub fn compare<'a, F>(&self, other: LazyNodes<'a, F>) -> Result<()>
pub fn compare<F>(&self, other: LazyNodes<F>) -> Result<()>
where
F: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a,
F: for<'b, 'c> FnOnce(&'b NodeFactory<'c>) -> VNode<'c>,
{
Ok(())
}
// Do a full compare - everything must match
// Ignores listeners and children components
pub fn compare_full<'a, F>(&self, other: LazyNodes<'a, F>) -> Result<()>
pub fn compare_full<F>(&self, other: LazyNodes<F>) -> Result<()>
where
F: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a,
F: for<'b, 'c> FnOnce(&'b NodeFactory<'c>) -> VNode<'c>,
{
Ok(())
}
@@ -69,9 +69,9 @@ impl DebugRenderer {
Ok(())
}
pub fn render_nodes<'a, F>(&self, other: LazyNodes<'a, F>) -> Result<()>
pub fn render_nodes<F>(&self, other: LazyNodes<F>) -> Result<()>
where
F: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a,
F: for<'b, 'c> FnOnce(&'b NodeFactory<'c>) -> VNode<'c>,
{
Ok(())
}
+195 -66
View File
@@ -124,14 +124,12 @@ pub mod on {
macro_rules! event_directory {
( $(
$(
#[$attr:meta]
)*
$( #[$attr:meta] )*
$eventdata:ident($wrapper:ident): [
$(
#[$method_attr:meta]
$( #[$method_attr:meta] )*
$name:ident
)*
$( $name:ident )*
];
)* ) => {
$(
@@ -149,8 +147,8 @@ pub mod on {
}
}
$(#[$method_attr])*
$(
$(#[$method_attr])*
pub fn $name<'a>(
c: &'_ NodeFactory<'a>,
callback: impl Fn($wrapper) + 'a,
@@ -181,35 +179,51 @@ pub mod on {
//
//
event_directory! {
ClipboardEventInner(ClipboardEvent): [
/// Called when "copy"
oncopy
/// oncut
oncut
/// onpaste
onpaste
];
CompositionEventInner(CompositionEvent): [
/// oncompositionend
oncompositionend
/// oncompositionstart
oncompositionstart
/// oncompositionupdate
oncompositionupdate
];
KeyboardEventInner(KeyboardEvent): [
/// onkeydown
onkeydown
/// onkeypress
onkeypress
/// onkeyup
onkeyup
];
FocusEventInner(FocusEvent): [
/// onfocus
onfocus
/// onblur
onblur
];
FormEventInner(FormEvent): [
/// onchange
onchange
/// oninput
oninput
/// oninvalid
oninvalid
/// onreset
onreset
/// onsubmit
onsubmit
];
@@ -237,63 +251,202 @@ pub mod on {
/// ```
///
/// ## Event Handlers
/// - click
/// - contextmenu
/// - doubleclick
/// - drag
/// - dragend
/// - dragenter
/// - dragexit
/// - dragleave
/// - dragover
/// - dragstart
/// - drop
/// - mousedown
/// - mouseenter
/// - mouseleave
/// - mousemove
/// - mouseout
/// - mouseover
/// - mouseup
/// - [`onclick`]
/// - [`oncontextmenu`]
/// - [`ondoubleclick`]
/// - [`ondrag`]
/// - [`ondragend`]
/// - [`ondragenter`]
/// - [`ondragexit`]
/// - [`ondragleave`]
/// - [`ondragover`]
/// - [`ondragstart`]
/// - [`ondrop`]
/// - [`onmousedown`]
/// - [`onmouseenter`]
/// - [`onmouseleave`]
/// - [`onmousemove`]
/// - [`onmouseout`]
/// - [`onmouseover`]
/// - [`onmouseup`]
MouseEventInner(MouseEvent): [
/// Onclick!
/// Execute a callback when a button is clicked.
///
/// ## Description
///
/// An element receives a click event when a pointing device button (such as a mouse's primary mouse button)
/// is both pressed and released while the pointer is located inside the element.
///
/// - Bubbles: Yes
/// - Cancelable: Yes
/// - Interface: [`MouseEvent`]
///
/// If the button is pressed on one element and the pointer is moved outside the element before the button
/// is released, the event is fired on the most specific ancestor element that contained both elements.
/// `click` fires after both the `mousedown` and `mouseup` events have fired, in that order.
///
/// ## Example
/// ```
/// rsx!( button { "click me", onclick: move |_| log::info!("Clicked!`") } )
/// ```
///
/// ## Reference
/// - https://www.w3schools.com/tags/ev_onclick.asp
/// - https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event
///
onclick
/// oncontextmenu
oncontextmenu
/// ondoubleclick
ondoubleclick
/// ondrag
ondrag
/// ondragend
ondragend
/// ondragenter
ondragenter
/// ondragexit
ondragexit
/// ondragleave
ondragleave
/// ondragover
ondragover
/// ondragstart
ondragstart
/// ondrop
ondrop
/// onmousedown
onmousedown
/// onmouseenter
onmouseenter
/// onmouseleave
onmouseleave
/// onmousemove
onmousemove
/// onmouseout
onmouseout
/// onmouseover
onmouseover
/// onmouseup
onmouseup
];
PointerEventInner(PointerEvent): [
pointerdown pointermove pointerup pointercancel gotpointercapture
lostpointercapture pointerenter pointerleave pointerover pointerout
/// pointerdown
onpointerdown
/// pointermove
onpointermove
/// pointerup
onpointerup
/// pointercancel
onpointercancel
/// gotpointercapture
ongotpointercapture
/// lostpointercapture
onlostpointercapture
/// pointerenter
onpointerenter
/// pointerleave
onpointerleave
/// pointerover
onpointerover
/// pointerout
onpointerout
];
SelectionEventInner(SelectionEvent): [select];
TouchEventInner(TouchEvent): [touchcancel touchend touchmove touchstart];
UIEventInner(UIEvent): [scroll];
WheelEventInner(WheelEvent): [wheel];
SelectionEventInner(SelectionEvent): [
/// onselect
onselect
];
TouchEventInner(TouchEvent): [
/// ontouchcancel
ontouchcancel
/// ontouchend
ontouchend
/// ontouchmove
ontouchmove
/// ontouchstart
ontouchstart
];
UIEventInner(UIEvent): [
///
scroll
];
WheelEventInner(WheelEvent): [
///
wheel
];
MediaEventInner(MediaEvent): [
abort canplay canplaythrough durationchange emptied encrypted
ended error loadeddata loadedmetadata loadstart pause play
playing progress ratechange seeked seeking stalled suspend
timeupdate volumechange waiting
///abort
onabort
///canplay
oncanplay
///canplaythrough
oncanplaythrough
///durationchange
ondurationchange
///emptied
onemptied
///encrypted
onencrypted
///ended
onended
///error
onerror
///loadeddata
onloadeddata
///loadedmetadata
onloadedmetadata
///loadstart
onloadstart
///pause
onpause
///play
onplay
///playing
onplaying
///progress
onprogress
///ratechange
onratechange
///seeked
onseeked
///seeking
onseeking
///stalled
onstalled
///suspend
onsuspend
///timeupdate
ontimeupdate
///volumechange
onvolumechange
///waiting
onwaiting
];
AnimationEventInner(AnimationEvent): [
/// onanimationstart
onanimationstart
/// onanimationend
onanimationend
/// onanimationiteration
onanimationiteration
];
TransitionEventInner(TransitionEvent): [
///
ontransitionend
];
ToggleEventInner(ToggleEvent): [
///
ontoggle
];
AnimationEventInner(AnimationEvent): [animationstart animationend animationiteration];
TransitionEventInner(TransitionEvent): [transitionend];
ToggleEventInner(ToggleEvent): [toggle];
}
pub trait GenericEventInner {
@@ -404,7 +557,6 @@ pub mod on {
fn alt_key(&self) -> bool;
fn button(&self) -> i16;
fn buttons(&self) -> u16;
/// Get the X coordinate of the mouse relative to the window
fn client_x(&self) -> i32;
fn client_y(&self) -> i32;
@@ -709,26 +861,3 @@ pub mod on {
}
}
}
// mod tests {
// use std::rc::Rc;
// use crate as dioxus;
// use crate::events::on::MouseEvent;
// use crate::prelude::*;
// fn autocomplete() {
// // let v = move |evt| {
// // let r = evt.alt_key();
// // };
// let g = rsx! {
// button {
// onclick: move |evt| {
// let r = evt.alt_key();
// }
// }
// };
// }
// }
+1 -2
View File
@@ -16,7 +16,7 @@ pub mod component;
pub mod styles;
pub mod util; // Logic for extending FC
pub mod debug_renderer;
// pub mod debug_renderer;
pub mod diff;
pub mod error; // Error type we expose to the renderers
@@ -62,7 +62,6 @@ pub mod prelude {
pub use crate::nodebuilder::LazyNodes;
pub use crate::nodebuilder::ChildrenList;
pub use crate::nodebuilder::{DioxusElement, NodeFactory};
// pub use nodes::iterables::IterableNodes;
/// This type alias is an internal way of abstracting over the static functions that represent components.
+49 -84
View File
@@ -6,6 +6,7 @@ use std::{
cell::{Cell, RefCell},
fmt::Arguments,
intrinsics::transmute,
marker::PhantomData,
u128,
};
@@ -511,8 +512,9 @@ where
pub fn iter_child(mut self, nodes: impl IntoIterator<Item = impl IntoVNode<'a>>) -> Self {
let len_before = self.children.len();
for item in nodes {
let child = item.into_vnode(&self.cx);
self.children.push(child);
todo!()
// let child = item.into_vnode(&self.cx);
// self.children.push(child);
}
if cfg!(debug_assertions) {
if self.children.len() > len_before + 1 {
@@ -541,52 +543,53 @@ impl<'a> IntoIterator for VNode<'a> {
}
}
impl<'a> IntoVNode<'a> for VNode<'a> {
fn into_vnode(self, cx: &NodeFactory<'a>) -> VNode<'a> {
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
self
}
}
impl<'a> IntoVNode<'a> for &VNode<'a> {
fn into_vnode(self, cx: &NodeFactory<'a>) -> VNode<'a> {
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a>
// where
// 'a: 'c,
{
todo!()
// cloning is cheap since vnodes are just references into bump arenas
self.clone()
// self.clone()
}
}
pub trait IntoVNode<'a> {
fn into_vnode(self, cx: &NodeFactory<'a>) -> VNode<'a>;
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a>;
}
pub trait VNodeBuilder<'a, G>: IntoIterator<Item = G>
where
G: IntoVNode<'a>,
{
}
// pub trait VNodeBuilder<'a, G>: IntoIterator<Item = G>
// where
// G: IntoVNode<'a>,
// {
// }
impl<'a, F> VNodeBuilder<'a, LazyNodes<'a, F>> for LazyNodes<'a, F> where
F: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a
{
}
// impl<'a, F> VNodeBuilder<'a, LazyNodes<F>> for LazyNodes<F> where F: FnOnce(NodeFactory) -> VNode {}
// Wrap the the node-builder closure in a concrete type.
// ---
// This is a bit of a hack to implement the IntoVNode trait for closure types.
pub struct LazyNodes<'a, G>
where
G: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a,
G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
{
inner: G,
_p: std::marker::PhantomData<&'a ()>,
_p: PhantomData<&'a ()>,
}
impl<'a, G> LazyNodes<'a, G>
where
G: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a,
G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
{
pub fn new(f: G) -> Self {
Self {
inner: f,
_p: std::default::Default::default(),
_p: PhantomData {},
}
}
}
@@ -598,9 +601,9 @@ where
// rsx! { {nodes } }
impl<'a, G> IntoVNode<'a> for LazyNodes<'a, G>
where
G: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a,
G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
{
fn into_vnode(self, cx: &NodeFactory<'a>) -> VNode<'a> {
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
(self.inner)(cx)
}
}
@@ -608,7 +611,7 @@ where
// Required because anything that enters brackets in the rsx! macro needs to implement IntoIterator
impl<'a, G> IntoIterator for LazyNodes<'a, G>
where
G: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a,
G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
{
type Item = Self;
type IntoIter = std::iter::Once<Self::Item>;
@@ -617,23 +620,23 @@ where
}
}
impl<'a> IntoVNode<'a> for () {
fn into_vnode(self, cx: &NodeFactory<'a>) -> VNode<'a> {
todo!();
VNode::Suspended {
real: Cell::new(RealDomNode::empty()),
}
}
}
// impl IntoVNode<'_> for () {
// fn into_vnode<'a>(self, cx: NodeFactory<'a>) -> VNode<'a> {
// todo!();
// VNode::Suspended {
// real: Cell::new(RealDomNode::empty()),
// }
// }
// }
impl<'a> IntoVNode<'a> for Option<()> {
fn into_vnode(self, cx: &NodeFactory<'a>) -> VNode<'a> {
todo!();
VNode::Suspended {
real: Cell::new(RealDomNode::empty()),
}
}
}
// impl IntoVNode<'_> for Option<()> {
// fn into_vnode<'a>(self, cx: NodeFactory<'a>) -> VNode<'a> {
// todo!();
// VNode::Suspended {
// real: Cell::new(RealDomNode::empty()),
// }
// }
// }
/// Construct a text VNode.
///
@@ -702,7 +705,7 @@ pub fn attr<'a>(name: &'static str, value: &'a str) -> Attribute<'a> {
}
pub fn virtual_child<'a, T: Properties + 'a>(
cx: &NodeFactory<'a>,
cx: NodeFactory<'a>,
f: FC<T>,
props: T,
key: Option<&'a str>, // key: NodeKey<'a>,
@@ -713,54 +716,28 @@ pub fn virtual_child<'a, T: Properties + 'a>(
// todo!()
VNode::Component(
cx.bump()
.alloc(crate::nodes::VComponent::new(cx, f, props, key, children)),
.alloc(crate::nodes::VComponent::new(&cx, f, props, key, children)),
// cx.bump()
// .alloc(crate::nodes::VComponent::new(f, props, key)),
)
}
pub fn vfragment<'a>(
cx: &NodeFactory<'a>,
cx: NodeFactory<'a>,
key: Option<&'a str>, // key: NodeKey<'a>,
children: &'a [VNode<'a>],
) -> VNode<'a> {
VNode::Fragment(cx.bump().alloc(VFragment::new(key, children)))
}
pub struct ChildrenList<'a, 'b> {
cx: &'b NodeFactory<'a>,
children: bumpalo::collections::Vec<'a, VNode<'a>>,
}
impl<'a, 'b> ChildrenList<'a, 'b> {
pub fn new(cx: &'b NodeFactory<'a>) -> Self {
Self {
cx,
children: bumpalo::collections::Vec::new_in(cx.bump()),
}
}
pub fn add_child(mut self, nodes: impl IntoIterator<Item = impl IntoVNode<'a>>) -> Self {
for item in nodes {
let child = item.into_vnode(&self.cx);
self.children.push(child);
}
self
}
pub fn finish(self) -> &'a [VNode<'a>] {
self.children.into_bump_slice()
}
}
/// This struct provides an ergonomic API to quickly build VNodes.
///
/// NodeFactory is used to build VNodes in the component's memory space.
/// This struct adds metadata to the final VNode about listeners, attributes, and children
#[derive(Clone)]
#[derive(Copy, Clone)]
pub struct NodeFactory<'a> {
pub scope_ref: &'a Scope,
pub listener_id: Cell<usize>,
pub listener_id: &'a Cell<usize>,
}
impl<'a> NodeFactory<'a> {
@@ -791,7 +768,7 @@ impl<'a> NodeFactory<'a> {
pub fn attr(
&self,
name: &'static str,
val: Arguments<'a>,
val: Arguments,
namespace: Option<&'static str>,
) -> Attribute<'a> {
let value = raw_text(self.bump(), val);
@@ -802,18 +779,6 @@ impl<'a> NodeFactory<'a> {
}
}
pub fn child_list(&self) -> ChildrenList {
ChildrenList::new(&self)
}
pub fn fragment_builder<'b>(
&'b self,
key: Option<&'a str>,
builder: impl FnOnce(ChildrenList<'a, 'b>) -> &'a [VNode<'a>],
) -> VNode<'a> {
self.fragment(builder(ChildrenList::new(&self)), key)
}
pub fn fragment(&self, children: &'a [VNode<'a>], key: Option<&'a str>) -> VNode<'a> {
VNode::Fragment(self.bump().alloc(VFragment {
children,
@@ -822,12 +787,12 @@ impl<'a> NodeFactory<'a> {
}
pub fn fragment_from_iter(
&self,
self,
node_iter: impl IntoIterator<Item = impl IntoVNode<'a>>,
) -> VNode<'a> {
let mut nodes = bumpalo::collections::Vec::new_in(self.bump());
for node in node_iter.into_iter() {
nodes.push(node.into_vnode(&self));
nodes.push(node.into_vnode(self));
}
VNode::Fragment(
self.bump()
+19 -22
View File
@@ -393,6 +393,8 @@ pub struct Scope {
// could also use ourborous
hooks: RefCell<Vec<Hook>>,
pub(crate) listener_idx: Cell<usize>,
// Unsafety:
// - is self-refenrential and therefore needs to point into the bump
// Stores references into the listeners attached to the vnodes
@@ -463,6 +465,7 @@ impl Scope {
height,
event_channel,
arena_link,
listener_idx: Default::default(),
frames: ActiveFrame::new(),
hooks: Default::default(),
shared_contexts: Default::default(),
@@ -506,13 +509,9 @@ impl Scope {
// Remove all the outdated listeners
self.listeners.borrow_mut().clear();
// self.listeners
// .try_borrow_mut()
// .ok()
// .ok_or(Error::FatalInternal("Borrowing listener failed"))?
// .drain(..);
self.hookidx.set(0);
self.listener_idx.set(0);
let caller = self
.caller
@@ -522,12 +521,8 @@ impl Scope {
// Cast the caller ptr from static to one with our own reference
let c2: &OpaqueComponent = caller.as_ref();
let c3: &OpaqueComponent = unsafe { std::mem::transmute(c2) };
// let c2: &OpaqueComponent<'static> = caller.as_ref();
// let c3: &OpaqueComponent<'sel> = unsafe { std::mem::transmute(c2) };
let unsafe_head = unsafe { self.own_vnodes(c3) };
self.frames.cur_frame_mut().head_node = unsafe_head;
self.frames.cur_frame_mut().head_node = unsafe { self.own_vnodes(c3) };
Ok(())
}
@@ -685,13 +680,15 @@ pub trait Scoped<'src>: Sized {
/// cx.render(lazy_tree)
/// }
///```
fn render<'a, F: for<'b> FnOnce(&'b NodeFactory<'src>) -> VNode<'src> + 'src + 'a>(
fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
self,
lazy_nodes: LazyNodes<'src, F>,
) -> VNode<'src> {
lazy_nodes.into_vnode(&NodeFactory {
scope_ref: self.get_scope(),
listener_id: 0.into(),
let scope_ref = self.get_scope();
let listener_id = &scope_ref.listener_idx;
lazy_nodes.into_vnode(NodeFactory {
scope_ref,
listener_id,
})
}
@@ -890,14 +887,14 @@ Any function prefixed with "use" should not be called conditionally.
#[derive(Clone)]
pub struct SuspendedContext {}
impl SuspendedContext {
pub fn render<'a, 'src, F: for<'b> FnOnce(&'b NodeFactory<'src>) -> VNode<'src> + 'src + 'a>(
self,
lazy_nodes: LazyNodes<'src, F>,
) -> VNode<'src> {
todo!()
}
}
// impl SuspendedContext {
// pub fn render<'a, F: for<'b, 'src> FnOnce(&'b NodeFactory<'src>) -> VNode<'src>>(
// &self,
// lazy_nodes: LazyNodes<F>,
// ) -> VNode {
// todo!()
// }
// }
// ==================================================================================
// Supporting structs for the above abstractions