Skip to content
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

Provide an easier-to-use rand API #1431

Closed
wants to merge 4 commits into from
Closed

Conversation

Cassy343
Copy link

@Cassy343 Cassy343 commented Dec 7, 2021

I saw that issue #728 hit a dead end a while ago, and I figured that with the somewhat recent stabilization of const generics that it could be picked up again. I extend random construction to arrays of all integer types, however I do use unsafe code to accomplish this. If it is desirable to stick with strictly safe code, then that is definitely possible, however it will likely be more inefficient.

Copy link
Owner

@briansmith briansmith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea seems good. I think we need to have some tests added. In particular, expand the test coverage to all the types you added, and also arrays of length 0.

src/rand.rs Outdated
assert!(
N == 0 || (isize::MAX as usize) / N >= mem::size_of::<T>(),
"Array too large to be converted to slice of u8"
);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this assertion necessary? I thought it was already UB to have self be larger than isize bytes?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should have tests for the case where N == 0 and where core::mem::size_of<T> is zero.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I want to be sure the compiler can evaluate an expression at compile time, I do:

const NO_OVERFLOW: bool = N == 0 || (isize::MAX as usize) / N >= mem::size_of::<T>();
assert!(NO_OVERFLOW);

I'd rather not have the string in the assertion. I'm working to eliminate all such strings.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this assertion necessary? I thought it was already UB to have self be larger than isize bytes?

Ope I somehow managed to not read the * mem::size_of<T> part in the docs. I'll take that out - it makes matters simpler anyway.

// derived from another mutable slice
// - Because T is POD, and because `len` is calculated based on the size of T,
// `data` points to `len` initialized u8s
// - We co-opt the lifetime of `self`, so no borrow checker rules are broken
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about this:

        // - We co-opt the lifetime of `self`, so no borrow checker rules are broken

It's hard for me to remember the exact circumstances, but I recall trying to do something similar and finding that I was running into a conflict with the mutable noalias optimization or similar.

This, in conjunction with wanting to avoid the need to initially zero all the bytes to start with, made me want to rewrite this whole module in terms of MaybeUninit and pointers.

WDYT?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I had not heard of the mutable noalias optimization before, and quick google searches of it suggest that it's actually buggy in the LLVM. In a world where there is no mis-compilation, the function signature should essentially be equivalent to fn as_mut_bytes<'a>(&'a mut self) -> &'a mut [u8], and since 'a will be inferred by the usage of the return value, it will extend the borrow of self accordingly. I can ask some other rustaceans I know about it to double check though.

When reading through the module I also thought about what it would look like to switch it over to using raw pointers. I think that's a viable option (and skips the pain of creating an initially zeroed-out array), but I didn't want to get waist deep with changing SecureRandom on my first contribution.

@Cassy343
Copy link
Author

Is there any interest in moving the issue this PR addresses forward or should I close this PR?

@briansmith
Copy link
Owner

Thanks for the PR. See rust-random/getrandom#293 and the discussion in the related getrandom issue, where I discuss some of the API considerations and propose an alternative to defining a Pod/zerocopy/bytemuch-style API. I'm going to close this in favor of moving in that direction.

@briansmith briansmith closed this Oct 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants