Skip to content

Commit

Permalink
Allow Error::raw_os_error to return non-i32 codes (#569)
Browse files Browse the repository at this point in the history
This allows us to remove some UEFI-specific exceptions from the code.

This PR only partially resolves #568 since we still use `NonZeroU32` on
UEFI targets, but it should be sufficient to future-proof ourselves for
the v0.3 release.
  • Loading branch information
newpavlov authored Dec 18, 2024
1 parent e27f6ec commit dc89211
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 18 deletions.
41 changes: 28 additions & 13 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@ extern crate std;

use core::{fmt, num::NonZeroU32};

// This private alias mirrors `std::io::RawOsError`:
// https://doc.rust-lang.org/std/io/type.RawOsError.html)
cfg_if::cfg_if!(
if #[cfg(target_os = "uefi")] {
type RawOsError = usize;
} else {
type RawOsError = i32;
}
);

/// A small and `no_std` compatible error type
///
/// The [`Error::raw_os_error()`] will indicate if the error is from the OS, and
Expand Down Expand Up @@ -57,20 +67,25 @@ impl Error {
/// Extract the raw OS error code (if this error came from the OS)
///
/// This method is identical to [`std::io::Error::raw_os_error()`][1], except
/// that it works in `no_std` contexts. If this method returns `None`, the
/// error value can still be formatted via the `Display` implementation.
/// that it works in `no_std` contexts. On most targets this method returns
/// `Option<i32>`, but some platforms (e.g. UEFI) may use a different primitive
/// type like `usize`. Consult with the [`RawOsError`] docs for more information.
///
/// If this method returns `None`, the error value can still be formatted via
/// the `Display` implementation.
///
/// [1]: https://doc.rust-lang.org/std/io/struct.Error.html#method.raw_os_error
/// [`RawOsError`]: https://doc.rust-lang.org/std/io/type.RawOsError.html
#[inline]
pub fn raw_os_error(self) -> Option<i32> {
i32::try_from(self.0.get()).ok().map(|errno| {
// On SOLID, negate the error code again to obtain the original error code.
if cfg!(target_os = "solid_asp3") {
-errno
} else {
errno
}
})
pub fn raw_os_error(self) -> Option<RawOsError> {
let code = self.0.get();
if code >= Self::INTERNAL_START {
return None;
}
let errno = RawOsError::try_from(code).ok()?;
#[cfg(target_os = "solid_asp3")]
let errno = -errno;
Some(errno)
}

/// Creates a new instance of an `Error` from a particular custom error code.
Expand Down Expand Up @@ -134,7 +149,7 @@ impl fmt::Debug for Error {
let mut dbg = f.debug_struct("Error");
if let Some(errno) = self.raw_os_error() {
dbg.field("os_error", &errno);
#[cfg(all(feature = "std", not(target_os = "uefi")))]
#[cfg(feature = "std")]
dbg.field("description", &std::io::Error::from_raw_os_error(errno));
} else if let Some(desc) = self.internal_desc() {
dbg.field("internal_code", &self.0.get());
Expand All @@ -150,7 +165,7 @@ impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(errno) = self.raw_os_error() {
cfg_if! {
if #[cfg(all(feature = "std", not(target_os = "uefi")))] {
if #[cfg(feature = "std")] {
std::io::Error::from_raw_os_error(errno).fmt(f)
} else {
write!(f, "OS Error: {}", errno)
Expand Down
5 changes: 0 additions & 5 deletions src/error_std_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,10 @@ use std::io;

impl From<Error> for io::Error {
fn from(err: Error) -> Self {
#[cfg(not(target_os = "uefi"))]
match err.raw_os_error() {
Some(errno) => io::Error::from_raw_os_error(errno),
None => io::Error::new(io::ErrorKind::Other, err),
}
#[cfg(target_os = "uefi")]
{
io::Error::new(io::ErrorKind::Other, err)
}
}
}

Expand Down

0 comments on commit dc89211

Please sign in to comment.