tauri_plugin_notifications/
error.rs

1// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
2// SPDX-License-Identifier: Apache-2.0
3// SPDX-License-Identifier: MIT
4
5use serde::{ser::Serializer, Serialize};
6
7pub type Result<T> = std::result::Result<T, Error>;
8
9/// Replica of the tauri::plugin::mobile::ErrorResponse for desktop platforms.
10#[cfg(desktop)]
11#[derive(Debug, thiserror::Error, Clone, serde::Deserialize)]
12pub struct ErrorResponse<T = ()> {
13    /// Error code.
14    pub code: Option<String>,
15    /// Error message.
16    pub message: Option<String>,
17    /// Optional error data.
18    #[serde(flatten)]
19    pub data: T,
20}
21
22#[cfg(desktop)]
23impl<T> std::fmt::Display for ErrorResponse<T> {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        if let Some(code) = &self.code {
26            write!(f, "[{code}]")?;
27            if self.message.is_some() {
28                write!(f, " - ")?;
29            }
30        }
31        if let Some(message) = &self.message {
32            write!(f, "{message}")?;
33        }
34        Ok(())
35    }
36}
37
38/// Replica of the tauri::plugin::mobile::PluginInvokeError for desktop platforms.
39#[cfg(desktop)]
40#[derive(Debug, thiserror::Error)]
41pub enum PluginInvokeError {
42    /// Error returned from direct desktop plugin.
43    #[error(transparent)]
44    InvokeRejected(#[from] ErrorResponse),
45    /// Failed to deserialize response.
46    #[error("failed to deserialize response: {0}")]
47    CannotDeserializeResponse(serde_json::Error),
48    /// Failed to serialize request payload.
49    #[error("failed to serialize payload: {0}")]
50    CannotSerializePayload(serde_json::Error),
51}
52
53#[derive(Debug, thiserror::Error)]
54pub enum Error {
55    #[error(transparent)]
56    Io(#[from] std::io::Error),
57    #[cfg(mobile)]
58    #[error(transparent)]
59    PluginInvoke(#[from] tauri::plugin::mobile::PluginInvokeError),
60    #[cfg(desktop)]
61    #[error(transparent)]
62    PluginInvoke(#[from] crate::error::PluginInvokeError),
63}
64
65impl Serialize for Error {
66    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
67    where
68        S: Serializer,
69    {
70        serializer.serialize_str(self.to_string().as_ref())
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77    use std::io;
78
79    #[test]
80    fn test_io_error_conversion() {
81        let io_err = io::Error::new(io::ErrorKind::NotFound, "file not found");
82        let err: Error = io_err.into();
83        assert!(matches!(err, Error::Io(_)));
84    }
85
86    #[test]
87    fn test_io_error_serialization() {
88        let io_err = io::Error::new(io::ErrorKind::PermissionDenied, "access denied");
89        let err = Error::Io(io_err);
90        let json = serde_json::to_string(&err).expect("Failed to serialize IO error");
91        assert!(json.contains("access denied"));
92    }
93
94    #[test]
95    fn test_io_error_display() {
96        let io_err = io::Error::new(io::ErrorKind::NotFound, "test error");
97        let err = Error::Io(io_err);
98        let display_str = format!("{}", err);
99        assert!(display_str.contains("test error"));
100    }
101
102    #[cfg(mobile)]
103    #[test]
104    fn test_plugin_invoke_error_conversion() {
105        use tauri::plugin::mobile::PluginInvokeError;
106
107        let plugin_err = PluginInvokeError::MethodNotFound("test_method".to_string());
108        let err: Error = plugin_err.into();
109        assert!(matches!(err, Error::PluginInvoke(_)));
110    }
111
112    #[test]
113    fn test_result_type_err() {
114        let io_err = io::Error::other("test");
115        let result: Result<i32> = Err(Error::Io(io_err));
116        assert!(result.is_err());
117    }
118}