Coverage Report

Created: 2026-02-14 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}