nx/
result.rs

1//! Common result support
2
3use core::fmt;
4use core::result;
5
6use nx_derive::{Request, Response};
7
8const MODULE_BITS: u32 = 9;
9const DESCRIPTION_BITS: u32 = 13;
10const DEFAULT_VALUE: u32 = 0;
11const SUCCESS_VALUE: u32 = DEFAULT_VALUE;
12
13#[inline]
14const fn pack_value(module: u32, description: u32) -> u32 {
15    module | (description << MODULE_BITS)
16}
17
18#[inline]
19const fn unpack_module(value: u32) -> u32 {
20    value & !(!DEFAULT_VALUE << MODULE_BITS)
21}
22
23#[inline]
24const fn unpack_description(value: u32) -> u32 {
25    (value >> MODULE_BITS) & !(!DEFAULT_VALUE << DESCRIPTION_BITS)
26}
27
28/// Represents a (raw) result value used all over the OS
29///
30/// These are referred as `Result` on docs/official code, but we intentionally name it as [`ResultCode`] to distinguish it from the [`Result`] enum type
31///
32/// Results are often displayed/shown, for example, like `2168-0002`, which corresponds to `<2000 + module>-<description>`
33///
34/// [`Debug`][`fmt::Debug`] formatting formats the results as a hex-value (`0x4A8`), while [`Display`][`fmt::Display`] formatting formats the result in the format described above (`2168-0002`)
35#[derive(Request, Response, Copy, Clone, PartialEq, Eq, Default)]
36#[repr(C)]
37pub struct ResultCode {
38    value: u32,
39}
40
41impl ResultCode {
42    /// Creates a [`ResultCode`] from a raw value
43    ///
44    /// # Arguments
45    ///
46    /// * `value`: The raw value
47    #[inline]
48    pub const fn new(value: u32) -> Self {
49        Self { value }
50    }
51
52    /// Wrapper for creating a new [`Result::Err`] value with the following raw result
53    ///
54    /// # Arguments
55    ///
56    /// * `value`: The raw value, note that it mustn't be `0`/success (that would be undefined behavior)
57    #[inline]
58    pub const fn new_err<T>(value: u32) -> Result<T> {
59        Err(Self::new(value))
60    }
61
62    /// Returns whether the [`ResultCode`] is successful
63    ///
64    /// A result value of `0` is a successful value, this essentially checks that
65    #[inline]
66    pub const fn is_success(&self) -> bool {
67        self.value == SUCCESS_VALUE
68    }
69
70    /// Returns whether the [`ResultCode`] is not successful
71    ///
72    /// This is the exact opposite of [`is_success`][`ResultCode::is_success`]
73    #[inline]
74    pub const fn is_failure(&self) -> bool {
75        !self.is_success()
76    }
77
78    /// Gets the raw value of the [`ResultCode`]
79    #[inline]
80    pub const fn get_value(&self) -> u32 {
81        self.value
82    }
83
84    /// Gets the module of the [`ResultCode`]
85    #[inline]
86    pub const fn get_module(&self) -> u32 {
87        unpack_module(self.value)
88    }
89
90    /// Gets the description of the [`ResultCode`]
91    #[inline]
92    pub const fn get_description(&self) -> u32 {
93        unpack_description(self.value)
94    }
95}
96
97impl fmt::Debug for ResultCode {
98    fn fmt(&self, fmt: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
99        write!(fmt, "{:#X}", self.value)
100    }
101}
102
103impl fmt::Display for ResultCode {
104    fn fmt(&self, fmt: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
105        write!(
106            fmt,
107            "{:0>4}-{:0>4}",
108            2000 + self.get_module(),
109            self.get_description()
110        )
111    }
112}
113
114/// Represents a result holding a certain value or a  [`ResultCode`] as an indication of failure
115pub type Result<T> = result::Result<T, ResultCode>;
116
117/// Produces a `Result` whose value will depend on whether the supplied [`ResultCode`] was successful
118///
119/// # Arguments
120///
121/// * `rc`: The [`ResultCode`] value
122/// * `value`: The value to pack if the [`ResultCode`] is successful
123#[inline(always)]
124pub fn pack<T>(rc: ResultCode, value: T) -> Result<T> {
125    if rc.is_success() { Ok(value) } else { Err(rc) }
126}
127
128/// Produces the [`ResultCode`] corresponding to a packed result
129///
130/// # Arguments
131///
132/// * `rc`: The [`Result`] to unpack
133#[inline(always)]
134pub fn unpack<T>(rc: &Result<T>) -> ResultCode {
135    match rc {
136        Ok(_) => ResultSuccess::make(),
137        Err(rc) => *rc,
138    }
139}
140
141/// Represents a base trait for result value definitions to follow
142pub trait ResultBase {
143    /// Gets the result definition's module
144    fn get_module() -> u32;
145
146    /// Gets the result definition's description
147    fn get_description() -> u32;
148
149    /// Gets the result definition's raw value
150    #[inline(always)]
151    fn get_value() -> u32 {
152        pack_value(Self::get_module(), Self::get_description())
153    }
154
155    /// Produces a [`ResultCode`] from this result definition
156    #[inline(always)]
157    fn make() -> ResultCode {
158        ResultCode::new(Self::get_value())
159    }
160
161    /// Produces a [`Result::Err`] value from this result definition
162    #[inline(always)]
163    fn make_err<T>() -> Result<T> {
164        ResultCode::new_err(Self::get_value())
165    }
166
167    /// Returns whether the given [`ResultCode`] matches this result definition
168    ///
169    /// # Arguments
170    ///
171    /// * `rc`: The [`ResultCode`] to check
172    #[inline(always)]
173    fn matches(rc: ResultCode) -> bool {
174        rc.get_value() == Self::get_value()
175    }
176}
177
178// TODO: document all results? are the names not explicit enough?
179
180result_define! {
181    Success: 0, 0
182}