fix constructing no argument components

This commit is contained in:
Evan Almloff committed 2024-01-11 11:44:18 -06:00
1 parent 1794debf79
commit bcbb647d02
5 files changed
+40 -23

No files matched your search

+10 -10
View File
@@ -1,5 +1,5 @@
use crate::{nodes::RenderReturn, Element}; use crate::{nodes::RenderReturn, properties::HasProps};
use std::{any::Any, ops::Deref, panic::AssertUnwindSafe}; use std::{any::Any, ops::Deref, panic::AssertUnwindSafe, rc::Rc};
/// A boxed version of AnyProps that can be cloned /// A boxed version of AnyProps that can be cloned
pub(crate) struct BoxedAnyProps { pub(crate) struct BoxedAnyProps {
@@ -38,22 +38,22 @@ pub(crate) trait AnyProps {
fn duplicate(&self) -> Box<dyn AnyProps>; fn duplicate(&self) -> Box<dyn AnyProps>;
} }
pub(crate) struct VProps<P> { pub(crate) struct VProps<P: 'static, Phantom: 'static> {
pub render_fn: fn(P) -> Element, pub render_fn: Rc<dyn HasProps<Phantom, Props = P>>,
pub memo: fn(&P, &P) -> bool, pub memo: fn(&P, &P) -> bool,
pub props: P, pub props: P,
pub name: &'static str, pub name: &'static str,
} }
impl<P> VProps<P> { impl<P: 'static, Phantom: 'static> VProps<P, Phantom> {
pub(crate) fn new( pub(crate) fn new(
render_fn: fn(P) -> Element, render_fn: impl HasProps<Phantom, Props = P> + 'static,
memo: fn(&P, &P) -> bool, memo: fn(&P, &P) -> bool,
props: P, props: P,
name: &'static str, name: &'static str,
) -> Self { ) -> Self {
Self { Self {
render_fn, render_fn: Rc::new(render_fn),
memo, memo,
props, props,
name, name,
@@ -61,7 +61,7 @@ impl<P> VProps<P> {
} }
} }
impl<P: Clone + 'static> AnyProps for VProps<P> { impl<P: Clone + 'static, Phantom> AnyProps for VProps<P, Phantom> {
fn memoize(&self, other: &dyn Any) -> bool { fn memoize(&self, other: &dyn Any) -> bool {
match other.downcast_ref::<P>() { match other.downcast_ref::<P>() {
Some(other) => (self.memo)(&self.props, other), Some(other) => (self.memo)(&self.props, other),
@@ -76,7 +76,7 @@ impl<P: Clone + 'static> AnyProps for VProps<P> {
fn render(&self) -> RenderReturn { fn render(&self) -> RenderReturn {
let res = std::panic::catch_unwind(AssertUnwindSafe(move || { let res = std::panic::catch_unwind(AssertUnwindSafe(move || {
// Call the render function directly // Call the render function directly
(self.render_fn)(self.props.clone()) self.render_fn.call(self.props.clone())
})); }));
match res { match res {
@@ -92,7 +92,7 @@ impl<P: Clone + 'static> AnyProps for VProps<P> {
fn duplicate(&self) -> Box<dyn AnyProps> { fn duplicate(&self) -> Box<dyn AnyProps> {
Box::new(Self { Box::new(Self {
render_fn: self.render_fn, render_fn: self.render_fn.clone(),
memo: self.memo, memo: self.memo,
props: self.props.clone(), props: self.props.clone(),
name: self.name, name: self.name,
+2 -2
View File
@@ -102,8 +102,8 @@ pub fn once<State: Clone + 'static>(initializer: impl FnOnce() -> State) -> Stat
/// Get the current render since the inception of this component /// Get the current render since the inception of this component
/// ///
/// This can be used as a helpful diagnostic when debugging hooks/renders, etc /// This can be used as a helpful diagnostic when debugging hooks/renders, etc
pub fn generation() -> Option<usize> { pub fn generation() -> usize {
with_current_scope(|cx| Some(cx.generation())).expect("to be in a dioxus runtime") with_current_scope(|cx| cx.generation()).expect("to be in a dioxus runtime")
} }
/// Get the parent of the current scope if it exists /// Get the parent of the current scope if it exists
+11 -5
View File
@@ -1,5 +1,6 @@
use crate::any_props::{BoxedAnyProps, VProps}; use crate::any_props::{BoxedAnyProps, VProps};
use crate::innerlude::{ElementRef, EventHandler, MountId, ScopeState}; use crate::innerlude::{ElementRef, EventHandler, MountId, ScopeState};
use crate::properties::HasProps;
use crate::{arena::ElementId, Element, Event}; use crate::{arena::ElementId, Element, Event};
use crate::{Properties, VirtualDom}; use crate::{Properties, VirtualDom};
use std::ops::Deref; use std::ops::Deref;
@@ -443,7 +444,7 @@ pub struct VComponent {
/// The function pointer of the component, known at compile time /// The function pointer of the component, known at compile time
/// ///
/// It is possible that components get folded at compile time, so these shouldn't be really used as a key /// It is possible that components get folded at compile time, so these shouldn't be really used as a key
pub(crate) render_fn: *const (), pub(crate) render_fn: TypeId,
pub(crate) props: BoxedAnyProps, pub(crate) props: BoxedAnyProps,
} }
@@ -463,16 +464,21 @@ impl VComponent {
/// fn(Scope<Props>) -> Element; /// fn(Scope<Props>) -> Element;
/// async fn(Scope<Props<'_>>) -> Element; /// async fn(Scope<Props<'_>>) -> Element;
/// ``` /// ```
pub fn new<P>(component: fn(P) -> Element, props: P, fn_name: &'static str) -> Self pub fn new<F: HasProps<P> + 'static, P: 'static>(
component: F,
props: F::Props,
fn_name: &'static str,
) -> Self
where where
// The properties must be valid until the next bump frame // The properties must be valid until the next bump frame
P: Properties, F::Props: Properties + 'static,
{ {
let vcomp = VProps::new(component, P::memoize, props, fn_name); let render_fn_id = TypeId::of::<F>();
let vcomp = VProps::new(component, F::Props::memoize, props, fn_name);
VComponent { VComponent {
name: fn_name, name: fn_name,
render_fn: component as *const (), render_fn: render_fn_id,
props: BoxedAnyProps::new(vcomp), props: BoxedAnyProps::new(vcomp),
} }
} }
+16 -5
View File
@@ -67,25 +67,36 @@ impl EmptyBuilder {
/// This utility function launches the builder method so rsx! and html! macros can use the typed-builder pattern /// This utility function launches the builder method so rsx! and html! macros can use the typed-builder pattern
/// to initialize a component's props. /// to initialize a component's props.
pub fn fc_to_builder<F: HasProps<P>, P>( pub fn fc_to_builder<F: HasProps<P>, P>(_: F) -> <<F as HasProps<P>>::Props as Properties>::Builder
_: F, where
) -> <<F as HasProps<P>>::Props as Properties>::Builder { F::Props: Properties,
{
F::Props::builder() F::Props::builder()
} }
/// A function pointer that can be used to create a component. /// A function pointer that can be used to create a component.
pub trait HasProps<P> { pub trait HasProps<P> {
type Props: Properties; type Props: 'static;
fn call(&self, props: Self::Props) -> Element;
} }
impl<T: Properties, F: Fn(T) -> Element> HasProps<(T,)> for F { impl<T: 'static, F: Fn(T) -> Element> HasProps<(T,)> for F {
type Props = T; type Props = T;
fn call(&self, props: T) -> Element {
self(props)
}
} }
#[doc(hidden)] #[doc(hidden)]
pub struct ZeroElementMarker; pub struct ZeroElementMarker;
impl<F: Fn() -> Element> HasProps<ZeroElementMarker> for F { impl<F: Fn() -> Element> HasProps<ZeroElementMarker> for F {
type Props = (); type Props = ();
fn call(&self, _: ()) -> Element {
self()
}
} }
#[test] #[test]
+1 -1
View File
@@ -4,7 +4,7 @@ use dioxus::prelude::*;
#[test] #[test]
fn state_shares() { fn state_shares() {
fn app() -> Element { fn app() -> Element {
cx.provide_context(generation() as i32); cx.provide_context(generation().unwrap() as i32);
render!(child_1 {}) render!(child_1 {})
} }