From 86d1dba699170d6f448fdafaf2abf9e8ede03747 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 27 Mar 2024 14:08:05 -0500 Subject: [PATCH] Check type of launch config (#2125) * Check type of launch config * fix cargo check * compile when using an explicit platform with other platforms enabled * fix formatting * fix overlapping TryIntoConfig implementations * fix desktop headless tests --------- Co-authored-by: Jonathan Kelley --- examples/calculator.rs | 2 +- examples/custom_html.rs | 2 +- examples/suspense.rs | 8 +- packages/config-macro/src/lib.rs | 29 +++++-- packages/dioxus/src/launch.rs | 127 +++++++++++++++++++++++-------- 5 files changed, 125 insertions(+), 43 deletions(-) diff --git a/examples/calculator.rs b/examples/calculator.rs index f063151ec..f8064c199 100644 --- a/examples/calculator.rs +++ b/examples/calculator.rs @@ -13,7 +13,7 @@ use dioxus::html::input_data::keyboard_types::Key; use dioxus::prelude::*; fn main() { - LaunchBuilder::new() + LaunchBuilder::desktop() .with_cfg(desktop!({ use dioxus::desktop::{Config, LogicalSize, WindowBuilder}; Config::new().with_window( diff --git a/examples/custom_html.rs b/examples/custom_html.rs index dbaf31d94..dbbe334f0 100644 --- a/examples/custom_html.rs +++ b/examples/custom_html.rs @@ -4,7 +4,7 @@ use dioxus::prelude::*; fn main() { - LaunchBuilder::desktop() + LaunchBuilder::new() .with_cfg( dioxus::desktop::Config::new().with_custom_index( r#" diff --git a/examples/suspense.rs b/examples/suspense.rs index 7a26dd5b6..df3151f22 100644 --- a/examples/suspense.rs +++ b/examples/suspense.rs @@ -15,14 +15,14 @@ use dioxus::desktop::{Config, LogicalSize, WindowBuilder}; use dioxus::prelude::*; fn main() { - LaunchBuilder::desktop() - .with_cfg( + LaunchBuilder::new() + .with_cfg(desktop! { Config::new().with_window( WindowBuilder::new() .with_title("Doggo Fetcher") .with_inner_size(LogicalSize::new(600.0, 800.0)), - ), - ) + ) + }) .launch(app) } diff --git a/packages/config-macro/src/lib.rs b/packages/config-macro/src/lib.rs index 13a38dcf8..9cfb9946c 100644 --- a/packages/config-macro/src/lib.rs +++ b/packages/config-macro/src/lib.rs @@ -15,7 +15,7 @@ pub fn server_only(input: TokenStream) -> TokenStream { } } else { quote! { - || {} + {} } } .into() @@ -30,7 +30,7 @@ pub fn client(input: TokenStream) -> TokenStream { } } else { quote! { - || {} + {} } } .into() @@ -45,7 +45,7 @@ pub fn web(input: TokenStream) -> TokenStream { } } else { quote! { - || {} + {} } } .into() @@ -60,7 +60,22 @@ pub fn desktop(input: TokenStream) -> TokenStream { } } else { quote! { - || {} + {} + } + } + .into() +} + +#[proc_macro] +pub fn mobile(input: TokenStream) -> TokenStream { + if cfg!(feature = "mobile") { + let input = TokenStream2::from(input); + quote! { + #input + } + } else { + quote! { + {} } } .into() @@ -75,7 +90,7 @@ pub fn fullstack(input: TokenStream) -> TokenStream { } } else { quote! { - || {} + {} } } .into() @@ -90,7 +105,7 @@ pub fn ssr(input: TokenStream) -> TokenStream { } } else { quote! { - || {} + {} } } .into() @@ -105,7 +120,7 @@ pub fn liveview(input: TokenStream) -> TokenStream { } } else { quote! { - || {} + {} } } .into() diff --git a/packages/dioxus/src/launch.rs b/packages/dioxus/src/launch.rs index dfd199bdd..44231862e 100644 --- a/packages/dioxus/src/launch.rs +++ b/packages/dioxus/src/launch.rs @@ -1,6 +1,7 @@ //! Launch helper macros for fullstack apps #![allow(clippy::new_without_default)] #![allow(unused)] +use dioxus_config_macro::*; use std::any::Any; use crate::prelude::*; @@ -11,7 +12,7 @@ pub struct LaunchBuilder { launch_fn: LaunchFn, contexts: Vec>, - platform_config: Option>, + platform_config: Option, } pub type LaunchFn = fn(fn() -> Element, Vec>, Cfg); @@ -126,52 +127,118 @@ impl LaunchBuilder { } } +/// A trait for converting a type into a platform-specific config: +/// - A unit value will be converted into `None` +/// - Any config will be converted into `Some(config)` +/// - If the config is for another platform, it will be converted into `None` +pub trait TryIntoConfig { + fn into_config(self) -> Option; +} + +// A config can always be converted into itself +impl TryIntoConfig for Cfg { + fn into_config(self) -> Option { + Some(self) + } +} + +// The unit type can be converted into the current platform config. +// This makes it possible to use the `desktop!`, `web!`, etc macros with the launch API. +#[cfg(any( + feature = "liveview", + feature = "desktop", + feature = "mobile", + feature = "web", + feature = "fullstack" +))] +impl TryIntoConfig for () { + fn into_config(self) -> Option { + None + } +} + impl LaunchBuilder { /// Provide a platform-specific config to the builder. - pub fn with_cfg(mut self, config: impl Into>) -> Self { - if let Some(config) = config.into() { - self.platform_config = Some(Box::new(config)); - } + pub fn with_cfg(mut self, config: impl TryIntoConfig) -> Self { + self.platform_config = self.platform_config.or(config.into_config()); self } /// Launch your application. pub fn launch(self, app: fn() -> Element) { - let cfg: Box = self - .platform_config - .and_then(|c| c.downcast().ok()) - .unwrap_or_default(); + let cfg = self.platform_config.unwrap_or_default(); - (self.launch_fn)(app, self.contexts, *cfg) + (self.launch_fn)(app, self.contexts, cfg) } } +/// Re-export the platform we expect the user wants +/// +/// If multiple platforms are enabled, we use this priority (from highest to lowest): +/// - `fullstack` +/// - `desktop` +/// - `mobile` +/// - `web` +/// - `liveview` mod current_platform { - #[cfg(all(feature = "desktop", not(feature = "fullstack")))] - pub use dioxus_desktop::launch::*; + macro_rules! if_else_cfg { + (if $attr:meta { $then:item } else { $else:item }) => { + #[cfg($attr)] + $then + #[cfg(not($attr))] + $else + }; + } + use crate::prelude::TryIntoConfig; - #[cfg(all(feature = "mobile", not(feature = "fullstack")))] - pub use dioxus_mobile::launch::*; + #[cfg(any(feature = "desktop", feature = "mobile"))] + if_else_cfg! { + if not(feature = "fullstack") { + pub use dioxus_desktop::launch::*; + } else { + impl TryIntoConfig for ::dioxus_desktop::Config { + fn into_config(self) -> Option { + None + } + } + } + } #[cfg(feature = "fullstack")] pub use dioxus_fullstack::launch::*; - #[cfg(all( - feature = "web", - not(any(feature = "desktop", feature = "mobile", feature = "fullstack")) - ))] - pub use dioxus_web::launch::*; + #[cfg(feature = "web")] + if_else_cfg! { + if not(any(feature = "desktop", feature = "mobile", feature = "fullstack")) { + pub use dioxus_web::launch::*; + } else { + impl TryIntoConfig for ::dioxus_web::Config { + fn into_config(self) -> Option { + None + } + } + } + } - #[cfg(all( - feature = "liveview", - not(any( - feature = "web", - feature = "desktop", - feature = "mobile", - feature = "fullstack" - )) - ))] - pub use dioxus_liveview::launch::*; + #[cfg(feature = "liveview")] + if_else_cfg! { + if + not(any( + feature = "web", + feature = "desktop", + feature = "mobile", + feature = "fullstack" + )) + { + pub use dioxus_liveview::launch::*; + } else { + impl TryIntoConfig for ::dioxus_liveview::Config { + fn into_config(self) -> Option { + None + } + } + } + } #[cfg(not(any( feature = "liveview", @@ -210,7 +277,7 @@ pub fn launch(app: fn() -> Element) { #[cfg_attr(docsrs, doc(cfg(feature = "web")))] /// Launch your web application without any additional configuration. See [`LaunchBuilder`] for more options. pub fn launch_web(app: fn() -> Element) { - LaunchBuilder::web().launch(app) + LaunchBuilder::new().launch(app) } #[cfg(feature = "desktop")]