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}