1#[cfg(feature = "std")]
2extern crate std;
3
4use core::{fmt, num::NonZeroU32};
5
6cfg_if::cfg_if!(
9 if #[cfg(target_os = "uefi")] {
10 type RawOsError = usize;
11 } else {
12 type RawOsError = i32;
13 }
14);
15
16#[derive(Copy, Clone, Eq, PartialEq)]
31pub struct Error(NonZeroU32);
32
33impl Error {
34 pub const UNSUPPORTED: Error = Self::new_internal(0);
36 pub const ERRNO_NOT_POSITIVE: Error = Self::new_internal(1);
38 pub const UNEXPECTED: Error = Self::new_internal(2);
40
41 pub const INTERNAL_START: u32 = 1 << 31;
45
46 pub const CUSTOM_START: u32 = (1 << 31) + (1 << 30);
49
50 #[allow(dead_code)]
60 pub(super) fn from_os_error(code: u32) -> Self {
61 match NonZeroU32::new(code) {
62 Some(code) if code.get() < Self::INTERNAL_START => Self(code),
63 _ => Self::UNEXPECTED,
64 }
65 }
66
67 #[inline]
80 pub fn raw_os_error(self) -> Option<RawOsError> {
81 let code = self.0.get();
82 if code >= Self::INTERNAL_START {
83 return None;
84 }
85 let errno = RawOsError::try_from(code).ok()?;
86 #[cfg(target_os = "solid_asp3")]
87 let errno = -errno;
88 Some(errno)
89 }
90
91 pub const fn new_custom(n: u16) -> Error {
93 let code = Error::CUSTOM_START + (n as u32);
95 Error(unsafe { NonZeroU32::new_unchecked(code) })
96 }
97
98 pub(crate) const fn new_internal(n: u16) -> Error {
100 let code = Error::INTERNAL_START + (n as u32);
102 Error(unsafe { NonZeroU32::new_unchecked(code) })
103 }
104
105 fn internal_desc(&self) -> Option<&'static str> {
106 let desc = match *self {
107 Error::UNSUPPORTED => "getrandom: this target is not supported",
108 Error::ERRNO_NOT_POSITIVE => "errno: did not return a positive value",
109 Error::UNEXPECTED => "unexpected situation",
110 #[cfg(any(
111 target_os = "ios",
112 target_os = "visionos",
113 target_os = "watchos",
114 target_os = "tvos",
115 ))]
116 Error::IOS_RANDOM_GEN => "SecRandomCopyBytes: iOS Security framework failure",
117 #[cfg(all(windows, target_vendor = "win7"))]
118 Error::WINDOWS_RTL_GEN_RANDOM => "RtlGenRandom: Windows system function failure",
119 #[cfg(all(feature = "wasm_js", getrandom_backend = "wasm_js"))]
120 Error::WEB_CRYPTO => "Web Crypto API is unavailable",
121 #[cfg(target_os = "vxworks")]
122 Error::VXWORKS_RAND_SECURE => "randSecure: VxWorks RNG module is not initialized",
123
124 #[cfg(any(
125 getrandom_backend = "rdrand",
126 all(target_arch = "x86_64", target_env = "sgx")
127 ))]
128 Error::FAILED_RDRAND => "RDRAND: failed multiple times: CPU issue likely",
129 #[cfg(any(
130 getrandom_backend = "rdrand",
131 all(target_arch = "x86_64", target_env = "sgx")
132 ))]
133 Error::NO_RDRAND => "RDRAND: instruction not supported",
134
135 #[cfg(getrandom_backend = "rndr")]
136 Error::RNDR_FAILURE => "RNDR: Could not generate a random number",
137 #[cfg(getrandom_backend = "rndr")]
138 Error::RNDR_NOT_AVAILABLE => "RNDR: Register not supported",
139 _ => return None,
140 };
141 Some(desc)
142 }
143}
144
145impl fmt::Debug for Error {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147 let mut dbg = f.debug_struct("Error");
148 if let Some(errno) = self.raw_os_error() {
149 dbg.field("os_error", &errno);
150 #[cfg(feature = "std")]
151 dbg.field("description", &std::io::Error::from_raw_os_error(errno));
152 } else if let Some(desc) = self.internal_desc() {
153 dbg.field("internal_code", &self.0.get());
154 dbg.field("description", &desc);
155 } else {
156 dbg.field("unknown_code", &self.0.get());
157 }
158 dbg.finish()
159 }
160}
161
162impl fmt::Display for Error {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 if let Some(errno) = self.raw_os_error() {
165 cfg_if! {
166 if #[cfg(feature = "std")] {
167 std::io::Error::from_raw_os_error(errno).fmt(f)
168 } else {
169 write!(f, "OS Error: {}", errno)
170 }
171 }
172 } else if let Some(desc) = self.internal_desc() {
173 f.write_str(desc)
174 } else {
175 write!(f, "Unknown Error: {}", self.0.get())
176 }
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use super::Error;
183 use core::mem::size_of;
184
185 #[test]
186 fn test_size() {
187 assert_eq!(size_of::<Error>(), 4);
188 assert_eq!(size_of::<Result<(), Error>>(), 4);
189 }
190}