1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
use zbus::DBusError;

use crate::desktop::{dynamic_launcher::UnexpectedIconError, request::ResponseError};

/// An error type that describes the various DBus errors.
///
/// See <https://github.com/flatpak/xdg-desktop-portal/blob/master/src/xdp-utils.h#L119-L127>.
#[allow(missing_docs)]
#[derive(DBusError, Debug)]
#[zbus(prefix = "org.freedesktop.portal.Error")]
pub enum PortalError {
    #[zbus(error)]
    /// ZBus specific error.
    ZBus(zbus::Error),
    /// Request failed.
    Failed(String),
    /// Invalid arguments passed.
    InvalidArgument(String),
    /// Not found.
    NotFound(String),
    /// Exists already.
    Exist(String),
    /// Method not allowed to be called.
    NotAllowed(String),
    /// Request cancelled.
    Cancelled(String),
    /// Window destroyed.
    WindowDestroyed(String),
}

#[derive(Debug)]
#[non_exhaustive]
/// The error type for ashpd.
pub enum Error {
    /// The portal request didn't succeed.
    Response(ResponseError),
    /// Something Failed on the portal request.
    Portal(PortalError),
    /// A zbus::fdo specific error.
    Zbus(zbus::Error),
    /// A signal returned no response.
    NoResponse,
    /// Failed to parse a string into an enum variant
    ParseError(&'static str),
    /// Input/Output
    IO(std::io::Error),
    /// A pipewire error
    #[cfg(feature = "pipewire")]
    Pipewire(pipewire::Error),
    /// Invalid AppId
    ///
    /// See <https://developer.gnome.org/documentation/tutorials/application-id.html#rules-for-application-ids>
    InvalidAppID,
    /// An error indicating that an interior nul byte was found
    NulTerminated(usize),
    /// Requires a newer interface version.
    ///
    /// The inner fields are the required version and the version advertised by
    /// the interface.
    RequiresVersion(u32, u32),
    /// An error indicating that a Icon::Bytes was expected but wrong type was
    /// passed
    UnexpectedIcon,
}

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

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Response(e) => f.write_str(&format!("Portal request didn't succeed: {e}")),
            Self::Zbus(e) => f.write_str(&format!("ZBus Error: {e}")),
            Self::Portal(e) => f.write_str(&format!("Portal request failed: {e}")),
            Self::NoResponse => f.write_str("Portal error: no response"),
            Self::IO(e) => f.write_str(&format!("IO: {e}")),
            #[cfg(feature = "pipewire")]
            Self::Pipewire(e) => f.write_str(&format!("Pipewire: {e}")),
            Self::ParseError(e) => f.write_str(e),
            Self::InvalidAppID => f.write_str("Invalid app id"),
            Self::NulTerminated(u) => write!(f, "Nul byte found in provided data at position {u}"),
            Self::RequiresVersion(required, current) => write!(
                f,
                "This interface requires version {required}, but {current} is available"
            ),
            Self::UnexpectedIcon => write!(
                f,
                "Expected icon of type Icon::Bytes but a different type was used."
            ),
        }
    }
}

impl From<ResponseError> for Error {
    fn from(e: ResponseError) -> Self {
        Self::Response(e)
    }
}

impl From<PortalError> for Error {
    fn from(e: PortalError) -> Self {
        Self::Portal(e)
    }
}

#[cfg(feature = "pipewire")]
impl From<pipewire::Error> for Error {
    fn from(e: pipewire::Error) -> Self {
        Self::Pipewire(e)
    }
}

impl From<zbus::fdo::Error> for Error {
    fn from(e: zbus::fdo::Error) -> Self {
        Self::Zbus(zbus::Error::FDO(Box::new(e)))
    }
}

impl From<zbus::Error> for Error {
    fn from(e: zbus::Error) -> Self {
        Self::Zbus(e)
    }
}

impl From<zbus::zvariant::Error> for Error {
    fn from(e: zbus::zvariant::Error) -> Self {
        Self::Zbus(zbus::Error::Variant(e))
    }
}

impl From<std::io::Error> for Error {
    fn from(e: std::io::Error) -> Self {
        Self::IO(e)
    }
}

impl From<UnexpectedIconError> for Error {
    fn from(_: UnexpectedIconError) -> Self {
        Self::UnexpectedIcon
    }
}