Skip to content

Commit 3ce7578

Browse files
committed
Add OsRng wasm support
1 parent 893b50b commit 3ce7578

File tree

5 files changed

+68
-11
lines changed

5 files changed

+68
-11
lines changed

.travis.yml

+7
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ matrix:
2424
after_success:
2525
- travis-cargo --only nightly doc-upload
2626

27+
- rust: nightly
28+
install:
29+
- rustup target add wasm32-unknown-unknown
30+
- cargo install --force cargo-web
31+
script:
32+
- cargo web test --target wasm32-unknown-unknown --nodejs
33+
2734
script:
2835
- cargo test
2936
- cargo test --tests --no-default-features

Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,6 @@ cloudabi = "0.0.3"
4848

4949
[target.'cfg(target_os = "fuchsia")'.dependencies]
5050
fuchsia-zircon = "0.3.2"
51+
52+
[target.wasm32-unknown-unknown.dependencies]
53+
stdweb = "0.4"

src/lib.rs

+6
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@
249249
#![cfg_attr(not(feature="std"), no_std)]
250250
#![cfg_attr(all(feature="alloc", not(feature="std")), feature(alloc))]
251251
#![cfg_attr(feature = "i128_support", feature(i128_type, i128))]
252+
#![cfg_attr(all(target_arch = "wasm32", not(target_os = "emscripten")), recursion_limit="128")]
252253

253254
#[cfg(feature="std")] extern crate std as core;
254255
#[cfg(all(feature = "alloc", not(feature="std")))] extern crate alloc;
@@ -257,6 +258,10 @@
257258
#[cfg(feature="serde-1")] extern crate serde;
258259
#[cfg(feature="serde-1")] #[macro_use] extern crate serde_derive;
259260

261+
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
262+
#[macro_use]
263+
extern crate stdweb;
264+
260265
#[cfg(feature = "log")] #[macro_use] extern crate log;
261266
#[cfg(not(feature = "log"))] macro_rules! trace { ($($x:tt)*) => () }
262267
#[cfg(not(feature = "log"))] macro_rules! debug { ($($x:tt)*) => () }
@@ -1553,6 +1558,7 @@ mod test {
15531558

15541559
#[test]
15551560
#[cfg(feature="std")]
1561+
#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
15561562
fn test_thread_rng() {
15571563
let mut r = thread_rng();
15581564
r.gen::<i32>();

src/os.rs

+46-5
Original file line numberDiff line numberDiff line change
@@ -576,27 +576,60 @@ mod imp {
576576

577577
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
578578
mod imp {
579-
use std::io;
579+
use stdweb::unstable::TryInto;
580+
use stdweb::web::error::Error as WebError;
581+
use {Error, ErrorKind};
580582

581583
#[derive(Debug)]
582584
pub struct OsRng;
583585

584586
impl OsRng {
585587
pub fn new() -> Result<OsRng, Error> {
586-
Err(Error::new(ErrorKind::Unavailable, "not supported on WASM"))
588+
Ok(OsRng)
587589
}
590+
588591
pub fn try_fill_bytes(&mut self, v: &mut [u8]) -> Result<(), Error> {
589-
Err(Error::new(ErrorKind::Unavailable, "not supported on WASM"))
592+
let len = v.len() as u32;
593+
let ptr = v.as_mut_ptr() as i32;
594+
595+
let result = js! {
596+
let len = @{ len };
597+
let ptr = @{ ptr };
598+
599+
try {
600+
try {
601+
let array = new Uint8Array(len);
602+
window.crypto.getRandomValues(array);
603+
HEAPU8.set(array, ptr);
604+
} catch(err) {
605+
if (err instanceof ReferenceError) {
606+
let bytes = require("crypto").randomBytes(len);
607+
HEAPU8.set(new Uint8Array(bytes), ptr);
608+
} else {
609+
throw err;
610+
}
611+
}
612+
613+
return { success: true };
614+
} catch(err) {
615+
return { success: false, error: err };
616+
}
617+
};
618+
619+
if js!{ return @{ result.as_ref() }.success } == true {
620+
Ok(())
621+
} else {
622+
let err: WebError = js!{ return @{ result }.error }.try_into().unwrap();
623+
Err(Error::with_cause(ErrorKind::Other, "WASM Error", err))
624+
}
590625
}
591626
}
592627
}
593628

594629
#[cfg(test)]
595630
mod test {
596-
use std::sync::mpsc::channel;
597631
use RngCore;
598632
use OsRng;
599-
use std::thread;
600633

601634
#[test]
602635
fn test_os_rng() {
@@ -607,10 +640,18 @@ mod test {
607640

608641
let mut v = [0u8; 1000];
609642
r.fill_bytes(&mut v);
643+
644+
let mut v2 = [0u8; 1000];
645+
r.fill_bytes(&mut v2);
646+
647+
assert_ne!(v[..], v2[..]);
610648
}
611649

650+
#[cfg(not(any(target_arch = "wasm32", target_arch = "asmjs")))]
612651
#[test]
613652
fn test_os_rng_tasks() {
653+
use std::sync::mpsc::channel;
654+
use std::thread;
614655

615656
let mut txs = vec!();
616657
for _ in 0..20 {

src/seq.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,8 @@ mod test {
257257
let mut r = ::test::rng(402);
258258

259259
// sample 0 items
260-
assert_eq!(&sample_slice(&mut r, empty, 0)[..], []);
261-
assert_eq!(&sample_slice(&mut r, &[42, 2, 42], 0)[..], []);
260+
assert_eq!(&sample_slice(&mut r, empty, 0)[..], [0u8; 0]);
261+
assert_eq!(&sample_slice(&mut r, &[42, 2, 42], 0)[..], [0u8; 0]);
262262

263263
// sample 1 item
264264
assert_eq!(&sample_slice(&mut r, &[42], 1)[..], [42]);
@@ -269,12 +269,12 @@ mod test {
269269
let v = sample_slice(&mut r, &[42, 133], 2);
270270
assert!(&v[..] == [42, 133] || v[..] == [133, 42]);
271271

272-
assert_eq!(&sample_indices_inplace(&mut r, 0, 0)[..], []);
273-
assert_eq!(&sample_indices_inplace(&mut r, 1, 0)[..], []);
272+
assert_eq!(&sample_indices_inplace(&mut r, 0, 0)[..], [0usize; 0]);
273+
assert_eq!(&sample_indices_inplace(&mut r, 1, 0)[..], [0usize; 0]);
274274
assert_eq!(&sample_indices_inplace(&mut r, 1, 1)[..], [0]);
275275

276-
assert_eq!(&sample_indices_cache(&mut r, 0, 0)[..], []);
277-
assert_eq!(&sample_indices_cache(&mut r, 1, 0)[..], []);
276+
assert_eq!(&sample_indices_cache(&mut r, 0, 0)[..], [0usize; 0]);
277+
assert_eq!(&sample_indices_cache(&mut r, 1, 0)[..], [0usize; 0]);
278278
assert_eq!(&sample_indices_cache(&mut r, 1, 1)[..], [0]);
279279

280280
// Make sure lucky 777's aren't lucky

0 commit comments

Comments
 (0)