1 | ///! Facilities for dealing with UEFI operation results. |
2 | use core::fmt::Debug; |
3 | |
4 | /// The error type that we use, essentially a status code + optional additional data |
5 | mod error; |
6 | pub use self::error::Error; |
7 | |
8 | /// Definition of UEFI's standard status codes |
9 | mod status; |
10 | pub use self::status::Status; |
11 | |
12 | /// Return type of most UEFI functions. Both success and error payloads are optional. |
13 | /// |
14 | /// Almost all UEFI operations provide a status code as an output which |
15 | /// indicates either success, a warning, or an error. This type alias maps |
16 | /// [`Status::SUCCESS`] to the `Ok` variant (with optional `Output` data), and |
17 | /// maps both warning and error statuses to the `Err` variant of type [`Error`], |
18 | /// which may carry optional inner `ErrData`. |
19 | /// |
20 | /// Warnings are treated as errors by default because they generally indicate |
21 | /// an abnormal situation. |
22 | /// |
23 | /// Some convenience methods are provided by the [`ResultExt`] trait. |
24 | pub type Result<Output = (), ErrData = ()> = core::result::Result<Output, Error<ErrData>>; |
25 | |
26 | /// Extension trait which provides some convenience methods for [`Result`]. |
27 | pub trait ResultExt<Output, ErrData: Debug> { |
28 | /// Extract the UEFI status from this result |
29 | fn status(&self) -> Status; |
30 | |
31 | /// Transform the ErrData value to () |
32 | fn discard_errdata(self) -> Result<Output>; |
33 | |
34 | /// Calls `op` if the result contains a warning, otherwise returns |
35 | /// the result unchanged. |
36 | /// |
37 | /// By default warning statuses are treated as errors (i.e. stored in the |
38 | /// `Err` variant) because they generally indicate an abnormal |
39 | /// situation. In rare cases though it may be helpful to handle a |
40 | /// warning. This method is similar to [`Result::or_else`], except that |
41 | /// `op` is called only when the status is a warning. |
42 | /// |
43 | /// # Example |
44 | /// |
45 | /// ``` |
46 | /// use uefi::{Result, ResultExt, Status}; |
47 | /// |
48 | /// # fn x() -> uefi::Result { |
49 | /// # let some_result = Result::from(Status::WARN_RESET_REQUIRED); |
50 | /// // Treat a specific warning as success, propagate others as errors. |
51 | /// some_result.handle_warning(|err| { |
52 | /// if err.status() == Status::WARN_RESET_REQUIRED { |
53 | /// Ok(()) |
54 | /// } else { |
55 | /// Err(err) |
56 | /// } |
57 | /// })?; |
58 | /// # Status::SUCCESS.into() |
59 | /// # } |
60 | /// ``` |
61 | fn handle_warning<O>(self, op: O) -> Result<Output, ErrData> |
62 | where |
63 | O: FnOnce(Error<ErrData>) -> Result<Output, ErrData>; |
64 | } |
65 | |
66 | impl<Output, ErrData: Debug> ResultExt<Output, ErrData> for Result<Output, ErrData> { |
67 | fn status(&self) -> Status { |
68 | match self { |
69 | Ok(_) => Status::SUCCESS, |
70 | Err(e) => e.status(), |
71 | } |
72 | } |
73 | |
74 | fn discard_errdata(self) -> Result<Output> { |
75 | match self { |
76 | Ok(o) => Ok(o), |
77 | Err(e) => Err(e.status().into()), |
78 | } |
79 | } |
80 | |
81 | fn handle_warning<O>(self, op: O) -> Result<Output, ErrData> |
82 | where |
83 | O: FnOnce(Error<ErrData>) -> Result<Output, ErrData>, |
84 | { |
85 | match self { |
86 | Ok(output) => Ok(output), |
87 | Err(err) => { |
88 | if err.status().is_warning() { |
89 | op(err) |
90 | } else { |
91 | Err(err) |
92 | } |
93 | } |
94 | } |
95 | } |
96 | } |
97 | |