sbi_spec/binary/sbi_ret.rs
1/// SBI functions return type.
2///
3/// > SBI functions must return a pair of values in a0 and a1,
4/// > with a0 returning an error code.
5/// > This is analogous to returning the C structure `SbiRet`.
6///
7/// Note: if this structure is used in function return on conventional
8/// Rust code, it would not require pinning memory representation as
9/// extern C. The `repr(C)` is set in case that some users want to use
10/// this structure in FFI code.
11#[derive(Clone, Copy, PartialEq, Eq)]
12#[repr(C)]
13pub struct SbiRet<T = usize> {
14 /// Error number.
15 pub error: T,
16 /// Result value.
17 pub value: T,
18}
19
20/// Standard RISC-V SBI error IDs in `usize`.
21pub mod id {
22 use super::SbiRegister;
23
24 /// SBI success state return value.
25 #[doc(alias = "SBI_SUCCESS")]
26 pub const RET_SUCCESS: usize = <usize as SbiRegister>::RET_SUCCESS;
27 /// Error for SBI call failed for unknown reasons.
28 #[doc(alias = "SBI_ERR_FAILED")]
29 pub const RET_ERR_FAILED: usize = <usize as SbiRegister>::RET_ERR_FAILED;
30 /// Error for target operation not supported.
31 #[doc(alias = "SBI_ERR_NOT_SUPPORTED")]
32 pub const RET_ERR_NOT_SUPPORTED: usize = <usize as SbiRegister>::RET_ERR_NOT_SUPPORTED;
33 /// Error for invalid parameter.
34 #[doc(alias = "SBI_ERR_INVALID_PARAM")]
35 pub const RET_ERR_INVALID_PARAM: usize = <usize as SbiRegister>::RET_ERR_INVALID_PARAM;
36 /// Error for denied.
37 #[doc(alias = "SBI_ERR_DENIED")]
38 pub const RET_ERR_DENIED: usize = <usize as SbiRegister>::RET_ERR_DENIED;
39 /// Error for invalid address.
40 #[doc(alias = "SBI_ERR_INVALID_ADDRESS")]
41 pub const RET_ERR_INVALID_ADDRESS: usize = <usize as SbiRegister>::RET_ERR_INVALID_ADDRESS;
42 /// Error for resource already available.
43 #[doc(alias = "SBI_ERR_ALREADY_AVAILABLE")]
44 pub const RET_ERR_ALREADY_AVAILABLE: usize = <usize as SbiRegister>::RET_ERR_ALREADY_AVAILABLE;
45 /// Error for resource already started.
46 #[doc(alias = "SBI_ERR_ALREADY_STARTED")]
47 pub const RET_ERR_ALREADY_STARTED: usize = <usize as SbiRegister>::RET_ERR_ALREADY_STARTED;
48 /// Error for resource already stopped.
49 #[doc(alias = "SBI_ERR_ALREADY_STOPPED")]
50 pub const RET_ERR_ALREADY_STOPPED: usize = <usize as SbiRegister>::RET_ERR_ALREADY_STOPPED;
51 /// Error for shared memory not available.
52 #[doc(alias = "SBI_ERR_NO_SHMEM")]
53 pub const RET_ERR_NO_SHMEM: usize = <usize as SbiRegister>::RET_ERR_NO_SHMEM;
54 /// Error for invalid state.
55 #[doc(alias = "SBI_ERR_INVALID_STATE")]
56 pub const RET_ERR_INVALID_STATE: usize = <usize as SbiRegister>::RET_ERR_INVALID_STATE;
57 /// Error for bad or invalid range.
58 #[doc(alias = "SBI_ERR_BAD_RANGE")]
59 pub const RET_ERR_BAD_RANGE: usize = <usize as SbiRegister>::RET_ERR_BAD_RANGE;
60 /// Error for failed due to timeout.
61 #[doc(alias = "SBI_ERR_TIMEOUT")]
62 pub const RET_ERR_TIMEOUT: usize = <usize as SbiRegister>::RET_ERR_TIMEOUT;
63 /// Error for input or output error.
64 #[doc(alias = "SBI_ERR_IO")]
65 pub const RET_ERR_IO: usize = <usize as SbiRegister>::RET_ERR_IO;
66 /// Error for denied or not allowed due to lock status.
67 #[doc(alias = "SBI_ERR_DENIED_LOCKED")]
68 pub const RET_ERR_DENIED_LOCKED: usize = <usize as SbiRegister>::RET_ERR_DENIED_LOCKED;
69 // ^^ Note: remember to add a test case in `rustsbi_sbi_ret_constructors` in this file,
70 // and `test_binary` in lib.rs after adding an error number!
71}
72// Use each constants in `id` module, so that any `match` operations will not treat constant
73// names (`RET_ERR_*`) as newly defined variable names.
74use id::*;
75
76/// Data type of register that can be passed to the RISC-V SBI ABI.
77///
78/// This trait defines the requirements for types that are used as the underlying
79/// representation for both the `value` and `error` fields in the `SbiRet` structure.
80/// In most cases, this trait is implemented for primitive integer types (e.g., `usize`),
81/// but it can also be implemented for other types that satisfy the constraints.
82///
83/// # Examples
84///
85/// Implemented automatically for all types that satisfy `Copy`, `Eq`, and `Debug`.
86pub trait SbiRegister: Copy + Eq + Ord + core::fmt::Debug {
87 /// SBI success state return value.
88 const RET_SUCCESS: Self;
89 /// Error for SBI call failed for unknown reasons.
90 const RET_ERR_FAILED: Self;
91 /// Error for target operation not supported.
92 const RET_ERR_NOT_SUPPORTED: Self;
93 /// Error for invalid parameter.
94 const RET_ERR_INVALID_PARAM: Self;
95 /// Error for denied.
96 const RET_ERR_DENIED: Self;
97 /// Error for invalid address.
98 const RET_ERR_INVALID_ADDRESS: Self;
99 /// Error for resource already available.
100 const RET_ERR_ALREADY_AVAILABLE: Self;
101 /// Error for resource already started.
102 const RET_ERR_ALREADY_STARTED: Self;
103 /// Error for resource already stopped.
104 const RET_ERR_ALREADY_STOPPED: Self;
105 /// Error for shared memory not available.
106 const RET_ERR_NO_SHMEM: Self;
107 /// Error for invalid state.
108 const RET_ERR_INVALID_STATE: Self;
109 /// Error for bad or invalid range.
110 const RET_ERR_BAD_RANGE: Self;
111 /// Error for failed due to timeout.
112 const RET_ERR_TIMEOUT: Self;
113 /// Error for input or output error.
114 const RET_ERR_IO: Self;
115 /// Error for denied or not allowed due to lock status.
116 const RET_ERR_DENIED_LOCKED: Self;
117
118 /// Zero value for this type; this is used on `value` fields once `SbiRet` returns an error.
119 const ZERO: Self;
120 /// Full-ones value for this type; this is used on SBI mask structures like `CounterMask`
121 /// and `HartMask`.
122 const FULL_MASK: Self;
123
124 /// Converts an `SbiRet` of this type to a `Result` of self and `Error`.
125 fn into_result(ret: SbiRet<Self>) -> Result<Self, Error<Self>>;
126}
127
128macro_rules! impl_sbi_register {
129 ($ty:ty, $signed:ty) => {
130 impl SbiRegister for $ty {
131 const RET_SUCCESS: Self = 0;
132 const RET_ERR_FAILED: Self = -1 as $signed as $ty;
133 const RET_ERR_NOT_SUPPORTED: Self = -2 as $signed as $ty;
134 const RET_ERR_INVALID_PARAM: Self = -3 as $signed as $ty;
135 const RET_ERR_DENIED: Self = -4 as $signed as $ty;
136 const RET_ERR_INVALID_ADDRESS: Self = -5 as $signed as $ty;
137 const RET_ERR_ALREADY_AVAILABLE: Self = -6 as $signed as $ty;
138 const RET_ERR_ALREADY_STARTED: Self = -7 as $signed as $ty;
139 const RET_ERR_ALREADY_STOPPED: Self = -8 as $signed as $ty;
140 const RET_ERR_NO_SHMEM: Self = -9 as $signed as $ty;
141 const RET_ERR_INVALID_STATE: Self = -10 as $signed as $ty;
142 const RET_ERR_BAD_RANGE: Self = -11 as $signed as $ty;
143 const RET_ERR_TIMEOUT: Self = -12 as $signed as $ty;
144 const RET_ERR_IO: Self = -13 as $signed as $ty;
145 const RET_ERR_DENIED_LOCKED: Self = -14 as $signed as $ty;
146 const ZERO: Self = 0;
147 const FULL_MASK: Self = !0;
148
149 fn into_result(ret: SbiRet<Self>) -> Result<Self, Error<Self>> {
150 match ret.error {
151 Self::RET_SUCCESS => Ok(ret.value),
152 Self::RET_ERR_FAILED => Err(Error::Failed),
153 Self::RET_ERR_NOT_SUPPORTED => Err(Error::NotSupported),
154 Self::RET_ERR_INVALID_PARAM => Err(Error::InvalidParam),
155 Self::RET_ERR_DENIED => Err(Error::Denied),
156 Self::RET_ERR_INVALID_ADDRESS => Err(Error::InvalidAddress),
157 Self::RET_ERR_ALREADY_AVAILABLE => Err(Error::AlreadyAvailable),
158 Self::RET_ERR_ALREADY_STARTED => Err(Error::AlreadyStarted),
159 Self::RET_ERR_ALREADY_STOPPED => Err(Error::AlreadyStopped),
160 Self::RET_ERR_NO_SHMEM => Err(Error::NoShmem),
161 Self::RET_ERR_INVALID_STATE => Err(Error::InvalidState),
162 Self::RET_ERR_BAD_RANGE => Err(Error::BadRange),
163 Self::RET_ERR_TIMEOUT => Err(Error::Timeout),
164 Self::RET_ERR_IO => Err(Error::Io),
165 Self::RET_ERR_DENIED_LOCKED => Err(Error::DeniedLocked),
166 unknown => Err(Error::Custom(unknown as _)),
167 }
168 }
169 }
170 };
171}
172
173impl_sbi_register!(usize, isize);
174impl_sbi_register!(isize, isize);
175impl_sbi_register!(u32, i32);
176impl_sbi_register!(i32, i32);
177impl_sbi_register!(u64, i64);
178impl_sbi_register!(i64, i64);
179impl_sbi_register!(u128, i128);
180impl_sbi_register!(i128, i128);
181
182impl<T: SbiRegister + core::fmt::LowerHex> core::fmt::Debug for SbiRet<T> {
183 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
184 match T::into_result(*self) {
185 Ok(value) => write!(f, "{:?}", value),
186 Err(err) => match err {
187 Error::Failed => write!(f, "<SBI call failed>"),
188 Error::NotSupported => write!(f, "<SBI feature not supported>"),
189 Error::InvalidParam => write!(f, "<SBI invalid parameter>"),
190 Error::Denied => write!(f, "<SBI denied>"),
191 Error::InvalidAddress => write!(f, "<SBI invalid address>"),
192 Error::AlreadyAvailable => write!(f, "<SBI already available>"),
193 Error::AlreadyStarted => write!(f, "<SBI already started>"),
194 Error::AlreadyStopped => write!(f, "<SBI already stopped>"),
195 Error::NoShmem => write!(f, "<SBI shared memory not available>"),
196 Error::InvalidState => write!(f, "<SBI invalid state>"),
197 Error::BadRange => write!(f, "<SBI bad range>"),
198 Error::Timeout => write!(f, "<SBI timeout>"),
199 Error::Io => write!(f, "<SBI input/output error>"),
200 Error::DeniedLocked => write!(f, "<SBI denied due to locked status>"),
201 Error::Custom(unknown) => write!(f, "[SBI Unknown error: {:#x}]", unknown),
202 },
203 }
204 }
205}
206
207/// RISC-V SBI error in enumeration.
208#[derive(Debug, Clone, Copy, PartialEq, Eq)]
209pub enum Error<T = usize> {
210 /// Error for SBI call failed for unknown reasons.
211 Failed,
212 /// Error for target operation not supported.
213 NotSupported,
214 /// Error for invalid parameter.
215 InvalidParam,
216 /// Error for denied.
217 Denied,
218 /// Error for invalid address.
219 InvalidAddress,
220 /// Error for resource already available.
221 AlreadyAvailable,
222 /// Error for resource already started.
223 AlreadyStarted,
224 /// Error for resource already stopped.
225 AlreadyStopped,
226 /// Error for shared memory not available.
227 NoShmem,
228 /// Error for invalid state.
229 InvalidState,
230 /// Error for bad or invalid range.
231 BadRange,
232 /// Error for failed due to timeout.
233 Timeout,
234 /// Error for input or output error.
235 Io,
236 /// Error for denied or not allowed due to lock status.
237 DeniedLocked,
238 /// Custom error code.
239 Custom(T),
240}
241
242impl<T: SbiRegister> SbiRet<T> {
243 /// Returns success SBI state with given `value`.
244 #[inline]
245 pub const fn success(value: T) -> Self {
246 Self {
247 error: T::RET_SUCCESS,
248 value,
249 }
250 }
251
252 /// The SBI call request failed for unknown reasons.
253 #[inline]
254 pub const fn failed() -> Self {
255 Self {
256 error: T::RET_ERR_FAILED,
257 value: T::ZERO,
258 }
259 }
260
261 /// SBI call failed due to not supported by target ISA,
262 /// operation type not supported,
263 /// or target operation type not implemented on purpose.
264 #[inline]
265 pub const fn not_supported() -> Self {
266 Self {
267 error: T::RET_ERR_NOT_SUPPORTED,
268 value: T::ZERO,
269 }
270 }
271
272 /// SBI call failed due to invalid hart mask parameter,
273 /// invalid target hart id,
274 /// invalid operation type,
275 /// or invalid resource index.
276 #[inline]
277 pub const fn invalid_param() -> Self {
278 Self {
279 error: T::RET_ERR_INVALID_PARAM,
280 value: T::ZERO,
281 }
282 }
283 /// SBI call denied for unsatisfied entry criteria, or insufficient access
284 /// permission to debug console or CPPC register.
285 #[inline]
286 pub const fn denied() -> Self {
287 Self {
288 error: T::RET_ERR_DENIED,
289 value: T::ZERO,
290 }
291 }
292
293 /// SBI call failed for invalid mask start address,
294 /// not a valid physical address parameter,
295 /// or the target address is prohibited by PMP to run in supervisor mode.
296 #[inline]
297 pub const fn invalid_address() -> Self {
298 Self {
299 error: T::RET_ERR_INVALID_ADDRESS,
300 value: T::ZERO,
301 }
302 }
303
304 /// SBI call failed for the target resource is already available,
305 /// e.g., the target hart is already started when caller still requests it to start.
306 #[inline]
307 pub const fn already_available() -> Self {
308 Self {
309 error: T::RET_ERR_ALREADY_AVAILABLE,
310 value: T::ZERO,
311 }
312 }
313
314 /// SBI call failed for the target resource is already started,
315 /// e.g., target performance counter is started.
316 #[inline]
317 pub const fn already_started() -> Self {
318 Self {
319 error: T::RET_ERR_ALREADY_STARTED,
320 value: T::ZERO,
321 }
322 }
323
324 /// SBI call failed for the target resource is already stopped,
325 /// e.g., target performance counter is stopped.
326 #[inline]
327 pub const fn already_stopped() -> Self {
328 Self {
329 error: T::RET_ERR_ALREADY_STOPPED,
330 value: T::ZERO,
331 }
332 }
333
334 /// SBI call failed for shared memory is not available,
335 /// e.g. nested acceleration shared memory is not available.
336 #[inline]
337 pub const fn no_shmem() -> Self {
338 Self {
339 error: T::RET_ERR_NO_SHMEM,
340 value: T::ZERO,
341 }
342 }
343
344 /// SBI call failed for invalid state,
345 /// e.g. register a software event but the event is not in unused state.
346 #[inline]
347 pub const fn invalid_state() -> Self {
348 Self {
349 error: T::RET_ERR_INVALID_STATE,
350 value: T::ZERO,
351 }
352 }
353
354 /// SBI call failed for bad or invalid range,
355 /// e.g. the software event is not exist in the specified range.
356 #[inline]
357 pub const fn bad_range() -> Self {
358 Self {
359 error: T::RET_ERR_BAD_RANGE,
360 value: T::ZERO,
361 }
362 }
363
364 /// SBI call failed for timeout,
365 /// e.g. message send timeout.
366 #[inline]
367 pub const fn timeout() -> Self {
368 Self {
369 error: T::RET_ERR_TIMEOUT,
370 value: T::ZERO,
371 }
372 }
373
374 /// SBI call failed for input or output error.
375 #[inline]
376 pub const fn io() -> Self {
377 Self {
378 error: T::RET_ERR_IO,
379 value: T::ZERO,
380 }
381 }
382 /// SBI call failed for denied or not allowed due to lock status.
383 #[inline]
384 pub const fn denied_locked() -> Self {
385 Self {
386 error: T::RET_ERR_DENIED_LOCKED,
387 value: T::ZERO,
388 }
389 }
390}
391
392impl<T: SbiRegister> From<Error<T>> for SbiRet<T> {
393 #[inline]
394 fn from(value: Error<T>) -> Self {
395 match value {
396 Error::Failed => SbiRet::failed(),
397 Error::NotSupported => SbiRet::not_supported(),
398 Error::InvalidParam => SbiRet::invalid_param(),
399 Error::Denied => SbiRet::denied(),
400 Error::InvalidAddress => SbiRet::invalid_address(),
401 Error::AlreadyAvailable => SbiRet::already_available(),
402 Error::AlreadyStarted => SbiRet::already_started(),
403 Error::AlreadyStopped => SbiRet::already_stopped(),
404 Error::NoShmem => SbiRet::no_shmem(),
405 Error::InvalidState => SbiRet::invalid_state(),
406 Error::BadRange => SbiRet::bad_range(),
407 Error::Timeout => SbiRet::timeout(),
408 Error::Io => SbiRet::io(),
409 Error::DeniedLocked => SbiRet::denied_locked(),
410 Error::Custom(error) => SbiRet {
411 error,
412 value: T::ZERO,
413 },
414 }
415 }
416}
417
418impl SbiRet {
419 /// Converts to a [`Result`] of value and error.
420 #[inline]
421 pub const fn into_result(self) -> Result<usize, Error> {
422 match self.error {
423 RET_SUCCESS => Ok(self.value),
424 RET_ERR_FAILED => Err(Error::Failed),
425 RET_ERR_NOT_SUPPORTED => Err(Error::NotSupported),
426 RET_ERR_INVALID_PARAM => Err(Error::InvalidParam),
427 RET_ERR_DENIED => Err(Error::Denied),
428 RET_ERR_INVALID_ADDRESS => Err(Error::InvalidAddress),
429 RET_ERR_ALREADY_AVAILABLE => Err(Error::AlreadyAvailable),
430 RET_ERR_ALREADY_STARTED => Err(Error::AlreadyStarted),
431 RET_ERR_ALREADY_STOPPED => Err(Error::AlreadyStopped),
432 RET_ERR_NO_SHMEM => Err(Error::NoShmem),
433 RET_ERR_INVALID_STATE => Err(Error::InvalidState),
434 RET_ERR_BAD_RANGE => Err(Error::BadRange),
435 RET_ERR_TIMEOUT => Err(Error::Timeout),
436 RET_ERR_IO => Err(Error::Io),
437 RET_ERR_DENIED_LOCKED => Err(Error::DeniedLocked),
438 unknown => Err(Error::Custom(unknown as _)),
439 }
440 }
441
442 /// Returns `true` if current SBI return succeeded.
443 ///
444 /// # Examples
445 ///
446 /// Basic usage:
447 ///
448 /// ```
449 /// # use sbi_spec::binary::SbiRet;
450 /// let x = SbiRet::success(0);
451 /// assert_eq!(x.is_ok(), true);
452 ///
453 /// let x = SbiRet::failed();
454 /// assert_eq!(x.is_ok(), false);
455 /// ```
456 #[must_use = "if you intended to assert that this is ok, consider `.unwrap()` instead"]
457 #[inline]
458 pub const fn is_ok(&self) -> bool {
459 matches!(self.error, RET_SUCCESS)
460 }
461
462 /// Returns `true` if the SBI call succeeded and the value inside of it matches a predicate.
463 ///
464 /// # Examples
465 ///
466 /// Basic usage:
467 ///
468 /// ```
469 /// # use sbi_spec::binary::SbiRet;
470 /// let x = SbiRet::success(2);
471 /// assert_eq!(x.is_ok_and(|x| x > 1), true);
472 ///
473 /// let x = SbiRet::success(0);
474 /// assert_eq!(x.is_ok_and(|x| x > 1), false);
475 ///
476 /// let x = SbiRet::no_shmem();
477 /// assert_eq!(x.is_ok_and(|x| x > 1), false);
478 /// ```
479 #[must_use]
480 #[inline]
481 pub fn is_ok_and(self, f: impl FnOnce(usize) -> bool) -> bool {
482 self.into_result().is_ok_and(f)
483 }
484
485 /// Returns `true` if current SBI return is an error.
486 ///
487 /// # Examples
488 ///
489 /// Basic usage:
490 ///
491 /// ```
492 /// # use sbi_spec::binary::SbiRet;
493 /// let x = SbiRet::success(0);
494 /// assert_eq!(x.is_err(), false);
495 ///
496 /// let x = SbiRet::not_supported();
497 /// assert_eq!(x.is_err(), true);
498 /// ```
499 #[must_use = "if you intended to assert that this is err, consider `.unwrap_err()` instead"]
500 #[inline]
501 pub const fn is_err(&self) -> bool {
502 !self.is_ok()
503 }
504
505 /// Returns `true` if the result is an error and the value inside of it matches a predicate.
506 ///
507 /// # Examples
508 ///
509 /// ```
510 /// # use sbi_spec::binary::{SbiRet, Error};
511 /// let x = SbiRet::denied();
512 /// assert_eq!(x.is_err_and(|x| x == Error::Denied), true);
513 ///
514 /// let x = SbiRet::invalid_address();
515 /// assert_eq!(x.is_err_and(|x| x == Error::Denied), false);
516 ///
517 /// let x = SbiRet::success(0);
518 /// assert_eq!(x.is_err_and(|x| x == Error::Denied), false);
519 /// ```
520 #[must_use]
521 #[inline]
522 pub fn is_err_and(self, f: impl FnOnce(Error) -> bool) -> bool {
523 self.into_result().is_err_and(f)
524 }
525
526 /// Converts from `SbiRet` to [`Option<usize>`].
527 ///
528 /// Converts `self` into an [`Option<usize>`], consuming `self`,
529 /// and discarding the error, if any.
530 ///
531 /// # Examples
532 ///
533 /// Basic usage:
534 ///
535 /// ```
536 /// # use sbi_spec::binary::SbiRet;
537 /// let x = SbiRet::success(2);
538 /// assert_eq!(x.ok(), Some(2));
539 ///
540 /// let x = SbiRet::invalid_param();
541 /// assert_eq!(x.ok(), None);
542 /// ```
543 // fixme: should be pub const fn once this function in Result is stabilized in constant
544 #[inline]
545 pub fn ok(self) -> Option<usize> {
546 self.into_result().ok()
547 }
548
549 /// Converts from `SbiRet` to [`Option<Error>`].
550 ///
551 /// Converts `self` into an [`Option<Error>`], consuming `self`,
552 /// and discarding the success value, if any.
553 ///
554 /// # Examples
555 ///
556 /// Basic usage:
557 ///
558 /// ```
559 /// # use sbi_spec::binary::{SbiRet, Error};
560 /// let x = SbiRet::success(2);
561 /// assert_eq!(x.err(), None);
562 ///
563 /// let x = SbiRet::denied();
564 /// assert_eq!(x.err(), Some(Error::Denied));
565 /// ```
566 // fixme: should be pub const fn once this function in Result is stabilized in constant
567 #[inline]
568 pub fn err(self) -> Option<Error> {
569 self.into_result().err()
570 }
571
572 /// Maps a `SbiRet` to `Result<U, Error>` by applying a function to a
573 /// contained success value, leaving an error value untouched.
574 ///
575 /// This function can be used to compose the results of two functions.
576 ///
577 /// # Examples
578 ///
579 /// Gets detail of a PMU counter and judge if it is a firmware counter.
580 ///
581 /// ```
582 /// # use sbi_spec::binary::SbiRet;
583 /// # use core::mem::size_of;
584 /// # mod sbi_rt {
585 /// # use sbi_spec::binary::SbiRet;
586 /// # const TYPE_MASK: usize = 1 << (core::mem::size_of::<usize>() - 1);
587 /// # pub fn pmu_counter_get_info(_: usize) -> SbiRet { SbiRet::success(TYPE_MASK) }
588 /// # }
589 /// // We assume that counter index 42 is a firmware counter.
590 /// let counter_idx = 42;
591 /// // Masks PMU counter type by setting highest bit in `usize`.
592 /// const TYPE_MASK: usize = 1 << (size_of::<usize>() - 1);
593 /// // Highest bit of returned `counter_info` represents whether it's
594 /// // a firmware counter or a hardware counter.
595 /// let is_firmware_counter = sbi_rt::pmu_counter_get_info(counter_idx)
596 /// .map(|counter_info| counter_info & TYPE_MASK != 0);
597 /// // If that bit is set, it is a firmware counter.
598 /// assert_eq!(is_firmware_counter, Ok(true));
599 /// ```
600 #[inline]
601 pub fn map<U, F: FnOnce(usize) -> U>(self, op: F) -> Result<U, Error> {
602 self.into_result().map(op)
603 }
604
605 /// Returns the provided default (if error),
606 /// or applies a function to the contained value (if success).
607 ///
608 /// Arguments passed to `map_or` are eagerly evaluated;
609 /// if you are passing the result of a function call,
610 /// it is recommended to use [`map_or_else`],
611 /// which is lazily evaluated.
612 ///
613 /// [`map_or_else`]: SbiRet::map_or_else
614 ///
615 /// # Examples
616 ///
617 /// ```
618 /// # use sbi_spec::binary::SbiRet;
619 /// let x = SbiRet::success(3);
620 /// assert_eq!(x.map_or(42, |v| v & 0b1), 1);
621 ///
622 /// let x = SbiRet::invalid_address();
623 /// assert_eq!(x.map_or(42, |v| v & 0b1), 42);
624 /// ```
625 #[inline]
626 pub fn map_or<U, F: FnOnce(usize) -> U>(self, default: U, f: F) -> U {
627 self.into_result().map_or(default, f)
628 }
629
630 /// Maps a `SbiRet` to `usize` value by applying fallback function `default` to
631 /// a contained error, or function `f` to a contained success value.
632 ///
633 /// This function can be used to unpack a successful result
634 /// while handling an error.
635 ///
636 /// # Examples
637 ///
638 /// Basic usage:
639 ///
640 /// ```
641 /// # use sbi_spec::binary::SbiRet;
642 /// let k = 21;
643 ///
644 /// let x = SbiRet::success(3);
645 /// assert_eq!(x.map_or_else(|e| k * 2, |v| v & 0b1), 1);
646 ///
647 /// let x = SbiRet::already_available();
648 /// assert_eq!(x.map_or_else(|e| k * 2, |v| v & 0b1), 42);
649 /// ```
650 #[inline]
651 pub fn map_or_else<U, D: FnOnce(Error) -> U, F: FnOnce(usize) -> U>(
652 self,
653 default: D,
654 f: F,
655 ) -> U {
656 self.into_result().map_or_else(default, f)
657 }
658
659 /// Maps a `SbiRet` to `Result<T, F>` by applying a function to a
660 /// contained error as [`Error`] struct, leaving success value untouched.
661 ///
662 /// This function can be used to pass through a successful result while handling
663 /// an error.
664 ///
665 /// # Examples
666 ///
667 /// Basic usage:
668 ///
669 /// ```
670 /// # use sbi_spec::binary::{SbiRet, Error};
671 /// fn stringify(x: Error) -> String {
672 /// if x == Error::AlreadyStarted {
673 /// "error: already started!".to_string()
674 /// } else {
675 /// "error: other error!".to_string()
676 /// }
677 /// }
678 ///
679 /// let x = SbiRet::success(2);
680 /// assert_eq!(x.map_err(stringify), Ok(2));
681 ///
682 /// let x = SbiRet::already_started();
683 /// assert_eq!(x.map_err(stringify), Err("error: already started!".to_string()));
684 /// ```
685 #[inline]
686 pub fn map_err<F, O: FnOnce(Error) -> F>(self, op: O) -> Result<usize, F> {
687 self.into_result().map_err(op)
688 }
689
690 /// Calls a function with a reference to the contained value if current SBI call succeeded.
691 ///
692 /// Returns the original result.
693 ///
694 /// # Examples
695 ///
696 /// ```
697 /// # use sbi_spec::binary::SbiRet;
698 /// // Assume that SBI debug console have read 512 bytes into a buffer.
699 /// let ret = SbiRet::success(512);
700 /// // Inspect the SBI DBCN call result.
701 /// let idx = ret
702 /// .inspect(|x| println!("bytes written: {x}"))
703 /// .map(|x| x - 1)
704 /// .expect("SBI DBCN call failed");
705 /// assert_eq!(idx, 511);
706 /// ```
707 #[inline]
708 pub fn inspect<F: FnOnce(&usize)>(self, f: F) -> Self {
709 if let Ok(ref t) = self.into_result() {
710 f(t);
711 }
712
713 self
714 }
715
716 /// Calls a function with a reference to the contained value if current SBI result is an error.
717 ///
718 /// Returns the original result.
719 ///
720 /// # Examples
721 ///
722 /// ```
723 /// # use sbi_spec::binary::SbiRet;
724 /// // Assume that SBI debug console write operation failed for invalid parameter.
725 /// let ret = SbiRet::invalid_param();
726 /// // Print the error if SBI DBCN call failed.
727 /// let ret = ret.inspect_err(|e| eprintln!("failed to read from SBI console: {e:?}"));
728 /// ```
729 #[inline]
730 pub fn inspect_err<F: FnOnce(&Error)>(self, f: F) -> Self {
731 if let Err(ref e) = self.into_result() {
732 f(e);
733 }
734
735 self
736 }
737
738 // TODO: pub fn iter(&self) -> Iter
739 // TODO: pub fn iter_mut(&mut self) -> IterMut
740
741 /// Returns the contained success value, consuming the `self` value.
742 ///
743 /// # Panics
744 ///
745 /// Panics if self is an SBI error with a panic message including the
746 /// passed message, and the content of the SBI state.
747 ///
748 /// # Examples
749 ///
750 /// Basic usage:
751 ///
752 /// ```should_panic
753 /// # use sbi_spec::binary::SbiRet;
754 /// let x = SbiRet::already_stopped();
755 /// x.expect("Testing expect"); // panics with `Testing expect`
756 /// ```
757 #[inline]
758 pub fn expect(self, msg: &str) -> usize {
759 self.into_result().expect(msg)
760 }
761
762 /// Returns the contained success value, consuming the `self` value.
763 ///
764 /// # Panics
765 ///
766 /// Panics if self is an SBI error, with a panic message provided by the
767 /// SBI error converted into [`Error`] struct.
768 ///
769 /// # Examples
770 ///
771 /// Basic usage:
772 ///
773 /// ```
774 /// # use sbi_spec::binary::SbiRet;
775 /// let x = SbiRet::success(2);
776 /// assert_eq!(x.unwrap(), 2);
777 /// ```
778 ///
779 /// ```should_panic
780 /// # use sbi_spec::binary::SbiRet;
781 /// let x = SbiRet::failed();
782 /// x.unwrap(); // panics
783 /// ```
784 #[inline]
785 pub fn unwrap(self) -> usize {
786 self.into_result().unwrap()
787 }
788
789 // Note: No unwrap_or_default as we cannot determine a meaningful default value for a successful SbiRet.
790
791 /// Returns the contained error as [`Error`] struct, consuming the `self` value.
792 ///
793 /// # Panics
794 ///
795 /// Panics if the self is SBI success value, with a panic message
796 /// including the passed message, and the content of the success value.
797 ///
798 /// # Examples
799 ///
800 /// Basic usage:
801 ///
802 /// ```should_panic
803 /// # use sbi_spec::binary::SbiRet;
804 /// let x = SbiRet::success(10);
805 /// x.expect_err("Testing expect_err"); // panics with `Testing expect_err`
806 /// ```
807 #[inline]
808 pub fn expect_err(self, msg: &str) -> Error {
809 self.into_result().expect_err(msg)
810 }
811
812 /// Returns the contained error as [`Error`] struct, consuming the `self` value.
813 ///
814 /// # Panics
815 ///
816 /// Panics if the self is SBI success value, with a custom panic message provided
817 /// by the success value.
818 ///
819 /// # Examples
820 ///
821 /// ```should_panic
822 /// # use sbi_spec::binary::SbiRet;
823 /// let x = SbiRet::success(2);
824 /// x.unwrap_err(); // panics with `2`
825 /// ```
826 ///
827 /// ```
828 /// # use sbi_spec::binary::{SbiRet, Error};
829 /// let x = SbiRet::not_supported();
830 /// assert_eq!(x.unwrap_err(), Error::NotSupported);
831 /// ```
832 #[inline]
833 pub fn unwrap_err(self) -> Error {
834 self.into_result().unwrap_err()
835 }
836
837 // TODO: pub fn into_ok(self) -> usize and pub fn into_err(self) -> Error
838 // once `unwrap_infallible` is stabilized
839
840 /// Returns `res` if self is success value, otherwise otherwise returns the contained error
841 /// of `self` as [`Error`] struct.
842 ///
843 /// Arguments passed to `and` are eagerly evaluated; if you are passing the
844 /// result of a function call, it is recommended to use [`and_then`], which is
845 /// lazily evaluated.
846 ///
847 /// [`and_then`]: SbiRet::and_then
848 ///
849 /// # Examples
850 ///
851 /// Basic usage:
852 ///
853 /// ```
854 /// # use sbi_spec::binary::{SbiRet, Error};
855 /// let x = SbiRet::success(2);
856 /// let y = SbiRet::invalid_param().into_result();
857 /// assert_eq!(x.and(y), Err(Error::InvalidParam));
858 ///
859 /// let x = SbiRet::denied();
860 /// let y = SbiRet::success(3).into_result();
861 /// assert_eq!(x.and(y), Err(Error::Denied));
862 ///
863 /// let x = SbiRet::invalid_address();
864 /// let y = SbiRet::already_available().into_result();
865 /// assert_eq!(x.and(y), Err(Error::InvalidAddress));
866 ///
867 /// let x = SbiRet::success(4);
868 /// let y = SbiRet::success(5).into_result();
869 /// assert_eq!(x.and(y), Ok(5));
870 /// ```
871 // fixme: should be pub const fn once this function in Result is stabilized in constant
872 // fixme: should parameter be `res: SbiRet`?
873 #[inline]
874 pub fn and<U>(self, res: Result<U, Error>) -> Result<U, Error> {
875 self.into_result().and(res)
876 }
877
878 /// Calls `op` if self is success value, otherwise returns the contained error
879 /// as [`Error`] struct.
880 ///
881 /// This function can be used for control flow based on `SbiRet` values.
882 ///
883 /// # Examples
884 ///
885 /// ```
886 /// # use sbi_spec::binary::{SbiRet, Error};
887 /// fn sq_then_to_string(x: usize) -> Result<String, Error> {
888 /// x.checked_mul(x).map(|sq| sq.to_string()).ok_or(Error::Failed)
889 /// }
890 ///
891 /// assert_eq!(SbiRet::success(2).and_then(sq_then_to_string), Ok(4.to_string()));
892 /// assert_eq!(SbiRet::success(1_000_000_000_000).and_then(sq_then_to_string), Err(Error::Failed));
893 /// assert_eq!(SbiRet::invalid_param().and_then(sq_then_to_string), Err(Error::InvalidParam));
894 /// ```
895 #[inline]
896 pub fn and_then<U, F: FnOnce(usize) -> Result<U, Error>>(self, op: F) -> Result<U, Error> {
897 self.into_result().and_then(op)
898 }
899
900 /// Returns `res` if self is SBI error, otherwise returns the success value of `self`.
901 ///
902 /// Arguments passed to `or` are eagerly evaluated; if you are passing the
903 /// result of a function call, it is recommended to use [`or_else`], which is
904 /// lazily evaluated.
905 ///
906 /// [`or_else`]: Result::or_else
907 ///
908 /// # Examples
909 ///
910 /// Basic usage:
911 ///
912 /// ```
913 /// # use sbi_spec::binary::{SbiRet, Error};
914 /// let x = SbiRet::success(2);
915 /// let y = SbiRet::invalid_param().into_result();
916 /// assert_eq!(x.or(y), Ok(2));
917 ///
918 /// let x = SbiRet::denied();
919 /// let y = SbiRet::success(3).into_result();
920 /// assert_eq!(x.or(y), Ok(3));
921 ///
922 /// let x = SbiRet::invalid_address();
923 /// let y = SbiRet::already_available().into_result();
924 /// assert_eq!(x.or(y), Err(Error::AlreadyAvailable));
925 ///
926 /// let x = SbiRet::success(4);
927 /// let y = SbiRet::success(100).into_result();
928 /// assert_eq!(x.or(y), Ok(4));
929 /// ```
930 // fixme: should be pub const fn once this function in Result is stabilized in constant
931 // fixme: should parameter be `res: SbiRet`?
932 #[inline]
933 pub fn or<F>(self, res: Result<usize, F>) -> Result<usize, F> {
934 self.into_result().or(res)
935 }
936
937 /// Calls `op` if self is SBI error, otherwise returns the success value of `self`.
938 ///
939 /// This function can be used for control flow based on result values.
940 ///
941 ///
942 /// # Examples
943 ///
944 /// Basic usage:
945 ///
946 /// ```
947 /// # use sbi_spec::binary::{SbiRet, Error};
948 /// fn is_failed(x: Error) -> Result<usize, bool> { Err(x == Error::Failed) }
949 ///
950 /// assert_eq!(SbiRet::success(2).or_else(is_failed), Ok(2));
951 /// assert_eq!(SbiRet::failed().or_else(is_failed), Err(true));
952 /// ```
953 #[inline]
954 pub fn or_else<F, O: FnOnce(Error) -> Result<usize, F>>(self, op: O) -> Result<usize, F> {
955 self.into_result().or_else(op)
956 }
957
958 /// Returns the contained success value or a provided default.
959 ///
960 /// Arguments passed to `unwrap_or` are eagerly evaluated; if you are passing
961 /// the result of a function call, it is recommended to use [`unwrap_or_else`],
962 /// which is lazily evaluated.
963 ///
964 /// [`unwrap_or_else`]: SbiRet::unwrap_or_else
965 ///
966 /// # Examples
967 ///
968 /// Basic usage:
969 ///
970 /// ```
971 /// # use sbi_spec::binary::SbiRet;
972 /// let default = 2;
973 /// let x = SbiRet::success(9);
974 /// assert_eq!(x.unwrap_or(default), 9);
975 ///
976 /// let x = SbiRet::invalid_param();
977 /// assert_eq!(x.unwrap_or(default), default);
978 /// ```
979 // fixme: should be pub const fn once this function in Result is stabilized in constant
980 #[inline]
981 pub fn unwrap_or(self, default: usize) -> usize {
982 self.into_result().unwrap_or(default)
983 }
984
985 /// Returns the contained success value or computes it from a closure.
986 ///
987 /// # Examples
988 ///
989 /// Basic usage:
990 ///
991 /// ```
992 /// # use sbi_spec::binary::{SbiRet, Error};
993 /// fn invalid_use_zero(x: Error) -> usize { if x == Error::InvalidParam { 0 } else { 3 } }
994 ///
995 /// assert_eq!(SbiRet::success(2).unwrap_or_else(invalid_use_zero), 2);
996 /// assert_eq!(SbiRet::invalid_param().unwrap_or_else(invalid_use_zero), 0);
997 /// ```
998 #[inline]
999 pub fn unwrap_or_else<F: FnOnce(Error) -> usize>(self, op: F) -> usize {
1000 self.into_result().unwrap_or_else(op)
1001 }
1002
1003 /// Returns the contained success value, consuming the `self` value,
1004 /// without checking that the `SbiRet` contains an error value.
1005 ///
1006 /// # Safety
1007 ///
1008 /// Calling this method on an `SbiRet` containing an error value results
1009 /// in *undefined behavior*.
1010 ///
1011 /// # Examples
1012 ///
1013 /// ```
1014 /// # use sbi_spec::binary::{SbiRet, Error};
1015 /// let x = SbiRet::success(3);
1016 /// assert_eq!(unsafe { x.unwrap_unchecked() }, 3);
1017 /// ```
1018 ///
1019 /// ```no_run
1020 /// # use sbi_spec::binary::SbiRet;
1021 /// let x = SbiRet::no_shmem();
1022 /// unsafe { x.unwrap_unchecked(); } // Undefined behavior!
1023 /// ```
1024 #[inline]
1025 pub unsafe fn unwrap_unchecked(self) -> usize {
1026 unsafe { self.into_result().unwrap_unchecked() }
1027 }
1028
1029 /// Returns the contained `Error` value, consuming the `self` value,
1030 /// without checking that the `SbiRet` does not contain a success value.
1031 ///
1032 /// # Safety
1033 ///
1034 /// Calling this method on an `SbiRet` containing a success value results
1035 /// in *undefined behavior*.
1036 ///
1037 /// # Examples
1038 ///
1039 /// ```no_run
1040 /// # use sbi_spec::binary::SbiRet;
1041 /// let x = SbiRet::success(4);
1042 /// unsafe { x.unwrap_unchecked(); } // Undefined behavior!
1043 /// ```
1044 ///
1045 /// ```
1046 /// # use sbi_spec::binary::{SbiRet, Error};
1047 /// let x = SbiRet::failed();
1048 /// assert_eq!(unsafe { x.unwrap_err_unchecked() }, Error::Failed);
1049 /// ```
1050 #[inline]
1051 pub unsafe fn unwrap_err_unchecked(self) -> Error {
1052 unsafe { self.into_result().unwrap_err_unchecked() }
1053 }
1054}
1055
1056impl IntoIterator for SbiRet {
1057 type Item = usize;
1058 type IntoIter = core::result::IntoIter<usize>;
1059
1060 /// Returns a consuming iterator over the possibly contained value.
1061 ///
1062 /// The iterator yields one value if the result contains a success value, otherwise none.
1063 ///
1064 /// # Examples
1065 ///
1066 /// ```
1067 /// # use sbi_spec::binary::SbiRet;
1068 /// let x = SbiRet::success(5);
1069 /// let v: Vec<usize> = x.into_iter().collect();
1070 /// assert_eq!(v, [5]);
1071 ///
1072 /// let x = SbiRet::not_supported();
1073 /// let v: Vec<usize> = x.into_iter().collect();
1074 /// assert_eq!(v, []);
1075 /// ```
1076 #[inline]
1077 fn into_iter(self) -> Self::IntoIter {
1078 self.into_result().into_iter()
1079 }
1080}
1081
1082// TODO: implement Try and FromResidual for SbiRet once those traits are stabilized
1083/*
1084impl core::ops::Try for SbiRet {
1085 type Output = usize;
1086 type Residual = Result<core::convert::Infallible, Error>;
1087
1088 #[inline]
1089 fn from_output(output: Self::Output) -> Self {
1090 SbiRet::success(output)
1091 }
1092
1093 #[inline]
1094 fn branch(self) -> core::ops::ControlFlow<Self::Residual, Self::Output> {
1095 self.into_result().branch()
1096 }
1097}
1098
1099impl core::ops::FromResidual<Result<core::convert::Infallible, Error>> for SbiRet {
1100 #[inline]
1101 #[track_caller]
1102 fn from_residual(residual: Result<core::convert::Infallible, Error>) -> Self {
1103 match residual {
1104 Err(e) => e.into(),
1105 }
1106 }
1107}
1108
1109/// ```
1110/// # use sbi_spec::binary::SbiRet;
1111/// fn test() -> SbiRet {
1112/// let value = SbiRet::failed()?;
1113/// SbiRet::success(0)
1114/// }
1115/// assert_eq!(test(), SbiRet::failed());
1116/// ```
1117mod test_try_trait_for_sbiret {}
1118*/
1119
1120#[cfg(test)]
1121mod tests {
1122 use super::*;
1123
1124 #[test]
1125 #[rustfmt::skip]
1126 fn rustsbi_sbi_ret_constructors() {
1127 assert_eq!(SbiRet::success(0), SbiRet { value: 0, error: 0 });
1128 assert_eq!(SbiRet::success(1037), SbiRet { value: 1037, error: 0 });
1129 assert_eq!(SbiRet::success(usize::MAX), SbiRet { value: usize::MAX, error: 0 });
1130
1131 assert_eq!(SbiRet::failed(), SbiRet { value: 0, error: usize::MAX - 1 + 1 });
1132 assert_eq!(SbiRet::not_supported(), SbiRet { value: 0, error: usize::MAX - 2 + 1 });
1133 assert_eq!(SbiRet::invalid_param(), SbiRet { value: 0, error: usize::MAX - 3 + 1 });
1134 assert_eq!(SbiRet::denied(), SbiRet { value: 0, error: usize::MAX - 4 + 1 });
1135 assert_eq!(SbiRet::invalid_address(), SbiRet { value: 0, error: usize::MAX - 5 + 1 });
1136 assert_eq!(SbiRet::already_available(), SbiRet { value: 0, error: usize::MAX - 6 + 1 });
1137 assert_eq!(SbiRet::already_started(), SbiRet { value: 0, error: usize::MAX - 7 + 1 });
1138 assert_eq!(SbiRet::already_stopped(), SbiRet { value: 0, error: usize::MAX - 8 + 1 });
1139 assert_eq!(SbiRet::no_shmem(), SbiRet { value: 0, error: usize::MAX - 9 + 1 });
1140 assert_eq!(SbiRet::invalid_state(), SbiRet { value: 0, error: usize::MAX - 10 + 1 });
1141 assert_eq!(SbiRet::bad_range(), SbiRet { value: 0, error: usize::MAX - 11 + 1 });
1142 assert_eq!(SbiRet::timeout(), SbiRet { value: 0, error: usize::MAX - 12 + 1 });
1143 assert_eq!(SbiRet::io(), SbiRet { value: 0, error: usize::MAX - 13 + 1 });
1144 assert_eq!(SbiRet::denied_locked(), SbiRet { value: 0, error: usize::MAX - 14 + 1 });
1145 }
1146}