fix fullstack send bound

This commit is contained in:
Evan Almloff committed 2024-01-17 15:46:29 -06:00
1 parent dab87c0144
commit 499e81fa82
9 files changed
+74 -69

No files matched your search

+7 -6
View File
@@ -3,8 +3,8 @@ use std::{any::Any, panic::AssertUnwindSafe};
pub(crate) type BoxedAnyProps = Box<dyn AnyProps>;
/// A trait that essentially allows VComponentProps to be used generically
pub(crate) trait AnyProps {
/// A trait for a component that can be rendered.
pub trait AnyProps: 'static {
fn render(&self) -> RenderReturn;
fn memoize(&self, other: &dyn Any) -> bool;
fn props(&self) -> &dyn Any;
@@ -17,17 +17,18 @@ pub(crate) fn new_any_props<F: ComponentFunction<P, M>, P: Clone + 'static, M: '
memo: fn(&P, &P) -> bool,
props: P,
name: &'static str,
) -> Box<dyn AnyProps> {
Box::new(VProps {
) -> VProps<F, P, M> {
VProps {
render_fn,
memo,
props,
name,
phantom: std::marker::PhantomData,
})
}
}
struct VProps<F: ComponentFunction<P, M>, P, M> {
/// A component along with the props the component uses to render.
pub struct VProps<F: ComponentFunction<P, M>, P, M> {
render_fn: F,
memo: fn(&P, &P) -> bool,
props: P,
+6 -5
View File
@@ -23,6 +23,7 @@ mod tasks;
mod virtual_dom;
pub(crate) mod innerlude {
pub use crate::any_props::*;
pub use crate::arena::*;
pub use crate::dirty_scope::*;
pub use crate::error_boundary::*;
@@ -75,11 +76,11 @@ pub(crate) mod innerlude {
pub use crate::innerlude::{
fc_to_builder, generation, schedule_update, schedule_update_any, use_hook, vdom_is_rendering,
AnyValue, Attribute, AttributeValue, BoxedContext, CapturedError, Component, ComponentFunction,
CrossPlatformConfig, DynamicNode, Element, ElementId, Event, Fragment, HasAttributes,
IntoDynNode, Mutation, Mutations, NoOpMutations, PlatformBuilder, Properties, RenderReturn,
Runtime, ScopeId, ScopeState, Task, Template, TemplateAttribute, TemplateNode, VComponent,
VNode, VNodeInner, VPlaceholder, VText, VirtualDom, WriteMutations,
AnyProps, AnyValue, Attribute, AttributeValue, BoxedContext, CapturedError, Component,
ComponentFunction, CrossPlatformConfig, DynamicNode, Element, ElementId, Event, Fragment,
HasAttributes, IntoDynNode, Mutation, Mutations, NoOpMutations, PlatformBuilder, Properties,
RenderReturn, Runtime, ScopeId, ScopeState, Task, Template, TemplateAttribute, TemplateNode,
VComponent, VNode, VNodeInner, VPlaceholder, VProps, VText, VirtualDom, WriteMutations,
};
/// The purpose of this module is to alleviate imports of many common types
+6 -1
View File
@@ -529,7 +529,12 @@ impl VComponent {
P: Properties + 'static,
{
let render_fn = component.id();
let props = new_any_props(component, <P as Properties>::memoize, props, fn_name);
let props = Box::new(new_any_props(
component,
<P as Properties>::memoize,
props,
fn_name,
));
VComponent {
name: fn_name,
+17 -20
View File
@@ -1,8 +1,9 @@
use std::any::Any;
use crate::{
properties::{ComponentFunction, RootProps},
VComponent, VirtualDom,
any_props::{new_any_props, AnyProps, VProps},
properties::ComponentFunction,
VirtualDom,
};
/// A boxed object that can be injected into a component's context.
@@ -43,30 +44,26 @@ impl<T: Any + Clone> ClonableAny for T {
}
/// The platform-independent part of the config needed to launch an application.
pub struct CrossPlatformConfig {
pub struct CrossPlatformConfig<P: AnyProps> {
/// The root component function.
component: VComponent,
component: P,
/// The contexts to provide to the root component.
root_contexts: Vec<BoxedContext>,
}
impl CrossPlatformConfig {
impl<F: ComponentFunction<Props, M>, Props: Clone + 'static, M: 'static>
CrossPlatformConfig<VProps<F, Props, M>>
{
/// Create a new cross-platform config.
pub fn new<Props: Clone + 'static, M: 'static>(
component: impl ComponentFunction<Props, M>,
props: Props,
root_contexts: Vec<BoxedContext>,
) -> Self {
Self {
component: VComponent::new(
move |props: RootProps<Props>| component.rebuild(props.0),
RootProps(props),
"root",
),
pub fn new(component: F, props: Props, root_contexts: Vec<BoxedContext>) -> Self {
CrossPlatformConfig {
component: new_any_props(component, |_, _| true, props, "root"),
root_contexts,
}
}
}
impl<P: AnyProps> CrossPlatformConfig<P> {
/// Push a new context into the root component's context.
pub fn push_context<T: Any + Clone + 'static>(&mut self, context: T) {
self.root_contexts.push(BoxedContext::new(context));
@@ -85,18 +82,18 @@ impl CrossPlatformConfig {
}
/// A builder to launch a specific platform.
pub trait PlatformBuilder {
pub trait PlatformBuilder<P: AnyProps> {
/// The platform-specific config needed to launch an application.
type Config: Default;
/// Launch the app.
fn launch(config: CrossPlatformConfig, platform_config: Self::Config);
fn launch(config: CrossPlatformConfig<P>, platform_config: Self::Config);
}
impl PlatformBuilder for () {
impl<P: AnyProps> PlatformBuilder<P> for () {
type Config = ();
fn launch(_: CrossPlatformConfig, _: Self::Config) {
fn launch(_: CrossPlatformConfig<P>, _: Self::Config) {
panic!("No platform is currently enabled. Please enable a platform feature for the dioxus crate.");
}
}
+6 -12
View File
@@ -3,6 +3,7 @@
//! This module provides the primary mechanics to create a hook-based, concurrent VDOM for Rust.
use crate::{
any_props::{new_any_props, AnyProps},
arena::ElementId,
innerlude::{
DirtyScope, ElementRef, ErrorBoundary, NoOpMutations, SchedulerMsg, ScopeState, VNodeMount,
@@ -10,10 +11,9 @@ use crate::{
},
nodes::RenderReturn,
nodes::{Template, TemplateId},
properties::RootProps,
runtime::{Runtime, RuntimeGuard},
scopes::ScopeId,
AttributeValue, BoxedContext, ComponentFunction, Element, Event, Mutations, Task, VComponent,
AttributeValue, BoxedContext, ComponentFunction, Element, Event, Mutations, Task,
};
use futures_util::{pin_mut, StreamExt};
use rustc_hash::{FxHashMap, FxHashSet};
@@ -259,17 +259,11 @@ impl VirtualDom {
/// let mut dom = VirtualDom::new_with_props(Example, SomeProps { name: "jane" });
/// let mutations = dom.rebuild();
/// ```
pub fn new_with_props<P: Clone + 'static, M>(
pub fn new_with_props<P: Clone + 'static, M: 'static>(
root: impl ComponentFunction<P, M>,
root_props: P,
) -> Self {
let vcomponent = VComponent::new(
move |props: RootProps<P>| root.rebuild(props.0),
RootProps(root_props),
"root",
);
Self::new_with_component(vcomponent)
Self::new_with_component(new_any_props(root, |_, _| true, root_props, "root"))
}
/// Create a new virtualdom and build it immediately
@@ -309,7 +303,7 @@ impl VirtualDom {
/// let mut dom = VirtualDom::new_from_root(VComponent::new(Example, SomeProps { name: "jane" }, "Example"));
/// let mutations = dom.rebuild();
/// ```
pub fn new_with_component(root: VComponent) -> Self {
pub fn new_with_component(root: impl AnyProps + 'static) -> Self {
let (tx, rx) = futures_channel::mpsc::unbounded();
let mut dom = Self {
@@ -324,7 +318,7 @@ impl VirtualDom {
suspended_scopes: Default::default(),
};
let root = dom.new_scope(root.props, "app");
let root = dom.new_scope(Box::new(root), "app");
// Unlike react, we provide a default error boundary that just renders the error as a string
root.context()