launch.rs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. //! Launch helper macros for fullstack apps
  2. #![allow(clippy::new_without_default)]
  3. #![allow(unused)]
  4. use std::any::Any;
  5. use crate::prelude::*;
  6. /// A builder for a fullstack app.
  7. #[must_use]
  8. pub struct LaunchBuilder<Cfg: 'static = (), ContextFn: ?Sized = ValidContext> {
  9. launch_fn: LaunchFn<Cfg, ContextFn>,
  10. contexts: Vec<Box<ContextFn>>,
  11. platform_config: Option<Box<dyn Any>>,
  12. }
  13. pub type LaunchFn<Cfg, Context> = fn(fn() -> Element, Vec<Box<Context>>, Cfg);
  14. #[cfg(any(feature = "fullstack", feature = "liveview"))]
  15. type ValidContext = SendContext;
  16. #[cfg(not(any(feature = "fullstack", feature = "liveview")))]
  17. type ValidContext = UnsendContext;
  18. type SendContext = dyn Fn() -> Box<dyn Any> + Send + Sync + 'static;
  19. type UnsendContext = dyn Fn() -> Box<dyn Any> + 'static;
  20. impl LaunchBuilder {
  21. /// 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.
  22. pub fn new() -> LaunchBuilder<current_platform::Config, ValidContext> {
  23. LaunchBuilder {
  24. launch_fn: current_platform::launch,
  25. contexts: Vec::new(),
  26. platform_config: None,
  27. }
  28. }
  29. /// Launch your web application.
  30. #[cfg(feature = "web")]
  31. #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "web")))]
  32. pub fn web() -> LaunchBuilder<dioxus_web::Config, UnsendContext> {
  33. LaunchBuilder {
  34. launch_fn: dioxus_web::launch::launch,
  35. contexts: Vec::new(),
  36. platform_config: None,
  37. }
  38. }
  39. /// Launch your desktop application.
  40. #[cfg(feature = "desktop")]
  41. #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "desktop")))]
  42. pub fn desktop() -> LaunchBuilder<dioxus_desktop::Config, UnsendContext> {
  43. LaunchBuilder {
  44. launch_fn: dioxus_desktop::launch::launch,
  45. contexts: Vec::new(),
  46. platform_config: None,
  47. }
  48. }
  49. /// Launch your fullstack application.
  50. #[cfg(feature = "fullstack")]
  51. #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "fullstack")))]
  52. pub fn fullstack() -> LaunchBuilder<dioxus_fullstack::Config, SendContext> {
  53. LaunchBuilder {
  54. launch_fn: dioxus_fullstack::launch::launch,
  55. contexts: Vec::new(),
  56. platform_config: None,
  57. }
  58. }
  59. /// Launch your fullstack application.
  60. #[cfg(feature = "mobile")]
  61. #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "mobile")))]
  62. pub fn mobile() -> LaunchBuilder<dioxus_mobile::Config, UnsendContext> {
  63. LaunchBuilder {
  64. launch_fn: dioxus_mobile::launch::launch,
  65. contexts: Vec::new(),
  66. platform_config: None,
  67. }
  68. }
  69. #[cfg(feature = "tui")]
  70. #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "tui")))]
  71. /// Launch your tui application
  72. pub fn tui() -> LaunchBuilder<dioxus_tui::Config, UnsendContext> {
  73. LaunchBuilder {
  74. launch_fn: dioxus_tui::launch::launch,
  75. contexts: Vec::new(),
  76. platform_config: None,
  77. }
  78. }
  79. /// Provide a custom launch function for your application.
  80. ///
  81. /// Useful for third party renderers to tap into the launch builder API without having to reimplement it.
  82. pub fn custom<Cfg, List>(launch_fn: LaunchFn<Cfg, List>) -> LaunchBuilder<Cfg, List> {
  83. LaunchBuilder {
  84. launch_fn,
  85. contexts: vec![],
  86. platform_config: None,
  87. }
  88. }
  89. }
  90. // Fullstack platform builder
  91. impl<Cfg> LaunchBuilder<Cfg, UnsendContext> {
  92. /// Inject state into the root component's context that is created on the thread that the app is launched on.
  93. pub fn with_context_provider(mut self, state: impl Fn() -> Box<dyn Any> + 'static) -> Self {
  94. self.contexts.push(Box::new(state) as Box<UnsendContext>);
  95. self
  96. }
  97. /// Inject state into the root component's context.
  98. pub fn with_context(mut self, state: impl Any + Clone + 'static) -> Self {
  99. self.contexts
  100. .push(Box::new(move || Box::new(state.clone())));
  101. self
  102. }
  103. }
  104. impl<Cfg> LaunchBuilder<Cfg, SendContext> {
  105. /// Inject state into the root component's context that is created on the thread that the app is launched on.
  106. pub fn with_context_provider(
  107. mut self,
  108. state: impl Fn() -> Box<dyn Any> + Send + Sync + 'static,
  109. ) -> Self {
  110. self.contexts.push(Box::new(state) as Box<SendContext>);
  111. self
  112. }
  113. /// Inject state into the root component's context.
  114. pub fn with_context(mut self, state: impl Any + Clone + Send + Sync + 'static) -> Self {
  115. self.contexts
  116. .push(Box::new(move || Box::new(state.clone())));
  117. self
  118. }
  119. }
  120. impl<Cfg: Default + 'static, ContextFn: ?Sized> LaunchBuilder<Cfg, ContextFn> {
  121. /// Provide a platform-specific config to the builder.
  122. pub fn with_cfg<CG: 'static>(mut self, config: impl Into<Option<CG>>) -> Self {
  123. if let Some(config) = config.into() {
  124. self.platform_config = Some(Box::new(config));
  125. }
  126. self
  127. }
  128. /// Launch your application.
  129. pub fn launch(self, app: fn() -> Element) {
  130. let cfg: Box<Cfg> = self
  131. .platform_config
  132. .and_then(|c| c.downcast().ok())
  133. .unwrap_or_default();
  134. (self.launch_fn)(app, self.contexts, *cfg)
  135. }
  136. }
  137. mod current_platform {
  138. #[cfg(all(feature = "desktop", not(feature = "fullstack")))]
  139. pub use dioxus_desktop::launch::*;
  140. #[cfg(all(feature = "mobile", not(feature = "fullstack")))]
  141. pub use dioxus_desktop::launch::*;
  142. #[cfg(feature = "fullstack")]
  143. pub use dioxus_fullstack::launch::*;
  144. #[cfg(all(
  145. feature = "web",
  146. not(any(feature = "desktop", feature = "mobile", feature = "fullstack"))
  147. ))]
  148. pub use dioxus_web::launch::*;
  149. #[cfg(all(
  150. feature = "liveview",
  151. not(any(
  152. feature = "web",
  153. feature = "desktop",
  154. feature = "mobile",
  155. feature = "fullstack"
  156. ))
  157. ))]
  158. pub use dioxus_liveview::launch::*;
  159. #[cfg(all(
  160. feature = "tui",
  161. not(any(
  162. feature = "liveview",
  163. feature = "web",
  164. feature = "desktop",
  165. feature = "mobile",
  166. feature = "fullstack"
  167. ))
  168. ))]
  169. pub use dioxus_tui::launch::*;
  170. #[cfg(not(any(
  171. feature = "liveview",
  172. feature = "desktop",
  173. feature = "mobile",
  174. feature = "web",
  175. feature = "tui",
  176. feature = "fullstack"
  177. )))]
  178. pub type Config = ();
  179. #[cfg(not(any(
  180. feature = "liveview",
  181. feature = "desktop",
  182. feature = "mobile",
  183. feature = "web",
  184. feature = "tui",
  185. feature = "fullstack"
  186. )))]
  187. pub fn launch(
  188. root: fn() -> dioxus_core::Element,
  189. contexts: Vec<Box<super::ValidContext>>,
  190. platform_config: (),
  191. ) {
  192. #[cfg(feature = "third-party-renderer")]
  193. panic!("No first party renderer feature enabled. It looks like you are trying to use a third party renderer. You will need to use the launch function from the third party renderer crate.");
  194. panic!("No platform feature enabled. Please enable one of the following features: liveview, desktop, mobile, web, tui, fullstack to use the launch API.");
  195. }
  196. }
  197. /// Launch your application without any additional configuration. See [`LaunchBuilder`] for more options.
  198. pub fn launch(app: fn() -> Element) {
  199. LaunchBuilder::new().launch(app)
  200. }
  201. #[cfg(feature = "web")]
  202. #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "web")))]
  203. /// Launch your web application without any additional configuration. See [`LaunchBuilder`] for more options.
  204. pub fn launch_web(app: fn() -> Element) {
  205. LaunchBuilder::web().launch(app)
  206. }
  207. #[cfg(feature = "desktop")]
  208. #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "desktop")))]
  209. /// Launch your desktop application without any additional configuration. See [`LaunchBuilder`] for more options.
  210. pub fn launch_desktop(app: fn() -> Element) {
  211. LaunchBuilder::desktop().launch(app)
  212. }
  213. #[cfg(feature = "fullstack")]
  214. #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "fullstack")))]
  215. /// Launch your fullstack application without any additional configuration. See [`LaunchBuilder`] for more options.
  216. pub fn launch_fullstack(app: fn() -> Element) {
  217. LaunchBuilder::fullstack().launch(app)
  218. }
  219. #[cfg(feature = "tui")]
  220. #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "tui")))]
  221. /// Launch your tui application without any additional configuration. See [`LaunchBuilder`] for more options.
  222. pub fn launch_tui(app: fn() -> Element) {
  223. LaunchBuilder::tui().launch(app)
  224. }