1 // Copyright 2018 Developers of the Rand project.
3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5 // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6 // option. This file may not be copied, modified, or distributed
7 // except according to those terms.
9 use core
::num
::NonZeroU32
;
11 /// A small and `no_std` compatible error type.
13 /// The [`Error::raw_os_error()`] will indicate if the error is from the OS, and
14 /// if so, which error code the OS gave the application. If such an error is
15 /// encountered, please consult with your system documentation.
17 /// Internally this type is a NonZeroU32, with certain values reserved for
18 /// certain purposes, see [`Error::INTERNAL_START`] and [`Error::CUSTOM_START`].
19 #[derive(Copy, Clone, Eq, PartialEq)]
20 pub struct Error(NonZeroU32
);
23 #[deprecated(since = "0.1.7")]
25 pub const UNKNOWN
: Error
= UNSUPPORTED
;
26 #[deprecated(since = "0.1.7")]
27 /// System entropy source is unavailable.
28 pub const UNAVAILABLE
: Error
= UNSUPPORTED
;
30 /// Codes below this point represent OS Errors (i.e. positive i32 values).
31 /// Codes at or above this point, but below [`Error::CUSTOM_START`] are
32 /// reserved for use by the `rand` and `getrandom` crates.
33 pub const INTERNAL_START
: u32 = 1 << 31;
35 /// Codes at or above this point can be used by users to define their own
37 pub const CUSTOM_START
: u32 = (1 << 31) + (1 << 30);
39 /// Extract the raw OS error code (if this error came from the OS)
41 /// This method is identical to `std::io::Error::raw_os_error()`, except
42 /// that it works in `no_std` contexts. If this method returns `None`, the
43 /// error value can still be formatted via the `Display` implementation.
45 pub fn raw_os_error(self) -> Option
<i32> {
46 if self.0.get() < Self::INTERNAL_START
{
47 Some(self.0.get() as i32)
53 /// Extract the bare error code.
55 /// This code can either come from the underlying OS, or be a custom error.
56 /// Use [`Error::raw_os_error()`] to disambiguate.
58 pub fn code(self) -> NonZeroU32
{
65 fn os_err(errno
: i32, buf
: &mut [u8]) -> Option
<&str> {
66 let buf_ptr
= buf
.as_mut_ptr() as *mut libc
::c_char
;
67 if unsafe { libc::strerror_r(errno, buf_ptr, buf.len()) }
!= 0 {
71 // Take up to trailing null byte
73 let idx
= buf
.iter().position(|&b
| b
== 0).unwrap_or(n
);
74 core
::str::from_utf8(&buf
[..idx
]).ok()
76 } else if #[cfg(target_os = "wasi")] {
77 fn os_err(errno
: i32, _buf
: &mut [u8]) -> Option
<wasi
::Error
> {
78 wasi
::Error
::from_raw_error(errno
as _
)
81 fn os_err(_errno
: i32, _buf
: &mut [u8]) -> Option
<&str> {
87 impl fmt
::Debug
for Error
{
88 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
89 let mut dbg
= f
.debug_struct("Error");
90 if let Some(errno
) = self.raw_os_error() {
91 dbg
.field("os_error", &errno
);
92 let mut buf
= [0u8; 128];
93 if let Some(err
) = os_err(errno
, &mut buf
) {
94 dbg
.field("description", &err
);
96 } else if let Some(desc
) = internal_desc(*self) {
97 dbg
.field("internal_code", &self.0.get());
98 dbg
.field("description", &desc
);
100 dbg
.field("unknown_code", &self.0.get());
106 impl fmt
::Display
for Error
{
107 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
108 if let Some(errno
) = self.raw_os_error() {
109 let mut buf
= [0u8; 128];
110 match os_err(errno
, &mut buf
) {
111 Some(err
) => err
.fmt(f
),
112 None
=> write
!(f
, "OS Error: {}", errno
),
114 } else if let Some(desc
) = internal_desc(*self) {
117 write
!(f
, "Unknown Error: {}", self.0.get())
122 impl From
<NonZeroU32
> for Error
{
123 fn from(code
: NonZeroU32
) -> Self {
128 // TODO: Convert to a function when min_version >= 1.33
129 macro_rules
! internal_error
{
131 Error(unsafe { NonZeroU32::new_unchecked(Error::INTERNAL_START + $n as u16 as u32) }
)
135 /// Internal Error constants
136 pub(crate) const UNSUPPORTED
: Error
= internal_error
!(0);
137 pub(crate) const ERRNO_NOT_POSITIVE
: Error
= internal_error
!(1);
138 pub(crate) const UNKNOWN_IO_ERROR
: Error
= internal_error
!(2);
139 pub(crate) const SEC_RANDOM_FAILED
: Error
= internal_error
!(3);
140 pub(crate) const RTL_GEN_RANDOM_FAILED
: Error
= internal_error
!(4);
141 pub(crate) const FAILED_RDRAND
: Error
= internal_error
!(5);
142 pub(crate) const NO_RDRAND
: Error
= internal_error
!(6);
143 pub(crate) const BINDGEN_CRYPTO_UNDEF
: Error
= internal_error
!(7);
144 pub(crate) const BINDGEN_GRV_UNDEF
: Error
= internal_error
!(8);
145 pub(crate) const STDWEB_NO_RNG
: Error
= internal_error
!(9);
146 pub(crate) const STDWEB_RNG_FAILED
: Error
= internal_error
!(10);
147 pub(crate) const RAND_SECURE_FATAL
: Error
= internal_error
!(11);
149 fn internal_desc(error
: Error
) -> Option
<&'
static str> {
151 UNSUPPORTED
=> Some("getrandom: this target is not supported"),
152 ERRNO_NOT_POSITIVE
=> Some("errno: did not return a positive value"),
153 UNKNOWN_IO_ERROR
=> Some("Unknown std::io::Error"),
154 SEC_RANDOM_FAILED
=> Some("SecRandomCopyBytes: call failed"),
155 RTL_GEN_RANDOM_FAILED
=> Some("RtlGenRandom: call failed"),
156 FAILED_RDRAND
=> Some("RDRAND: failed multiple times: CPU issue likely"),
157 NO_RDRAND
=> Some("RDRAND: instruction not supported"),
158 BINDGEN_CRYPTO_UNDEF
=> Some("wasm-bindgen: self.crypto is undefined"),
159 BINDGEN_GRV_UNDEF
=> Some("wasm-bindgen: crypto.getRandomValues is undefined"),
160 STDWEB_NO_RNG
=> Some("stdweb: no randomness source available"),
161 STDWEB_RNG_FAILED
=> Some("stdweb: failed to get randomness"),
162 RAND_SECURE_FATAL
=> Some("randSecure: random number generator module is not initialized"),
170 use core
::mem
::size_of
;
174 assert_eq
!(size_of
::<Error
>(), 4);
175 assert_eq
!(size_of
::<Result
<(), Error
>>(), 4);