Skip to content

Commit

Permalink
feat(core): improve and cleanup the Error enum (#3748)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasfernog committed Mar 22, 2022
1 parent 1099a96 commit da1e879
Show file tree
Hide file tree
Showing 15 changed files with 63 additions and 33 deletions.
5 changes: 5 additions & 0 deletions .changes/error-send-sync.md
@@ -0,0 +1,5 @@
---
"tauri": patch
---

The `Error` enum is now `Send + Sync`.
5 changes: 5 additions & 0 deletions .changes/runtime-error-sync.md
@@ -0,0 +1,5 @@
---
"tauri-runtime": patch
---

Force `Error` boxed errors to be `Sync`.
5 changes: 5 additions & 0 deletions .changes/simplify-setup-requirement-error.md
@@ -0,0 +1,5 @@
---
"tauri": patch
---

The `App::setup` closure can now return a boxed error directly.
2 changes: 1 addition & 1 deletion core/tauri-runtime-wry/src/lib.rs
Expand Up @@ -550,7 +550,7 @@ impl<T: UserEvent> ClipboardManager for ClipboardManagerWrapper<T> {
/// Wrapper around a [`wry::application::window::Icon`] that can be created from an [`WindowIcon`].
pub struct WryIcon(WryWindowIcon);

fn icon_err<E: std::error::Error + Send + 'static>(e: E) -> Error {
fn icon_err<E: std::error::Error + Send + Sync + 'static>(e: E) -> Error {
Error::InvalidIcon(Box::new(e))
}

Expand Down
8 changes: 4 additions & 4 deletions core/tauri-runtime/src/lib.rs
Expand Up @@ -98,7 +98,7 @@ pub enum UserAttentionType {
pub enum Error {
/// Failed to create webview.
#[error("failed to create webview: {0}")]
CreateWebview(Box<dyn std::error::Error + Send>),
CreateWebview(Box<dyn std::error::Error + Send + Sync>),
/// Failed to create window.
#[error("failed to create window")]
CreateWindow,
Expand All @@ -118,16 +118,16 @@ pub enum Error {
#[cfg(feature = "system-tray")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))]
#[error("error encountered during tray setup: {0}")]
SystemTray(Box<dyn std::error::Error + Send>),
SystemTray(Box<dyn std::error::Error + Send + Sync>),
/// Failed to load window icon.
#[error("invalid icon: {0}")]
InvalidIcon(Box<dyn std::error::Error + Send>),
InvalidIcon(Box<dyn std::error::Error + Send + Sync>),
/// Failed to get monitor on window operation.
#[error("failed to get monitor")]
FailedToGetMonitor,
/// Global shortcut error.
#[error(transparent)]
GlobalShortcut(Box<dyn std::error::Error + Send>),
GlobalShortcut(Box<dyn std::error::Error + Send + Sync>),
#[error("Invalid header name: {0}")]
InvalidHeaderName(#[from] InvalidHeaderName),
#[error("Invalid header value: {0}")]
Expand Down
2 changes: 1 addition & 1 deletion core/tauri/src/api/cli.rs
Expand Up @@ -90,7 +90,7 @@ impl Matches {
/// use tauri::api::cli::get_matches;
/// tauri::Builder::default()
/// .setup(|app| {
/// let matches = get_matches(app.config().tauri.cli.as_ref().unwrap(), app.package_info()).unwrap();
/// let matches = get_matches(app.config().tauri.cli.as_ref().unwrap(), app.package_info())?;
/// Ok(())
/// });
/// ```
Expand Down
2 changes: 1 addition & 1 deletion core/tauri/src/api/ipc.rs
Expand Up @@ -125,7 +125,7 @@ pub fn serialize_js_with<T: Serialize, F: FnOnce(&str) -> String>(
/// "console.log({}, {})",
/// serialize_js(&Foo { bar: "bar".to_string() }).unwrap(),
/// serialize_js(&Bar { baz: 0 }).unwrap()),
/// ).unwrap();
/// )?;
/// Ok(())
/// });
/// ```
Expand Down
4 changes: 2 additions & 2 deletions core/tauri/src/api/path.rs
Expand Up @@ -125,7 +125,7 @@ impl BaseDirectory {
/// use tauri::Manager;
/// tauri::Builder::default()
/// .setup(|app| {
/// let path = tauri::api::path::parse(&app.config(), app.package_info(), &app.env(), "$HOME/.bashrc").unwrap();
/// let path = tauri::api::path::parse(&app.config(), app.package_info(), &app.env(), "$HOME/.bashrc")?;
/// assert_eq!(path.to_str().unwrap(), "/home/${whoami}/.bashrc");
/// Ok(())
/// });
Expand Down Expand Up @@ -202,7 +202,7 @@ pub fn parse<P: AsRef<Path>>(
/// &app.env(),
/// "path/to/something",
/// Some(BaseDirectory::Config)
/// ).expect("failed to resolve path");
/// )?;
/// assert_eq!(path.to_str().unwrap(), "/home/${whoami}/.config/path/to/something");
/// Ok(())
/// });
Expand Down
2 changes: 1 addition & 1 deletion core/tauri/src/api/process.rs
Expand Up @@ -46,7 +46,7 @@ pub use command::*;
///
/// tauri::Builder::default()
/// .setup(|app| {
/// let current_binary_path = current_binary(&app.env()).unwrap();
/// let current_binary_path = current_binary(&app.env())?;
/// Ok(())
/// });
/// ```
Expand Down
2 changes: 1 addition & 1 deletion core/tauri/src/api/shell.rs
Expand Up @@ -101,7 +101,7 @@ impl Program {
/// tauri::Builder::default()
/// .setup(|app| {
/// // open the given URL on the system default browser
/// open(&app.shell_scope(), "https://github.com/tauri-apps/tauri", None).unwrap();
/// open(&app.shell_scope(), "https://github.com/tauri-apps/tauri", None)?;
/// Ok(())
/// });
/// ```
Expand Down
12 changes: 6 additions & 6 deletions core/tauri/src/app.rs
Expand Up @@ -775,7 +775,7 @@ impl<R: Runtime> Builder<R> {
#[must_use]
pub fn setup<F>(mut self, setup: F) -> Self
where
F: FnOnce(&mut App<R>) -> Result<(), Box<dyn std::error::Error + Send>> + Send + 'static,
F: FnOnce(&mut App<R>) -> Result<(), Box<dyn std::error::Error>> + Send + 'static,
{
self.setup = Box::new(setup);
self
Expand Down Expand Up @@ -1099,18 +1099,18 @@ impl<R: Runtime> Builder<R> {
use std::io::{Error, ErrorKind};
#[cfg(target_os = "linux")]
if let Some(TrayIcon::Raw(..)) = icon {
return Err(crate::Error::InvalidIcon(Box::new(Error::new(
return Err(crate::Error::InvalidIcon(Error::new(
ErrorKind::InvalidInput,
"system tray icons on linux must be a file path",
))));
)));
}

#[cfg(not(target_os = "linux"))]
if let Some(TrayIcon::File(_)) = icon {
return Err(crate::Error::InvalidIcon(Box::new(Error::new(
return Err(crate::Error::InvalidIcon(Error::new(
ErrorKind::InvalidInput,
"system tray icons on non-linux platforms must be the raw bytes",
))));
)));
}
}

Expand Down Expand Up @@ -1338,7 +1338,7 @@ impl<R: Runtime> Builder<R> {
let _window = app.manager.attach_window(app.handle(), detached);
}

(self.setup)(&mut app).map_err(|e| crate::Error::Setup(e))?;
(self.setup)(&mut app).map_err(|e| crate::Error::Setup(e.into()))?;

#[cfg(updater)]
app.run_updater();
Expand Down
5 changes: 2 additions & 3 deletions core/tauri/src/async_runtime.rs
Expand Up @@ -156,7 +156,7 @@ impl<T> Future for JoinHandle<T> {
type Output = crate::Result<T>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.get_mut() {
Self::Tokio(t) => t.poll(cx).map_err(|e| crate::Error::JoinError(Box::new(e))),
Self::Tokio(t) => t.poll(cx).map_err(Into::into),
}
}
}
Expand Down Expand Up @@ -334,8 +334,7 @@ mod tests {
5
});
join.abort();
if let crate::Error::JoinError(raw_box) = join.await.unwrap_err() {
let raw_error = raw_box.downcast::<tokio::task::JoinError>().unwrap();
if let crate::Error::JoinError(raw_error) = join.await.unwrap_err() {
assert!(raw_error.is_cancelled());
} else {
panic!("Abort did not result in the expected `JoinError`");
Expand Down
37 changes: 27 additions & 10 deletions core/tauri/src/error.rs
Expand Up @@ -2,7 +2,30 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use std::path::PathBuf;
use std::{fmt, path::PathBuf};

/// A generic boxed error.
#[derive(Debug)]
pub struct SetupError(Box<dyn std::error::Error>);

impl From<Box<dyn std::error::Error>> for SetupError {
fn from(error: Box<dyn std::error::Error>) -> Self {
Self(error)
}
}

// safety: the setup error is only used on the main thread
// and we exit the process immediately.
unsafe impl Send for SetupError {}
unsafe impl Sync for SetupError {}

impl fmt::Display for SetupError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}

impl std::error::Error for SetupError {}

/// Runtime errors that can happen inside a Tauri application.
#[derive(Debug, thiserror::Error)]
Expand All @@ -11,9 +34,6 @@ pub enum Error {
/// Runtime error.
#[error("runtime error: {0}")]
Runtime(#[from] tauri_runtime::Error),
/// Failed to create webview.
#[error("failed to create webview: {0}")]
CreateWebview(Box<dyn std::error::Error + Send>),
/// Failed to create window.
#[error("failed to create window")]
CreateWindow,
Expand Down Expand Up @@ -47,7 +67,7 @@ pub enum Error {
Base64Decode(#[from] base64::DecodeError),
/// Failed to load window icon.
#[error("invalid icon: {0}")]
InvalidIcon(Box<dyn std::error::Error + Send>),
InvalidIcon(std::io::Error),
/// Client with specified ID not found.
#[error("http client dropped or not initialized")]
HttpClientNotInitialized,
Expand All @@ -62,7 +82,7 @@ pub enum Error {
InvalidArgs(&'static str, &'static str, serde_json::Error),
/// Encountered an error in the setup hook,
#[error("error encountered during setup hook: {0}")]
Setup(Box<dyn std::error::Error + Send>),
Setup(SetupError),
/// Tauri updater error.
#[cfg(updater)]
#[cfg_attr(doc_cfg, doc(cfg(feature = "updater")))]
Expand All @@ -71,16 +91,13 @@ pub enum Error {
/// Error initializing plugin.
#[error("failed to initialize plugin `{0}`: {1}")]
PluginInitialization(String, String),
/// Encountered an error creating the app system tray,
#[error("error encountered during tray setup: {0}")]
SystemTray(Box<dyn std::error::Error + Send>),
/// A part of the URL is malformed or invalid. This may occur when parsing and combining
/// user-provided URLs and paths.
#[error("invalid url: {0}")]
InvalidUrl(url::ParseError),
/// Task join error.
#[error(transparent)]
JoinError(Box<dyn std::error::Error + Send>),
JoinError(#[from] tokio::task::JoinError),
/// Path not allowed by the scope.
#[error("path not allowed on the configured scope: {0}")]
PathNotAllowed(PathBuf),
Expand Down
2 changes: 1 addition & 1 deletion core/tauri/src/hooks.rs
Expand Up @@ -16,7 +16,7 @@ use tauri_macros::default_runtime;

/// A closure that is run when the Tauri application is setting up.
pub type SetupHook<R> =
Box<dyn FnOnce(&mut App<R>) -> Result<(), Box<dyn std::error::Error + Send>> + Send>;
Box<dyn FnOnce(&mut App<R>) -> Result<(), Box<dyn std::error::Error>> + Send>;

/// A closure that is run everytime Tauri receives a message it doesn't explicitly handle.
pub type InvokeHandler<R> = dyn Fn(Invoke<R>) + Send + Sync + 'static;
Expand Down
3 changes: 1 addition & 2 deletions core/tauri/src/window.rs
Expand Up @@ -199,8 +199,7 @@ impl<R: Runtime> WindowBuilder<R> {
/// }
/// }
/// })
/// .build()
/// .unwrap();
/// .build()?;
/// Ok(())
/// });
/// ```
Expand Down

0 comments on commit da1e879

Please sign in to comment.