-
Notifications
You must be signed in to change notification settings - Fork 186
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
Add support for Custom RNGs #109
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.
Looks like a nice solution to #4 to me.
I get why you built this on top of your CI changes, but it doesn't require your other PR (removing dummy
), and I'm not convinced we want that (although I believe the main objection to making wasm32-unknown-unknown
a compile failure was that it's a breaking change).
Although it's a nice demonstration of custom RNGs, is there much point in moving the WASM implementations out of the base crate? Dependency reduction?
src/error.rs
Outdated
pub(crate) const STDWEB_NO_RNG: Error = internal_error!(9); | ||
pub(crate) const STDWEB_RNG_FAILED: Error = internal_error!(10); | ||
#[doc(hidden)] | ||
pub const BINDGEN_CRYPTO_UNDEF: Error = internal_error!(7); |
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 hide these? They are defined constants either way.
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'll need to go back an document these (this was just to make the CI happy). There's also the separate question of if we should expose all of the Error
constants or just those necessary to make the custom RNGs work. What do you think?
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 also the issue of Debug
/ Display
implementations (error strings) when moving implementations out of the main crate.
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'm not sure what you mean? The error strings would stay in the main getrandom
, I guess it means Custom RNGs not in this repo just have to use numbers instead of words. That's not ideal, but fixing it is probably just too hard.
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.
Fixing it is rust-random/rand#837 which it looks like we will not solve. But for these WASM crates we should keep the error stings in getrandom
.
Unless we add an auxilliary extern Rust function:
fn __getrandom_error_msg(code: NonZeroU32) -> Option<&'static str>;
I don't believe it's worth it for now though (and it doesn't solve error messages for anything outside getrandom
).
src/custom.rs
Outdated
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { | ||
extern "Rust" { | ||
#[allow(improper_ctypes)] // See rust-lang/rust#64593 | ||
fn __getrandom_custom(dest: &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.
Looks like a nice solution.
The call stack is now potentially getrandom::getrandom
→ getrandom::getrandom_inner
→ __getrandom_custom
→ provider::getrandom_inner
, but use of #[inline]
in a couple of places reduces this to 2.
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 even without the #[inline]
Rust will manage to get rid of all the intermediate function calls except the __getrandom_custom
, but I should run a compile test to make sure.
I'm not sure if inlining is automatically available across module boundaries, I know we need #[inline] if we want to do across crate boundaries.
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.
Yes, and I think __getrandom_custom
can never be inlined (without LTO), but it shouldn't be a big issue.
Ya the previous discussion is why I proposed it. I think having the dummy impl is almost never what a user wants. I think that regardless of if we implement Of course, what to do for no-implementation One interesting concept is that a "dummy" impl could be just another Custom RNG |
We can always re-add the |
The main reason (other than making the dependency story easier) would be to eliminate the need for crates to keep reexporting the Thinking of a large Rust application, where I'm not sure how this calculation changes if we are able to detect at build-time if we are in |
The alternative being, as we tell The complication is that we have more crate versions to deal with. If we release |
External crates have another benefit: it makes custom Of course, those have specific
So the situation isn't too bad, provided two conditions are met:
For example, let's say we have the following versions of
Then we can have:
and nothing should break. The following use cases all work how you would expect:
The only issue would be if there are multiple Custom RNG handlers in a crate's dependency tree, then you'd get a linking error. However, that shouldn't happen as Cargo should only select on of This all works because the |
Agreed. Thus we have extra incentive to make sure the API is stable; this looks fine to me but given the scarcity of doc around extern "Rust" {
fn __getrandom_custom(dest: &mut [u8]) -> Result<(), Error>;
} |
Continuing the discussion from @newpavlov and @dhardy's comments in #107
I poorly communicated how I wanted to fix the potential First, this PR will add in a Second, we will consider a simplified version of the
To do this, [dependencies]
getrandom = "0.2"
[target.wasm32-unknown-unknown.dependencies]
wasm-bindgen = { package = "getrandom-wasm-bindgen", version = "0.1", optional = true }
stdweb = { package = "getrandom-stdweb", version = "0.1", optional = true }
getrandom-dummy = "0.1" and the following code in its #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
cfg_if! {
if #[cfg(feature = "wasm-bindgen")] {
extern crate wasm_bindgen;
} else if #[cfg(feature = "stdweb")] {
extern crate stdweb;
} else {
extern crate getrandom_dummy;
}
} ensuring that for all EDIT: Note that the code above is (about) what would be in the |
EDIT: this comment is wrong, see #109 (comment) As for [features]
std = ["getrandom", "getrandom/std"]
[dependencies]
getrandom = { version = "0.2", default-features = false, optional = true } This allows [features]
std = ["getrandom/std"]
[dependencies]
getrandom = { version = "0.2", default-features = false } and unconditionally depend on This |
Edit: the first paragraph is wrong; see below. @josephlr the use of Maybe we can get away with simply telling people don't enable both; I don't know. Why add a Since |
Crap, I forgot about this. Scratch the stuff about
This crate would mainly be used to allow crates to migrate to the new system, while exposing their old APIs, while using less code. It also allow you to work around a Cargo limitation where you can't have enable features on a crate based on specific targets. The final reason is that it would allow us to actually remove the I would expect |
So this isn't true, but I thought the same thing (that I also make sure this wasn't a particular linker property. But the |
From testing, it appears that my understanding is wrong on this and that linking only happens if (a) Note that one can also write Furthermore, this means that an application adding a dependency on, say, The language spec doesn't directly cover this unfortunately. The section on extern crates does talk about linking, but it is not clear whether this has been updated for Edition 2018. The sections on use declarations and linking also do not clear this up. |
Looks like we submitted at the exact same time 😁
I also ran into this sometimes, apparently the key is to make sure the custom RNG crates are of type
I agree that it could be a little more convenient, but it's not too bad (you just need one line in your lib's Do you think this is still the way to go for Custom RNGs?
I agree, but it does seem like the referencing of a crate (not its declaration as a Cargo dependency) is what controls all aspects of linking. |
b2367d0
to
fe00336
Compare
@dhardy @newpavlov I rebased this, updated the description, and better split the changes into commits. Let me know if you think any of these changes should be in their own PR. |
I would prefer to keep anything to-do with
The Cargo features issue shouldn't apply here ( |
Make sense, |
9d4c68b
to
b057dfc
Compare
I've rebased this onto #120 and improved the commit messages to be more readable. I also renamed the Custom RNG implementations to be I've addressed all of the outstanding feedback, so I think the only thing left here is to update the module documentation and |
6eeba77
to
00d5950
Compare
@josephlr |
f67987a
to
e8d6f15
Compare
This is a breaking change for #98, so it's being merged against the 0.2 branch.
This change consists on several significant changes, so reviewing on a per commit basis may be the easiest. The changes (in rough commit order) are:
getrandom::Error
constants are moved to be associated constants, and they are now all public and documented.wasm32
implementations (wasm-bindgen
andstdweb
) are removed from the main cratecustom
Cargo feature) to enable registering and using a custom RNG implementation. This is done by having the custom function be declared with#[no_mangle]
, and having the function called viaextern "C"
.stdweb-getrandom
: Replacing thestdweb
featurewasm-bindgen-getrandom
: Replacing thewasm-bindgen
featureFixes #4 and allows for having a
getrandom-rdrand
Custom RNG (which provides a better solution for #84)