1use std::any::Any;
2
3#[derive(zbus::DBusError, Debug, Clone)]
4#[zbus(prefix = "org.gnome.glycin.Error")]
5#[non_exhaustive]
6pub enum RemoteError {
10 #[zbus(error)]
11 ZBus(zbus::Error),
12 LoadingError(String),
13 InternalLoaderError(String),
14 EditingError(String),
15 InternalEditorError(String),
16 UnsupportedImageFormat(String),
17 ConversionTooLargerError,
18 OutOfMemory(String),
19 Aborted,
20 NoMoreFrames,
21}
22
23type Location = std::panic::Location<'static>;
24
25impl ProcessError {
26 pub fn into_loader_error(self) -> RemoteError {
27 match self {
28 err @ ProcessError::ExpectedError { .. } => RemoteError::LoadingError(err.to_string()),
29 err @ ProcessError::InternalError { .. } => {
30 RemoteError::InternalLoaderError(err.to_string())
31 }
32 ProcessError::UnsupportedImageFormat(msg) => RemoteError::UnsupportedImageFormat(msg),
33 ProcessError::ConversionTooLargerError => RemoteError::ConversionTooLargerError,
34 err @ ProcessError::OutOfMemory { .. } => RemoteError::OutOfMemory(err.to_string()),
35 ProcessError::NoMoreFrames => RemoteError::NoMoreFrames,
36 }
37 }
38
39 pub fn into_editor_error(self) -> RemoteError {
40 match self {
41 err @ ProcessError::ExpectedError { .. } => RemoteError::EditingError(err.to_string()),
42 err @ ProcessError::InternalError { .. } => {
43 RemoteError::InternalEditorError(err.to_string())
44 }
45 ProcessError::UnsupportedImageFormat(msg) => RemoteError::UnsupportedImageFormat(msg),
46 ProcessError::ConversionTooLargerError => RemoteError::ConversionTooLargerError,
47 err @ ProcessError::OutOfMemory { .. } => RemoteError::OutOfMemory(err.to_string()),
48 ProcessError::NoMoreFrames => RemoteError::NoMoreFrames,
49 }
50 }
51}
52
53#[derive(thiserror::Error, Debug)]
54#[non_exhaustive]
55pub enum ProcessError {
56 #[error("{location}: {err}")]
57 ExpectedError { err: String, location: Location },
58 #[error("{location}: Internal error: {err}")]
59 InternalError { err: String, location: Location },
60 #[error("Unsupported image format: {0}")]
61 UnsupportedImageFormat(String),
62 #[error("Dimension too large for system")]
63 ConversionTooLargerError,
64 #[error("{location}: Not enough memory available")]
65 OutOfMemory { location: Location },
66 #[error("No more frames available")]
67 NoMoreFrames,
68}
69
70impl ProcessError {
71 #[track_caller]
72 pub fn expected(err: &impl ToString) -> Self {
73 Self::ExpectedError {
74 err: err.to_string(),
75 location: *Location::caller(),
76 }
77 }
78
79 #[track_caller]
80 pub fn out_of_memory() -> Self {
81 Self::OutOfMemory {
82 location: *Location::caller(),
83 }
84 }
85}
86
87impl From<DimensionTooLargerError> for ProcessError {
88 fn from(err: DimensionTooLargerError) -> Self {
89 eprintln!("Decoding error: {err:?}");
90 Self::ConversionTooLargerError
91 }
92}
93
94pub trait GenericContexts<T> {
95 fn expected_error(self) -> Result<T, ProcessError>;
96 fn internal_error(self) -> Result<T, ProcessError>;
97}
98
99impl<T, E> GenericContexts<T> for Result<T, E>
100where
101 E: std::error::Error + Any,
102{
103 #[track_caller]
104 fn expected_error(self) -> Result<T, ProcessError> {
105 match self {
106 Ok(x) => Ok(x),
107 Err(err) => Err(
108 if let Some(err) = ((&err) as &dyn Any).downcast_ref::<ProcessError>() {
109 if matches!(err, ProcessError::OutOfMemory { .. }) {
110 ProcessError::out_of_memory()
111 } else {
112 ProcessError::expected(err)
113 }
114 } else if let Some(err) =
115 ((&err) as &dyn Any).downcast_ref::<glycin_common::Error>()
116 {
117 if matches!(err, glycin_common::Error::OutOfMemory) {
118 ProcessError::out_of_memory()
119 } else {
120 ProcessError::expected(err)
121 }
122 } else {
123 ProcessError::expected(&err)
124 },
125 ),
126 }
127 }
128
129 #[track_caller]
130 fn internal_error(self) -> Result<T, ProcessError> {
131 match self {
132 Ok(x) => Ok(x),
133 Err(err) => Err(ProcessError::InternalError {
134 err: err.to_string(),
135 location: *Location::caller(),
136 }),
137 }
138 }
139}
140
141impl<T> GenericContexts<T> for Option<T> {
142 #[track_caller]
143 fn expected_error(self) -> Result<T, ProcessError> {
144 match self {
145 Some(x) => Ok(x),
146 None => Err(ProcessError::ExpectedError {
147 err: String::from("None"),
148 location: *Location::caller(),
149 }),
150 }
151 }
152
153 #[track_caller]
154 fn internal_error(self) -> Result<T, ProcessError> {
155 match self {
156 Some(x) => Ok(x),
157 None => Err(ProcessError::InternalError {
158 err: String::from("None"),
159 location: *Location::caller(),
160 }),
161 }
162 }
163}
164
165#[derive(Debug, Clone)]
166pub struct DimensionTooLargerError;
167
168impl std::fmt::Display for DimensionTooLargerError {
169 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
170 f.write_str("Dimension too large for system")
171 }
172}
173
174impl std::error::Error for DimensionTooLargerError {}