Skip to main content

thruput_sdk/
re_throw.rs

1use crate::exn::{LibraryExn, syscall_exn, syscall_throw};
2use crate::sys::{SysErr, SyscallNo};
3
4/// A type that can re-throw itself as a contract exception or fault.
5pub trait ReThrow {
6    /// Re-throw this error. Exceptions are propagated as exceptions;
7    /// faults panic (a fault stays a fault).
8    #[cfg_attr(not(target_arch = "riscv32"), track_caller)]
9    fn re_throw(self) -> !;
10}
11
12/// Extension trait for transparently propagating a contract error.
13pub trait OrReThrow<T> {
14    /// On `Err`, re-throw the error. On `Ok`, return the value.
15    fn or_re_throw(self) -> T;
16}
17
18impl<T, E: ReThrow> OrReThrow<T> for Result<T, E> {
19    #[cfg_attr(not(target_arch = "riscv32"), track_caller)]
20    fn or_re_throw(self) -> T {
21        match self {
22            Ok(v) => v,
23            Err(e) => e.re_throw(),
24        }
25    }
26}
27
28impl ReThrow for core::convert::Infallible {
29    #[cfg_attr(not(target_arch = "riscv32"), track_caller)]
30    fn re_throw(self) -> ! {
31        match self {}
32    }
33}
34
35/// Extension trait for turning a failed raw syscall into the SDK's syscall
36/// exception. A [`SysErr`] is only the error code, so the caller names the
37/// syscall; the exception carries both (see
38/// [`SyscallExn`](crate::exn::SyscallExn)).
39pub trait OrSyscallThrow<T> {
40    /// On `Err`, throw the syscall exception for `callno` (see
41    /// [`syscall_throw`]). On `Ok`, return the value.
42    fn or_syscall_throw(self, callno: SyscallNo) -> T;
43
44    /// On `Err`, convert to the [`LibraryExn`] that
45    /// [`or_syscall_throw`](Self::or_syscall_throw) would throw (see
46    /// [`syscall_exn`]).
47    fn or_syscall_exn(self, callno: SyscallNo) -> Result<T, LibraryExn>;
48}
49
50impl<T> OrSyscallThrow<T> for Result<T, SysErr> {
51    // A `match`, not `unwrap_or_else`: a closure is not `track_caller`, so
52    // the throw would report this line instead of the caller's.
53    #[cfg_attr(not(target_arch = "riscv32"), track_caller)]
54    fn or_syscall_throw(self, callno: SyscallNo) -> T {
55        match self {
56            Ok(v) => v,
57            Err(errno) => syscall_throw(callno, errno),
58        }
59    }
60
61    fn or_syscall_exn(self, callno: SyscallNo) -> Result<T, LibraryExn> {
62        self.map_err(|errno| syscall_exn(callno, errno))
63    }
64}