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

Add support for wasm-bindgen #541

Merged
merged 1 commit into from Jul 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions .travis.yml
Expand Up @@ -57,6 +57,12 @@ matrix:
script:
- cargo web test --target wasm32-unknown-unknown --nodejs --features=stdweb

- rust: nightly
install:
- rustup target add wasm32-unknown-unknown
script:
- cargo build --target wasm32-unknown-unknown --features wasm-bindgen

- rust: nightly
install:
- rustup target add thumbv6m-none-eabi
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -50,6 +50,7 @@ fuchsia-zircon = { version = "0.3.2", optional = true }
[target.wasm32-unknown-unknown.dependencies]
# use with `--target wasm32-unknown-unknown --features=stdweb`
stdweb = { version = "0.4", optional = true }
wasm-bindgen = { version = "0.2", optional = true }

[dev-dependencies]
# This is for testing serde, unfortunately we can't specify feature-gated dev
Expand Down
6 changes: 5 additions & 1 deletion README.md
Expand Up @@ -117,8 +117,12 @@ optional features are available:
- `log` enables some logging via the `log` crate.
- `nightly` enables all unstable features (`i128_support`).
- `serde1` enables serialization for some types, via Serde version 1.
- `stdweb` enables support for `OsRng` on `wasm-unknown-unknown` via `stdweb`
- `stdweb` enables support for `OsRng` on `wasm32-unknown-unknown` via `stdweb`
combined with `cargo-web`.
- `wasm-bindgen` enables support for `OsRng` on `wasm32-unknown-unknown` via
[`wasm-bindgen`]

[`wasm-bindgen`]: https://github.com/rustwasm/wasm-bindgen

`no_std` mode is activated by setting `default-features = false`; this removes
functionality depending on `std`:
Expand Down
12 changes: 8 additions & 4 deletions src/deprecated.rs
Expand Up @@ -263,7 +263,8 @@ impl CryptoRng for StdRng {}
target_os = "redox",
target_os = "fuchsia",
windows,
all(target_arch = "wasm32", feature = "stdweb")
all(target_arch = "wasm32", feature = "stdweb"),
all(target_arch = "wasm32", feature = "wasm-bindgen"),
)))]
#[derive(Clone, Debug)]
#[deprecated(since="0.6.0", note="import with rand::rngs::OsRng instead")]
Expand All @@ -283,7 +284,8 @@ pub struct OsRng(rngs::OsRng);
target_os = "redox",
target_os = "fuchsia",
windows,
all(target_arch = "wasm32", feature = "stdweb")
all(target_arch = "wasm32", feature = "stdweb"),
all(target_arch = "wasm32", feature = "wasm-bindgen"),
)))]
#[cfg(feature="std")]
impl RngCore for OsRng {
Expand Down Expand Up @@ -322,7 +324,8 @@ impl RngCore for OsRng {
target_os = "redox",
target_os = "fuchsia",
windows,
all(target_arch = "wasm32", feature = "stdweb")
all(target_arch = "wasm32", feature = "stdweb"),
all(target_arch = "wasm32", feature = "wasm-bindgen"),
)))]
#[cfg(feature="std")]
impl OsRng {
Expand All @@ -345,7 +348,8 @@ impl OsRng {
target_os = "redox",
target_os = "fuchsia",
windows,
all(target_arch = "wasm32", feature = "stdweb")
all(target_arch = "wasm32", feature = "stdweb"),
all(target_arch = "wasm32", feature = "wasm-bindgen"),
)))]
#[cfg(feature="std")]
impl CryptoRng for OsRng {}
Expand Down
126 changes: 98 additions & 28 deletions src/lib.rs
Expand Up @@ -84,7 +84,7 @@
//!
//! The [`distributions` module] provides implementations
//! of some other distributions, including Normal, Log-Normal and Exponential.
//!
//!
//! It is worth noting that the functionality already mentioned is implemented
//! with distributions: [`gen`] samples values using the [`Standard`]
//! distribution, while [`gen_range`] uses [`Uniform`].
Expand All @@ -109,7 +109,7 @@
//!
//! // thread_rng is often the most convenient source of randomness:
//! let mut rng = thread_rng();
//!
//!
//! if rng.gen() { // random bool
//! let x: f64 = rng.gen(); // random number in range [0, 1)
//! println!("x is: {}", x);
Expand Down Expand Up @@ -230,6 +230,9 @@
#![cfg_attr(all(feature="i128_support", feature="nightly"), feature(i128_type, i128))]
#![cfg_attr(all(feature="simd_support", feature="nightly"), feature(stdsimd))]
#![cfg_attr(feature = "stdweb", recursion_limit="128")]
#![cfg_attr(feature = "wasm-bindgen", feature(proc_macro))]
#![cfg_attr(feature = "wasm-bindgen", feature(wasm_import_module))]
#![cfg_attr(feature = "wasm-bindgen", feature(wasm_custom_section))]

#[cfg(feature="std")] extern crate std as core;
#[cfg(all(feature = "alloc", not(feature="std")))] extern crate alloc;
Expand All @@ -242,6 +245,9 @@
#[macro_use]
extern crate stdweb;

#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))]
extern crate wasm_bindgen;

extern crate rand_core;

#[cfg(feature = "log")] #[macro_use] extern crate log;
Expand Down Expand Up @@ -297,7 +303,8 @@ pub mod seq;
target_os = "redox",
target_os = "fuchsia",
windows,
all(target_arch = "wasm32", feature = "stdweb")
all(target_arch = "wasm32", feature = "stdweb"),
all(target_arch = "wasm32", feature = "wasm-bindgen"),
)))]
#[doc(hidden)]
pub use deprecated::OsRng;
Expand Down Expand Up @@ -329,7 +336,8 @@ pub mod jitter {
target_os = "redox",
target_os = "fuchsia",
windows,
all(target_arch = "wasm32", feature = "stdweb")
all(target_arch = "wasm32", feature = "stdweb"),
all(target_arch = "wasm32", feature = "wasm-bindgen"),
)))]
#[doc(hidden)]
pub mod os {
Expand Down Expand Up @@ -364,20 +372,20 @@ use distributions::uniform::{SampleUniform, UniformSampler, SampleBorrow};

/// An automatically-implemented extension trait on [`RngCore`] providing high-level
/// generic methods for sampling values and other convenience methods.
///
///
/// This is the primary trait to use when generating random values.
///
///
/// # Generic usage
///
///
/// The basic pattern is `fn foo<R: Rng + ?Sized>(rng: &mut R)`. Some
/// things are worth noting here:
///
///
/// - Since `Rng: RngCore` and every `RngCore` implements `Rng`, it makes no
/// difference whether we use `R: Rng` or `R: RngCore`.
/// - The `+ ?Sized` un-bounding allows functions to be called directly on
/// type-erased references; i.e. `foo(r)` where `r: &mut RngCore`. Without
/// this it would be necessary to write `foo(&mut r)`.
///
///
/// An alternative pattern is possible: `fn foo<R: Rng>(rng: R)`. This has some
/// trade-offs. It allows the argument to be consumed directly without a `&mut`
/// (which is how `from_rng(thread_rng())` works); also it still works directly
Expand All @@ -386,20 +394,20 @@ use distributions::uniform::{SampleUniform, UniformSampler, SampleBorrow};
/// hence many uses of `rng` require an extra reference, either explicitly
/// (`distr.sample(&mut rng)`) or implicitly (`rng.gen()`); one may hope the
/// optimiser can remove redundant references later.
///
///
/// Example:
///
///
/// ```
/// # use rand::thread_rng;
/// use rand::Rng;
///
///
/// fn foo<R: Rng + ?Sized>(rng: &mut R) -> f32 {
/// rng.gen()
/// }
///
/// # let v = foo(&mut thread_rng());
/// ```
///
///
/// [`RngCore`]: trait.RngCore.html
pub trait Rng: RngCore {
/// Return a random value supporting the [`Standard`] distribution.
Expand Down Expand Up @@ -624,7 +632,7 @@ pub trait Rng: RngCore {
/// Return a random element from `values`.
///
/// Deprecated: use [`SliceRandom::choose`] instead.
///
///
/// [`SliceRandom::choose`]: seq/trait.SliceRandom.html#method.choose
#[deprecated(since="0.6.0", note="use SliceRandom::choose instead")]
fn choose<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T> {
Expand All @@ -635,7 +643,7 @@ pub trait Rng: RngCore {
/// Return a mutable pointer to a random element from `values`.
///
/// Deprecated: use [`SliceRandom::choose_mut`] instead.
///
///
/// [`SliceRandom::choose_mut`]: seq/trait.SliceRandom.html#method.choose_mut
#[deprecated(since="0.6.0", note="use SliceRandom::choose_mut instead")]
fn choose_mut<'a, T>(&mut self, values: &'a mut [T]) -> Option<&'a mut T> {
Expand All @@ -646,7 +654,7 @@ pub trait Rng: RngCore {
/// Shuffle a mutable slice in place.
///
/// Deprecated: use [`SliceRandom::shuffle`] instead.
///
///
/// [`SliceRandom::shuffle`]: seq/trait.SliceRandom.html#method.shuffle
#[deprecated(since="0.6.0", note="use SliceRandom::shuffle instead")]
fn shuffle<T>(&mut self, values: &mut [T]) {
Expand All @@ -658,15 +666,15 @@ pub trait Rng: RngCore {
impl<R: RngCore + ?Sized> Rng for R {}

/// Trait for casting types to byte slices
///
///
/// This is used by the [`fill`] and [`try_fill`] methods.
///
///
/// [`fill`]: trait.Rng.html#method.fill
/// [`try_fill`]: trait.Rng.html#method.try_fill
pub trait AsByteSliceMut {
/// Return a mutable reference to self as a byte slice
fn as_byte_slice_mut(&mut self) -> &mut [u8];

/// Call `to_le` on each element (i.e. byte-swap on Big Endian platforms).
fn to_le(&mut self);
}
Expand All @@ -675,7 +683,7 @@ impl AsByteSliceMut for [u8] {
fn as_byte_slice_mut(&mut self) -> &mut [u8] {
self
}

fn to_le(&mut self) {}
}

Expand All @@ -698,7 +706,7 @@ macro_rules! impl_as_byte_slice {
}
}
}

fn to_le(&mut self) {
for x in self {
*x = x.to_le();
Expand All @@ -724,7 +732,7 @@ macro_rules! impl_as_byte_slice_arrays {
($n:expr,) => {};
($n:expr, $N:ident, $($NN:ident,)*) => {
impl_as_byte_slice_arrays!($n - 1, $($NN,)*);

impl<T> AsByteSliceMut for [T; $n] where [T]: AsByteSliceMut {
fn as_byte_slice_mut(&mut self) -> &mut [u8] {
self[..].as_byte_slice_mut()
Expand All @@ -743,7 +751,7 @@ macro_rules! impl_as_byte_slice_arrays {
fn as_byte_slice_mut(&mut self) -> &mut [u8] {
self[..].as_byte_slice_mut()
}

fn to_le(&mut self) {
self[..].to_le()
}
Expand Down Expand Up @@ -874,6 +882,68 @@ pub fn random<T>() -> T where Standard: Distribution<T> {
thread_rng().gen()
}

// Due to rustwasm/wasm-bindgen#201 this can't be defined in the inner os
// modules, so hack around it for now and place it at the root.
#[cfg(all(feature = "wasm-bindgen", target_arch = "wasm32"))]
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub mod __wbg_shims {

// `extern { type Foo; }` isn't supported on 1.22 syntactically, so use a
// macro to work around that.
macro_rules! rust_122_compat {
($($t:tt)*) => ($($t)*)
}

rust_122_compat! {
extern crate wasm_bindgen;

pub use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern {
pub type This;
pub static this: This;

#[wasm_bindgen(method, getter, structural, js_name = self)]
pub fn self_(me: &This) -> JsValue;
#[wasm_bindgen(method, getter, structural)]
pub fn crypto(me: &This) -> JsValue;

pub type BrowserCrypto;

// TODO: these `structural` annotations here ideally wouldn't be here to
// avoid a JS shim, but for now with feature detection they're
// unavoidable.
#[wasm_bindgen(method, js_name = getRandomValues, structural, getter)]
pub fn get_random_values_fn(me: &BrowserCrypto) -> JsValue;
#[wasm_bindgen(method, js_name = getRandomValues, structural)]
pub fn get_random_values(me: &BrowserCrypto, buf: &mut [u8]);

#[wasm_bindgen(js_name = require)]
pub fn node_require(s: &str) -> NodeCrypto;

pub type NodeCrypto;

#[wasm_bindgen(method, js_name = randomFillSync, structural)]
pub fn random_fill_sync(me: &NodeCrypto, buf: &mut [u8]);
}

// TODO: replace with derive once rustwasm/wasm-bindgen#400 is merged
impl Clone for BrowserCrypto {
fn clone(&self) -> BrowserCrypto {
BrowserCrypto { obj: self.obj.clone() }
}
}

impl Clone for NodeCrypto {
fn clone(&self) -> NodeCrypto {
NodeCrypto { obj: self.obj.clone() }
}
}
}
}

#[cfg(test)]
mod test {
use rngs::mock::StepRng;
Expand Down Expand Up @@ -936,25 +1006,25 @@ mod test {
}
}
}

#[test]
fn test_fill() {
let x = 9041086907909331047; // a random u64
let mut rng = StepRng::new(x, 0);

// Convert to byte sequence and back to u64; byte-swap twice if BE.
let mut array = [0u64; 2];
rng.fill(&mut array[..]);
assert_eq!(array, [x, x]);
assert_eq!(rng.next_u64(), x);

// Convert to bytes then u32 in LE order
let mut array = [0u32; 2];
rng.fill(&mut array[..]);
assert_eq!(array, [x as u32, (x >> 32) as u32]);
assert_eq!(rng.next_u32(), x as u32);
}

#[test]
fn test_fill_empty() {
let mut array = [0u32; 0];
Expand Down Expand Up @@ -1029,7 +1099,7 @@ mod test {
assert_eq!(r.gen_range(0, 1), 0);
let _c: u8 = Standard.sample(&mut r);
}

#[test]
#[cfg(feature="std")]
fn test_random() {
Expand Down