-
Notifications
You must be signed in to change notification settings - Fork 432
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rand_core::Error new version #771
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still have to think about this. Stripping out the little-used kind
feature does allow some simplification. Stripping out the msg
does reduce the size of the type, but last time I looked at the effect of error-type size on performance I saw no effect (I may have missed something, but without evidence for this I don't believe we should concern ourselves much with the size).
This is a big breaking change for anyone doing almost anything with Error
aside from Error::from
and the std::error
impl, so we should think carefully before merging (I don't know if it's possible to use Crater to test this).
/// | ||
/// PRNG initialization: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worth having two separate examples? The one below does demonstrate direct usage of next_u32
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I wanted to remove the second example to keep this file more in sync with rand_os
, but I thought you added reseeding example for a reason. So if you don't want to keep it I will remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is one of the major use-cases for OsRng
, hence I showed both.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the example below you demonstrate u32
generation using StdRng
, not OsRng
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both, actually. Maybe it's not clear enough.
I will return pub struct Error {
msg: &'static str,
#[cfg(not(feature="std"))]
code: ErrorCode,
#[cfg(feature="std")]
cause: Box<dyn std::error::Error + Send + Sync>,
} As for breakage, I thought you will publish |
Where should it be moved? It is nice to have when implementing RNGs, so I think it makes sense in |
To a separate crate. To me those block utilities look similar to how |
Maybe we should make Yes, this would require bumping the I don't know that we need more micro-cratering. We could put the block stuff behind a feature-gate, perhaps, but I think most users of |
The problem here is that it is not extensible (i.e. you can't add message for your custom system entropy source). We may add |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at how the new error type affects our code, it appears sufficient, other than one place it would be nice to include an extra message.
It isn't ideal however; e.g. in no_std
mode I think it will only be able to output an error code, not a message.
@@ -54,13 +52,3 @@ impl ::std::error::Error for TimerError { | |||
self.description() | |||
} | |||
} | |||
|
|||
impl From<TimerError> for Error { | |||
fn from(err: TimerError) -> Error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we want this (and it's also not incompatible with the current Error type).
Error::with_cause(ErrorKind::Unavailable, "OsRng failed", e)) | ||
getrandom(dest).map_err(|e| { | ||
#[cfg(feature="std")] { | ||
rand_core::Error::from_cause(e) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nicer not to have to use a cfg
here (e.g. make from_code
work either way). That means the std
feature is also not needed on this crate.
"error reading from Read source", err) | ||
} | ||
}) | ||
self.reader.read_exact(dest).map_err(Error::from_cause) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In theory it's nice to be able to include an extra message here (error manifesting and cause), but not critical.
/// | ||
/// PRNG initialization: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both, actually. Maybe it's not clear enough.
Error::with_cause(ErrorKind::Unavailable, "OsRng failed", e)) | ||
getrandom(dest).map_err(|e| { | ||
#[cfg(feature="std")] { | ||
rand_core::Error::from_cause(e) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As before: shouldn't need the cfg
here.
This still needs deciding. My current thoughts are that since these changes aren't actually fixing anything and the current |
What about #738? As I've wrote earlier you can close/postpone this PR if you are unwilling to publish v0.5 or break backwards compatibility promise a bit. We probably could've kept backward compatibility if My current thoughts on ideal internal structure of BTW removing block stuff from |
I believe you are correct about this fixing #738; for some reason I thought the fundamental problem was Semver allows breaking changes in minor versions (before 1.0) and in major versions; this isn't the issue. The issue is simply how much work needs to be done to fix downstream crates each time they bump the
Mapping is difficult to do in an extensible way, as you already noted for Since the contents of error messages are not part of the API, I wouldn't advise anybody to match against them. However, I've yet to see any good reason to match against the error code anyway, hence I see no need to support this. The About the "cause": this is supposed to be an optional extra detail, not the sole detail (e.g. in Suggestion: /// Error type of random number generators
#[derive(Debug)]
pub struct Error {
/// The error message
pub msg: &'static str,
#[cfg(feature="std")]
cause: Option<Box<stdError + Send + Sync>>,
}
impl Error {
/// Create a new instance, with specified message.
pub fn new(msg: &'static str) -> Self {
#[cfg(feature="std")] {
Error { msg, cause: None }
}
#[cfg(not(feature="std"))] {
Error { msg }
}
}
/// Create a new instance, with specified message, and a chained cause.
///
/// Note: `stdError` is an alias for `std::error::Error`.
#[cfg(feature="std")]
pub fn with_cause<E>(msg: &'static str, cause: E) -> Self
where E: Into<Box<stdError + Send + Sync>>
{
Error { kind, msg, cause: Some(cause.into()) }
}
/// 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()
}
} (Or make It's worth noting that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, my thoughts on this. As you mentioned...
We should pay some attention to reporting meaningful errors, not merely forwarding a code from somewhere. We should at least do this when using std
; for no_std
the best trade-off might be to only forward a code, or maybe we should piggy-back the log
feature (or another) to add details.
As discussed, there may be sufficient value in minimising the size of the error type to avoid more than a single pointer. This doesn't mean we need to exclude details like the error message however; IMO it would be better to double-Box
to include this.
Of course, we should learn our lessons from #738 and from the breakage we now need: the API should, as far as possible, not change between std
and no_std
configurations (although behaviour might), and we shouldn't have pub
fields. I suggest:
pub fn new(msg: &'static str) -> Self;
pub fn with_code(msg: &'static str, code: NonZeroU32) -> Self;
pub fn with_cause<E>(msg: &'static str, cause: E) -> Self;
[cfg(feature="std")] pub fn take_cause(...;
pub fn msg(&self) -> &str; // may return a default string with `no_std`
// possibly also fn code(&self) -> Option<NonZeroU32> ?
The problem is that this doesn't solve #738. I don't like the proposed solution because it forces crates like rand_jitter
and now rand_os
to use a cfg
. I wonder if we could have a generic version (like the current no_std
version of with_cause
) and use specialisation to capture the cause only when this lib and the error source both support std
?
Closed in favor of #800. |
Revise rand_core::Error (alt #771)
A slightly modified variant of approach proposed in #738.
Unfortunately with this approach we lose an ability to differentiate between retryable errors. We can bring it back by returning
ErrorKind
field or by replacing it withretryable
flag, but I am not sure if it's worth the trouble.