Skip to main content

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}