1 use super::{Error, Result};
2 use core::fmt::Debug;
3 
4 pub use uefi_raw::Status;
5 
6 /// Extension trait which provides some convenience methods for [`Status`].
7 pub trait StatusExt {
8     /// Converts this status code into a [`uefi::Result`].
9     ///
10     /// If the status does not indicate success, the status representing the specific error
11     /// code is embedded into the `Err` variant of type [`uefi::Error`].
to_result(self) -> Result12     fn to_result(self) -> Result;
13 
14     /// Converts this status code into a [`uefi::Result`] with a given `Ok` value.
15     ///
16     /// If the status does not indicate success, the status representing the specific error
17     /// code is embedded into the `Err` variant of type [`uefi::Error`].
to_result_with_val<T>(self, val: impl FnOnce() -> T) -> Result<T, ()>18     fn to_result_with_val<T>(self, val: impl FnOnce() -> T) -> Result<T, ()>;
19 
20     /// Converts this status code into a [`uefi::Result`] with a given `Err` payload.
21     ///
22     /// If the status does not indicate success, the status representing the specific error
23     /// code is embedded into the `Err` variant of type [`uefi::Error`].
to_result_with_err<ErrData: Debug>( self, err: impl FnOnce(Status) -> ErrData, ) -> Result<(), ErrData>24     fn to_result_with_err<ErrData: Debug>(
25         self,
26         err: impl FnOnce(Status) -> ErrData,
27     ) -> Result<(), ErrData>;
28 
29     /// Convert this status code into a result with a given `Ok` value and `Err` payload.
30     ///
31     /// If the status does not indicate success, the status representing the specific error
32     /// code is embedded into the `Err` variant of type [`uefi::Error`].
to_result_with<T, ErrData: Debug>( self, val: impl FnOnce() -> T, err: impl FnOnce(Status) -> ErrData, ) -> Result<T, ErrData>33     fn to_result_with<T, ErrData: Debug>(
34         self,
35         val: impl FnOnce() -> T,
36         err: impl FnOnce(Status) -> ErrData,
37     ) -> Result<T, ErrData>;
38 }
39 
40 impl StatusExt for Status {
41     #[inline]
to_result(self) -> Result42     fn to_result(self) -> Result {
43         if self.is_success() {
44             Ok(())
45         } else {
46             Err(self.into())
47         }
48     }
49 
50     #[inline]
to_result_with_val<T>(self, val: impl FnOnce() -> T) -> Result<T, ()>51     fn to_result_with_val<T>(self, val: impl FnOnce() -> T) -> Result<T, ()> {
52         if self.is_success() {
53             Ok(val())
54         } else {
55             Err(self.into())
56         }
57     }
58 
59     #[inline]
to_result_with_err<ErrData: Debug>( self, err: impl FnOnce(Self) -> ErrData, ) -> Result<(), ErrData>60     fn to_result_with_err<ErrData: Debug>(
61         self,
62         err: impl FnOnce(Self) -> ErrData,
63     ) -> Result<(), ErrData> {
64         if self.is_success() {
65             Ok(())
66         } else {
67             Err(Error::new(self, err(self)))
68         }
69     }
70 
71     #[inline]
to_result_with<T, ErrData: Debug>( self, val: impl FnOnce() -> T, err: impl FnOnce(Self) -> ErrData, ) -> Result<T, ErrData>72     fn to_result_with<T, ErrData: Debug>(
73         self,
74         val: impl FnOnce() -> T,
75         err: impl FnOnce(Self) -> ErrData,
76     ) -> Result<T, ErrData> {
77         if self.is_success() {
78             Ok(val())
79         } else {
80             Err(Error::new(self, err(self)))
81         }
82     }
83 }
84 
85 #[cfg(test)]
86 mod tests {
87     use super::*;
88 
89     #[test]
test_status_to_result()90     fn test_status_to_result() {
91         assert!(Status::SUCCESS.to_result().is_ok());
92         assert!(Status::WARN_DELETE_FAILURE.to_result().is_err());
93         assert!(Status::BUFFER_TOO_SMALL.to_result().is_err());
94 
95         assert_eq!(Status::SUCCESS.to_result_with_val(|| 123).unwrap(), 123);
96         assert!(Status::WARN_DELETE_FAILURE
97             .to_result_with_val(|| 123)
98             .is_err());
99         assert!(Status::BUFFER_TOO_SMALL.to_result_with_val(|| 123).is_err());
100 
101         assert!(Status::SUCCESS.to_result_with_err(|_| 123).is_ok());
102         assert_eq!(
103             *Status::WARN_DELETE_FAILURE
104                 .to_result_with_err(|_| 123)
105                 .unwrap_err()
106                 .data(),
107             123
108         );
109         assert_eq!(
110             *Status::BUFFER_TOO_SMALL
111                 .to_result_with_err(|_| 123)
112                 .unwrap_err()
113                 .data(),
114             123
115         );
116 
117         assert_eq!(
118             Status::SUCCESS.to_result_with(|| 123, |_| 456).unwrap(),
119             123
120         );
121         assert_eq!(
122             *Status::WARN_DELETE_FAILURE
123                 .to_result_with(|| 123, |_| 456)
124                 .unwrap_err()
125                 .data(),
126             456
127         );
128         assert_eq!(
129             *Status::BUFFER_TOO_SMALL
130                 .to_result_with(|| 123, |_| 456)
131                 .unwrap_err()
132                 .data(),
133             456
134         );
135     }
136 }
137