From 942fe4ab314323a66077fece4655c6e8e8c810a8 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Tue, 28 May 2024 21:59:19 +0200 Subject: [PATCH] Support returning errors when creating the app (#4565) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The closure passed to `eframe::run_native` now returns a `Result`, allowing you to return an error during app creation, which will be returned to the caller of `run_native`. This means you need to wrap your `Box::new(MyApp::new(…))` in an `Ok(…)`. * Closes https://github.com/emilk/egui/issues/4474 --- crates/eframe/src/epi.rs | 4 +++- crates/eframe/src/lib.rs | 13 +++++++++---- crates/eframe/src/native/glow_integration.rs | 2 +- crates/eframe/src/native/wgpu_integration.rs | 4 ++-- crates/eframe/src/web/app_runner.rs | 7 ++++--- crates/eframe/src/web/web_runner.rs | 2 +- crates/egui_demo_app/src/main.rs | 2 +- crates/egui_demo_app/src/web.rs | 2 +- examples/confirm_exit/src/main.rs | 2 +- examples/custom_3d_glow/src/main.rs | 2 +- examples/custom_font/src/main.rs | 2 +- examples/custom_font_style/src/main.rs | 2 +- examples/custom_keypad/src/main.rs | 2 +- examples/custom_plot_manipulation/src/main.rs | 2 +- examples/custom_window_frame/src/main.rs | 2 +- examples/file_dialog/src/main.rs | 2 +- examples/hello_world/src/main.rs | 2 +- examples/hello_world_par/src/main.rs | 2 +- examples/images/src/main.rs | 2 +- examples/keyboard_events/src/main.rs | 2 +- examples/multiple_viewports/src/main.rs | 2 +- examples/puffin_profiler/src/main.rs | 2 +- examples/save_plot/src/main.rs | 2 +- examples/screenshot/src/main.rs | 2 +- examples/serial_windows/src/main.rs | 6 +++--- examples/user_attention/src/main.rs | 2 +- tests/test_inline_glow_paint/src/main.rs | 2 +- tests/test_viewports/src/main.rs | 2 +- 28 files changed, 44 insertions(+), 36 deletions(-) diff --git a/crates/eframe/src/epi.rs b/crates/eframe/src/epi.rs index 7b75811ccbc6..b1a432dd978b 100644 --- a/crates/eframe/src/epi.rs +++ b/crates/eframe/src/epi.rs @@ -41,10 +41,12 @@ pub type EventLoopBuilderHook = Box) #[cfg(any(feature = "glow", feature = "wgpu"))] pub type WindowBuilderHook = Box egui::ViewportBuilder>; +type DynError = Box; + /// This is how your app is created. /// /// You can use the [`CreationContext`] to setup egui, restore state, setup OpenGL things, etc. -pub type AppCreator = Box) -> Box>; +pub type AppCreator = Box) -> Result, DynError>>; /// Data that is passed to [`AppCreator`] that can be used to setup and initialize your app. pub struct CreationContext<'s> { diff --git a/crates/eframe/src/lib.rs b/crates/eframe/src/lib.rs index e1df19a8b0bc..0fc1f26a1408 100644 --- a/crates/eframe/src/lib.rs +++ b/crates/eframe/src/lib.rs @@ -30,7 +30,7 @@ //! //! fn main() { //! let native_options = eframe::NativeOptions::default(); -//! eframe::run_native("My egui App", native_options, Box::new(|cc| Box::new(MyEguiApp::new(cc)))); +//! eframe::run_native("My egui App", native_options, Box::new(|cc| Ok(Box::new(MyEguiApp::new(cc))))); //! } //! //! #[derive(Default)] @@ -90,7 +90,7 @@ //! .start( //! canvas_id, //! eframe::WebOptions::default(), -//! Box::new(|cc| Box::new(MyEguiApp::new(cc))), +//! Box::new(|cc| Ok(Box::new(MyEguiApp::new(cc))),) //! ) //! .await //! } @@ -199,7 +199,7 @@ pub mod icon_data; /// /// fn main() -> eframe::Result<()> { /// let native_options = eframe::NativeOptions::default(); -/// eframe::run_native("MyApp", native_options, Box::new(|cc| Box::new(MyEguiApp::new(cc)))) +/// eframe::run_native("MyApp", native_options, Box::new(|cc| Ok(Box::new(MyEguiApp::new(cc))))) /// } /// /// #[derive(Default)] @@ -324,7 +324,7 @@ pub fn run_simple_native( run_native( app_name, native_options, - Box::new(|_cc| Box::new(SimpleApp { update_fun })), + Box::new(|_cc| Ok(Box::new(SimpleApp { update_fun }))), ) } @@ -333,6 +333,9 @@ pub fn run_simple_native( /// The different problems that can occur when trying to run `eframe`. #[derive(Debug)] pub enum Error { + /// Something went wrong in user code when creating the app. + AppCreation(Box), + /// An error from [`winit`]. #[cfg(not(target_arch = "wasm32"))] Winit(winit::error::OsError), @@ -403,6 +406,8 @@ impl From for Error { impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { + Self::AppCreation(err) => write!(f, "app creation error: {err}"), + #[cfg(not(target_arch = "wasm32"))] Self::Winit(err) => { write!(f, "winit error: {err}") diff --git a/crates/eframe/src/native/glow_integration.rs b/crates/eframe/src/native/glow_integration.rs index 28eb1a4ef24d..bfdee21d8d94 100644 --- a/crates/eframe/src/native/glow_integration.rs +++ b/crates/eframe/src/native/glow_integration.rs @@ -313,7 +313,7 @@ impl GlowWinitApp { raw_window_handle: window.window_handle().map(|h| h.as_raw()), }; crate::profile_scope!("app_creator"); - app_creator(&cc) + app_creator(&cc).map_err(crate::Error::AppCreation)? }; let glutin = Rc::new(RefCell::new(glutin)); diff --git a/crates/eframe/src/native/wgpu_integration.rs b/crates/eframe/src/native/wgpu_integration.rs index dbf4f4446902..28f149f0b3fd 100644 --- a/crates/eframe/src/native/wgpu_integration.rs +++ b/crates/eframe/src/native/wgpu_integration.rs @@ -182,7 +182,7 @@ impl WgpuWinitApp { storage: Option>, window: Window, builder: ViewportBuilder, - ) -> Result<&mut WgpuWinitRunning, egui_wgpu::WgpuError> { + ) -> crate::Result<&mut WgpuWinitRunning> { crate::profile_function!(); #[allow(unsafe_code, unused_mut, unused_unsafe)] @@ -272,7 +272,7 @@ impl WgpuWinitApp { }; let app = { crate::profile_scope!("user_app_creator"); - app_creator(&cc) + app_creator(&cc).map_err(crate::Error::AppCreation)? }; let mut viewport_from_window = HashMap::default(); diff --git a/crates/eframe/src/web/app_runner.rs b/crates/eframe/src/web/app_runner.rs index 872921591acd..75fee203417f 100644 --- a/crates/eframe/src/web/app_runner.rs +++ b/crates/eframe/src/web/app_runner.rs @@ -30,7 +30,7 @@ impl Drop for AppRunner { impl AppRunner { /// # Errors - /// Failure to initialize WebGL renderer. + /// Failure to initialize WebGL renderer, or failure to create app. pub async fn new( canvas_id: &str, web_options: crate::WebOptions, @@ -71,7 +71,7 @@ impl AppRunner { let theme = system_theme.unwrap_or(web_options.default_theme); egui_ctx.set_visuals(theme.egui_visuals()); - let app = app_creator(&epi::CreationContext { + let cc = epi::CreationContext { egui_ctx: egui_ctx.clone(), integration_info: info.clone(), storage: Some(&storage), @@ -86,7 +86,8 @@ impl AppRunner { wgpu_render_state: painter.render_state(), #[cfg(all(feature = "wgpu", feature = "glow"))] wgpu_render_state: None, - }); + }; + let app = app_creator(&cc).map_err(|err| err.to_string())?; let frame = epi::Frame { info, diff --git a/crates/eframe/src/web/web_runner.rs b/crates/eframe/src/web/web_runner.rs index 6a230a8e3292..e25d0da181b2 100644 --- a/crates/eframe/src/web/web_runner.rs +++ b/crates/eframe/src/web/web_runner.rs @@ -54,7 +54,7 @@ impl WebRunner { /// Create the application, install callbacks, and start running the app. /// /// # Errors - /// Failing to initialize graphics. + /// Failing to initialize graphics, or failure to create app. pub async fn start( &self, canvas_id: &str, diff --git a/crates/egui_demo_app/src/main.rs b/crates/egui_demo_app/src/main.rs index 9d660ed046cd..e30a73f22eae 100644 --- a/crates/egui_demo_app/src/main.rs +++ b/crates/egui_demo_app/src/main.rs @@ -48,7 +48,7 @@ fn main() -> Result<(), eframe::Error> { eframe::run_native( "egui demo app", options, - Box::new(|cc| Box::new(egui_demo_app::WrapApp::new(cc))), + Box::new(|cc| Ok(Box::new(egui_demo_app::WrapApp::new(cc)))), ) } diff --git a/crates/egui_demo_app/src/web.rs b/crates/egui_demo_app/src/web.rs index f4b9e5de15c5..ce06399b27f3 100644 --- a/crates/egui_demo_app/src/web.rs +++ b/crates/egui_demo_app/src/web.rs @@ -32,7 +32,7 @@ impl WebHandle { .start( canvas_id, eframe::WebOptions::default(), - Box::new(|cc| Box::new(WrapApp::new(cc))), + Box::new(|cc| Ok(Box::new(WrapApp::new(cc)))), ) .await } diff --git a/examples/confirm_exit/src/main.rs b/examples/confirm_exit/src/main.rs index 14816e1bdeab..1ec4a7e0f157 100644 --- a/examples/confirm_exit/src/main.rs +++ b/examples/confirm_exit/src/main.rs @@ -12,7 +12,7 @@ fn main() -> Result<(), eframe::Error> { eframe::run_native( "Confirm exit", options, - Box::new(|_cc| Box::::default()), + Box::new(|_cc| Ok(Box::::default())), ) } diff --git a/examples/custom_3d_glow/src/main.rs b/examples/custom_3d_glow/src/main.rs index 241124b7c174..c4b89103d3fd 100644 --- a/examples/custom_3d_glow/src/main.rs +++ b/examples/custom_3d_glow/src/main.rs @@ -19,7 +19,7 @@ fn main() -> Result<(), eframe::Error> { eframe::run_native( "Custom 3D painting in eframe using glow", options, - Box::new(|cc| Box::new(MyApp::new(cc))), + Box::new(|cc| Ok(Box::new(MyApp::new(cc)))), ) } diff --git a/examples/custom_font/src/main.rs b/examples/custom_font/src/main.rs index f42c5763150b..9687cb0215b4 100644 --- a/examples/custom_font/src/main.rs +++ b/examples/custom_font/src/main.rs @@ -12,7 +12,7 @@ fn main() -> Result<(), eframe::Error> { eframe::run_native( "egui example: custom font", options, - Box::new(|cc| Box::new(MyApp::new(cc))), + Box::new(|cc| Ok(Box::new(MyApp::new(cc)))), ) } diff --git a/examples/custom_font_style/src/main.rs b/examples/custom_font_style/src/main.rs index c1a61e3e69ca..11608bfc0120 100644 --- a/examples/custom_font_style/src/main.rs +++ b/examples/custom_font_style/src/main.rs @@ -11,7 +11,7 @@ fn main() -> Result<(), eframe::Error> { eframe::run_native( "egui example: global font style", options, - Box::new(|cc| Box::new(MyApp::new(cc))), + Box::new(|cc| Ok(Box::new(MyApp::new(cc)))), ) } diff --git a/examples/custom_keypad/src/main.rs b/examples/custom_keypad/src/main.rs index 654de25fa44c..d72d520a1104 100644 --- a/examples/custom_keypad/src/main.rs +++ b/examples/custom_keypad/src/main.rs @@ -20,7 +20,7 @@ fn main() -> Result<(), eframe::Error> { // This gives us image support: egui_extras::install_image_loaders(&cc.egui_ctx); - Box::::default() + Ok(Box::::default()) }), ) } diff --git a/examples/custom_plot_manipulation/src/main.rs b/examples/custom_plot_manipulation/src/main.rs index e423d890fcbb..1d4abca3a6bb 100644 --- a/examples/custom_plot_manipulation/src/main.rs +++ b/examples/custom_plot_manipulation/src/main.rs @@ -11,7 +11,7 @@ fn main() -> Result<(), eframe::Error> { eframe::run_native( "Plot", options, - Box::new(|_cc| Box::::default()), + Box::new(|_cc| Ok(Box::::default())), ) } diff --git a/examples/custom_window_frame/src/main.rs b/examples/custom_window_frame/src/main.rs index bb098652cbfe..bd29788ac1aa 100644 --- a/examples/custom_window_frame/src/main.rs +++ b/examples/custom_window_frame/src/main.rs @@ -19,7 +19,7 @@ fn main() -> Result<(), eframe::Error> { eframe::run_native( "Custom window frame", // unused title options, - Box::new(|_cc| Box::::default()), + Box::new(|_cc| Ok(Box::::default())), ) } diff --git a/examples/file_dialog/src/main.rs b/examples/file_dialog/src/main.rs index 267c22e111ce..840a72fb5c75 100644 --- a/examples/file_dialog/src/main.rs +++ b/examples/file_dialog/src/main.rs @@ -14,7 +14,7 @@ fn main() -> Result<(), eframe::Error> { eframe::run_native( "Native file dialogs and drag-and-drop files", options, - Box::new(|_cc| Box::::default()), + Box::new(|_cc| Ok(Box::::default())), ) } diff --git a/examples/hello_world/src/main.rs b/examples/hello_world/src/main.rs index 1c74f4c49928..2780d0ce56ed 100644 --- a/examples/hello_world/src/main.rs +++ b/examples/hello_world/src/main.rs @@ -16,7 +16,7 @@ fn main() -> Result<(), eframe::Error> { // This gives us image support: egui_extras::install_image_loaders(&cc.egui_ctx); - Box::::default() + Ok(Box::::default()) }), ) } diff --git a/examples/hello_world_par/src/main.rs b/examples/hello_world_par/src/main.rs index 2896f24843fc..ecf7034c2e13 100644 --- a/examples/hello_world_par/src/main.rs +++ b/examples/hello_world_par/src/main.rs @@ -17,7 +17,7 @@ fn main() -> Result<(), eframe::Error> { eframe::run_native( "My parallel egui App", options, - Box::new(|_cc| Box::new(MyApp::new())), + Box::new(|_cc| Ok(Box::new(MyApp::new()))), ) } diff --git a/examples/images/src/main.rs b/examples/images/src/main.rs index 8a124e051a55..a1a15a17c47f 100644 --- a/examples/images/src/main.rs +++ b/examples/images/src/main.rs @@ -15,7 +15,7 @@ fn main() -> Result<(), eframe::Error> { Box::new(|cc| { // This gives us image support: egui_extras::install_image_loaders(&cc.egui_ctx); - Box::::default() + Ok(Box::::default()) }), ) } diff --git a/examples/keyboard_events/src/main.rs b/examples/keyboard_events/src/main.rs index bf0b3389981d..3c1223d671da 100644 --- a/examples/keyboard_events/src/main.rs +++ b/examples/keyboard_events/src/main.rs @@ -10,7 +10,7 @@ fn main() -> Result<(), eframe::Error> { eframe::run_native( "Keyboard events", options, - Box::new(|_cc| Box::::default()), + Box::new(|_cc| Ok(Box::::default())), ) } diff --git a/examples/multiple_viewports/src/main.rs b/examples/multiple_viewports/src/main.rs index 262002e2c5b7..0ed26e4e8a00 100644 --- a/examples/multiple_viewports/src/main.rs +++ b/examples/multiple_viewports/src/main.rs @@ -17,7 +17,7 @@ fn main() -> Result<(), eframe::Error> { eframe::run_native( "Multiple viewports", options, - Box::new(|_cc| Box::::default()), + Box::new(|_cc| Ok(Box::::default())), ) } diff --git a/examples/puffin_profiler/src/main.rs b/examples/puffin_profiler/src/main.rs index 8fe30d679fff..2987e93c5e8d 100644 --- a/examples/puffin_profiler/src/main.rs +++ b/examples/puffin_profiler/src/main.rs @@ -22,7 +22,7 @@ fn main() -> Result<(), eframe::Error> { ..Default::default() }, - Box::new(|_cc| Box::::default()), + Box::new(|_cc| Ok(Box::::default())), ) } diff --git a/examples/save_plot/src/main.rs b/examples/save_plot/src/main.rs index 61657faae861..fa24ec842953 100644 --- a/examples/save_plot/src/main.rs +++ b/examples/save_plot/src/main.rs @@ -14,7 +14,7 @@ fn main() -> Result<(), eframe::Error> { eframe::run_native( "My egui App with a plot", options, - Box::new(|_cc| Box::::default()), + Box::new(|_cc| Ok(Box::::default())), ) } diff --git a/examples/screenshot/src/main.rs b/examples/screenshot/src/main.rs index c0c627e86a79..24eccd2d27cb 100644 --- a/examples/screenshot/src/main.rs +++ b/examples/screenshot/src/main.rs @@ -14,7 +14,7 @@ fn main() -> Result<(), eframe::Error> { eframe::run_native( "Take screenshots and display with eframe/egui", options, - Box::new(|_cc| Box::::default()), + Box::new(|_cc| Ok(Box::::default())), ) } diff --git a/examples/serial_windows/src/main.rs b/examples/serial_windows/src/main.rs index 04bed8006aed..9ea1f3ea8ef7 100644 --- a/examples/serial_windows/src/main.rs +++ b/examples/serial_windows/src/main.rs @@ -23,7 +23,7 @@ fn main() -> Result<(), eframe::Error> { eframe::run_native( "First Window", options.clone(), - Box::new(|_cc| Box::new(MyApp { has_next: true })), + Box::new(|_cc| Ok(Box::new(MyApp { has_next: true }))), )?; std::thread::sleep(std::time::Duration::from_secs(2)); @@ -32,7 +32,7 @@ fn main() -> Result<(), eframe::Error> { eframe::run_native( "Second Window", options.clone(), - Box::new(|_cc| Box::new(MyApp { has_next: true })), + Box::new(|_cc| Ok(Box::new(MyApp { has_next: true }))), )?; std::thread::sleep(std::time::Duration::from_secs(2)); @@ -41,7 +41,7 @@ fn main() -> Result<(), eframe::Error> { eframe::run_native( "Third Window", options, - Box::new(|_cc| Box::new(MyApp { has_next: false })), + Box::new(|_cc| Ok(Box::new(MyApp { has_next: false }))), ) } diff --git a/examples/user_attention/src/main.rs b/examples/user_attention/src/main.rs index cbe27b6d5bc1..15f0676cf0a9 100644 --- a/examples/user_attention/src/main.rs +++ b/examples/user_attention/src/main.rs @@ -15,7 +15,7 @@ fn main() -> eframe::Result<()> { eframe::run_native( "User attention test", native_options, - Box::new(|cc| Box::new(Application::new(cc))), + Box::new(|cc| Ok(Box::new(Application::new(cc)))), ) } diff --git a/tests/test_inline_glow_paint/src/main.rs b/tests/test_inline_glow_paint/src/main.rs index 7851ad63b8b3..12569652665c 100644 --- a/tests/test_inline_glow_paint/src/main.rs +++ b/tests/test_inline_glow_paint/src/main.rs @@ -16,7 +16,7 @@ fn main() -> Result<(), Box> { eframe::run_native( "My test app", options, - Box::new(|_cc| Box::::default()), + Box::new(|_cc| Ok(Box::::default())), )?; Ok(()) } diff --git a/tests/test_viewports/src/main.rs b/tests/test_viewports/src/main.rs index 8bbb1b22a070..6687e8c01563 100644 --- a/tests/test_viewports/src/main.rs +++ b/tests/test_viewports/src/main.rs @@ -22,7 +22,7 @@ fn main() { ..Default::default() }, - Box::new(|_| Box::::default()), + Box::new(|_cc| Ok(Box::::default())), ); }