Skip to main content

thruput_xdr/
syserr.rs

1use crate::*;
2use core::fmt;
3
4#[cfg_attr(
5    feature = "xdrs",
6    derive(
7        xdrs::ReadXDR,
8        xdrs::WriteXDR,
9        xdrs::ConstWriteXDR,
10        xdrs::ConstXDRSize
11    )
12)]
13#[derive(Copy, Clone, PartialEq, Eq)]
14#[cfg_attr(feature = "std", derive(thiserror::Error))]
15#[cfg_attr(feature = "std", error("{:?}", self))]
16#[repr(transparent)]
17/// Raw error code returned across the syscall boundary.
18///
19/// Wraps the `i32` produced by a syscall; the known values are the
20/// [`SyscallErrorCode`] constants, with
21/// `kSyscallErrorCodeNone` (0) meaning success. Unknown codes are
22/// preserved as-is, so `Debug` falls back to the numeric value.
23pub struct SysErr(pub i32);
24
25impl SysErr {
26    /// Returns whether this error carries exactly `code`.
27    pub fn is_code(&self, code: SyscallErrorCode) -> bool {
28        self.0 == code.0
29    }
30
31    /// Returns whether this is the success code (`kSyscallErrorCodeNone`).
32    pub fn is_none(&self) -> bool {
33        self.is_code(SyscallErrorCode::kSyscallErrorCodeNone)
34    }
35
36    /// Returns whether this is any code other than success.
37    pub fn is_some(&self) -> bool {
38        !self.is_none()
39    }
40
41    /// Returns whether the syscall failed because the storage key does
42    /// not exist (`kSyscallErrorCodeStorageKeyNotExist`).
43    pub fn is_storage_key_not_exist(self) -> bool {
44        self.is_code(SyscallErrorCode::kSyscallErrorCodeStorageKeyNotExist)
45    }
46
47    /// Returns whether the syscall rejected its input
48    /// (`kSyscallErrorCodeInvalidSyscallInput`).
49    pub fn is_invalid_input(self) -> bool {
50        self.is_code(SyscallErrorCode::kSyscallErrorCodeInvalidSyscallInput)
51    }
52}
53
54impl fmt::Debug for SysErr {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        let code = SyscallErrorCode(self.0);
57        match code {
58            SyscallErrorCode::kSyscallErrorCodeNone => {
59                write!(f, "SysErr<None>")
60            }
61            SyscallErrorCode::kSyscallErrorCodeFault => {
62                write!(f, "SysErr<Fault>")
63            }
64            SyscallErrorCode::kSyscallErrorCodeNoSyscall => {
65                write!(f, "SysErr<NoSyscall>")
66            }
67            SyscallErrorCode::kSyscallErrorCodeIsRootTransaction => {
68                write!(f, "SysErr<IsRootTransaction>")
69            }
70            SyscallErrorCode::kSyscallErrorCodeReentrance => {
71                write!(f, "SysErr<Reentrance>")
72            }
73            SyscallErrorCode::kSyscallErrorCodeContractAlreadyDeployed => {
74                write!(f, "SysErr<ContractAlreadyDeployed>")
75            }
76            SyscallErrorCode::kSyscallErrorCodeNoReturnBufferAvailable => {
77                write!(f, "SysErr<NoReturnBufferAvailable>")
78            }
79            SyscallErrorCode::kSyscallErrorCodeInvalidSyscallInput => {
80                write!(f, "SysErr<InvalidSyscallInput>")
81            }
82            SyscallErrorCode::kSyscallErrorCodeStorageKeyNotExist => {
83                write!(f, "SysErr<StorageKeyNotExist>")
84            }
85            SyscallErrorCode::kSyscallErrorCodeNoRetrocausalQueueEntry => {
86                write!(f, "SysErr<NoRetrocausalQueueEntry>")
87            }
88            SyscallErrorCode::kSyscallErrorCodeRetrocausalQueueReadLimitReached => {
89                write!(f, "SysErr<RetrocausalQueueReadLimitReached>")
90            }
91            SyscallErrorCode::kSyscallErrorCodeInvokeDepthExceeded => {
92                write!(f, "SysErr<InvokeDepthExceeded>")
93            }
94            _ => write!(f, "SysErr({})", self.0),
95        }
96    }
97}
98
99impl From<SyscallErrorCode> for SysErr {
100    fn from(code: SyscallErrorCode) -> Self {
101        SysErr(code.0)
102    }
103}
104
105impl From<SysErr> for i32 {
106    fn from(err: SysErr) -> Self {
107        err.0
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114    use std::format;
115
116    #[test]
117    fn debug_names_every_known_code() {
118        for code in
119            0..=SyscallErrorCode::kSyscallErrorCodeInvokeDepthExceeded.0
120        {
121            let debug = format!("{:?}", SysErr(code));
122            assert!(debug.starts_with("SysErr<"), "{code} prints as {debug}");
123        }
124        assert_eq!(format!("{:?}", SysErr(1000)), "SysErr(1000)");
125    }
126}