|
9 | 9 | //! Error types
|
10 | 10 |
|
11 | 11 | use core::fmt;
|
12 |
| - |
13 |
| -#[cfg(feature="std")] |
14 |
| -use std::error::Error as stdError; |
15 |
| -#[cfg(feature="std")] |
16 |
| -use std::io; |
17 |
| - |
18 |
| -/// Error kind which can be matched over. |
19 |
| -#[derive(PartialEq, Eq, Debug, Copy, Clone)] |
20 |
| -pub enum ErrorKind { |
21 |
| - /// Feature is not available; not recoverable. |
22 |
| - /// |
23 |
| - /// This is the most permanent failure type and implies the error cannot be |
24 |
| - /// resolved simply by retrying (e.g. the feature may not exist in this |
25 |
| - /// build of the application or on the current platform). |
26 |
| - Unavailable, |
27 |
| - /// General failure; there may be a chance of recovery on retry. |
28 |
| - /// |
29 |
| - /// This is the catch-all kind for errors from known and unknown sources |
30 |
| - /// which do not have a more specific kind / handling method. |
31 |
| - /// |
32 |
| - /// It is suggested to retry a couple of times or retry later when |
33 |
| - /// handling; some error sources may be able to resolve themselves, |
34 |
| - /// although this is not likely. |
35 |
| - Unexpected, |
36 |
| - /// A transient failure which likely can be resolved or worked around. |
37 |
| - /// |
38 |
| - /// This error kind exists for a few specific cases where it is known that |
39 |
| - /// the error likely can be resolved internally, but is reported anyway. |
40 |
| - Transient, |
41 |
| - /// Not ready yet: recommended to try again a little later. |
42 |
| - /// |
43 |
| - /// This error kind implies the generator needs more time or needs some |
44 |
| - /// other part of the application to do something else first before it is |
45 |
| - /// ready for use; for example this may be used by external generators |
46 |
| - /// which require time for initialization. |
47 |
| - NotReady, |
48 |
| - #[doc(hidden)] |
49 |
| - __Nonexhaustive, |
50 |
| -} |
51 |
| - |
52 |
| -impl ErrorKind { |
53 |
| - /// True if this kind of error may resolve itself on retry. |
54 |
| - /// |
55 |
| - /// See also `should_wait()`. |
56 |
| - pub fn should_retry(self) -> bool { |
57 |
| - self != ErrorKind::Unavailable |
58 |
| - } |
59 |
| - |
60 |
| - /// True if we should retry but wait before retrying |
61 |
| - /// |
62 |
| - /// This implies `should_retry()` is true. |
63 |
| - pub fn should_wait(self) -> bool { |
64 |
| - self == ErrorKind::NotReady |
65 |
| - } |
66 |
| - |
67 |
| - /// A description of this error kind |
68 |
| - pub fn description(self) -> &'static str { |
69 |
| - match self { |
70 |
| - ErrorKind::Unavailable => "permanently unavailable", |
71 |
| - ErrorKind::Unexpected => "unexpected failure", |
72 |
| - ErrorKind::Transient => "transient failure", |
73 |
| - ErrorKind::NotReady => "not ready yet", |
74 |
| - ErrorKind::__Nonexhaustive => unreachable!(), |
75 |
| - } |
76 |
| - } |
77 |
| -} |
| 12 | +use core::num::NonZeroU32; |
78 | 13 |
|
79 | 14 |
|
80 | 15 | /// Error type of random number generators
|
81 |
| -/// |
82 |
| -/// This is a relatively simple error type, designed for compatibility with and |
83 |
| -/// without the Rust `std` library. It embeds a "kind" code, a message (static |
84 |
| -/// string only), and an optional chained cause (`std` only). The `kind` and |
85 |
| -/// `msg` fields can be accessed directly; cause can be accessed via |
86 |
| -/// `std::error::Error::cause` or `Error::take_cause`. Construction can only be |
87 |
| -/// done via `Error::new` or `Error::with_cause`. |
| 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. |
88 | 20 | #[derive(Debug)]
|
89 | 21 | pub struct Error {
|
90 |
| - /// The error kind |
91 |
| - pub kind: ErrorKind, |
92 |
| - /// The error message |
93 |
| - pub msg: &'static str, |
94 | 22 | #[cfg(feature="std")]
|
95 |
| - cause: Option<Box<stdError + Send + Sync>>, |
| 23 | + inner: Box<dyn std::error::Error + Send + Sync + 'static>, |
| 24 | + #[cfg(not(feature="std"))] |
| 25 | + code: NonZeroU32, |
96 | 26 | }
|
97 | 27 |
|
98 | 28 | impl Error {
|
99 |
| - /// Create a new instance, with specified kind and a message. |
100 |
| - pub fn new(kind: ErrorKind, msg: &'static str) -> Self { |
101 |
| - #[cfg(feature="std")] { |
102 |
| - Error { kind, msg, cause: None } |
103 |
| - } |
104 |
| - #[cfg(not(feature="std"))] { |
105 |
| - Error { kind, msg } |
106 |
| - } |
107 |
| - } |
108 |
| - |
109 |
| - /// Create a new instance, with specified kind, message, and a |
110 |
| - /// chained cause. |
| 29 | + /// Construct from any type supporting `std::error::Error` |
111 | 30 | ///
|
112 |
| - /// Note: `stdError` is an alias for `std::error::Error`. |
| 31 | + /// Available only when configured with `std`. |
113 | 32 | ///
|
114 |
| - /// If not targetting `std` (i.e. `no_std`), this function is replaced by |
115 |
| - /// another with the same prototype, except that there are no bounds on the |
116 |
| - /// type `E` (because both `Box` and `stdError` are unavailable), and the |
117 |
| - /// `cause` is ignored. |
| 33 | + /// See also `From<NonZeroU32>`, which is available with and without `std`. |
118 | 34 | #[cfg(feature="std")]
|
119 |
| - pub fn with_cause<E>(kind: ErrorKind, msg: &'static str, cause: E) -> Self |
120 |
| - where E: Into<Box<stdError + Send + Sync>> |
| 35 | + pub fn new<E>(err: E) -> Self |
| 36 | + where E: Into<Box<dyn std::error::Error + Send + Sync + 'static>> |
121 | 37 | {
|
122 |
| - Error { kind, msg, cause: Some(cause.into()) } |
| 38 | + Error { inner: err.into() } |
123 | 39 | }
|
124 | 40 |
|
125 |
| - /// Create a new instance, with specified kind, message, and a |
126 |
| - /// chained cause. |
| 41 | + /// Reference the inner error (`std` only) |
127 | 42 | ///
|
128 |
| - /// In `no_std` mode the *cause* is ignored. |
129 |
| - #[cfg(not(feature="std"))] |
130 |
| - pub fn with_cause<E>(kind: ErrorKind, msg: &'static str, _cause: E) -> Self { |
131 |
| - Error { kind, msg } |
| 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 | + pub fn inner(&self) -> &(dyn std::error::Error + Send + Sync + 'static) { |
| 47 | + &*self.inner |
132 | 48 | }
|
133 | 49 |
|
134 |
| - /// Take the cause, if any. This allows the embedded cause to be extracted. |
135 |
| - /// This uses `Option::take`, leaving `self` with no cause. |
| 50 | + /// Unwrap the inner error (`std` only) |
| 51 | + /// |
| 52 | + /// When configured with `std`, this is a trivial operation and never |
| 53 | + /// panics. Without `std`, this method is simply unavailable. |
136 | 54 | #[cfg(feature="std")]
|
137 |
| - pub fn take_cause(&mut self) -> Option<Box<stdError + Send + Sync>> { |
138 |
| - self.cause.take() |
| 55 | + pub fn take_inner(self) -> Box<dyn std::error::Error + Send + Sync + 'static> { |
| 56 | + self.inner |
| 57 | + } |
| 58 | + |
| 59 | + /// Retrieve the error code, if any. |
| 60 | + /// |
| 61 | + /// If this `Error` was constructed via `From<NonZeroU32>`, then this method |
| 62 | + /// will return this `NonZeroU32` code (for `no_std` this is always the |
| 63 | + /// case). Otherwise, this method will return `None`. |
| 64 | + pub fn code(&self) -> Option<NonZeroU32> { |
| 65 | + #[cfg(feature="std")] { |
| 66 | + self.inner.downcast_ref::<ErrorCode>().map(|c| c.0) |
| 67 | + } |
| 68 | + #[cfg(not(feature="std"))] { |
| 69 | + Some(self.code) |
| 70 | + } |
139 | 71 | }
|
140 | 72 | }
|
141 | 73 |
|
142 | 74 | impl fmt::Display for Error {
|
143 | 75 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
144 | 76 | #[cfg(feature="std")] {
|
145 |
| - if let Some(ref cause) = self.cause { |
146 |
| - return write!(f, "{} ({}); cause: {}", |
147 |
| - self.msg, self.kind.description(), cause); |
148 |
| - } |
| 77 | + write!(f, "{}", self.inner) |
| 78 | + } |
| 79 | + #[cfg(not(feature="std"))] { |
| 80 | + write!(f, "error code {}", self.code) |
149 | 81 | }
|
150 |
| - write!(f, "{} ({})", self.msg, self.kind.description()) |
151 | 82 | }
|
152 | 83 | }
|
153 | 84 |
|
154 |
| -#[cfg(feature="std")] |
155 |
| -impl stdError for Error { |
156 |
| - fn description(&self) -> &str { |
157 |
| - self.msg |
| 85 | +impl From<NonZeroU32> for Error { |
| 86 | + fn from(code: NonZeroU32) -> Self { |
| 87 | + #[cfg(feature="std")] { |
| 88 | + Error { inner: Box::new(ErrorCode(code)) } |
| 89 | + } |
| 90 | + #[cfg(not(feature="std"))] { |
| 91 | + Error { code } |
| 92 | + } |
158 | 93 | }
|
| 94 | +} |
159 | 95 |
|
160 |
| - fn cause(&self) -> Option<&stdError> { |
161 |
| - self.cause.as_ref().map(|e| e.as_ref() as &stdError) |
| 96 | +#[cfg(feature="getrandom")] |
| 97 | +impl From<getrandom::Error> for Error { |
| 98 | + fn from(error: getrandom::Error) -> Self { |
| 99 | + #[cfg(feature="std")] { |
| 100 | + Error { inner: Box::new(error) } |
| 101 | + } |
| 102 | + #[cfg(not(feature="std"))] { |
| 103 | + Error { code: error.code() } |
| 104 | + } |
| 105 | + } |
| 106 | +} |
| 107 | + |
| 108 | +#[cfg(feature="std")] |
| 109 | +impl std::error::Error for Error { |
| 110 | + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { |
| 111 | + self.inner.source() |
162 | 112 | }
|
163 | 113 | }
|
164 | 114 |
|
165 | 115 | #[cfg(feature="std")]
|
166 |
| -impl From<Error> for io::Error { |
| 116 | +impl From<Error> for std::io::Error { |
167 | 117 | fn from(error: Error) -> Self {
|
168 |
| - use std::io::ErrorKind::*; |
169 |
| - match error.kind { |
170 |
| - ErrorKind::Unavailable => io::Error::new(NotFound, error), |
171 |
| - ErrorKind::Unexpected | |
172 |
| - ErrorKind::Transient => io::Error::new(Other, error), |
173 |
| - ErrorKind::NotReady => io::Error::new(WouldBlock, error), |
174 |
| - ErrorKind::__Nonexhaustive => unreachable!(), |
175 |
| - } |
| 118 | + std::io::Error::new(std::io::ErrorKind::Other, error) |
176 | 119 | }
|
177 | 120 | }
|
| 121 | + |
| 122 | +#[cfg(feature="std")] |
| 123 | +#[derive(Debug, Copy, Clone)] |
| 124 | +struct ErrorCode(NonZeroU32); |
| 125 | + |
| 126 | +#[cfg(feature="std")] |
| 127 | +impl fmt::Display for ErrorCode { |
| 128 | + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 129 | + write!(f, "error code {}", self.0) |
| 130 | + } |
| 131 | +} |
| 132 | + |
| 133 | +#[cfg(feature="std")] |
| 134 | +impl std::error::Error for ErrorCode {} |
0 commit comments