From fd091b04316db9dc5fafadbd6bdbe60b127408a9 Mon Sep 17 00:00:00 2001 From: Daniel Mueller Date: Thu, 2 Jan 2020 08:32:06 -0800 Subject: Update nitrokey crate to 0.4.0 This change finally updates the version of the nitrokey crate that we consume to 0.4.0. Along with that we update rand_core, one of its dependencies, to 0.5.1. Further more we add cfg-if in version 0.1.10 and getrandom in version 0.1.13, both of which are now new (non-development) dependencies. Import subrepo nitrokey/:nitrokey at e81057037e9b4f370b64c0a030a725bc6bdfb870 Import subrepo cfg-if/:cfg-if at 4484a6faf816ff8058088ad857b0c6bb2f4b02b2 Import subrepo getrandom/:getrandom at d661aa7e1b8cc80b47dabe3d2135b3b47d2858af Import subrepo rand/:rand at d877ed528248b52d947e0484364a4e1ae59ca502 --- rand/rand_core/src/error.rs | 267 +++++++++++++++++++++++--------------------- 1 file changed, 140 insertions(+), 127 deletions(-) (limited to 'rand/rand_core/src/error.rs') diff --git a/rand/rand_core/src/error.rs b/rand/rand_core/src/error.rs index 5a8459e..30b095c 100644 --- a/rand/rand_core/src/error.rs +++ b/rand/rand_core/src/error.rs @@ -9,169 +9,182 @@ //! Error types use core::fmt; +use core::num::NonZeroU32; -#[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, +/// Error type of random number generators +/// +/// In order to be compatible with `std` and `no_std`, this type has two +/// possible implementations: with `std` a boxed `Error` trait object is stored, +/// while with `no_std` we merely store an error code. +pub struct Error { + #[cfg(feature="std")] + inner: Box, + #[cfg(not(feature="std"))] + code: NonZeroU32, } -impl ErrorKind { - /// True if this kind of error may resolve itself on retry. +impl Error { + /// Construct from any type supporting `std::error::Error` + /// + /// Available only when configured with `std`. /// - /// See also `should_wait()`. - pub fn should_retry(self) -> bool { - self != ErrorKind::Unavailable + /// See also `From`, which is available with and without `std`. + #[cfg(feature="std")] + #[inline] + pub fn new(err: E) -> Self + where E: Into> + { + Error { inner: err.into() } } - /// True if we should retry but wait before retrying + /// Reference the inner error (`std` only) /// - /// This implies `should_retry()` is true. - pub fn should_wait(self) -> bool { - self == ErrorKind::NotReady + /// When configured with `std`, this is a trivial operation and never + /// panics. Without `std`, this method is simply unavailable. + #[cfg(feature="std")] + #[inline] + pub fn inner(&self) -> &(dyn std::error::Error + Send + Sync + 'static) { + &*self.inner } - /// 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!(), - } + /// Unwrap the inner error (`std` only) + /// + /// When configured with `std`, this is a trivial operation and never + /// panics. Without `std`, this method is simply unavailable. + #[cfg(feature="std")] + #[inline] + pub fn take_inner(self) -> Box { + self.inner } -} - + + /// Codes below this point represent OS Errors (i.e. positive i32 values). + /// Codes at or above this point, but below [`Error::CUSTOM_START`] are + /// reserved for use by the `rand` and `getrandom` crates. + pub const INTERNAL_START: u32 = 1 << 31; -/// 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>, -} + /// Codes at or above this point can be used by users to define their own + /// custom errors. + pub const CUSTOM_START: u32 = (1 << 31) + (1 << 30); -impl Error { - /// Create a new instance, with specified kind and a message. - pub fn new(kind: ErrorKind, msg: &'static str) -> Self { + /// Extract the raw OS error code (if this error came from the OS) + /// + /// This method is identical to `std::io::Error::raw_os_error()`, except + /// that it works in `no_std` contexts. If this method returns `None`, the + /// error value can still be formatted via the `Diplay` implementation. + #[inline] + pub fn raw_os_error(&self) -> Option { #[cfg(feature="std")] { - Error { kind, msg, cause: None } + if let Some(e) = self.inner.downcast_ref::() { + return e.raw_os_error(); + } } - #[cfg(not(feature="std"))] { - Error { kind, msg } + match self.code() { + Some(code) if u32::from(code) < Self::INTERNAL_START => + Some(u32::from(code) as i32), + _ => None, } } - - /// 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(kind: ErrorKind, msg: &'static str, cause: E) -> Self - where E: Into> - { - Error { kind, msg, cause: Some(cause.into()) } - } - - /// Create a new instance, with specified kind, message, and a - /// chained cause. + + /// Retrieve the error code, if any. /// - /// In `no_std` mode the *cause* is ignored. - #[cfg(not(feature="std"))] - pub fn with_cause(kind: ErrorKind, msg: &'static str, _cause: E) -> Self { - Error { kind, msg } + /// If this `Error` was constructed via `From`, then this method + /// will return this `NonZeroU32` code (for `no_std` this is always the + /// case). Otherwise, this method will return `None`. + #[inline] + pub fn code(&self) -> Option { + #[cfg(feature="std")] { + self.inner.downcast_ref::().map(|c| c.0) + } + #[cfg(not(feature="std"))] { + Some(self.code) + } } - - /// 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> { - self.cause.take() +} + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + #[cfg(feature="std")] { + write!(f, "Error {{ inner: {:?} }}", self.inner) + } + #[cfg(all(feature="getrandom", not(feature="std")))] { + getrandom::Error::from(self.code).fmt(f) + } + #[cfg(not(feature="getrandom"))] { + write!(f, "Error {{ code: {} }}", self.code) + } } } 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.inner) + } + #[cfg(all(feature="getrandom", not(feature="std")))] { + getrandom::Error::from(self.code).fmt(f) + } + #[cfg(not(feature="getrandom"))] { + write!(f, "error code {}", self.code) } - write!(f, "{} ({})", self.msg, self.kind.description()) } } -#[cfg(feature="std")] -impl stdError for Error { - fn description(&self) -> &str { - self.msg +impl From for Error { + #[inline] + fn from(code: NonZeroU32) -> Self { + #[cfg(feature="std")] { + Error { inner: Box::new(ErrorCode(code)) } + } + #[cfg(not(feature="std"))] { + Error { code } + } + } +} + +#[cfg(feature="getrandom")] +impl From for Error { + #[inline] + fn from(error: getrandom::Error) -> Self { + #[cfg(feature="std")] { + Error { inner: Box::new(error) } + } + #[cfg(not(feature="std"))] { + Error { code: error.code() } + } } +} - fn cause(&self) -> Option<&stdError> { - self.cause.as_ref().map(|e| e.as_ref() as &stdError) +#[cfg(feature="std")] +impl std::error::Error for Error { + #[inline] + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + self.inner.source() } } #[cfg(feature="std")] -impl From for io::Error { +impl From for std::io::Error { + #[inline] 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!(), + if let Some(code) = error.raw_os_error() { + std::io::Error::from_raw_os_error(code) + } else { + std::io::Error::new(std::io::ErrorKind::Other, error) } } } + +#[cfg(feature="std")] +#[derive(Debug, Copy, Clone)] +struct ErrorCode(NonZeroU32); + +#[cfg(feature="std")] +impl fmt::Display for ErrorCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "error code {}", self.0) + } +} + +#[cfg(feature="std")] +impl std::error::Error for ErrorCode {} -- cgit v1.2.1