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.
8 use core
::{fmt, num::NonZeroU32}
;
10 /// A small and `no_std` compatible error type
12 /// The [`Error::raw_os_error()`] will indicate if the error is from the OS, and
13 /// if so, which error code the OS gave the application. If such an error is
14 /// encountered, please consult with your system documentation.
16 /// Internally this type is a NonZeroU32, with certain values reserved for
17 /// certain purposes, see [`Error::INTERNAL_START`] and [`Error::CUSTOM_START`].
19 /// *If this crate's `"std"` Cargo feature is enabled*, then:
20 /// - [`getrandom::Error`][Error] implements
21 /// [`std::error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html)
22 /// - [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html) implements
23 /// [`From<getrandom::Error>`](https://doc.rust-lang.org/std/convert/trait.From.html).
24 #[derive(Copy, Clone, Eq, PartialEq)]
25 pub struct Error(NonZeroU32
);
27 const fn internal_error(n
: u16) -> Error
{
28 // SAFETY: code > 0 as INTERNAL_START > 0 and adding n won't overflow a u32.
29 let code
= Error
::INTERNAL_START
+ (n
as u32);
30 Error(unsafe { NonZeroU32::new_unchecked(code) }
)
34 /// This target/platform is not supported by `getrandom`.
35 pub const UNSUPPORTED
: Error
= internal_error(0);
36 /// The platform-specific `errno` returned a non-positive value.
37 pub const ERRNO_NOT_POSITIVE
: Error
= internal_error(1);
38 /// Call to iOS [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/1399291-secrandomcopybytes) failed.
39 pub const IOS_SEC_RANDOM
: Error
= internal_error(3);
40 /// Call to Windows [`RtlGenRandom`](https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom) failed.
41 pub const WINDOWS_RTL_GEN_RANDOM
: Error
= internal_error(4);
42 /// RDRAND instruction failed due to a hardware issue.
43 pub const FAILED_RDRAND
: Error
= internal_error(5);
44 /// RDRAND instruction unsupported on this target.
45 pub const NO_RDRAND
: Error
= internal_error(6);
46 /// The browser does not have support for `self.crypto`.
47 pub const WEB_CRYPTO
: Error
= internal_error(7);
48 /// The browser does not have support for `crypto.getRandomValues`.
49 pub const WEB_GET_RANDOM_VALUES
: Error
= internal_error(8);
50 /// On VxWorks, call to `randSecure` failed (random number generator is not yet initialized).
51 pub const VXWORKS_RAND_SECURE
: Error
= internal_error(11);
52 /// NodeJS does not have support for the `crypto` module.
53 pub const NODE_CRYPTO
: Error
= internal_error(12);
54 /// NodeJS does not have support for `crypto.randomFillSync`.
55 pub const NODE_RANDOM_FILL_SYNC
: Error
= internal_error(13);
57 /// Codes below this point represent OS Errors (i.e. positive i32 values).
58 /// Codes at or above this point, but below [`Error::CUSTOM_START`] are
59 /// reserved for use by the `rand` and `getrandom` crates.
60 pub const INTERNAL_START
: u32 = 1 << 31;
62 /// Codes at or above this point can be used by users to define their own
64 pub const CUSTOM_START
: u32 = (1 << 31) + (1 << 30);
66 /// Extract the raw OS error code (if this error came from the OS)
68 /// This method is identical to [`std::io::Error::raw_os_error()`][1], except
69 /// that it works in `no_std` contexts. If this method returns `None`, the
70 /// error value can still be formatted via the `Display` implementation.
72 /// [1]: https://doc.rust-lang.org/std/io/struct.Error.html#method.raw_os_error
74 pub fn raw_os_error(self) -> Option
<i32> {
75 if self.0.get() < Self::INTERNAL_START
{
77 #[cfg(target_os = "solid_asp3")]
78 // On SOLID, negate the error code again to obtain the original
80 () => Some(-(self.0.get() as i32)),
81 #[cfg(not(target_os = "solid_asp3"))]
82 () => Some(self.0.get() as i32),
89 /// Extract the bare error code.
91 /// This code can either come from the underlying OS, or be a custom error.
92 /// Use [`Error::raw_os_error()`] to disambiguate.
94 pub const fn code(self) -> NonZeroU32
{
101 fn os_err(errno
: i32, buf
: &mut [u8]) -> Option
<&str> {
102 let buf_ptr
= buf
.as_mut_ptr() as *mut libc
::c_char
;
103 if unsafe { libc::strerror_r(errno, buf_ptr, buf.len()) }
!= 0 {
107 // Take up to trailing null byte
109 let idx
= buf
.iter().position(|&b
| b
== 0).unwrap_or(n
);
110 core
::str::from_utf8(&buf
[..idx
]).ok()
113 fn os_err(_errno
: i32, _buf
: &mut [u8]) -> Option
<&str> {
119 impl fmt
::Debug
for Error
{
120 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
121 let mut dbg
= f
.debug_struct("Error");
122 if let Some(errno
) = self.raw_os_error() {
123 dbg
.field("os_error", &errno
);
124 let mut buf
= [0u8; 128];
125 if let Some(err
) = os_err(errno
, &mut buf
) {
126 dbg
.field("description", &err
);
128 } else if let Some(desc
) = internal_desc(*self) {
129 dbg
.field("internal_code", &self.0.get());
130 dbg
.field("description", &desc
);
132 dbg
.field("unknown_code", &self.0.get());
138 impl fmt
::Display
for Error
{
139 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
140 if let Some(errno
) = self.raw_os_error() {
141 let mut buf
= [0u8; 128];
142 match os_err(errno
, &mut buf
) {
143 Some(err
) => err
.fmt(f
),
144 None
=> write
!(f
, "OS Error: {}", errno
),
146 } else if let Some(desc
) = internal_desc(*self) {
149 write
!(f
, "Unknown Error: {}", self.0.get())
154 impl From
<NonZeroU32
> for Error
{
155 fn from(code
: NonZeroU32
) -> Self {
160 fn internal_desc(error
: Error
) -> Option
<&'
static str> {
162 Error
::UNSUPPORTED
=> Some("getrandom: this target is not supported"),
163 Error
::ERRNO_NOT_POSITIVE
=> Some("errno: did not return a positive value"),
164 Error
::IOS_SEC_RANDOM
=> Some("SecRandomCopyBytes: iOS Security framework failure"),
165 Error
::WINDOWS_RTL_GEN_RANDOM
=> Some("RtlGenRandom: Windows system function failure"),
166 Error
::FAILED_RDRAND
=> Some("RDRAND: failed multiple times: CPU issue likely"),
167 Error
::NO_RDRAND
=> Some("RDRAND: instruction not supported"),
168 Error
::WEB_CRYPTO
=> Some("Web Crypto API is unavailable"),
169 Error
::WEB_GET_RANDOM_VALUES
=> Some("Web API crypto.getRandomValues is unavailable"),
170 Error
::VXWORKS_RAND_SECURE
=> Some("randSecure: VxWorks RNG module is not initialized"),
171 Error
::NODE_CRYPTO
=> Some("Node.js crypto module is unavailable"),
172 Error
::NODE_RANDOM_FILL_SYNC
=> Some("Node.js API crypto.randomFillSync is unavailable"),
180 use core
::mem
::size_of
;
184 assert_eq
!(size_of
::<Error
>(), 4);
185 assert_eq
!(size_of
::<Result
<(), Error
>>(), 4);