#[cfg(feature = "std")]
extern crate std;
use core::fmt;
cfg_if::cfg_if!(
if #[cfg(target_os = "uefi")] {
type RawOsError = usize;
type NonZeroRawOsError = core::num::NonZeroUsize;
const UEFI_ERROR_FLAG: RawOsError = 1 << (RawOsError::BITS - 1);
} else {
type RawOsError = i32;
type NonZeroRawOsError = core::num::NonZeroI32;
}
);
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Error(NonZeroRawOsError);
impl Error {
pub const UNSUPPORTED: Error = Self::new_internal(0);
pub const ERRNO_NOT_POSITIVE: Error = Self::new_internal(1);
pub const UNEXPECTED: Error = Self::new_internal(2);
const INTERNAL_START: RawOsError = 1 << 16;
const CUSTOM_START: RawOsError = 1 << 17;
#[cfg(not(target_os = "uefi"))]
#[allow(dead_code)]
pub(super) fn from_neg_error_code(code: RawOsError) -> Self {
if code < 0 {
let code = NonZeroRawOsError::new(code).expect("`code` is negative");
Self(code)
} else {
Error::UNEXPECTED
}
}
#[cfg(target_os = "uefi")]
#[allow(dead_code)]
pub(super) fn from_uefi_code(code: RawOsError) -> Self {
if code & UEFI_ERROR_FLAG != 0 {
let code = NonZeroRawOsError::new(code).expect("The highest bit of `code` is set to 1");
Self(code)
} else {
Self::UNEXPECTED
}
}
#[inline]
pub fn raw_os_error(self) -> Option<RawOsError> {
let code = self.0.get();
#[cfg(target_os = "uefi")]
{
if code & UEFI_ERROR_FLAG != 0 {
Some(code)
} else {
None
}
}
#[cfg(not(target_os = "uefi"))]
{
if code >= 0 {
None
} else if cfg!(not(target_os = "solid_asp3")) {
code.checked_neg()
} else {
Some(code)
}
}
}
pub const fn new_custom(n: u16) -> Error {
let code = Error::CUSTOM_START + (n as RawOsError);
Error(unsafe { NonZeroRawOsError::new_unchecked(code) })
}
pub(crate) const fn new_internal(n: u16) -> Error {
let code = Error::INTERNAL_START + (n as RawOsError);
Error(unsafe { NonZeroRawOsError::new_unchecked(code) })
}
fn internal_desc(&self) -> Option<&'static str> {
let desc = match *self {
Error::UNSUPPORTED => "getrandom: this target is not supported",
Error::ERRNO_NOT_POSITIVE => "errno: did not return a positive value",
Error::UNEXPECTED => "unexpected situation",
#[cfg(any(
target_os = "ios",
target_os = "visionos",
target_os = "watchos",
target_os = "tvos",
))]
Error::IOS_RANDOM_GEN => "SecRandomCopyBytes: iOS Security framework failure",
#[cfg(all(windows, target_vendor = "win7"))]
Error::WINDOWS_RTL_GEN_RANDOM => "RtlGenRandom: Windows system function failure",
#[cfg(all(feature = "wasm_js", getrandom_backend = "wasm_js"))]
Error::WEB_CRYPTO => "Web Crypto API is unavailable",
#[cfg(target_os = "vxworks")]
Error::VXWORKS_RAND_SECURE => "randSecure: VxWorks RNG module is not initialized",
#[cfg(any(
getrandom_backend = "rdrand",
all(target_arch = "x86_64", target_env = "sgx")
))]
Error::FAILED_RDRAND => "RDRAND: failed multiple times: CPU issue likely",
#[cfg(any(
getrandom_backend = "rdrand",
all(target_arch = "x86_64", target_env = "sgx")
))]
Error::NO_RDRAND => "RDRAND: instruction not supported",
#[cfg(getrandom_backend = "rndr")]
Error::RNDR_FAILURE => "RNDR: Could not generate a random number",
#[cfg(getrandom_backend = "rndr")]
Error::RNDR_NOT_AVAILABLE => "RNDR: Register not supported",
_ => return None,
};
Some(desc)
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut dbg = f.debug_struct("Error");
if let Some(errno) = self.raw_os_error() {
dbg.field("os_error", &errno);
#[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());
dbg.field("description", &desc);
} else {
dbg.field("unknown_code", &self.0.get());
}
dbg.finish()
}
}
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(feature = "std")] {
std::io::Error::from_raw_os_error(errno).fmt(f)
} else {
write!(f, "OS Error: {errno}")
}
}
} else if let Some(desc) = self.internal_desc() {
f.write_str(desc)
} else {
write!(f, "Unknown Error: {}", self.0.get())
}
}
}