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}