1 // Copyright 2018 Developers of the Rand project. 2 // 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 9 //! Error types 10 11 use core::fmt; 12 use core::num::NonZeroU32; 13 14 15 /// Error type of random number generators 16 /// 17 /// In order to be compatible with `std` and `no_std`, this type has two 18 /// possible implementations: with `std` a boxed `Error` trait object is stored, 19 /// while with `no_std` we merely store an error code. 20 pub struct Error { 21 #[cfg(feature="std")] 22 inner: Box<dyn std::error::Error + Send + Sync + 'static>, 23 #[cfg(not(feature="std"))] 24 code: NonZeroU32, 25 } 26 27 impl Error { 28 /// Construct from any type supporting `std::error::Error` 29 /// 30 /// Available only when configured with `std`. 31 /// 32 /// See also `From<NonZeroU32>`, which is available with and without `std`. 33 #[cfg(feature="std")] 34 #[inline] new<E>(err: E) -> Self where E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>35 pub fn new<E>(err: E) -> Self 36 where E: Into<Box<dyn std::error::Error + Send + Sync + 'static>> 37 { 38 Error { inner: err.into() } 39 } 40 41 /// Reference the inner error (`std` only) 42 /// 43 /// When configured with `std`, this is a trivial operation and never 44 /// panics. Without `std`, this method is simply unavailable. 45 #[cfg(feature="std")] 46 #[inline] inner(&self) -> &(dyn std::error::Error + Send + Sync + 'static)47 pub fn inner(&self) -> &(dyn std::error::Error + Send + Sync + 'static) { 48 &*self.inner 49 } 50 51 /// Unwrap the inner error (`std` only) 52 /// 53 /// When configured with `std`, this is a trivial operation and never 54 /// panics. Without `std`, this method is simply unavailable. 55 #[cfg(feature="std")] 56 #[inline] take_inner(self) -> Box<dyn std::error::Error + Send + Sync + 'static>57 pub fn take_inner(self) -> Box<dyn std::error::Error + Send + Sync + 'static> { 58 self.inner 59 } 60 61 /// Codes below this point represent OS Errors (i.e. positive i32 values). 62 /// Codes at or above this point, but below [`Error::CUSTOM_START`] are 63 /// reserved for use by the `rand` and `getrandom` crates. 64 pub const INTERNAL_START: u32 = 1 << 31; 65 66 /// Codes at or above this point can be used by users to define their own 67 /// custom errors. 68 pub const CUSTOM_START: u32 = (1 << 31) + (1 << 30); 69 70 /// Extract the raw OS error code (if this error came from the OS) 71 /// 72 /// This method is identical to `std::io::Error::raw_os_error()`, except 73 /// that it works in `no_std` contexts. If this method returns `None`, the 74 /// error value can still be formatted via the `Diplay` implementation. 75 #[inline] raw_os_error(&self) -> Option<i32>76 pub fn raw_os_error(&self) -> Option<i32> { 77 #[cfg(feature="std")] { 78 if let Some(e) = self.inner.downcast_ref::<std::io::Error>() { 79 return e.raw_os_error(); 80 } 81 } 82 match self.code() { 83 Some(code) if u32::from(code) < Self::INTERNAL_START => 84 Some(u32::from(code) as i32), 85 _ => None, 86 } 87 } 88 89 /// Retrieve the error code, if any. 90 /// 91 /// If this `Error` was constructed via `From<NonZeroU32>`, then this method 92 /// will return this `NonZeroU32` code (for `no_std` this is always the 93 /// case). Otherwise, this method will return `None`. 94 #[inline] code(&self) -> Option<NonZeroU32>95 pub fn code(&self) -> Option<NonZeroU32> { 96 #[cfg(feature="std")] { 97 self.inner.downcast_ref::<ErrorCode>().map(|c| c.0) 98 } 99 #[cfg(not(feature="std"))] { 100 Some(self.code) 101 } 102 } 103 } 104 105 impl fmt::Debug for Error { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result106 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 107 #[cfg(feature="std")] { 108 write!(f, "Error {{ inner: {:?} }}", self.inner) 109 } 110 #[cfg(all(feature="getrandom", not(feature="std")))] { 111 getrandom::Error::from(self.code).fmt(f) 112 } 113 #[cfg(not(feature="getrandom"))] { 114 write!(f, "Error {{ code: {} }}", self.code) 115 } 116 } 117 } 118 119 impl fmt::Display for Error { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result120 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 121 #[cfg(feature="std")] { 122 write!(f, "{}", self.inner) 123 } 124 #[cfg(all(feature="getrandom", not(feature="std")))] { 125 getrandom::Error::from(self.code).fmt(f) 126 } 127 #[cfg(not(feature="getrandom"))] { 128 write!(f, "error code {}", self.code) 129 } 130 } 131 } 132 133 impl From<NonZeroU32> for Error { 134 #[inline] from(code: NonZeroU32) -> Self135 fn from(code: NonZeroU32) -> Self { 136 #[cfg(feature="std")] { 137 Error { inner: Box::new(ErrorCode(code)) } 138 } 139 #[cfg(not(feature="std"))] { 140 Error { code } 141 } 142 } 143 } 144 145 #[cfg(feature="getrandom")] 146 impl From<getrandom::Error> for Error { 147 #[inline] from(error: getrandom::Error) -> Self148 fn from(error: getrandom::Error) -> Self { 149 #[cfg(feature="std")] { 150 Error { inner: Box::new(error) } 151 } 152 #[cfg(not(feature="std"))] { 153 Error { code: error.code() } 154 } 155 } 156 } 157 158 #[cfg(feature="std")] 159 impl std::error::Error for Error { 160 #[inline] source(&self) -> Option<&(dyn std::error::Error + 'static)>161 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 162 self.inner.source() 163 } 164 } 165 166 #[cfg(feature="std")] 167 impl From<Error> for std::io::Error { 168 #[inline] from(error: Error) -> Self169 fn from(error: Error) -> Self { 170 if let Some(code) = error.raw_os_error() { 171 std::io::Error::from_raw_os_error(code) 172 } else { 173 std::io::Error::new(std::io::ErrorKind::Other, error) 174 } 175 } 176 } 177 178 #[cfg(feature="std")] 179 #[derive(Debug, Copy, Clone)] 180 struct ErrorCode(NonZeroU32); 181 182 #[cfg(feature="std")] 183 impl fmt::Display for ErrorCode { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result184 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 185 write!(f, "error code {}", self.0) 186 } 187 } 188 189 #[cfg(feature="std")] 190 impl std::error::Error for ErrorCode {} 191