rand_core/error.rs
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
11use core::fmt;
12
13#[cfg(feature="std")]
14use std::error::Error as stdError;
15#[cfg(feature="std")]
16use std::io;
17
18/// Error kind which can be matched over.
19#[derive(PartialEq, Eq, Debug, Copy, Clone)]
20pub 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
52impl 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}
78
79
80/// 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`.
88#[derive(Debug)]
89pub struct Error {
90 /// The error kind
91 pub kind: ErrorKind,
92 /// The error message
93 pub msg: &'static str,
94 #[cfg(feature="std")]
95 cause: Option<Box<stdError + Send + Sync>>,
96}
97
98impl 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.
111 ///
112 /// Note: `stdError` is an alias for `std::error::Error`.
113 ///
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.
118 #[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>>
121 {
122 Error { kind, msg, cause: Some(cause.into()) }
123 }
124
125 /// Create a new instance, with specified kind, message, and a
126 /// chained cause.
127 ///
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 }
132 }
133
134 /// Take the cause, if any. This allows the embedded cause to be extracted.
135 /// This uses `Option::take`, leaving `self` with no cause.
136 #[cfg(feature="std")]
137 pub fn take_cause(&mut self) -> Option<Box<stdError + Send + Sync>> {
138 self.cause.take()
139 }
140}
141
142impl fmt::Display for Error {
143 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
144 #[cfg(feature="std")] {
145 if let Some(ref cause) = self.cause {
146 return write!(f, "{} ({}); cause: {}",
147 self.msg, self.kind.description(), cause);
148 }
149 }
150 write!(f, "{} ({})", self.msg, self.kind.description())
151 }
152}
153
154#[cfg(feature="std")]
155impl stdError for Error {
156 fn description(&self) -> &str {
157 self.msg
158 }
159
160 fn cause(&self) -> Option<&stdError> {
161 self.cause.as_ref().map(|e| e.as_ref() as &stdError)
162 }
163}
164
165#[cfg(feature="std")]
166impl From<Error> for io::Error {
167 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 }
176 }
177}