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 <jkelleyrtp@gmail.com>
This commit is contained in:
Evan AlmloffandJonathan Kelley authored and GitHub committed 2024-03-27 12:08:05 -07:00
1 parent 44f3047780
commit 86d1dba699
5 files changed
+125 -43

No files matched your search

+1 -1
View File
@@ -13,7 +13,7 @@ use dioxus::html::input_data::keyboard_types::Key;
use dioxus::prelude::*; use dioxus::prelude::*;
fn main() { fn main() {
LaunchBuilder::new() LaunchBuilder::desktop()
.with_cfg(desktop!({ .with_cfg(desktop!({
use dioxus::desktop::{Config, LogicalSize, WindowBuilder}; use dioxus::desktop::{Config, LogicalSize, WindowBuilder};
Config::new().with_window( Config::new().with_window(
+1 -1
View File
@@ -4,7 +4,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
fn main() { fn main() {
LaunchBuilder::desktop() LaunchBuilder::new()
.with_cfg( .with_cfg(
dioxus::desktop::Config::new().with_custom_index( dioxus::desktop::Config::new().with_custom_index(
r#" r#"
+4 -4
View File
@@ -15,14 +15,14 @@ use dioxus::desktop::{Config, LogicalSize, WindowBuilder};
use dioxus::prelude::*; use dioxus::prelude::*;
fn main() { fn main() {
LaunchBuilder::desktop() LaunchBuilder::new()
.with_cfg( .with_cfg(desktop! {
Config::new().with_window( Config::new().with_window(
WindowBuilder::new() WindowBuilder::new()
.with_title("Doggo Fetcher") .with_title("Doggo Fetcher")
.with_inner_size(LogicalSize::new(600.0, 800.0)), .with_inner_size(LogicalSize::new(600.0, 800.0)),
), )
) })
.launch(app) .launch(app)
} }
+22 -7
View File
@@ -15,7 +15,7 @@ pub fn server_only(input: TokenStream) -> TokenStream {
} }
} else { } else {
quote! { quote! {
|| {} {}
} }
} }
.into() .into()
@@ -30,7 +30,7 @@ pub fn client(input: TokenStream) -> TokenStream {
} }
} else { } else {
quote! { quote! {
|| {} {}
} }
} }
.into() .into()
@@ -45,7 +45,7 @@ pub fn web(input: TokenStream) -> TokenStream {
} }
} else { } else {
quote! { quote! {
|| {} {}
} }
} }
.into() .into()
@@ -60,7 +60,22 @@ pub fn desktop(input: TokenStream) -> TokenStream {
} }
} else { } else {
quote! { quote! {
|| {} {}
}
}
.into()
}
#[proc_macro]
pub fn mobile(input: TokenStream) -> TokenStream {
if cfg!(feature = "mobile") {
let input = TokenStream2::from(input);
quote! {
#input
}
} else {
quote! {
{}
} }
} }
.into() .into()
@@ -75,7 +90,7 @@ pub fn fullstack(input: TokenStream) -> TokenStream {
} }
} else { } else {
quote! { quote! {
|| {} {}
} }
} }
.into() .into()
@@ -90,7 +105,7 @@ pub fn ssr(input: TokenStream) -> TokenStream {
} }
} else { } else {
quote! { quote! {
|| {} {}
} }
} }
.into() .into()
@@ -105,7 +120,7 @@ pub fn liveview(input: TokenStream) -> TokenStream {
} }
} else { } else {
quote! { quote! {
|| {} {}
} }
} }
.into() .into()
+97 -30
View File
@@ -1,6 +1,7 @@
//! Launch helper macros for fullstack apps //! Launch helper macros for fullstack apps
#![allow(clippy::new_without_default)] #![allow(clippy::new_without_default)]
#![allow(unused)] #![allow(unused)]
use dioxus_config_macro::*;
use std::any::Any; use std::any::Any;
use crate::prelude::*; use crate::prelude::*;
@@ -11,7 +12,7 @@ pub struct LaunchBuilder<Cfg: 'static = (), ContextFn: ?Sized = ValidContext> {
launch_fn: LaunchFn<Cfg, ContextFn>, launch_fn: LaunchFn<Cfg, ContextFn>,
contexts: Vec<Box<ContextFn>>, contexts: Vec<Box<ContextFn>>,
platform_config: Option<Box<dyn Any>>, platform_config: Option<Cfg>,
} }
pub type LaunchFn<Cfg, Context> = fn(fn() -> Element, Vec<Box<Context>>, Cfg); pub type LaunchFn<Cfg, Context> = fn(fn() -> Element, Vec<Box<Context>>, Cfg);
@@ -126,52 +127,118 @@ impl<Cfg> LaunchBuilder<Cfg, SendContext> {
} }
} }
/// 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<Config = Self> {
fn into_config(self) -> Option<Config>;
}
// A config can always be converted into itself
impl<Cfg> TryIntoConfig<Cfg> for Cfg {
fn into_config(self) -> Option<Cfg> {
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<current_platform::Config> for () {
fn into_config(self) -> Option<current_platform::Config> {
None
}
}
impl<Cfg: Default + 'static, ContextFn: ?Sized> LaunchBuilder<Cfg, ContextFn> { impl<Cfg: Default + 'static, ContextFn: ?Sized> LaunchBuilder<Cfg, ContextFn> {
/// Provide a platform-specific config to the builder. /// Provide a platform-specific config to the builder.
pub fn with_cfg<CG: 'static>(mut self, config: impl Into<Option<CG>>) -> Self { pub fn with_cfg(mut self, config: impl TryIntoConfig<Cfg>) -> Self {
if let Some(config) = config.into() { self.platform_config = self.platform_config.or(config.into_config());
self.platform_config = Some(Box::new(config));
}
self self
} }
/// Launch your application. /// Launch your application.
pub fn launch(self, app: fn() -> Element) { pub fn launch(self, app: fn() -> Element) {
let cfg: Box<Cfg> = self let cfg = self.platform_config.unwrap_or_default();
.platform_config
.and_then(|c| c.downcast().ok())
.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 { mod current_platform {
#[cfg(all(feature = "desktop", not(feature = "fullstack")))] macro_rules! if_else_cfg {
pub use dioxus_desktop::launch::*; (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")))] #[cfg(any(feature = "desktop", feature = "mobile"))]
pub use dioxus_mobile::launch::*; if_else_cfg! {
if not(feature = "fullstack") {
pub use dioxus_desktop::launch::*;
} else {
impl TryIntoConfig<crate::launch::current_platform::Config> for ::dioxus_desktop::Config {
fn into_config(self) -> Option<crate::launch::current_platform::Config> {
None
}
}
}
}
#[cfg(feature = "fullstack")] #[cfg(feature = "fullstack")]
pub use dioxus_fullstack::launch::*; pub use dioxus_fullstack::launch::*;
#[cfg(all( #[cfg(feature = "web")]
feature = "web", if_else_cfg! {
not(any(feature = "desktop", feature = "mobile", feature = "fullstack")) if not(any(feature = "desktop", feature = "mobile", feature = "fullstack")) {
))] pub use dioxus_web::launch::*;
pub use dioxus_web::launch::*; } else {
impl TryIntoConfig<crate::launch::current_platform::Config> for ::dioxus_web::Config {
fn into_config(self) -> Option<crate::launch::current_platform::Config> {
None
}
}
}
}
#[cfg(all( #[cfg(feature = "liveview")]
feature = "liveview", if_else_cfg! {
not(any( if
feature = "web", not(any(
feature = "desktop", feature = "web",
feature = "mobile", feature = "desktop",
feature = "fullstack" feature = "mobile",
)) feature = "fullstack"
))] ))
pub use dioxus_liveview::launch::*; {
pub use dioxus_liveview::launch::*;
} else {
impl<R: ::dioxus_liveview::LiveviewRouter> TryIntoConfig<crate::launch::current_platform::Config> for ::dioxus_liveview::Config<R> {
fn into_config(self) -> Option<crate::launch::current_platform::Config> {
None
}
}
}
}
#[cfg(not(any( #[cfg(not(any(
feature = "liveview", feature = "liveview",
@@ -210,7 +277,7 @@ pub fn launch(app: fn() -> Element) {
#[cfg_attr(docsrs, doc(cfg(feature = "web")))] #[cfg_attr(docsrs, doc(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(app: fn() -> Element) { pub fn launch_web(app: fn() -> Element) {
LaunchBuilder::web().launch(app) LaunchBuilder::new().launch(app)
} }
#[cfg(feature = "desktop")] #[cfg(feature = "desktop")]