aboutsummaryrefslogtreecommitdiff
path: root/rand/rand_core/src/error.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rand/rand_core/src/error.rs')
-rw-r--r--rand/rand_core/src/error.rs177
1 files changed, 177 insertions, 0 deletions
diff --git a/rand/rand_core/src/error.rs b/rand/rand_core/src/error.rs
new file mode 100644
index 0000000..5a8459e
--- /dev/null
+++ b/rand/rand_core/src/error.rs
@@ -0,0 +1,177 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Error types
+
+use core::fmt;
+
+#[cfg(feature="std")]
+use std::error::Error as stdError;
+#[cfg(feature="std")]
+use std::io;
+
+/// Error kind which can be matched over.
+#[derive(PartialEq, Eq, Debug, Copy, Clone)]
+pub enum ErrorKind {
+ /// Feature is not available; not recoverable.
+ ///
+ /// This is the most permanent failure type and implies the error cannot be
+ /// resolved simply by retrying (e.g. the feature may not exist in this
+ /// build of the application or on the current platform).
+ Unavailable,
+ /// General failure; there may be a chance of recovery on retry.
+ ///
+ /// This is the catch-all kind for errors from known and unknown sources
+ /// which do not have a more specific kind / handling method.
+ ///
+ /// It is suggested to retry a couple of times or retry later when
+ /// handling; some error sources may be able to resolve themselves,
+ /// although this is not likely.
+ Unexpected,
+ /// A transient failure which likely can be resolved or worked around.
+ ///
+ /// This error kind exists for a few specific cases where it is known that
+ /// the error likely can be resolved internally, but is reported anyway.
+ Transient,
+ /// Not ready yet: recommended to try again a little later.
+ ///
+ /// This error kind implies the generator needs more time or needs some
+ /// other part of the application to do something else first before it is
+ /// ready for use; for example this may be used by external generators
+ /// which require time for initialization.
+ NotReady,
+ #[doc(hidden)]
+ __Nonexhaustive,
+}
+
+impl ErrorKind {
+ /// True if this kind of error may resolve itself on retry.
+ ///
+ /// See also `should_wait()`.
+ pub fn should_retry(self) -> bool {
+ self != ErrorKind::Unavailable
+ }
+
+ /// True if we should retry but wait before retrying
+ ///
+ /// This implies `should_retry()` is true.
+ pub fn should_wait(self) -> bool {
+ self == ErrorKind::NotReady
+ }
+
+ /// A description of this error kind
+ pub fn description(self) -> &'static str {
+ match self {
+ ErrorKind::Unavailable => "permanently unavailable",
+ ErrorKind::Unexpected => "unexpected failure",
+ ErrorKind::Transient => "transient failure",
+ ErrorKind::NotReady => "not ready yet",
+ ErrorKind::__Nonexhaustive => unreachable!(),
+ }
+ }
+}
+
+
+/// Error type of random number generators
+///
+/// This is a relatively simple error type, designed for compatibility with and
+/// without the Rust `std` library. It embeds a "kind" code, a message (static
+/// string only), and an optional chained cause (`std` only). The `kind` and
+/// `msg` fields can be accessed directly; cause can be accessed via
+/// `std::error::Error::cause` or `Error::take_cause`. Construction can only be
+/// done via `Error::new` or `Error::with_cause`.
+#[derive(Debug)]
+pub struct Error {
+ /// The error kind
+ pub kind: ErrorKind,
+ /// The error message
+ pub msg: &'static str,
+ #[cfg(feature="std")]
+ cause: Option<Box<stdError + Send + Sync>>,
+}
+
+impl Error {
+ /// Create a new instance, with specified kind and a message.
+ pub fn new(kind: ErrorKind, msg: &'static str) -> Self {
+ #[cfg(feature="std")] {
+ Error { kind, msg, cause: None }
+ }
+ #[cfg(not(feature="std"))] {
+ Error { kind, msg }
+ }
+ }
+
+ /// Create a new instance, with specified kind, message, and a
+ /// chained cause.
+ ///
+ /// Note: `stdError` is an alias for `std::error::Error`.
+ ///
+ /// If not targetting `std` (i.e. `no_std`), this function is replaced by
+ /// another with the same prototype, except that there are no bounds on the
+ /// type `E` (because both `Box` and `stdError` are unavailable), and the
+ /// `cause` is ignored.
+ #[cfg(feature="std")]
+ pub fn with_cause<E>(kind: ErrorKind, msg: &'static str, cause: E) -> Self
+ where E: Into<Box<stdError + Send + Sync>>
+ {
+ Error { kind, msg, cause: Some(cause.into()) }
+ }
+
+ /// Create a new instance, with specified kind, message, and a
+ /// chained cause.
+ ///
+ /// In `no_std` mode the *cause* is ignored.
+ #[cfg(not(feature="std"))]
+ pub fn with_cause<E>(kind: ErrorKind, msg: &'static str, _cause: E) -> Self {
+ Error { kind, msg }
+ }
+
+ /// Take the cause, if any. This allows the embedded cause to be extracted.
+ /// This uses `Option::take`, leaving `self` with no cause.
+ #[cfg(feature="std")]
+ pub fn take_cause(&mut self) -> Option<Box<stdError + Send + Sync>> {
+ self.cause.take()
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ #[cfg(feature="std")] {
+ if let Some(ref cause) = self.cause {
+ return write!(f, "{} ({}); cause: {}",
+ self.msg, self.kind.description(), cause);
+ }
+ }
+ write!(f, "{} ({})", self.msg, self.kind.description())
+ }
+}
+
+#[cfg(feature="std")]
+impl stdError for Error {
+ fn description(&self) -> &str {
+ self.msg
+ }
+
+ fn cause(&self) -> Option<&stdError> {
+ self.cause.as_ref().map(|e| e.as_ref() as &stdError)
+ }
+}
+
+#[cfg(feature="std")]
+impl From<Error> for io::Error {
+ fn from(error: Error) -> Self {
+ use std::io::ErrorKind::*;
+ match error.kind {
+ ErrorKind::Unavailable => io::Error::new(NotFound, error),
+ ErrorKind::Unexpected |
+ ErrorKind::Transient => io::Error::new(Other, error),
+ ErrorKind::NotReady => io::Error::new(WouldBlock, error),
+ ErrorKind::__Nonexhaustive => unreachable!(),
+ }
+ }
+}