use super::Status;
use log::warn;
#[must_use]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Completion<T> {
status: Status,
result: T,
}
impl<T> Completion<T> {
pub fn new(status: Status, result: T) -> Self {
if status.is_error() {
built_with_error(status);
}
Self { status, result }
}
pub fn status(&self) -> Status {
self.status
}
pub fn split(self) -> (Status, T) {
(self.status, self.result)
}
pub fn log(self) -> T {
if self.status != Status::SUCCESS {
log_warning(self.status);
}
self.result
}
pub fn unwrap(self) -> T {
if self.status != Status::SUCCESS {
unwrap_failed(
"Called `Completion::unwrap()` with a warning status",
self.status,
);
}
self.result
}
pub fn expect(self, msg: &str) -> T {
if self.status != Status::SUCCESS {
unwrap_failed(msg, self.status);
}
self.result
}
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Completion<U> {
Completion {
status: self.status,
result: f(self.result),
}
}
pub fn with_status(self, extra_status: Status) -> Self {
if extra_status.is_success() {
self
} else {
Completion::new(extra_status, self.log())
}
}
}
impl From<Status> for Completion<()> {
fn from(status: Status) -> Self {
Completion::new(status, ())
}
}
impl<T> From<T> for Completion<T> {
fn from(result: T) -> Self {
Completion::new(Status::SUCCESS, result)
}
}
#[inline(never)]
#[cold]
fn built_with_error(error: Status) -> ! {
panic!(
"Completion was incorrectly built with error status: {:?}",
error
)
}
#[inline(never)]
#[cold]
fn unwrap_failed(msg: &str, warning: Status) -> ! {
panic!("{}: {:?}", msg, warning)
}
#[inline(never)]
#[cold]
fn log_warning(warning: Status) {
warn!("Encountered UEFI warning: {:?}", warning)
}