-
Notifications
You must be signed in to change notification settings - Fork 2
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
Error handling #7
Conversation
3fa27ca
to
a43a3f7
Compare
I am slowly getting better at rebasing 😄 |
rand_core/src/lib.rs
Outdated
pub struct Error; | ||
|
||
#[cfg(feature="std")] | ||
impl From<::std::io::Error> for 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 did not add this From
implementation yet.
I actually had one, that would map the IO errors you could get for OsRng
to the appropriate RngError
.
But I am not sure it would always be correct for other RNGs implementations. It are the more exotic ones that produce errors...
Not adding one forces RNG implementations to put a little more thought into their error handling. Which might be a plus... For ReadRng
the missing implementation did not really make it more difficult, and I also expect it not to for 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.
This sounds sensible to me.
@@ -76,8 +76,8 @@ impl Rng for MockAddRng<u64> { | |||
impls::next_u128_via_u64(self) | |||
} | |||
|
|||
fn try_fill(&mut self, dest: &mut [u8]) -> Result<()> { | |||
impls::try_fill_via_u32(self, dest) |
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.
via_u32
was a typo maybe?
rand_core/src/lib.rs
Outdated
} | ||
/// Error type for random number generators. | ||
#[derive(Copy, PartialEq, Eq, Clone, Debug)] | ||
pub enum RngError { |
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'd prefer the name Error
personally — less repetition and matches usual naming conventions.
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 thought I was following some sort of convention after reading the Error Handling Chapter in TRPL again. But Error
seems to be common, and it shorter. I will change it.
Also just noticed: It should implement the ::std::error::Error
trait.
rand_core/src/lib.rs
Outdated
} | ||
|
||
/// Result type (convenience type-def) | ||
pub type Result<T> = ::std::result::Result<T, 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.
Why remove this?
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.
Have you seen my reason in the PR description?
In part the reason is that I was bitten by the redefined Result type ;-).
But I don't really see a reason to have it, as we only use it in the trait definitions in a handful of places.
In a library that uses the std::result::Result
, would users also import rand::Result
? Or would they want to use the std one and import our rand::Error
?
It seems to me (but I am inexperienced) browsing documentation and copying examples is easier without the redefine...
rand_core/src/lib.rs
Outdated
NotAvailable, | ||
/// Needs (re)seeding. Depending on the RNG this can mean you have to wait | ||
/// and retry later, or you have to (re)seed it. | ||
EntropyLow, |
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.
Not so keen on the doc or name for this one, and not sure if the two different things should be combined anyway — what's the advantage?
Possible doc: For PRNGs, this implies they should be (re)seeded. For external RNGs (e.g. OsRng
) this implies you should wait and try again later.
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.
Ok, I will split them
rand_core/src/lib.rs
Outdated
pub type Result<T> = ::std::result::Result<T, Error>; | ||
fn cause(&self) -> Option<&::std::error::Error> { | ||
None | ||
} |
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 don't think there's any point implementing cause
if it just returns None
; this is the default impl.
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.
Didn't notice that. No, than I can happily remove it
Ok, removing the |
Yes, the discussion has died down a bit, but I agree there are still some things open. I also have some unposted comments on my pc about it, that need finishing :-). After playing with this Error enum a bit more, I miss that it can not return a cause. What do you think about a struct with this enum and a cause when using |
Regarding my previous comment — any chance you can split this PR? I hate reviewing stuff this big. But also it might be better to merge the Isaac stuff first. |
I was careful to split the PR in 3 commits. Each should be the smallest change that keeps building. It is your call. Shall I remove the second two commits, and make PR's for them when this one lands? |
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.
Couple of minor things. Looks like two of my comments were addressed by a later commit.
if is_getrandom_available() { | ||
return Ok(OsRng { inner: OsGetrandomRng }); | ||
} | ||
|
||
let reader = File::open("/dev/urandom")?; | ||
let reader = File::open("/dev/urandom").unwrap(); |
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.
Handle this error?
pub fn new() -> Result<OsRng> { | ||
let reader = File::open("rand:")?; | ||
pub fn new() -> Result<OsRng, Error> { | ||
let reader = File::open("rand:").unwrap(); |
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.
And this one
src/os.rs
Outdated
for s in v.chunks_mut(fuchsia_zircon::ZX_CPRNG_DRAW_MAX_LEN) { | ||
pub fn try_fill(&mut self, v: &mut [u8]) -> Result<(), 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.
Huh? Did this jump a line?
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.
That is weird, will fix.
src/read.rs
Outdated
match r.read(buf) { | ||
Ok(0) => return Err(Error::new(ErrorKind::Unavailable, None)), | ||
Ok(n) => buf = &mut mem::replace(&mut buf, &mut [])[n..], | ||
Err(_) => return Err(Error::new(ErrorKind::Other, None)), |
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.
Err(e) => return Err(Error::new(ErrorKind::Other, Box::new(e)))
src/read.rs
Outdated
0 => return Err(Error), | ||
n => buf = &mut mem::replace(&mut buf, &mut [])[n..], | ||
match r.read(buf) { | ||
Ok(0) => return Err(Error::new(ErrorKind::Unavailable, None)), |
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.
Nothing you can do with the given error type, but it does feel like the cause is missing here
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 fixed in the third commit, that gives ReadRng
better error handling
rand_core/src/lib.rs
Outdated
fn try_fill(&mut self, dest: &mut [u8]) -> Result<(), Error>; | ||
fn try_fill(&mut self, dest: &mut [u8]) -> Result<(), Error> { | ||
Ok(self.fill_bytes(dest)) | ||
} |
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.
Default impl... I'd like not to have this
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.
Maybe we can discuss it in #12? Personally I don't see a problem, but I may be missing something.
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.
There's an argument in the RFC about this
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 will remove it
For |
Also moved the `impl_uint_from_fill` macro from `os.rs` to `randcore`. I had to modify its error handling anyway, and it is shared with `OsRng`.
Removed the default implementation of |
Yes, I guess so. I'll merge this. Do a merge commit rather than a rebase on your other branch please. |
This PR tries out some of the error handling we seem to be arriving at in the RFC tread.
For the error enum I have now:
It occurred to me the variants
EntropyExhausted
andNetYetSeeded
on the RFC thread are essentially the same, so I combined them intoEntropyLow
.This commit partly undoes your work in 0a97209, I am sorry.
Maybe it is just me being to inexperienced, but the
Result
with two arguments looks clearer to me. I think it helps documentation-wise, as you can now click on the return typeRngError
in rustdoc and see the various causes. Because we have only four different methods that can return aResult
, it does not really seem an ergonomic loss.The second commit adds back
fill_bytes
. I gavetry_fill
a default implementation in terms offill_bytes
. This makes implementation of PRNGs (which usually never error) slightly simpler, as they don't have to use Result. Wrappers become slightly more complex, as they have to wrap another method.In the third commit I tried out the new error handling with
ReadRng
.Actually I was working on the
OsRng
implementations, and did not plan on writing this :-).So I have not touched the code in
os.rs
that much yet.