oasis_runtime_sdk/
error.rs1pub use oasis_core_runtime::types::Error as RuntimeError;
3
4use crate::{dispatcher, module::CallResult};
5
6pub trait Error: std::error::Error {
30    fn module_name(&self) -> &str;
32
33    fn code(&self) -> u32;
35
36    fn into_call_result(self) -> CallResult
38    where
39        Self: Sized,
40    {
41        match self.into_abort() {
42            Ok(err) => CallResult::Aborted(err),
43            Err(failed) => CallResult::Failed {
44                module: failed.module_name().to_owned(),
45                code: failed.code(),
46                message: failed.to_string(),
47            },
48        }
49    }
50
51    fn into_abort(self) -> Result<dispatcher::Error, Self>
54    where
55        Self: Sized,
56    {
57        Err(self)
58    }
59}
60
61impl Error for std::convert::Infallible {
62    fn module_name(&self) -> &str {
63        "(none)"
64    }
65
66    fn code(&self) -> u32 {
67        Default::default()
68    }
69}
70
71#[cfg(test)]
72mod test {
73    use super::*;
74
75    const MODULE_NAME_1: &str = "test1";
76    const MODULE_NAME_2: &str = "test2";
77
78    #[derive(thiserror::Error, Debug, oasis_runtime_sdk_macros::Error)]
79    #[sdk_error(module_name = "MODULE_NAME_1")]
80    enum ChildError {
81        #[error("first error")]
82        #[sdk_error(code = 1)]
83        Error1,
84
85        #[error("second error")]
86        #[sdk_error(code = 2)]
87        Error2,
88    }
89
90    #[derive(thiserror::Error, Debug, oasis_runtime_sdk_macros::Error)]
91    #[sdk_error(module_name = "MODULE_NAME_2")]
92    enum ParentError {
93        #[error("first error")]
94        #[sdk_error(code = 1)]
95        NotForwarded(#[source] ChildError),
96
97        #[error("nested error")]
98        #[sdk_error(transparent)]
99        Nested(#[source] ChildError),
100    }
101
102    #[derive(thiserror::Error, Debug, oasis_runtime_sdk_macros::Error)]
103    enum ParentParentError {
104        #[error("nested nested error")]
105        #[sdk_error(transparent)]
106        Nested(#[source] ParentError),
107    }
108
109    #[test]
110    fn test_error_sources_1() {
111        let err = ParentError::Nested(ChildError::Error1);
112        let result = err.into_call_result();
113
114        match result {
115            CallResult::Failed {
116                module,
117                code,
118                message: _,
119            } => {
120                assert_eq!(module, "test1");
121                assert_eq!(code, 1);
122            }
123            _ => panic!("expected failed result, got: {result:?}"),
124        }
125
126        let err = ParentError::Nested(ChildError::Error2);
127        let result = err.into_call_result();
128
129        match result {
130            CallResult::Failed {
131                module,
132                code,
133                message: _,
134            } => {
135                assert_eq!(module, "test1");
136                assert_eq!(code, 2);
137            }
138            _ => panic!("expected failed result, got: {result:?}"),
139        }
140    }
141
142    #[test]
143    fn test_error_sources_2() {
144        let err = ParentError::NotForwarded(ChildError::Error1);
145        let result = err.into_call_result();
146
147        match result {
148            CallResult::Failed {
149                module,
150                code,
151                message: _,
152            } => {
153                assert_eq!(module, "test2");
154                assert_eq!(code, 1);
155            }
156            _ => panic!("expected failed result, got: {result:?}"),
157        }
158
159        let err = ParentError::NotForwarded(ChildError::Error2);
160        let result = err.into_call_result();
161
162        match result {
163            CallResult::Failed {
164                module,
165                code,
166                message: _,
167            } => {
168                assert_eq!(module, "test2");
169                assert_eq!(code, 1);
170            }
171            _ => panic!("expected failed result, got: {result:?}"),
172        }
173    }
174
175    #[test]
176    fn test_error_sources_3() {
177        let err = ParentParentError::Nested(ParentError::Nested(ChildError::Error1));
178        let result = err.into_call_result();
179
180        match result {
181            CallResult::Failed {
182                module,
183                code,
184                message: _,
185            } => {
186                assert_eq!(module, "test1");
187                assert_eq!(code, 1);
188            }
189            _ => panic!("expected failed result, got: {result:?}"),
190        }
191    }
192}