use std::any::Any; use crate::{properties::ComponentFunction, Component, VirtualDom}; /// A boxed object that can be injected into a component's context. pub struct BoxedContext(Box); impl BoxedContext { /// Create a new boxed context. pub fn new(value: impl Any + Clone + 'static) -> Self { Self(Box::new(value)) } /// Unwrap the boxed context into its inner value. pub fn into_inner(self) -> Box { self.0.into_inner() } } impl Clone for BoxedContext { fn clone(&self) -> Self { Self(self.0.clone_box()) } } trait ClonableAny: Any { fn clone_box(&self) -> Box; fn into_inner(self: Box) -> Box; } impl ClonableAny for T { fn clone_box(&self) -> Box { Box::new(self.clone()) } fn into_inner(self: Box) -> Box { self } } /// The platform-independent part of the config needed to launch an application. pub struct CrossPlatformConfig { /// The root component function. pub component: Component, /// The props for the root component. pub props: Props, /// The contexts to provide to the root component. pub root_contexts: Vec, } impl CrossPlatformConfig { /// Create a new cross-platform config. pub fn new( component: impl ComponentFunction, props: Props, root_contexts: Vec, ) -> Self { Self { component: ComponentFunction::as_component(std::rc::Rc::new(component)), props, root_contexts, } } /// Build a virtual dom from the config. pub fn build_vdom(self) -> VirtualDom { let mut vdom = VirtualDom::new_with_props(self.component, self.props); for context in self.root_contexts { vdom.insert_boxed_root_context(context); } vdom } } /// A builder to launch a specific platform. pub trait PlatformBuilder { /// The platform-specific config needed to launch an application. type Config: Default; /// Launch the app. fn launch(config: CrossPlatformConfig, platform_config: Self::Config); } impl PlatformBuilder for () { type Config = (); fn launch(_: CrossPlatformConfig, _: Self::Config) { panic!("No platform is currently enabled. Please enable a platform feature for the dioxus crate."); } }