Skip to content

Commit ca1b7c4

Browse files
committed
rand_core::Error: replace internal representation and adjust API
This is a significant breaking change, discussed in #800. Also rand::rngs::adapter::read is no longer publically exported.
1 parent 959043d commit ca1b7c4

File tree

3 files changed

+76
-66
lines changed

3 files changed

+76
-66
lines changed

rand_core/src/error.rs

Lines changed: 52 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -12,78 +12,58 @@ use core::fmt;
1212
use core::num::NonZeroU32;
1313

1414

15-
// A randomly-chosen 24-bit prefix for our codes.
16-
#[cfg(not(feature="std"))]
17-
pub(crate) const CODE_PREFIX: u32 = 0x517e8100;
18-
1915
/// Error type of random number generators
20-
///
21-
/// This is a relatively simple error type, designed for compatibility with and
22-
/// without the Rust `std` library. It embeds a message (static
23-
/// string only), and an optional chained cause (`std` only). The
24-
/// `msg` field can be accessed directly; cause can be accessed via
25-
/// `std::error::Error::cause` or `Error::take_cause`. Construction can only be
26-
/// 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.
2720
#[derive(Debug)]
2821
pub struct Error {
29-
msg: &'static str,
3022
#[cfg(feature="std")]
31-
cause: Option<Box<std::error::Error + Send + Sync>>,
23+
inner: Box<dyn std::error::Error + Send + Sync + 'static>,
3224
#[cfg(not(feature="std"))]
3325
code: NonZeroU32,
3426
}
3527

3628
impl Error {
37-
/// Create a new instance, with a message.
38-
pub fn new(msg: &'static str) -> Self {
39-
#[cfg(feature="std")] {
40-
Error { msg, cause: None }
41-
}
42-
#[cfg(not(feature="std"))] {
43-
Error { msg, code: NonZeroU32::new(CODE_PREFIX).unwrap() }
44-
}
45-
}
46-
47-
/// Create a new instance, with a message and a chained cause.
48-
///
49-
/// This function is only available with the `std` feature.
50-
// NOTE: with specialisation we could support both.
29+
/// Construct from any type supporting `std::error::Error`
30+
///
31+
/// Available only when configured with `std`.
32+
///
33+
/// See also `From<NonZeroU32>`, which is available with and without `std`.
5134
#[cfg(feature="std")]
52-
pub fn with_cause<E>(msg: &'static str, cause: E) -> Self
53-
where E: Into<Box<std::error::Error + Send + Sync>>
35+
pub fn new<E>(err: E) -> Self
36+
where E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>
5437
{
55-
Error { msg, cause: Some(cause.into()) }
38+
Error { inner: err.into() }
5639
}
5740

58-
/// Create a new instance, with a message and an error code.
59-
pub fn with_code(msg: &'static str, code: NonZeroU32) -> Self {
60-
#[cfg(feature="std")] {
61-
Error { msg, cause: Some(Box::new(ErrorCode(code))) }
62-
}
63-
#[cfg(not(feature="std"))] {
64-
Error { msg, code }
65-
}
66-
}
67-
68-
/// Retrieve the error message.
69-
pub fn msg(&self) -> &str {
70-
self.msg
41+
/// Reference the inner error (`std` only)
42+
///
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
7148
}
7249

73-
/// Take the cause, if any. This allows the embedded cause to be extracted.
74-
/// This uses `Option::take`, leaving `self` with no cause.
75-
///
76-
/// This function is only available with the `std` feature.
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.
7754
#[cfg(feature="std")]
78-
pub fn take_cause(&mut self) -> Option<Box<std::error::Error + Send + Sync>> {
79-
self.cause.take()
55+
pub fn take_inner(self) -> Box<dyn std::error::Error + Send + Sync + 'static> {
56+
self.inner
8057
}
8158

8259
/// Retrieve the error code, if any.
83-
#[cfg(not(feature="std"))]
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`.
8464
pub fn code(&self) -> Option<NonZeroU32> {
8565
#[cfg(feature="std")] {
86-
self.cause.as_ref().and_then(|b| b.downcast_ref::<ErrorCode>()).map(|c| c.0)
66+
self.inner.downcast_ref::<ErrorCode>().map(|c| c.0)
8767
}
8868
#[cfg(not(feature="std"))] {
8969
Some(self.code)
@@ -93,31 +73,42 @@ impl Error {
9373

9474
impl fmt::Display for Error {
9575
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
96-
write!(f, "{}", self.msg)
76+
#[cfg(feature="std")] {
77+
write!(f, "{}", self.inner)
78+
}
79+
#[cfg(not(feature="std"))] {
80+
write!(f, "error code {}", self.code)
81+
}
82+
}
83+
}
84+
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+
}
9793
}
9894
}
9995

10096
#[cfg(feature="getrandom")]
10197
impl From<getrandom::Error> for Error {
10298
fn from(error: getrandom::Error) -> Self {
103-
let msg = "getrandom error";
10499
#[cfg(feature="std")] {
105-
Error { msg, cause: Some(Box::new(error)) }
100+
Error { inner: Box::new(error) }
106101
}
107102
#[cfg(not(feature="std"))] {
108-
Error { msg, code: error.code() }
103+
Error { code: error.code() }
109104
}
110105
}
111106
}
112107

113108
#[cfg(feature="std")]
114109
impl std::error::Error for Error {
115-
fn description(&self) -> &str {
116-
self.msg
117-
}
118-
119110
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
120-
self.cause.as_ref().map(|e| e.as_ref() as &std::error::Error)
111+
self.inner.source()
121112
}
122113
}
123114

@@ -135,7 +126,7 @@ struct ErrorCode(NonZeroU32);
135126
#[cfg(feature="std")]
136127
impl fmt::Display for ErrorCode {
137128
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
138-
write!(f, "ErrorCode({})", self.0)
129+
write!(f, "error code {}", self.0)
139130
}
140131
}
141132

src/rngs/adapter/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88

99
//! Wrappers / adapters forming RNGs
1010
11-
#[cfg(feature="std")] #[doc(hidden)] pub mod read;
11+
#[cfg(feature="std")] mod read;
1212
mod reseeding;
1313

14-
#[cfg(feature="std")] pub use self::read::ReadRng;
14+
#[cfg(feature="std")] pub use self::read::{ReadRng, ReadError};
1515
pub use self::reseeding::ReseedingRng;

src/rngs/adapter/read.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//! A wrapper around any Read to treat it as an RNG.
1111
1212
use std::io::Read;
13+
use std::fmt;
1314

1415
use rand_core::{RngCore, Error, impls};
1516

@@ -73,11 +74,27 @@ impl<R: Read> RngCore for ReadRng<R> {
7374
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
7475
if dest.len() == 0 { return Ok(()); }
7576
// Use `std::io::read_exact`, which retries on `ErrorKind::Interrupted`.
76-
self.reader.read_exact(dest).map_err(|err|
77-
Error::with_cause("error reading from Read source", err))
77+
self.reader.read_exact(dest).map_err(|e| Error::new(ReadError(e)))
7878
}
7979
}
8080

81+
/// `ReadRng` error type
82+
#[derive(Debug)]
83+
pub struct ReadError(std::io::Error);
84+
85+
impl fmt::Display for ReadError {
86+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87+
write!(f, "ReadError: {}", self.0)
88+
}
89+
}
90+
91+
impl std::error::Error for ReadError {
92+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
93+
Some(&self.0)
94+
}
95+
}
96+
97+
8198
#[cfg(test)]
8299
mod test {
83100
use super::ReadRng;
@@ -124,6 +141,8 @@ mod test {
124141

125142
let mut rng = ReadRng::new(&v[..]);
126143

127-
assert!(rng.try_fill_bytes(&mut w).is_err());
144+
let result = rng.try_fill_bytes(&mut w);
145+
assert!(result.is_err());
146+
println!("Error: {}", result.unwrap_err());
128147
}
129148
}

0 commit comments

Comments
 (0)