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