Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Error::raw_os_error to return non-i32 codes #569

Merged
merged 3 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 29 additions & 12 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,27 @@ 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| {
pub fn raw_os_error(self) -> Option<RawOsError> {
let code = self.0.get();
if code < Self::INTERNAL_START {
let res = RawOsError::try_from(code).ok();
// On SOLID, negate the error code again to obtain the original error code.
if cfg!(target_os = "solid_asp3") {
-errno
} else {
errno
}
})
#[cfg(target_os = "solid_asp3")]
let res = res.map(|errno| -errno);
res
} else {
None
}
newpavlov marked this conversation as resolved.
Show resolved Hide resolved
}

/// Creates a new instance of an `Error` from a particular custom error code.
Expand Down Expand Up @@ -134,7 +151,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 +167,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