|
1 |
| -use core::result; |
2 |
| -use log::warn; |
3 |
| - |
4 | 1 | /// Definition of UEFI's standard status codes
|
5 | 2 | mod status;
|
6 | 3 | pub use self::status::Status;
|
7 | 4 |
|
8 |
| -/// This type is used when an UEFI operation has completed, but some non-fatal |
9 |
| -/// problems may have been encountered along the way |
10 |
| -#[must_use] |
11 |
| -#[derive(Clone, Copy, Debug, PartialEq)] |
12 |
| -pub enum Completion<T> { |
13 |
| - /// The operation completed without problems |
14 |
| - Success(T), |
| 5 | +/// Completions are used to model operations which have completed, but may have |
| 6 | +/// encountered non-fatal errors ("warnings") along the way |
| 7 | +mod completion; |
| 8 | +pub use self::completion::Completion; |
15 | 9 |
|
16 |
| - /// The operation completed, but some non-fatal issues were encountered |
17 |
| - Warning(T, Status), |
18 |
| -} |
| 10 | +/// Return type of many UEFI functions. |
| 11 | +pub type Result<T> = core::result::Result<Completion<T>, Status>; |
19 | 12 |
|
20 |
| -impl<T> Completion<T> { |
21 |
| - /// Split the completion into a (status, value) pair |
22 |
| - pub fn split(self) -> (T, Status) { |
23 |
| - match self { |
24 |
| - Completion::Success(res) => (res, Status::SUCCESS), |
25 |
| - Completion::Warning(res, stat) => (res, stat), |
26 |
| - } |
27 |
| - } |
| 13 | +/// Extension trait for Result which helps dealing with UEFI's warnings |
| 14 | +pub trait ResultExt<T> { |
| 15 | + /// Treat warnings as errors |
| 16 | + fn warn_error(self) -> core::result::Result<T, Status>; |
28 | 17 |
|
29 |
| - /// Access the inner value, logging the warning if there is any |
30 |
| - pub fn value(self) -> T { |
31 |
| - match self { |
32 |
| - Completion::Success(res) => res, |
33 |
| - Completion::Warning(res, stat) => { |
34 |
| - warn!("Encountered UEFI warning: {:?}", stat); |
35 |
| - res |
36 |
| - } |
37 |
| - } |
38 |
| - } |
| 18 | + /// Ignore warnings, keepint a trace of them in the logs |
| 19 | + fn warn_log(self) -> core::result::Result<T, Status>; |
39 | 20 |
|
40 |
| - /// Assume that no warning occured, panic if not |
41 |
| - pub fn unwrap(self) -> T { |
42 |
| - match self { |
43 |
| - Completion::Success(res) => res, |
44 |
| - Completion::Warning(_, w) => { |
45 |
| - unwrap_failed("Called `Completion::unwrap()` on a `Warning` value", w) |
46 |
| - } |
47 |
| - } |
48 |
| - } |
| 21 | + /// Expect success without warnings, panic otherwise |
| 22 | + fn warn_unwrap(self) -> T; |
49 | 23 |
|
50 |
| - /// Assume that no warning occured, panic with provided message if not |
51 |
| - pub fn expect(self, msg: &str) -> T { |
52 |
| - match self { |
53 |
| - Completion::Success(res) => res, |
54 |
| - Completion::Warning(_, w) => unwrap_failed(msg, w), |
55 |
| - } |
56 |
| - } |
| 24 | + /// Expect success without warnings, panic with provided message otherwise |
| 25 | + fn warn_expect(self, msg: &str) -> T; |
| 26 | +} |
57 | 27 |
|
58 |
| - /// Transform the inner value without unwrapping the Completion |
59 |
| - pub fn map<U>(self, f: impl Fn(T) -> U) -> Completion<U> { |
| 28 | +impl<T> ResultExt<T> for Result<T> { |
| 29 | + fn warn_error(self) -> core::result::Result<T, Status> { |
60 | 30 | match self {
|
61 |
| - Completion::Success(res) => Completion::Success(f(res)), |
62 |
| - Completion::Warning(res, stat) => Completion::Warning(f(res), stat), |
| 31 | + Ok(Completion::Success(v)) => Ok(v), |
| 32 | + Ok(Completion::Warning(_, s)) => Err(s), |
| 33 | + Err(s) => Err(s), |
63 | 34 | }
|
64 | 35 | }
|
65 | 36 |
|
66 |
| - /// Merge this completion with a success or warning status |
67 |
| - /// |
68 |
| - /// Since this type only has storage for one warning, if two warnings must |
69 |
| - /// be stored, one of them will be spilled into the logs. |
70 |
| - /// |
71 |
| - pub fn with_warning(self, extra_stat: Status) -> Self { |
72 |
| - match self { |
73 |
| - Completion::Success(res) => { |
74 |
| - if extra_stat.is_success() { |
75 |
| - Completion::Success(res) |
76 |
| - } else { |
77 |
| - Completion::Warning(res, extra_stat) |
78 |
| - } |
79 |
| - } |
80 |
| - Completion::Warning(res, stat) => { |
81 |
| - if extra_stat.is_success() { |
82 |
| - Completion::Warning(res, stat) |
83 |
| - } else { |
84 |
| - warn!("Encountered UEFI warning {:?}", stat); |
85 |
| - Completion::Warning(res, extra_stat) |
86 |
| - } |
87 |
| - } |
88 |
| - } |
| 37 | + fn warn_log(self) -> core::result::Result<T, Status> { |
| 38 | + self.map(|completion| completion.value()) |
89 | 39 | }
|
90 |
| -} |
91 | 40 |
|
92 |
| -impl<T> From<T> for Completion<T> { |
93 |
| - fn from(res: T) -> Self { |
94 |
| - Completion::Success(res) |
| 41 | + fn warn_unwrap(self) -> T { |
| 42 | + self.unwrap().unwrap() |
95 | 43 | }
|
96 |
| -} |
97 | 44 |
|
98 |
| -// This is a separate function to reduce the code size of the methods |
99 |
| -#[inline(never)] |
100 |
| -#[cold] |
101 |
| -fn unwrap_failed(msg: &str, warning: Status) -> ! { |
102 |
| - panic!("{}: {:?}", msg, warning) |
| 45 | + fn warn_expect(self, msg: &str) -> T { |
| 46 | + self.expect(msg).expect(msg) |
| 47 | + } |
103 | 48 | }
|
104 |
| - |
105 |
| -/// Return type of many UEFI functions. |
106 |
| -pub type Result<T> = result::Result<Completion<T>, Status>; |
0 commit comments