/rust/registry/src/index.crates.io-1949cf8c6b5b557f/getrandom-0.3.1/src/error.rs
Line | Count | Source |
1 | | #[cfg(feature = "std")] |
2 | | extern crate std; |
3 | | |
4 | | use core::{fmt, num::NonZeroU32}; |
5 | | |
6 | | // This private alias mirrors `std::io::RawOsError`: |
7 | | // https://doc.rust-lang.org/std/io/type.RawOsError.html) |
8 | | cfg_if::cfg_if!( |
9 | | if #[cfg(target_os = "uefi")] { |
10 | | type RawOsError = usize; |
11 | | } else { |
12 | | type RawOsError = i32; |
13 | | } |
14 | | ); |
15 | | |
16 | | /// A small and `no_std` compatible error type |
17 | | /// |
18 | | /// The [`Error::raw_os_error()`] will indicate if the error is from the OS, and |
19 | | /// if so, which error code the OS gave the application. If such an error is |
20 | | /// encountered, please consult with your system documentation. |
21 | | /// |
22 | | /// Internally this type is a NonZeroU32, with certain values reserved for |
23 | | /// certain purposes, see [`Error::INTERNAL_START`] and [`Error::CUSTOM_START`]. |
24 | | /// |
25 | | /// *If this crate's `"std"` Cargo feature is enabled*, then: |
26 | | /// - [`getrandom::Error`][Error] implements |
27 | | /// [`std::error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html) |
28 | | /// - [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html) implements |
29 | | /// [`From<getrandom::Error>`](https://doc.rust-lang.org/std/convert/trait.From.html). |
30 | | #[derive(Copy, Clone, Eq, PartialEq)] |
31 | | pub struct Error(NonZeroU32); |
32 | | |
33 | | impl Error { |
34 | | /// This target/platform is not supported by `getrandom`. |
35 | | pub const UNSUPPORTED: Error = Self::new_internal(0); |
36 | | /// The platform-specific `errno` returned a non-positive value. |
37 | | pub const ERRNO_NOT_POSITIVE: Error = Self::new_internal(1); |
38 | | /// Encountered an unexpected situation which should not happen in practice. |
39 | | pub const UNEXPECTED: Error = Self::new_internal(2); |
40 | | |
41 | | /// Codes below this point represent OS Errors (i.e. positive i32 values). |
42 | | /// Codes at or above this point, but below [`Error::CUSTOM_START`] are |
43 | | /// reserved for use by the `rand` and `getrandom` crates. |
44 | | pub const INTERNAL_START: u32 = 1 << 31; |
45 | | |
46 | | /// Codes at or above this point can be used by users to define their own |
47 | | /// custom errors. |
48 | | pub const CUSTOM_START: u32 = (1 << 31) + (1 << 30); |
49 | | |
50 | | /// Creates a new instance of an `Error` from a particular OS error code. |
51 | | /// |
52 | | /// This method is analogous to [`std::io::Error::from_raw_os_error()`][1], |
53 | | /// except that it works in `no_std` contexts and `code` will be |
54 | | /// replaced with `Error::UNEXPECTED` if it isn't in the range |
55 | | /// `1..Error::INTERNAL_START`. Thus, for the result `r`, |
56 | | /// `r == Self::UNEXPECTED || r.raw_os_error().unsigned_abs() == code`. |
57 | | /// |
58 | | /// [1]: https://doc.rust-lang.org/std/io/struct.Error.html#method.from_raw_os_error |
59 | | #[allow(dead_code)] |
60 | 0 | pub(super) fn from_os_error(code: u32) -> Self { |
61 | 0 | match NonZeroU32::new(code) { |
62 | 0 | Some(code) if code.get() < Self::INTERNAL_START => Self(code), |
63 | 0 | _ => Self::UNEXPECTED, |
64 | | } |
65 | 0 | } |
66 | | |
67 | | /// Extract the raw OS error code (if this error came from the OS) |
68 | | /// |
69 | | /// This method is identical to [`std::io::Error::raw_os_error()`][1], except |
70 | | /// that it works in `no_std` contexts. On most targets this method returns |
71 | | /// `Option<i32>`, but some platforms (e.g. UEFI) may use a different primitive |
72 | | /// type like `usize`. Consult with the [`RawOsError`] docs for more information. |
73 | | /// |
74 | | /// If this method returns `None`, the error value can still be formatted via |
75 | | /// the `Display` implementation. |
76 | | /// |
77 | | /// [1]: https://doc.rust-lang.org/std/io/struct.Error.html#method.raw_os_error |
78 | | /// [`RawOsError`]: https://doc.rust-lang.org/std/io/type.RawOsError.html |
79 | | #[inline] |
80 | 0 | pub fn raw_os_error(self) -> Option<RawOsError> { |
81 | 0 | let code = self.0.get(); |
82 | 0 | if code >= Self::INTERNAL_START { |
83 | 0 | return None; |
84 | 0 | } |
85 | 0 | let errno = RawOsError::try_from(code).ok()?; |
86 | | #[cfg(target_os = "solid_asp3")] |
87 | | let errno = -errno; |
88 | 0 | Some(errno) |
89 | 0 | } |
90 | | |
91 | | /// Creates a new instance of an `Error` from a particular custom error code. |
92 | 0 | pub const fn new_custom(n: u16) -> Error { |
93 | | // SAFETY: code > 0 as CUSTOM_START > 0 and adding n won't overflow a u32. |
94 | 0 | let code = Error::CUSTOM_START + (n as u32); |
95 | 0 | Error(unsafe { NonZeroU32::new_unchecked(code) }) |
96 | 0 | } |
97 | | |
98 | | /// Creates a new instance of an `Error` from a particular internal error code. |
99 | 0 | pub(crate) const fn new_internal(n: u16) -> Error { |
100 | | // SAFETY: code > 0 as INTERNAL_START > 0 and adding n won't overflow a u32. |
101 | 0 | let code = Error::INTERNAL_START + (n as u32); |
102 | 0 | Error(unsafe { NonZeroU32::new_unchecked(code) }) |
103 | 0 | } |
104 | | |
105 | 0 | fn internal_desc(&self) -> Option<&'static str> { |
106 | 0 | let desc = match *self { |
107 | 0 | Error::UNSUPPORTED => "getrandom: this target is not supported", |
108 | 0 | Error::ERRNO_NOT_POSITIVE => "errno: did not return a positive value", |
109 | 0 | 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 | 0 | _ => return None, |
140 | | }; |
141 | 0 | Some(desc) |
142 | 0 | } |
143 | | } |
144 | | |
145 | | impl fmt::Debug for Error { |
146 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
147 | 0 | let mut dbg = f.debug_struct("Error"); |
148 | 0 | if let Some(errno) = self.raw_os_error() { |
149 | 0 | dbg.field("os_error", &errno); |
150 | 0 | #[cfg(feature = "std")] |
151 | 0 | dbg.field("description", &std::io::Error::from_raw_os_error(errno)); |
152 | 0 | } else if let Some(desc) = self.internal_desc() { |
153 | 0 | dbg.field("internal_code", &self.0.get()); |
154 | 0 | dbg.field("description", &desc); |
155 | 0 | } else { |
156 | 0 | dbg.field("unknown_code", &self.0.get()); |
157 | 0 | } |
158 | 0 | dbg.finish() |
159 | 0 | } |
160 | | } |
161 | | |
162 | | impl fmt::Display for Error { |
163 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
164 | 0 | if let Some(errno) = self.raw_os_error() { |
165 | | cfg_if! { |
166 | | if #[cfg(feature = "std")] { |
167 | 0 | std::io::Error::from_raw_os_error(errno).fmt(f) |
168 | | } else { |
169 | | write!(f, "OS Error: {}", errno) |
170 | | } |
171 | | } |
172 | 0 | } else if let Some(desc) = self.internal_desc() { |
173 | 0 | f.write_str(desc) |
174 | | } else { |
175 | 0 | write!(f, "Unknown Error: {}", self.0.get()) |
176 | | } |
177 | 0 | } |
178 | | } |
179 | | |
180 | | #[cfg(test)] |
181 | | mod 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 | | } |