1use jam_types::{InvokeOutcomeCode, SimpleResult, SimpleResultCode, LOWEST_ERROR};
2
3#[derive(Debug)]
5pub enum ApiError {
6 HostCallInvalid,
8 OutOfBounds,
10 IndexUnknown,
12 StorageFull,
14 BadCore,
16 NoCash,
18 GasLimitTooLow,
21 ActionInvalid,
23}
24
25impl From<u64> for ApiError {
26 fn from(code: SimpleResult) -> Self {
27 match code {
28 c if c == SimpleResultCode::HostCallInvalid as u64 => ApiError::HostCallInvalid,
29 c if c == SimpleResultCode::OutOfBounds as u64 => ApiError::OutOfBounds,
30 c if c == SimpleResultCode::IndexUnknown as u64 => ApiError::IndexUnknown,
31 c if c == SimpleResultCode::StorageFull as u64 => ApiError::StorageFull,
32 c if c == SimpleResultCode::BadCore as u64 => ApiError::BadCore,
33 c if c == SimpleResultCode::NoCash as u64 => ApiError::NoCash,
34 c if c == SimpleResultCode::GasLimitTooLow as u64 => ApiError::GasLimitTooLow,
35 c if c == SimpleResultCode::ActionInvalid as u64 => ApiError::ActionInvalid,
36 _ => panic!("unknown error code: {}", code),
37 }
38 }
39}
40
41pub type ApiResult<T> = Result<T, ApiError>;
43
44pub trait IntoApiOption<T> {
46 fn into_api_option(self) -> Option<T>;
47}
48
49impl IntoApiOption<()> for SimpleResult {
50 fn into_api_option(self) -> Option<()> {
51 if self == SimpleResultCode::Ok as u64 {
52 Some(())
53 } else if self == SimpleResultCode::Nothing as u64 {
54 None
55 } else {
56 panic!("Our own API impl has resulted in success value which is out of range.");
57 }
58 }
59}
60impl IntoApiOption<u64> for SimpleResult {
61 fn into_api_option(self) -> Option<u64> {
62 if self < LOWEST_ERROR {
63 Some(self)
64 } else if self == SimpleResultCode::Nothing as u64 {
65 None
66 } else {
67 panic!("Our own API impl has resulted in success value which is out of range.");
68 }
69 }
70}
71impl IntoApiOption<u32> for SimpleResult {
72 fn into_api_option(self) -> Option<u32> {
73 if self <= u32::MAX as _ {
74 Some(self as _)
75 } else if self == SimpleResultCode::Nothing as u64 {
76 None
77 } else {
78 panic!("Our own API impl has resulted in success value which is out of range.");
79 }
80 }
81}
82impl IntoApiOption<usize> for SimpleResult {
83 fn into_api_option(self) -> Option<usize> {
84 if self < LOWEST_ERROR && self <= usize::MAX as _ {
85 Some(self as _)
86 } else if self == SimpleResultCode::Nothing as u64 {
87 None
88 } else {
89 panic!("Our own API impl has resulted in success value which is out of range.");
90 }
91 }
92}
93
94pub trait IntoApiResult<T> {
96 fn into_api_result(self) -> ApiResult<T>;
97}
98
99impl IntoApiResult<()> for SimpleResult {
100 fn into_api_result(self) -> ApiResult<()> {
101 if self == SimpleResultCode::Ok as u64 {
102 Ok(())
103 } else {
104 Err(self.into())
105 }
106 }
107}
108impl IntoApiResult<u64> for SimpleResult {
109 fn into_api_result(self) -> ApiResult<u64> {
110 if self < LOWEST_ERROR {
111 Ok(self)
112 } else {
113 Err(self.into())
114 }
115 }
116}
117impl IntoApiResult<usize> for SimpleResult {
118 fn into_api_result(self) -> ApiResult<usize> {
119 if self <= usize::MAX as _ && self < LOWEST_ERROR {
120 Ok(self as usize)
121 } else if self < LOWEST_ERROR {
122 panic!("Our own API impl has resulted in success value which is out of range.");
123 } else {
124 Err(self.into())
125 }
126 }
127}
128impl IntoApiResult<u32> for SimpleResult {
129 fn into_api_result(self) -> ApiResult<u32> {
130 if self <= u32::MAX as _ {
131 Ok(self as u32)
132 } else if self < LOWEST_ERROR {
133 panic!("Our own API impl has resulted in success value which is out of range.");
134 } else {
135 Err(self.into())
136 }
137 }
138}
139impl IntoApiResult<Option<()>> for SimpleResult {
140 fn into_api_result(self) -> ApiResult<Option<()>> {
141 if self < LOWEST_ERROR {
142 Ok(Some(()))
143 } else if self == SimpleResultCode::Nothing as u64 {
144 Ok(None)
145 } else {
146 Err(self.into())
147 }
148 }
149}
150impl IntoApiResult<Option<u64>> for SimpleResult {
151 fn into_api_result(self) -> ApiResult<Option<u64>> {
152 if self < LOWEST_ERROR {
153 Ok(Some(self))
154 } else if self == SimpleResultCode::Nothing as u64 {
155 Ok(None)
156 } else {
157 Err(self.into())
158 }
159 }
160}
161impl IntoApiResult<Option<usize>> for SimpleResult {
162 fn into_api_result(self) -> ApiResult<Option<usize>> {
163 if self <= usize::MAX as _ && self < LOWEST_ERROR {
164 Ok(Some(self as usize))
165 } else if self < LOWEST_ERROR {
166 panic!("Our own API impl has resulted in success value which is out of range.");
167 } else if self == SimpleResultCode::Nothing as u64 {
168 Ok(None)
169 } else {
170 Err(self.into())
171 }
172 }
173}
174
175#[derive(Clone, Copy)]
177pub enum InvokeOutcome {
178 Halt,
180 PageFault(u64),
182 HostCallFault(u64),
184 Panic,
186 OutOfGas,
188}
189
190pub type InvokeResult = ApiResult<InvokeOutcome>;
192
193pub trait IntoInvokeResult {
195 fn into_invoke_result(self) -> InvokeResult;
197}
198
199impl IntoInvokeResult for (u64, u64) {
200 fn into_invoke_result(self) -> InvokeResult {
201 const STATUS_HALT: u64 = InvokeOutcomeCode::Halt as u64;
202 const STATUS_PANIC: u64 = InvokeOutcomeCode::Panic as u64;
203 const STATUS_FAULT: u64 = InvokeOutcomeCode::PageFault as u64;
204 const STATUS_HOST: u64 = InvokeOutcomeCode::HostCallFault as u64;
205 const STATUS_OOG: u64 = InvokeOutcomeCode::OutOfGas as u64;
206 match self {
208 (STATUS_HALT, _) => Ok(InvokeOutcome::Halt),
209 (STATUS_FAULT, address) => Ok(InvokeOutcome::PageFault(address)),
210 (STATUS_HOST, index) => Ok(InvokeOutcome::HostCallFault(index)),
211 (STATUS_PANIC, _) => Ok(InvokeOutcome::Panic),
212 (STATUS_OOG, _) => Ok(InvokeOutcome::OutOfGas),
213 (code, _) => Err(code.into()),
214 }
215 }
216}