try not double boxing
This commit is contained in:
1 parent
0c532c5e0c
commit
dab87c0144
11 files changed
+166
-103
No files matched your search
@@ -1,7 +1,7 @@
|
|||||||
use crate::{nodes::RenderReturn, Component};
|
use crate::{nodes::RenderReturn, ComponentFunction};
|
||||||
use std::{any::Any, panic::AssertUnwindSafe};
|
use std::{any::Any, panic::AssertUnwindSafe};
|
||||||
|
|
||||||
pub type BoxedAnyProps = Box<dyn AnyProps>;
|
pub(crate) type BoxedAnyProps = Box<dyn AnyProps>;
|
||||||
|
|
||||||
/// A trait that essentially allows VComponentProps to be used generically
|
/// A trait that essentially allows VComponentProps to be used generically
|
||||||
pub(crate) trait AnyProps {
|
pub(crate) trait AnyProps {
|
||||||
@@ -12,8 +12,8 @@ pub(crate) trait AnyProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new boxed props object.
|
/// Create a new boxed props object.
|
||||||
pub fn new_any_props<P: 'static + Clone>(
|
pub(crate) fn new_any_props<F: ComponentFunction<P, M>, P: Clone + 'static, M: 'static>(
|
||||||
render_fn: Component<P>,
|
render_fn: F,
|
||||||
memo: fn(&P, &P) -> bool,
|
memo: fn(&P, &P) -> bool,
|
||||||
props: P,
|
props: P,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
@@ -23,17 +23,21 @@ pub fn new_any_props<P: 'static + Clone>(
|
|||||||
memo,
|
memo,
|
||||||
props,
|
props,
|
||||||
name,
|
name,
|
||||||
|
phantom: std::marker::PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VProps<P> {
|
struct VProps<F: ComponentFunction<P, M>, P, M> {
|
||||||
render_fn: Component<P>,
|
render_fn: F,
|
||||||
memo: fn(&P, &P) -> bool,
|
memo: fn(&P, &P) -> bool,
|
||||||
props: P,
|
props: P,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
|
phantom: std::marker::PhantomData<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Clone + 'static> AnyProps for VProps<P> {
|
impl<F: ComponentFunction<P, M> + Clone, P: Clone + 'static, M: 'static> AnyProps
|
||||||
|
for VProps<F, P, M>
|
||||||
|
{
|
||||||
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),
|
||||||
@@ -47,7 +51,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 || {
|
||||||
(self.render_fn)(self.props.clone())
|
self.render_fn.rebuild(self.props.clone())
|
||||||
}));
|
}));
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
@@ -67,6 +71,7 @@ impl<P: Clone + 'static> AnyProps for VProps<P> {
|
|||||||
memo: self.memo,
|
memo: self.memo,
|
||||||
props: self.props.clone(),
|
props: self.props.clone(),
|
||||||
name: self.name,
|
name: self.name,
|
||||||
|
phantom: std::marker::PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -520,7 +520,7 @@ pub struct VComponent {
|
|||||||
|
|
||||||
impl VComponent {
|
impl VComponent {
|
||||||
/// Create a new [`VComponent`] variant
|
/// Create a new [`VComponent`] variant
|
||||||
pub fn new<P, M>(
|
pub fn new<P, M: 'static>(
|
||||||
component: impl ComponentFunction<P, M>,
|
component: impl ComponentFunction<P, M>,
|
||||||
props: P,
|
props: P,
|
||||||
fn_name: &'static str,
|
fn_name: &'static str,
|
||||||
@@ -528,9 +528,7 @@ impl VComponent {
|
|||||||
where
|
where
|
||||||
P: Properties + 'static,
|
P: Properties + 'static,
|
||||||
{
|
{
|
||||||
let component = Rc::new(component);
|
|
||||||
let render_fn = component.id();
|
let render_fn = component.id();
|
||||||
let component = component.as_component();
|
|
||||||
let props = new_any_props(component, <P as Properties>::memoize, props, fn_name);
|
let props = new_any_props(component, <P as Properties>::memoize, props, fn_name);
|
||||||
|
|
||||||
VComponent {
|
VComponent {
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
use crate::{properties::ComponentFunction, Component, VirtualDom};
|
use crate::{
|
||||||
|
properties::{ComponentFunction, RootProps},
|
||||||
|
VComponent, VirtualDom,
|
||||||
|
};
|
||||||
|
|
||||||
/// A boxed object that can be injected into a component's context.
|
/// A boxed object that can be injected into a component's context.
|
||||||
pub struct BoxedContext(Box<dyn ClonableAny>);
|
pub struct BoxedContext(Box<dyn ClonableAny>);
|
||||||
@@ -40,32 +43,38 @@ impl<T: Any + Clone> ClonableAny for T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The platform-independent part of the config needed to launch an application.
|
/// The platform-independent part of the config needed to launch an application.
|
||||||
pub struct CrossPlatformConfig<Props: Clone + 'static> {
|
pub struct CrossPlatformConfig {
|
||||||
/// The root component function.
|
/// The root component function.
|
||||||
pub component: Component<Props>,
|
component: VComponent,
|
||||||
/// The props for the root component.
|
|
||||||
pub props: Props,
|
|
||||||
/// The contexts to provide to the root component.
|
/// The contexts to provide to the root component.
|
||||||
pub root_contexts: Vec<BoxedContext>,
|
root_contexts: Vec<BoxedContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Props: Clone + 'static> CrossPlatformConfig<Props> {
|
impl CrossPlatformConfig {
|
||||||
/// Create a new cross-platform config.
|
/// Create a new cross-platform config.
|
||||||
pub fn new<M>(
|
pub fn new<Props: Clone + 'static, M: 'static>(
|
||||||
component: impl ComponentFunction<Props, M>,
|
component: impl ComponentFunction<Props, M>,
|
||||||
props: Props,
|
props: Props,
|
||||||
root_contexts: Vec<BoxedContext>,
|
root_contexts: Vec<BoxedContext>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
component: ComponentFunction::as_component(std::rc::Rc::new(component)),
|
component: VComponent::new(
|
||||||
props,
|
move |props: RootProps<Props>| component.rebuild(props.0),
|
||||||
|
RootProps(props),
|
||||||
|
"root",
|
||||||
|
),
|
||||||
root_contexts,
|
root_contexts,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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));
|
||||||
|
}
|
||||||
|
|
||||||
/// Build a virtual dom from the config.
|
/// Build a virtual dom from the config.
|
||||||
pub fn build_vdom(self) -> VirtualDom {
|
pub fn build_vdom(self) -> VirtualDom {
|
||||||
let mut vdom = VirtualDom::new_with_props(self.component, self.props);
|
let mut vdom = VirtualDom::new_with_component(self.component);
|
||||||
|
|
||||||
for context in self.root_contexts {
|
for context in self.root_contexts {
|
||||||
vdom.insert_boxed_root_context(context);
|
vdom.insert_boxed_root_context(context);
|
||||||
@@ -76,18 +85,18 @@ impl<Props: Clone + 'static> CrossPlatformConfig<Props> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A builder to launch a specific platform.
|
/// A builder to launch a specific platform.
|
||||||
pub trait PlatformBuilder<Props: Clone + 'static> {
|
pub trait PlatformBuilder {
|
||||||
/// The platform-specific config needed to launch an application.
|
/// The platform-specific config needed to launch an application.
|
||||||
type Config: Default;
|
type Config: Default;
|
||||||
|
|
||||||
/// Launch the app.
|
/// Launch the app.
|
||||||
fn launch(config: CrossPlatformConfig<Props>, platform_config: Self::Config);
|
fn launch(config: CrossPlatformConfig, platform_config: Self::Config);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Props: Clone + 'static> PlatformBuilder<Props> for () {
|
impl PlatformBuilder for () {
|
||||||
type Config = ();
|
type Config = ();
|
||||||
|
|
||||||
fn launch(_: CrossPlatformConfig<Props>, _: Self::Config) {
|
fn launch(_: CrossPlatformConfig, _: Self::Config) {
|
||||||
panic!("No platform is currently enabled. Please enable a platform feature for the dioxus crate.");
|
panic!("No platform is currently enabled. Please enable a platform feature for the dioxus crate.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::{any::TypeId, rc::Rc};
|
use std::any::TypeId;
|
||||||
|
|
||||||
use crate::innerlude::*;
|
use crate::innerlude::*;
|
||||||
|
|
||||||
@@ -45,6 +45,31 @@ impl Properties for () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Root properties never need to be memoized, so we can use a dummy implementation.
|
||||||
|
pub(crate) struct RootProps<P>(pub P);
|
||||||
|
|
||||||
|
impl<P> Clone for RootProps<P>
|
||||||
|
where
|
||||||
|
P: Clone,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self(self.0.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P> Properties for RootProps<P>
|
||||||
|
where
|
||||||
|
P: Clone + 'static,
|
||||||
|
{
|
||||||
|
type Builder = P;
|
||||||
|
fn builder() -> Self::Builder {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
fn memoize(&self, _other: &Self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We allow components to use the () generic parameter if they have no props. This impl enables the "build" method
|
// We allow components to use the () generic parameter if they have no props. This impl enables the "build" method
|
||||||
// that the macros use to anonymously complete prop construction.
|
// that the macros use to anonymously complete prop construction.
|
||||||
pub struct EmptyBuilder;
|
pub struct EmptyBuilder;
|
||||||
@@ -62,35 +87,35 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Any component that implements the `ComponentFn` trait can be used as a component.
|
/// Any component that implements the `ComponentFn` trait can be used as a component.
|
||||||
pub trait ComponentFunction<Props, Marker = ()>: 'static {
|
pub trait ComponentFunction<Props, Marker = ()>: Clone + 'static {
|
||||||
/// Get the type id of the component.
|
/// Get the type id of the component.
|
||||||
fn id(&self) -> TypeId {
|
fn id(&self) -> TypeId {
|
||||||
TypeId::of::<Self>()
|
TypeId::of::<Self>()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert the component to a function that takes props and returns an element.
|
/// Convert the component to a function that takes props and returns an element.
|
||||||
fn as_component(self: Rc<Self>) -> Component<Props>;
|
fn rebuild(&self, props: Props) -> Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Accept pre-formed component render functions as components
|
/// Accept pre-formed component render functions as components
|
||||||
impl<P: 'static> ComponentFunction<P> for Component<P> {
|
impl<P: 'static> ComponentFunction<P> for Component<P> {
|
||||||
fn as_component(self: Rc<Self>) -> Component<P> {
|
fn rebuild(&self, props: P) -> Element {
|
||||||
self.as_ref().clone()
|
(self)(props)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Accept any callbacks that take props
|
/// Accept any callbacks that take props
|
||||||
impl<F: Fn(P) -> Element + 'static, P> ComponentFunction<P> for F {
|
impl<F: Fn(P) -> Element + Clone + 'static, P> ComponentFunction<P> for F {
|
||||||
fn as_component(self: Rc<Self>) -> Component<P> {
|
fn rebuild(&self, props: P) -> Element {
|
||||||
self
|
self(props)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Accept any callbacks that take no props
|
/// Accept any callbacks that take no props
|
||||||
pub struct EmptyMarker;
|
pub struct EmptyMarker;
|
||||||
impl<F: Fn() -> Element + 'static> ComponentFunction<(), EmptyMarker> for F {
|
impl<F: Fn() -> Element + Clone + 'static> ComponentFunction<(), EmptyMarker> for F {
|
||||||
fn as_component(self: Rc<Self>) -> Rc<dyn Fn(()) -> Element> {
|
fn rebuild(&self, _: ()) -> Element {
|
||||||
Rc::new(move |_| self())
|
self()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
//! This module provides the primary mechanics to create a hook-based, concurrent VDOM for Rust.
|
//! This module provides the primary mechanics to create a hook-based, concurrent VDOM for Rust.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
any_props::new_any_props,
|
|
||||||
arena::ElementId,
|
arena::ElementId,
|
||||||
innerlude::{
|
innerlude::{
|
||||||
DirtyScope, ElementRef, ErrorBoundary, NoOpMutations, SchedulerMsg, ScopeState, VNodeMount,
|
DirtyScope, ElementRef, ErrorBoundary, NoOpMutations, SchedulerMsg, ScopeState, VNodeMount,
|
||||||
@@ -11,10 +10,10 @@ use crate::{
|
|||||||
},
|
},
|
||||||
nodes::RenderReturn,
|
nodes::RenderReturn,
|
||||||
nodes::{Template, TemplateId},
|
nodes::{Template, TemplateId},
|
||||||
properties::ComponentFunction,
|
properties::RootProps,
|
||||||
runtime::{Runtime, RuntimeGuard},
|
runtime::{Runtime, RuntimeGuard},
|
||||||
scopes::ScopeId,
|
scopes::ScopeId,
|
||||||
AttributeValue, BoxedContext, Element, Event, Mutations, Task,
|
AttributeValue, BoxedContext, ComponentFunction, Element, Event, Mutations, Task, VComponent,
|
||||||
};
|
};
|
||||||
use futures_util::{pin_mut, StreamExt};
|
use futures_util::{pin_mut, StreamExt};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
@@ -230,13 +229,6 @@ impl VirtualDom {
|
|||||||
Self::new_with_props(app, ())
|
Self::new_with_props(app, ())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new virtualdom and build it immediately
|
|
||||||
pub fn prebuilt(app: fn() -> Element) -> Self {
|
|
||||||
let mut dom = Self::new(app);
|
|
||||||
dom.rebuild_in_place();
|
|
||||||
dom
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new VirtualDom with the given properties for the root component.
|
/// Create a new VirtualDom with the given properties for the root component.
|
||||||
///
|
///
|
||||||
/// # Description
|
/// # Description
|
||||||
@@ -271,6 +263,53 @@ impl VirtualDom {
|
|||||||
root: impl ComponentFunction<P, M>,
|
root: impl ComponentFunction<P, M>,
|
||||||
root_props: P,
|
root_props: P,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let vcomponent = VComponent::new(
|
||||||
|
move |props: RootProps<P>| root.rebuild(props.0),
|
||||||
|
RootProps(root_props),
|
||||||
|
"root",
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::new_with_component(vcomponent)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new virtualdom and build it immediately
|
||||||
|
pub fn prebuilt(app: fn() -> Element) -> Self {
|
||||||
|
let mut dom = Self::new(app);
|
||||||
|
dom.rebuild_in_place();
|
||||||
|
dom
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new VirtualDom with the given properties for the root component.
|
||||||
|
///
|
||||||
|
/// # Description
|
||||||
|
///
|
||||||
|
/// Later, the props can be updated by calling "update" with a new set of props, causing a set of re-renders.
|
||||||
|
///
|
||||||
|
/// This is useful when a component tree can be driven by external state (IE SSR) but it would be too expensive
|
||||||
|
/// to toss out the entire tree.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```rust, ignore
|
||||||
|
/// #[derive(PartialEq, Props)]
|
||||||
|
/// struct SomeProps {
|
||||||
|
/// name: &'static str
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn Example(cx: SomeProps) -> Element {
|
||||||
|
/// rsx!{ div{ "hello {cx.name}" } })
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let dom = VirtualDom::new(Example);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Note: the VirtualDom is not progressed on creation. You must either "run_with_deadline" or use "rebuild" to progress it.
|
||||||
|
///
|
||||||
|
/// ```rust, ignore
|
||||||
|
/// 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 {
|
||||||
let (tx, rx) = futures_channel::mpsc::unbounded();
|
let (tx, rx) = futures_channel::mpsc::unbounded();
|
||||||
|
|
||||||
let mut dom = Self {
|
let mut dom = Self {
|
||||||
@@ -285,10 +324,7 @@ impl VirtualDom {
|
|||||||
suspended_scopes: Default::default(),
|
suspended_scopes: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let root = dom.new_scope(
|
let root = dom.new_scope(root.props, "app");
|
||||||
new_any_props(Rc::new(root).as_component(), |_, _| true, root_props, "app"),
|
|
||||||
"app",
|
|
||||||
);
|
|
||||||
|
|
||||||
// Unlike react, we provide a default error boundary that just renders the error as a string
|
// Unlike react, we provide a default error boundary that just renders the error as a string
|
||||||
root.context()
|
root.context()
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ use dioxus_html::{
|
|||||||
use std::{
|
use std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
marker::PhantomData,
|
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
@@ -29,10 +28,10 @@ use tao::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// The single top-level object that manages all the running windows, assets, shortcuts, etc
|
/// The single top-level object that manages all the running windows, assets, shortcuts, etc
|
||||||
pub(crate) struct App<Props: Clone + 'static> {
|
pub(crate) struct App {
|
||||||
// move the props into a cell so we can pop it out later to create the first window
|
// move the props into a cell so we can pop it out later to create the first window
|
||||||
// iOS panics if we create a window before the event loop is started, so we toss them into a cell
|
// iOS panics if we create a window before the event loop is started, so we toss them into a cell
|
||||||
pub(crate) dioxus_config: Cell<Option<CrossPlatformConfig<Props>>>,
|
pub(crate) dioxus_config: Cell<Option<CrossPlatformConfig>>,
|
||||||
pub(crate) cfg: Cell<Option<Config>>,
|
pub(crate) cfg: Cell<Option<Config>>,
|
||||||
|
|
||||||
// Stuff we need mutable access to
|
// Stuff we need mutable access to
|
||||||
@@ -59,10 +58,10 @@ pub struct SharedContext {
|
|||||||
pub(crate) target: EventLoopWindowTarget<UserWindowEvent>,
|
pub(crate) target: EventLoopWindowTarget<UserWindowEvent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Props: Clone + 'static> App<Props> {
|
impl App {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
cfg: Config,
|
cfg: Config,
|
||||||
dioxus_config: CrossPlatformConfig<Props>,
|
dioxus_config: CrossPlatformConfig,
|
||||||
) -> (EventLoop<UserWindowEvent>, Self) {
|
) -> (EventLoop<UserWindowEvent>, Self) {
|
||||||
let event_loop = EventLoopBuilder::<UserWindowEvent>::with_user_event().build();
|
let event_loop = EventLoopBuilder::<UserWindowEvent>::with_user_event().build();
|
||||||
|
|
||||||
|
|||||||
@@ -10,10 +10,7 @@ use tao::event::{Event, StartCause, WindowEvent};
|
|||||||
///
|
///
|
||||||
/// This will block the main thread, and *must* be spawned on the main thread. This function does not assume any runtime
|
/// This will block the main thread, and *must* be spawned on the main thread. This function does not assume any runtime
|
||||||
/// and is equivalent to calling launch_with_props with the tokio feature disabled.
|
/// and is equivalent to calling launch_with_props with the tokio feature disabled.
|
||||||
pub fn launch_with_props_blocking<Props: Clone + 'static>(
|
pub fn launch_with_props_blocking(dioxus_cfg: CrossPlatformConfig, desktop_config: Config) {
|
||||||
dioxus_cfg: CrossPlatformConfig<Props>,
|
|
||||||
desktop_config: Config,
|
|
||||||
) {
|
|
||||||
let (event_loop, mut app) = App::new(desktop_config, dioxus_cfg);
|
let (event_loop, mut app) = App::new(desktop_config, dioxus_cfg);
|
||||||
|
|
||||||
event_loop.run(move |window_event, _, control_flow| {
|
event_loop.run(move |window_event, _, control_flow| {
|
||||||
@@ -53,10 +50,10 @@ pub fn launch_with_props_blocking<Props: Clone + 'static>(
|
|||||||
/// The desktop renderer platform
|
/// The desktop renderer platform
|
||||||
pub struct DesktopPlatform;
|
pub struct DesktopPlatform;
|
||||||
|
|
||||||
impl<Props: Clone + 'static> PlatformBuilder<Props> for DesktopPlatform {
|
impl PlatformBuilder for DesktopPlatform {
|
||||||
type Config = Config;
|
type Config = Config;
|
||||||
|
|
||||||
fn launch(config: dioxus_core::CrossPlatformConfig<Props>, platform_config: Self::Config) {
|
fn launch(config: dioxus_core::CrossPlatformConfig, platform_config: Self::Config) {
|
||||||
#[cfg(feature = "tokio")]
|
#[cfg(feature = "tokio")]
|
||||||
tokio::runtime::Builder::new_multi_thread()
|
tokio::runtime::Builder::new_multi_thread()
|
||||||
.enable_all()
|
.enable_all()
|
||||||
|
|||||||
@@ -7,19 +7,17 @@ use dioxus_core::prelude::*;
|
|||||||
use dioxus_core::{BoxedContext, CrossPlatformConfig, PlatformBuilder};
|
use dioxus_core::{BoxedContext, CrossPlatformConfig, PlatformBuilder};
|
||||||
|
|
||||||
/// A builder for a fullstack app.
|
/// A builder for a fullstack app.
|
||||||
pub struct LaunchBuilder<Props: Clone + 'static, Platform: PlatformBuilder<Props> = CurrentPlatform>
|
pub struct LaunchBuilder<Platform: PlatformBuilder = CurrentPlatform> {
|
||||||
{
|
cross_platform_config: CrossPlatformConfig,
|
||||||
cross_platform_config: CrossPlatformConfig<Props>,
|
platform_config: Option<<Platform as PlatformBuilder>::Config>,
|
||||||
platform_config: Option<<Platform as PlatformBuilder<Props>>::Config>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default platform builder
|
// Default platform builder
|
||||||
impl<Props: Clone + 'static> LaunchBuilder<Props> {
|
impl LaunchBuilder {
|
||||||
/// Create a new builder for your application. This will create a launch configuration for the current platform based on the features enabled on the `dioxus` crate.
|
/// Create a new builder for your application. This will create a launch configuration for the current platform based on the features enabled on the `dioxus` crate.
|
||||||
pub fn new<M>(component: impl ComponentFunction<Props, M>) -> Self
|
pub fn new<Props: Clone + Default + 'static, M: 'static>(
|
||||||
where
|
component: impl ComponentFunction<Props, M>,
|
||||||
Props: Default,
|
) -> Self {
|
||||||
{
|
|
||||||
Self {
|
Self {
|
||||||
cross_platform_config: CrossPlatformConfig::new(
|
cross_platform_config: CrossPlatformConfig::new(
|
||||||
component,
|
component,
|
||||||
@@ -29,28 +27,29 @@ impl<Props: Clone + 'static> LaunchBuilder<Props> {
|
|||||||
platform_config: None,
|
platform_config: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new builder for your application with some root props. This will create a launch configuration for the current platform based on the features enabled on the `dioxus` crate.
|
||||||
|
pub fn new_with_props<Props: Clone + 'static, M: 'static>(
|
||||||
|
component: impl ComponentFunction<Props, M>,
|
||||||
|
props: Props,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
cross_platform_config: CrossPlatformConfig::new(component, props, Default::default()),
|
||||||
|
platform_config: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Props: Clone + 'static, Platform: PlatformBuilder<Props>> LaunchBuilder<Props, Platform> {
|
impl<Platform: PlatformBuilder> LaunchBuilder<Platform> {
|
||||||
/// Pass some props to your application.
|
|
||||||
pub fn props(mut self, props: Props) -> Self {
|
|
||||||
self.cross_platform_config.props = props;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inject state into the root component's context.
|
/// Inject state into the root component's context.
|
||||||
pub fn context(mut self, state: impl Any + Clone + 'static) -> Self {
|
pub fn context(mut self, state: impl Any + Clone + 'static) -> Self {
|
||||||
self.cross_platform_config
|
self.cross_platform_config
|
||||||
.root_contexts
|
.push_context(BoxedContext::new(state));
|
||||||
.push(BoxedContext::new(state));
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provide a platform-specific config to the builder.
|
/// Provide a platform-specific config to the builder.
|
||||||
pub fn cfg(
|
pub fn cfg(mut self, config: impl Into<Option<<Platform as PlatformBuilder>::Config>>) -> Self {
|
||||||
mut self,
|
|
||||||
config: impl Into<Option<<Platform as PlatformBuilder<Props>>::Config>>,
|
|
||||||
) -> Self {
|
|
||||||
if let Some(config) = config.into() {
|
if let Some(config) = config.into() {
|
||||||
self.platform_config = Some(config);
|
self.platform_config = Some(config);
|
||||||
}
|
}
|
||||||
@@ -68,7 +67,7 @@ impl<Props: Clone + 'static, Platform: PlatformBuilder<Props>> LaunchBuilder<Pro
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "web")]
|
#[cfg(feature = "web")]
|
||||||
impl<Props: Clone + 'static> LaunchBuilder<Props, dioxus_web::WebPlatform> {
|
impl LaunchBuilder<dioxus_web::WebPlatform> {
|
||||||
/// Launch your web application.
|
/// Launch your web application.
|
||||||
pub fn launch_web(self) {
|
pub fn launch_web(self) {
|
||||||
dioxus_web::WebPlatform::launch(
|
dioxus_web::WebPlatform::launch(
|
||||||
@@ -79,7 +78,7 @@ impl<Props: Clone + 'static> LaunchBuilder<Props, dioxus_web::WebPlatform> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "desktop")]
|
#[cfg(feature = "desktop")]
|
||||||
impl<Props: Clone + 'static> LaunchBuilder<Props, dioxus_desktop::DesktopPlatform> {
|
impl LaunchBuilder<dioxus_desktop::DesktopPlatform> {
|
||||||
/// Launch your desktop application.
|
/// Launch your desktop application.
|
||||||
pub fn launch_desktop(self) {
|
pub fn launch_desktop(self) {
|
||||||
dioxus_desktop::DesktopPlatform::launch(
|
dioxus_desktop::DesktopPlatform::launch(
|
||||||
@@ -97,7 +96,7 @@ type CurrentPlatform = dioxus_web::WebPlatform;
|
|||||||
type CurrentPlatform = ();
|
type CurrentPlatform = ();
|
||||||
|
|
||||||
/// Launch your application without any additional configuration. See [`LaunchBuilder`] for more options.
|
/// Launch your application without any additional configuration. See [`LaunchBuilder`] for more options.
|
||||||
pub fn launch<Props, Marker>(component: impl ComponentFunction<Props, Marker>)
|
pub fn launch<Props, Marker: 'static>(component: impl ComponentFunction<Props, Marker>)
|
||||||
where
|
where
|
||||||
Props: Default + Clone + 'static,
|
Props: Default + Clone + 'static,
|
||||||
{
|
{
|
||||||
@@ -106,7 +105,7 @@ where
|
|||||||
|
|
||||||
#[cfg(feature = "web")]
|
#[cfg(feature = "web")]
|
||||||
/// Launch your web application without any additional configuration. See [`LaunchBuilder`] for more options.
|
/// Launch your web application without any additional configuration. See [`LaunchBuilder`] for more options.
|
||||||
pub fn launch_web<Props, Marker>(component: impl ComponentFunction<Props, Marker>)
|
pub fn launch_web<Props, Marker: 'static>(component: impl ComponentFunction<Props, Marker>)
|
||||||
where
|
where
|
||||||
Props: Default + Clone + 'static,
|
Props: Default + Clone + 'static,
|
||||||
{
|
{
|
||||||
@@ -115,7 +114,7 @@ where
|
|||||||
|
|
||||||
#[cfg(feature = "desktop")]
|
#[cfg(feature = "desktop")]
|
||||||
/// Launch your desktop application without any additional configuration. See [`LaunchBuilder`] for more options.
|
/// Launch your desktop application without any additional configuration. See [`LaunchBuilder`] for more options.
|
||||||
pub fn launch_desktop<Props, Marker>(component: impl ComponentFunction<Props, Marker>)
|
pub fn launch_desktop<Props, Marker: 'static>(component: impl ComponentFunction<Props, Marker>)
|
||||||
where
|
where
|
||||||
Props: Default + Clone + 'static,
|
Props: Default + Clone + 'static,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -609,15 +609,13 @@ impl RouteEnum {
|
|||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
impl dioxus_core::ComponentFunction<#props> for #name {
|
impl dioxus_core::ComponentFunction<#props> for #name {
|
||||||
fn as_component(self: ::std::rc::Rc<Self>) -> Component<#props> {
|
fn rebuild(&self, props: #props) -> dioxus_core::Element {
|
||||||
::std::rc::Rc::new(move |props| {
|
let initial_route = self.clone();
|
||||||
let initial_route = self.as_ref().clone();
|
rsx! {
|
||||||
rsx! {
|
::dioxus_router::prelude::Router::<#name> {
|
||||||
::dioxus_router::prelude::Router::<#name> {
|
config: move || props.take().initial_route(initial_route)
|
||||||
config: move || props.take().initial_route(initial_route)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,10 +99,7 @@ mod rehydrate;
|
|||||||
/// wasm_bindgen_futures::spawn_local(app_fut);
|
/// wasm_bindgen_futures::spawn_local(app_fut);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn run_with_props<Props: Clone + 'static>(
|
pub async fn run_with_props(dioxus_config: CrossPlatformConfig, web_config: Config) {
|
||||||
dioxus_config: CrossPlatformConfig<Props>,
|
|
||||||
web_config: Config,
|
|
||||||
) {
|
|
||||||
tracing::info!("Starting up");
|
tracing::info!("Starting up");
|
||||||
|
|
||||||
let mut dom = dioxus_config.build_vdom();
|
let mut dom = dioxus_config.build_vdom();
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ use crate::Config;
|
|||||||
/// The web renderer platform
|
/// The web renderer platform
|
||||||
pub struct WebPlatform;
|
pub struct WebPlatform;
|
||||||
|
|
||||||
impl<Props: Clone + 'static> PlatformBuilder<Props> for WebPlatform {
|
impl PlatformBuilder for WebPlatform {
|
||||||
type Config = Config;
|
type Config = Config;
|
||||||
|
|
||||||
fn launch(config: CrossPlatformConfig<Props>, platform_config: Self::Config) {
|
fn launch(config: CrossPlatformConfig, platform_config: Self::Config) {
|
||||||
wasm_bindgen_futures::spawn_local(async move {
|
wasm_bindgen_futures::spawn_local(async move {
|
||||||
crate::run_with_props(config, platform_config).await;
|
crate::run_with_props(config, platform_config).await;
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in new issue
Block a user