From 8a3f3e785c602093780a4f8355a1c09cc6faab45 Mon Sep 17 00:00:00 2001 From: Bastien Orivel Date: Sat, 18 May 2019 13:39:31 +0000 Subject: [PATCH] Bug 1550903 - Part 2: Revendor dependencies. r=emilio,kats,froydnj It was unhappy about the new LICENSE (fuchsia-cprng) but it's the same as the other fuschia crates. Since I don't think this is used at build time but has the same license as the other fuschia crates, I put it in the RUNTIME_LICENSE_PACKAGE_WHITELIST list. I also removed sha1 from that list as it's not used anymore Differential Revision: https://phabricator.services.mozilla.com/D30746 --HG-- rename : third_party/rust/httparse/Cargo.toml => third_party/rust/autocfg/Cargo.toml rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/autocfg/LICENSE-APACHE rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/autocfg/LICENSE-MIT rename : third_party/rust/httparse/Cargo.toml => third_party/rust/cloudabi/Cargo.toml rename : third_party/rust/httparse/Cargo.toml => third_party/rust/fuchsia-cprng/Cargo.toml rename : third_party/rust/sha1/LICENSE => third_party/rust/fuchsia-cprng/LICENSE rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/mio-extras/LICENSE-APACHE rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/mio-extras/LICENSE-MIT rename : third_party/rust/rand/.cargo-checksum.json => third_party/rust/rand-0.4.3/.cargo-checksum.json rename : third_party/rust/rand/CHANGELOG.md => third_party/rust/rand-0.4.3/CHANGELOG.md rename : third_party/rust/rand/Cargo.toml => third_party/rust/rand-0.4.3/Cargo.toml rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/rand-0.4.3/LICENSE-APACHE rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/rand-0.4.3/LICENSE-MIT rename : third_party/rust/rand/README.md => third_party/rust/rand-0.4.3/README.md rename : third_party/rust/rand/appveyor.yml => third_party/rust/rand-0.4.3/appveyor.yml rename : third_party/rust/rand/benches/bench.rs => third_party/rust/rand-0.4.3/benches/bench.rs rename : third_party/rust/rand/benches/distributions/exponential.rs => third_party/rust/rand-0.4.3/benches/distributions/exponential.rs rename : third_party/rust/rand/benches/distributions/gamma.rs => third_party/rust/rand-0.4.3/benches/distributions/gamma.rs rename : third_party/rust/rand/benches/distributions/mod.rs => third_party/rust/rand-0.4.3/benches/distributions/mod.rs rename : third_party/rust/rand/benches/distributions/normal.rs => third_party/rust/rand-0.4.3/benches/distributions/normal.rs rename : third_party/rust/rand/benches/generators.rs => third_party/rust/rand-0.4.3/benches/generators.rs rename : third_party/rust/rand/benches/misc.rs => third_party/rust/rand-0.4.3/benches/misc.rs rename : third_party/rust/rand/src/distributions/exponential.rs => third_party/rust/rand-0.4.3/src/distributions/exponential.rs rename : third_party/rust/rand/src/distributions/gamma.rs => third_party/rust/rand-0.4.3/src/distributions/gamma.rs rename : third_party/rust/rand/src/distributions/mod.rs => third_party/rust/rand-0.4.3/src/distributions/mod.rs rename : third_party/rust/rand/src/distributions/normal.rs => third_party/rust/rand-0.4.3/src/distributions/normal.rs rename : third_party/rust/rand/src/distributions/range.rs => third_party/rust/rand-0.4.3/src/distributions/range.rs rename : third_party/rust/rand/src/distributions/ziggurat_tables.rs => third_party/rust/rand-0.4.3/src/distributions/ziggurat_tables.rs rename : third_party/rust/rand/src/jitter.rs => third_party/rust/rand-0.4.3/src/jitter.rs rename : third_party/rust/rand/src/lib.rs => third_party/rust/rand-0.4.3/src/lib.rs rename : third_party/rust/rand/src/os.rs => third_party/rust/rand-0.4.3/src/os.rs rename : third_party/rust/rand/src/prng/chacha.rs => third_party/rust/rand-0.4.3/src/prng/chacha.rs rename : third_party/rust/rand/src/prng/isaac.rs => third_party/rust/rand-0.4.3/src/prng/isaac.rs rename : third_party/rust/rand/src/prng/isaac64.rs => third_party/rust/rand-0.4.3/src/prng/isaac64.rs rename : third_party/rust/rand/src/prng/mod.rs => third_party/rust/rand-0.4.3/src/prng/mod.rs rename : third_party/rust/rand/src/prng/xorshift.rs => third_party/rust/rand-0.4.3/src/prng/xorshift.rs rename : third_party/rust/rand/src/rand_impls.rs => third_party/rust/rand-0.4.3/src/rand_impls.rs rename : third_party/rust/rand/src/read.rs => third_party/rust/rand-0.4.3/src/read.rs rename : third_party/rust/rand/src/reseeding.rs => third_party/rust/rand-0.4.3/src/reseeding.rs rename : third_party/rust/rand/src/seq.rs => third_party/rust/rand-0.4.3/src/seq.rs rename : third_party/rust/rand/utils/ziggurat_tables.py => third_party/rust/rand-0.4.3/utils/ziggurat_tables.py rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/rand_chacha/LICENSE-APACHE rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/rand_chacha/LICENSE-MIT rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/rand_core-0.3.1/LICENSE-APACHE rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/rand_core-0.3.1/LICENSE-MIT rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/rand_core/LICENSE-APACHE rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/rand_core/LICENSE-MIT rename : third_party/rust/httparse/Cargo.toml => third_party/rust/rand_hc/Cargo.toml rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/rand_hc/LICENSE-APACHE rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/rand_hc/LICENSE-MIT rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/rand_isaac/LICENSE-APACHE rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/rand_isaac/LICENSE-MIT rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/rand_jitter/LICENSE-APACHE rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/rand_jitter/LICENSE-MIT rename : third_party/rust/rand/src/jitter.rs => third_party/rust/rand_jitter/src/lib.rs rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/rand_os/LICENSE-APACHE rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/rand_os/LICENSE-MIT rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/rand_pcg/LICENSE-APACHE rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/rand_pcg/LICENSE-MIT rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/rand_xorshift/LICENSE-APACHE rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/rand_xorshift/LICENSE-MIT rename : third_party/rust/httparse/Cargo.toml => third_party/rust/rdrand/Cargo.toml rename : third_party/rust/rand/LICENSE-APACHE => third_party/rust/sha-1/LICENSE-APACHE rename : third_party/rust/rand/LICENSE-MIT => third_party/rust/sha-1/LICENSE-MIT extra : moz-landing-system : lando --- python/mozbuild/mozbuild/vendor_rust.py | 2 +- third_party/rust/autocfg/.cargo-checksum.json | 1 + third_party/rust/autocfg/Cargo.toml | 24 + third_party/rust/autocfg/LICENSE-APACHE | 201 + third_party/rust/autocfg/LICENSE-MIT | 25 + third_party/rust/autocfg/README.md | 68 + third_party/rust/autocfg/examples/integers.rs | 9 + third_party/rust/autocfg/examples/paths.rs | 22 + third_party/rust/autocfg/examples/traits.rs | 26 + third_party/rust/autocfg/examples/versions.rs | 9 + third_party/rust/autocfg/src/error.rs | 69 + third_party/rust/autocfg/src/lib.rs | 288 ++ third_party/rust/autocfg/src/tests.rs | 57 + third_party/rust/autocfg/src/version.rs | 62 + .../rust/cloudabi/.cargo-checksum.json | 1 + third_party/rust/cloudabi/Cargo.toml | 31 + third_party/rust/cloudabi/bitflags.rs | 51 + third_party/rust/cloudabi/cloudabi.rs | 2847 +++++++++++++ .../rust/fuchsia-cprng/.cargo-checksum.json | 1 + third_party/rust/fuchsia-cprng/AUTHORS | 10 + third_party/rust/fuchsia-cprng/Cargo.toml | 22 + .../rust/{sha1 => fuchsia-cprng}/LICENSE | 26 +- third_party/rust/fuchsia-cprng/PATENTS | 22 + third_party/rust/fuchsia-cprng/src/lib.rs | 57 + .../rust/httparse/.cargo-checksum.json | 2 +- third_party/rust/httparse/Cargo.toml | 9 +- third_party/rust/httparse/README.md | 11 +- third_party/rust/httparse/benches/parse.rs | 58 +- third_party/rust/httparse/build.rs | 155 + third_party/rust/httparse/src/iter.rs | 38 +- third_party/rust/httparse/src/lib.rs | 300 +- third_party/rust/httparse/src/macros.rs | 59 + third_party/rust/httparse/src/simd/avx2.rs | 116 + .../rust/httparse/src/simd/fallback.rs | 8 + third_party/rust/httparse/src/simd/mod.rs | 238 ++ third_party/rust/httparse/src/simd/sse42.rs | 84 + third_party/rust/httparse/tests/uri.rs | 3677 +++++++++++++++++ .../rust/lazycell/.cargo-checksum.json | 2 +- third_party/rust/lazycell/CHANGELOG.md | 46 + third_party/rust/lazycell/Cargo.toml | 2 +- third_party/rust/lazycell/LICENSE-MIT | 2 +- third_party/rust/lazycell/README.md | 2 +- third_party/rust/lazycell/src/lib.rs | 261 +- .../rust/mio-extras/.cargo-checksum.json | 1 + third_party/rust/mio-extras/CHANGELOG.md | 31 + third_party/rust/mio-extras/Cargo.toml | 39 + third_party/rust/mio-extras/LICENSE-APACHE | 201 + third_party/rust/mio-extras/LICENSE-MIT | 25 + third_party/rust/mio-extras/README.md | 28 + third_party/rust/mio-extras/src/channel.rs | 431 ++ third_party/rust/mio-extras/src/lib.rs | 33 + third_party/rust/mio-extras/src/timer.rs | 751 ++++ third_party/rust/mio-extras/test/mod.rs | 45 + .../rust/mio-extras/test/test_poll_channel.rs | 338 ++ .../rust/mio-extras/test/test_timer.rs | 304 ++ third_party/rust/mio/.cargo-checksum.json | 2 +- third_party/rust/mio/CHANGELOG.md | 5 + third_party/rust/mio/Cargo.toml | 6 +- .../ci/ios/deploy_and_run_on_ios_simulator.rs | 202 - third_party/rust/mio/ci/run-ios.sh | 34 - third_party/rust/mio/src/event_imp.rs | 2 + third_party/rust/mio/src/lib.rs | 9 +- third_party/rust/mio/src/poll.rs | 50 +- third_party/rust/mio/src/sys/unix/epoll.rs | 11 +- third_party/rust/mio/src/sys/unix/ready.rs | 55 +- third_party/rust/mio/test/mod.rs | 3 - third_party/rust/mio/test/test_timer.rs | 433 -- .../rust/rand-0.4.3/.cargo-checksum.json | 1 + third_party/rust/rand-0.4.3/CHANGELOG.md | 269 ++ third_party/rust/rand-0.4.3/Cargo.toml | 39 + third_party/rust/rand-0.4.3/LICENSE-APACHE | 201 + third_party/rust/rand-0.4.3/LICENSE-MIT | 25 + third_party/rust/rand-0.4.3/README.md | 139 + .../rust/{rand => rand-0.4.3}/appveyor.yml | 0 .../{rand => rand-0.4.3}/benches/bench.rs | 0 .../benches/distributions/exponential.rs | 0 .../benches/distributions/gamma.rs | 0 .../benches/distributions/mod.rs | 0 .../benches/distributions/normal.rs | 0 .../rust/rand-0.4.3/benches/generators.rs | 133 + third_party/rust/rand-0.4.3/benches/misc.rs | 62 + .../src/distributions/exponential.rs | 124 + .../rand-0.4.3/src/distributions/gamma.rs | 386 ++ .../rust/rand-0.4.3/src/distributions/mod.rs | 409 ++ .../rand-0.4.3/src/distributions/normal.rs | 201 + .../src/distributions/range.rs | 0 .../src/distributions/ziggurat_tables.rs | 280 ++ .../rust/{rand => rand-0.4.3}/src/jitter.rs | 0 third_party/rust/rand-0.4.3/src/lib.rs | 1214 ++++++ .../rust/{rand => rand-0.4.3}/src/os.rs | 0 .../{rand => rand-0.4.3}/src/prng/chacha.rs | 0 .../{rand => rand-0.4.3}/src/prng/isaac.rs | 0 .../{rand => rand-0.4.3}/src/prng/isaac64.rs | 0 third_party/rust/rand-0.4.3/src/prng/mod.rs | 51 + .../{rand => rand-0.4.3}/src/prng/xorshift.rs | 0 .../{rand => rand-0.4.3}/src/rand_impls.rs | 0 .../rust/{rand => rand-0.4.3}/src/read.rs | 0 .../{rand => rand-0.4.3}/src/reseeding.rs | 0 .../rust/{rand => rand-0.4.3}/src/seq.rs | 0 .../utils/ziggurat_tables.py | 0 third_party/rust/rand/.cargo-checksum.json | 2 +- third_party/rust/rand/CHANGELOG.md | 265 +- third_party/rust/rand/COPYRIGHT | 12 + third_party/rust/rand/Cargo.toml | 75 +- third_party/rust/rand/LICENSE-APACHE | 4 +- third_party/rust/rand/LICENSE-MIT | 1 + third_party/rust/rand/README.md | 191 +- .../rust/rand/benches/distributions.rs | 259 ++ third_party/rust/rand/benches/generators.rs | 233 +- third_party/rust/rand/benches/misc.rs | 152 +- third_party/rust/rand/benches/seq.rs | 174 + third_party/rust/rand/build.rs | 10 + third_party/rust/rand/examples/monte-carlo.rs | 51 + third_party/rust/rand/examples/monty-hall.rs | 116 + third_party/rust/rand/src/deprecated.rs | 544 +++ .../rust/rand/src/distributions/bernoulli.rs | 165 + .../rust/rand/src/distributions/binomial.rs | 177 + .../rust/rand/src/distributions/cauchy.rs | 115 + .../rust/rand/src/distributions/dirichlet.rs | 137 + .../rand/src/distributions/exponential.rs | 86 +- .../rust/rand/src/distributions/float.rs | 259 ++ .../rust/rand/src/distributions/gamma.rs | 209 +- .../rust/rand/src/distributions/integer.rs | 161 + .../rust/rand/src/distributions/mod.rs | 645 ++- .../rust/rand/src/distributions/normal.rs | 120 +- .../rust/rand/src/distributions/other.rs | 219 + .../rust/rand/src/distributions/pareto.rs | 74 + .../rust/rand/src/distributions/poisson.rs | 157 + .../rust/rand/src/distributions/triangular.rs | 86 + .../rust/rand/src/distributions/uniform.rs | 1283 ++++++ .../rand/src/distributions/unit_circle.rs | 101 + .../rand/src/distributions/unit_sphere.rs | 99 + .../rust/rand/src/distributions/utils.rs | 504 +++ .../rust/rand/src/distributions/weibull.rs | 71 + .../rust/rand/src/distributions/weighted.rs | 230 ++ .../rand/src/distributions/ziggurat_tables.rs | 9 +- third_party/rust/rand/src/lib.rs | 1544 +++---- third_party/rust/rand/src/prelude.rs | 27 + third_party/rust/rand/src/prng/mod.rs | 74 +- third_party/rust/rand/src/rngs/adapter/mod.rs | 15 + .../rust/rand/src/rngs/adapter/read.rs | 136 + .../rust/rand/src/rngs/adapter/reseeding.rs | 370 ++ third_party/rust/rand/src/rngs/entropy.rs | 248 ++ third_party/rust/rand/src/rngs/mock.rs | 59 + third_party/rust/rand/src/rngs/mod.rs | 167 + third_party/rust/rand/src/rngs/small.rs | 106 + third_party/rust/rand/src/rngs/std.rs | 85 + third_party/rust/rand/src/rngs/thread.rs | 137 + third_party/rust/rand/src/seq/index.rs | 378 ++ third_party/rust/rand/src/seq/mod.rs | 829 ++++ third_party/rust/rand/tests/uniformity.rs | 67 + .../rust/rand_chacha/.cargo-checksum.json | 1 + third_party/rust/rand_chacha/CHANGELOG.md | 12 + third_party/rust/rand_chacha/COPYRIGHT | 12 + third_party/rust/rand_chacha/Cargo.toml | 35 + third_party/rust/rand_chacha/LICENSE-APACHE | 201 + third_party/rust/rand_chacha/LICENSE-MIT | 26 + third_party/rust/rand_chacha/README.md | 45 + third_party/rust/rand_chacha/build.rs | 7 + third_party/rust/rand_chacha/src/chacha.rs | 449 ++ third_party/rust/rand_chacha/src/lib.rs | 25 + .../rust/rand_core-0.3.1/.cargo-checksum.json | 1 + third_party/rust/rand_core-0.3.1/CHANGELOG.md | 36 + third_party/rust/rand_core-0.3.1/COPYRIGHT | 12 + third_party/rust/rand_core-0.3.1/Cargo.toml | 37 + .../rust/rand_core-0.3.1/LICENSE-APACHE | 201 + third_party/rust/rand_core-0.3.1/LICENSE-MIT | 26 + third_party/rust/rand_core-0.3.1/README.md | 65 + third_party/rust/rand_core-0.3.1/src/block.rs | 499 +++ third_party/rust/rand_core-0.3.1/src/error.rs | 177 + third_party/rust/rand_core-0.3.1/src/impls.rs | 165 + third_party/rust/rand_core-0.3.1/src/le.rs | 68 + third_party/rust/rand_core-0.3.1/src/lib.rs | 46 + .../rust/rand_core/.cargo-checksum.json | 1 + third_party/rust/rand_core/CHANGELOG.md | 36 + third_party/rust/rand_core/COPYRIGHT | 12 + third_party/rust/rand_core/Cargo.toml | 41 + third_party/rust/rand_core/LICENSE-APACHE | 201 + third_party/rust/rand_core/LICENSE-MIT | 26 + third_party/rust/rand_core/README.md | 66 + third_party/rust/rand_core/src/block.rs | 499 +++ third_party/rust/rand_core/src/error.rs | 177 + third_party/rust/rand_core/src/impls.rs | 165 + third_party/rust/rand_core/src/le.rs | 68 + third_party/rust/rand_core/src/lib.rs | 477 +++ third_party/rust/rand_hc/.cargo-checksum.json | 1 + third_party/rust/rand_hc/CHANGELOG.md | 8 + third_party/rust/rand_hc/COPYRIGHT | 12 + third_party/rust/rand_hc/Cargo.toml | 32 + third_party/rust/rand_hc/LICENSE-APACHE | 201 + third_party/rust/rand_hc/LICENSE-MIT | 25 + third_party/rust/rand_hc/README.md | 44 + third_party/rust/rand_hc/src/hc128.rs | 462 +++ third_party/rust/rand_hc/src/lib.rs | 25 + .../rust/rand_isaac/.cargo-checksum.json | 1 + third_party/rust/rand_isaac/CHANGELOG.md | 12 + third_party/rust/rand_isaac/COPYRIGHT | 12 + third_party/rust/rand_isaac/Cargo.toml | 45 + third_party/rust/rand_isaac/LICENSE-APACHE | 201 + third_party/rust/rand_isaac/LICENSE-MIT | 26 + third_party/rust/rand_isaac/README.md | 47 + third_party/rust/rand_isaac/src/isaac.rs | 484 +++ third_party/rust/rand_isaac/src/isaac64.rs | 481 +++ .../rust/rand_isaac/src/isaac_array.rs | 136 + third_party/rust/rand_isaac/src/lib.rs | 36 + .../rust/rand_jitter/.cargo-checksum.json | 1 + third_party/rust/rand_jitter/CHANGELOG.md | 21 + third_party/rust/rand_jitter/COPYRIGHT | 12 + third_party/rust/rand_jitter/Cargo.toml | 42 + third_party/rust/rand_jitter/LICENSE-APACHE | 201 + third_party/rust/rand_jitter/LICENSE-MIT | 26 + third_party/rust/rand_jitter/README.md | 104 + third_party/rust/rand_jitter/benches/mod.rs | 18 + third_party/rust/rand_jitter/src/dummy_log.rs | 10 + third_party/rust/rand_jitter/src/error.rs | 70 + third_party/rust/rand_jitter/src/lib.rs | 718 ++++ third_party/rust/rand_jitter/src/platform.rs | 44 + third_party/rust/rand_jitter/tests/mod.rs | 31 + third_party/rust/rand_os/.cargo-checksum.json | 1 + third_party/rust/rand_os/CHANGELOG.md | 22 + third_party/rust/rand_os/COPYRIGHT | 12 + third_party/rust/rand_os/Cargo.toml | 53 + third_party/rust/rand_os/LICENSE-APACHE | 201 + third_party/rust/rand_os/LICENSE-MIT | 26 + third_party/rust/rand_os/README.md | 33 + third_party/rust/rand_os/src/cloudabi.rs | 39 + .../rand_os/src/dragonfly_haiku_emscripten.rs | 39 + third_party/rust/rand_os/src/dummy_log.rs | 10 + third_party/rust/rand_os/src/freebsd.rs | 45 + third_party/rust/rand_os/src/fuchsia.rs | 28 + third_party/rust/rand_os/src/lib.rs | 440 ++ third_party/rust/rand_os/src/linux_android.rs | 186 + third_party/rust/rand_os/src/macos.rs | 53 + third_party/rust/rand_os/src/netbsd.rs | 57 + .../rust/rand_os/src/openbsd_bitrig.rs | 40 + third_party/rust/rand_os/src/random_device.rs | 70 + third_party/rust/rand_os/src/redox.rs | 30 + third_party/rust/rand_os/src/sgx.rs | 38 + third_party/rust/rand_os/src/solarish.rs | 195 + .../rust/rand_os/src/wasm32_bindgen.rs | 92 + third_party/rust/rand_os/src/wasm32_stdweb.rs | 107 + third_party/rust/rand_os/src/windows.rs | 44 + third_party/rust/rand_os/tests/mod.rs | 80 + .../rust/rand_pcg/.cargo-checksum.json | 1 + third_party/rust/rand_pcg/CHANGELOG.md | 19 + third_party/rust/rand_pcg/COPYRIGHT | 12 + third_party/rust/rand_pcg/Cargo.toml | 47 + third_party/rust/rand_pcg/LICENSE-APACHE | 201 + third_party/rust/rand_pcg/LICENSE-MIT | 26 + third_party/rust/rand_pcg/README.md | 43 + third_party/rust/rand_pcg/build.rs | 7 + third_party/rust/rand_pcg/src/lib.rs | 48 + third_party/rust/rand_pcg/src/pcg128.rs | 122 + third_party/rust/rand_pcg/src/pcg64.rs | 141 + third_party/rust/rand_pcg/tests/lcg64xsh32.rs | 58 + .../rust/rand_pcg/tests/mcg128xsl64.rs | 59 + .../rust/rand_xorshift/.cargo-checksum.json | 1 + third_party/rust/rand_xorshift/CHANGELOG.md | 11 + third_party/rust/rand_xorshift/COPYRIGHT | 12 + third_party/rust/rand_xorshift/Cargo.toml | 45 + third_party/rust/rand_xorshift/LICENSE-APACHE | 201 + third_party/rust/rand_xorshift/LICENSE-MIT | 26 + third_party/rust/rand_xorshift/README.md | 45 + third_party/rust/rand_xorshift/src/lib.rs | 123 + third_party/rust/rand_xorshift/tests/mod.rs | 92 + third_party/rust/rdrand/.cargo-checksum.json | 1 + third_party/rust/rdrand/Cargo.toml | 28 + third_party/rust/rdrand/LICENSE | 12 + third_party/rust/rdrand/README.mkd | 8 + third_party/rust/rdrand/appveyor.yml | 27 + third_party/rust/rdrand/benches/rdrand.rs | 49 + third_party/rust/rdrand/benches/rdseed.rs | 49 + third_party/rust/rdrand/benches/std.rs | 31 + third_party/rust/rdrand/src/changelog.rs | 25 + third_party/rust/rdrand/src/lib.rs | 472 +++ third_party/rust/sha-1/.cargo-checksum.json | 1 + third_party/rust/sha-1/Cargo.toml | 53 + third_party/rust/sha-1/LICENSE-APACHE | 201 + third_party/rust/sha-1/LICENSE-MIT | 27 + third_party/rust/sha-1/benches/lib.rs | 7 + third_party/rust/sha-1/examples/sha1sum.rs | 49 + third_party/rust/sha-1/src/consts.rs | 19 + third_party/rust/sha-1/src/lib.rs | 115 + third_party/rust/sha-1/src/utils.rs | 300 ++ .../rust/sha-1/tests/data/one_million_a.bin | 1 + third_party/rust/sha-1/tests/data/sha1.blb | 1 + third_party/rust/sha-1/tests/lib.rs | 14 + third_party/rust/sha1/.cargo-checksum.json | 1 - third_party/rust/sha1/Cargo.toml | 12 - third_party/rust/sha1/README.md | 9 - third_party/rust/sha1/src/lib.rs | 334 -- third_party/rust/ws/.cargo-checksum.json | 2 +- third_party/rust/ws/CHANGELOG.md | 33 + third_party/rust/ws/Cargo.toml | 82 +- third_party/rust/ws/README.md | 4 +- .../rust/ws/examples/autobahn-client.rs | 57 +- .../rust/ws/examples/autobahn-server.rs | 25 +- third_party/rust/ws/examples/bench-server.rs | 22 +- third_party/rust/ws/examples/bench.rs | 46 +- third_party/rust/ws/examples/channel.rs | 102 +- third_party/rust/ws/examples/cli.rs | 105 +- third_party/rust/ws/examples/client.rs | 14 +- .../rust/ws/examples/external_shutdown.rs | 27 +- third_party/rust/ws/examples/html_chat.rs | 66 + third_party/rust/ws/examples/peer2peer.rs | 36 +- third_party/rust/ws/examples/pong.rs | 47 +- third_party/rust/ws/examples/remote_addr.rs | 10 +- third_party/rust/ws/examples/router.rs | 54 +- third_party/rust/ws/examples/server.rs | 12 +- third_party/rust/ws/examples/shared.rs | 13 +- third_party/rust/ws/examples/ssl-server.rs | 109 +- third_party/rust/ws/examples/threaded.rs | 24 +- .../rust/ws/examples/unsafe-ssl-client.rs | 50 +- third_party/rust/ws/src/communication.rs | 204 +- third_party/rust/ws/src/connection.rs | 685 +-- third_party/rust/ws/src/deflate/context.rs | 156 +- third_party/rust/ws/src/deflate/extension.rs | 210 +- third_party/rust/ws/src/deflate/mod.rs | 10 +- third_party/rust/ws/src/factory.rs | 39 +- third_party/rust/ws/src/frame.rs | 136 +- third_party/rust/ws/src/handler.rs | 128 +- third_party/rust/ws/src/handshake.rs | 284 +- third_party/rust/ws/src/io.rs | 632 +-- third_party/rust/ws/src/lib.rs | 138 +- third_party/rust/ws/src/message.rs | 22 +- third_party/rust/ws/src/protocol.rs | 92 +- third_party/rust/ws/src/result.rs | 97 +- third_party/rust/ws/src/stream.rs | 262 +- third_party/rust/ws/src/util.rs | 7 +- third_party/rust/ws/tests/deflate.rs | 53 +- third_party/rust/ws/tests/shutdown.rs | 15 +- toolkit/content/license.html | 41 - 332 files changed, 38996 insertions(+), 4598 deletions(-) create mode 100644 third_party/rust/autocfg/.cargo-checksum.json create mode 100644 third_party/rust/autocfg/Cargo.toml create mode 100644 third_party/rust/autocfg/LICENSE-APACHE create mode 100644 third_party/rust/autocfg/LICENSE-MIT create mode 100644 third_party/rust/autocfg/README.md create mode 100644 third_party/rust/autocfg/examples/integers.rs create mode 100644 third_party/rust/autocfg/examples/paths.rs create mode 100644 third_party/rust/autocfg/examples/traits.rs create mode 100644 third_party/rust/autocfg/examples/versions.rs create mode 100644 third_party/rust/autocfg/src/error.rs create mode 100644 third_party/rust/autocfg/src/lib.rs create mode 100644 third_party/rust/autocfg/src/tests.rs create mode 100644 third_party/rust/autocfg/src/version.rs create mode 100644 third_party/rust/cloudabi/.cargo-checksum.json create mode 100644 third_party/rust/cloudabi/Cargo.toml create mode 100644 third_party/rust/cloudabi/bitflags.rs create mode 100644 third_party/rust/cloudabi/cloudabi.rs create mode 100644 third_party/rust/fuchsia-cprng/.cargo-checksum.json create mode 100644 third_party/rust/fuchsia-cprng/AUTHORS create mode 100644 third_party/rust/fuchsia-cprng/Cargo.toml rename third_party/rust/{sha1 => fuchsia-cprng}/LICENSE (59%) create mode 100644 third_party/rust/fuchsia-cprng/PATENTS create mode 100644 third_party/rust/fuchsia-cprng/src/lib.rs create mode 100644 third_party/rust/httparse/build.rs create mode 100644 third_party/rust/httparse/src/macros.rs create mode 100644 third_party/rust/httparse/src/simd/avx2.rs create mode 100644 third_party/rust/httparse/src/simd/fallback.rs create mode 100644 third_party/rust/httparse/src/simd/mod.rs create mode 100644 third_party/rust/httparse/src/simd/sse42.rs create mode 100644 third_party/rust/httparse/tests/uri.rs create mode 100644 third_party/rust/mio-extras/.cargo-checksum.json create mode 100644 third_party/rust/mio-extras/CHANGELOG.md create mode 100644 third_party/rust/mio-extras/Cargo.toml create mode 100644 third_party/rust/mio-extras/LICENSE-APACHE create mode 100644 third_party/rust/mio-extras/LICENSE-MIT create mode 100644 third_party/rust/mio-extras/README.md create mode 100644 third_party/rust/mio-extras/src/channel.rs create mode 100644 third_party/rust/mio-extras/src/lib.rs create mode 100644 third_party/rust/mio-extras/src/timer.rs create mode 100644 third_party/rust/mio-extras/test/mod.rs create mode 100644 third_party/rust/mio-extras/test/test_poll_channel.rs create mode 100644 third_party/rust/mio-extras/test/test_timer.rs delete mode 100644 third_party/rust/mio/ci/ios/deploy_and_run_on_ios_simulator.rs delete mode 100755 third_party/rust/mio/ci/run-ios.sh delete mode 100644 third_party/rust/mio/test/test_timer.rs create mode 100644 third_party/rust/rand-0.4.3/.cargo-checksum.json create mode 100644 third_party/rust/rand-0.4.3/CHANGELOG.md create mode 100644 third_party/rust/rand-0.4.3/Cargo.toml create mode 100644 third_party/rust/rand-0.4.3/LICENSE-APACHE create mode 100644 third_party/rust/rand-0.4.3/LICENSE-MIT create mode 100644 third_party/rust/rand-0.4.3/README.md rename third_party/rust/{rand => rand-0.4.3}/appveyor.yml (100%) rename third_party/rust/{rand => rand-0.4.3}/benches/bench.rs (100%) rename third_party/rust/{rand => rand-0.4.3}/benches/distributions/exponential.rs (100%) rename third_party/rust/{rand => rand-0.4.3}/benches/distributions/gamma.rs (100%) rename third_party/rust/{rand => rand-0.4.3}/benches/distributions/mod.rs (100%) rename third_party/rust/{rand => rand-0.4.3}/benches/distributions/normal.rs (100%) create mode 100644 third_party/rust/rand-0.4.3/benches/generators.rs create mode 100644 third_party/rust/rand-0.4.3/benches/misc.rs create mode 100644 third_party/rust/rand-0.4.3/src/distributions/exponential.rs create mode 100644 third_party/rust/rand-0.4.3/src/distributions/gamma.rs create mode 100644 third_party/rust/rand-0.4.3/src/distributions/mod.rs create mode 100644 third_party/rust/rand-0.4.3/src/distributions/normal.rs rename third_party/rust/{rand => rand-0.4.3}/src/distributions/range.rs (100%) create mode 100644 third_party/rust/rand-0.4.3/src/distributions/ziggurat_tables.rs rename third_party/rust/{rand => rand-0.4.3}/src/jitter.rs (100%) create mode 100644 third_party/rust/rand-0.4.3/src/lib.rs rename third_party/rust/{rand => rand-0.4.3}/src/os.rs (100%) rename third_party/rust/{rand => rand-0.4.3}/src/prng/chacha.rs (100%) rename third_party/rust/{rand => rand-0.4.3}/src/prng/isaac.rs (100%) rename third_party/rust/{rand => rand-0.4.3}/src/prng/isaac64.rs (100%) create mode 100644 third_party/rust/rand-0.4.3/src/prng/mod.rs rename third_party/rust/{rand => rand-0.4.3}/src/prng/xorshift.rs (100%) rename third_party/rust/{rand => rand-0.4.3}/src/rand_impls.rs (100%) rename third_party/rust/{rand => rand-0.4.3}/src/read.rs (100%) rename third_party/rust/{rand => rand-0.4.3}/src/reseeding.rs (100%) rename third_party/rust/{rand => rand-0.4.3}/src/seq.rs (100%) rename third_party/rust/{rand => rand-0.4.3}/utils/ziggurat_tables.py (100%) create mode 100644 third_party/rust/rand/COPYRIGHT create mode 100644 third_party/rust/rand/benches/distributions.rs create mode 100644 third_party/rust/rand/benches/seq.rs create mode 100644 third_party/rust/rand/build.rs create mode 100644 third_party/rust/rand/examples/monte-carlo.rs create mode 100644 third_party/rust/rand/examples/monty-hall.rs create mode 100644 third_party/rust/rand/src/deprecated.rs create mode 100644 third_party/rust/rand/src/distributions/bernoulli.rs create mode 100644 third_party/rust/rand/src/distributions/binomial.rs create mode 100644 third_party/rust/rand/src/distributions/cauchy.rs create mode 100644 third_party/rust/rand/src/distributions/dirichlet.rs create mode 100644 third_party/rust/rand/src/distributions/float.rs create mode 100644 third_party/rust/rand/src/distributions/integer.rs create mode 100644 third_party/rust/rand/src/distributions/other.rs create mode 100644 third_party/rust/rand/src/distributions/pareto.rs create mode 100644 third_party/rust/rand/src/distributions/poisson.rs create mode 100644 third_party/rust/rand/src/distributions/triangular.rs create mode 100644 third_party/rust/rand/src/distributions/uniform.rs create mode 100644 third_party/rust/rand/src/distributions/unit_circle.rs create mode 100644 third_party/rust/rand/src/distributions/unit_sphere.rs create mode 100644 third_party/rust/rand/src/distributions/utils.rs create mode 100644 third_party/rust/rand/src/distributions/weibull.rs create mode 100644 third_party/rust/rand/src/distributions/weighted.rs create mode 100644 third_party/rust/rand/src/prelude.rs create mode 100644 third_party/rust/rand/src/rngs/adapter/mod.rs create mode 100644 third_party/rust/rand/src/rngs/adapter/read.rs create mode 100644 third_party/rust/rand/src/rngs/adapter/reseeding.rs create mode 100644 third_party/rust/rand/src/rngs/entropy.rs create mode 100644 third_party/rust/rand/src/rngs/mock.rs create mode 100644 third_party/rust/rand/src/rngs/mod.rs create mode 100644 third_party/rust/rand/src/rngs/small.rs create mode 100644 third_party/rust/rand/src/rngs/std.rs create mode 100644 third_party/rust/rand/src/rngs/thread.rs create mode 100644 third_party/rust/rand/src/seq/index.rs create mode 100644 third_party/rust/rand/src/seq/mod.rs create mode 100644 third_party/rust/rand/tests/uniformity.rs create mode 100644 third_party/rust/rand_chacha/.cargo-checksum.json create mode 100644 third_party/rust/rand_chacha/CHANGELOG.md create mode 100644 third_party/rust/rand_chacha/COPYRIGHT create mode 100644 third_party/rust/rand_chacha/Cargo.toml create mode 100644 third_party/rust/rand_chacha/LICENSE-APACHE create mode 100644 third_party/rust/rand_chacha/LICENSE-MIT create mode 100644 third_party/rust/rand_chacha/README.md create mode 100644 third_party/rust/rand_chacha/build.rs create mode 100644 third_party/rust/rand_chacha/src/chacha.rs create mode 100644 third_party/rust/rand_chacha/src/lib.rs create mode 100644 third_party/rust/rand_core-0.3.1/.cargo-checksum.json create mode 100644 third_party/rust/rand_core-0.3.1/CHANGELOG.md create mode 100644 third_party/rust/rand_core-0.3.1/COPYRIGHT create mode 100644 third_party/rust/rand_core-0.3.1/Cargo.toml create mode 100644 third_party/rust/rand_core-0.3.1/LICENSE-APACHE create mode 100644 third_party/rust/rand_core-0.3.1/LICENSE-MIT create mode 100644 third_party/rust/rand_core-0.3.1/README.md create mode 100644 third_party/rust/rand_core-0.3.1/src/block.rs create mode 100644 third_party/rust/rand_core-0.3.1/src/error.rs create mode 100644 third_party/rust/rand_core-0.3.1/src/impls.rs create mode 100644 third_party/rust/rand_core-0.3.1/src/le.rs create mode 100644 third_party/rust/rand_core-0.3.1/src/lib.rs create mode 100644 third_party/rust/rand_core/.cargo-checksum.json create mode 100644 third_party/rust/rand_core/CHANGELOG.md create mode 100644 third_party/rust/rand_core/COPYRIGHT create mode 100644 third_party/rust/rand_core/Cargo.toml create mode 100644 third_party/rust/rand_core/LICENSE-APACHE create mode 100644 third_party/rust/rand_core/LICENSE-MIT create mode 100644 third_party/rust/rand_core/README.md create mode 100644 third_party/rust/rand_core/src/block.rs create mode 100644 third_party/rust/rand_core/src/error.rs create mode 100644 third_party/rust/rand_core/src/impls.rs create mode 100644 third_party/rust/rand_core/src/le.rs create mode 100644 third_party/rust/rand_core/src/lib.rs create mode 100644 third_party/rust/rand_hc/.cargo-checksum.json create mode 100644 third_party/rust/rand_hc/CHANGELOG.md create mode 100644 third_party/rust/rand_hc/COPYRIGHT create mode 100644 third_party/rust/rand_hc/Cargo.toml create mode 100644 third_party/rust/rand_hc/LICENSE-APACHE create mode 100644 third_party/rust/rand_hc/LICENSE-MIT create mode 100644 third_party/rust/rand_hc/README.md create mode 100644 third_party/rust/rand_hc/src/hc128.rs create mode 100644 third_party/rust/rand_hc/src/lib.rs create mode 100644 third_party/rust/rand_isaac/.cargo-checksum.json create mode 100644 third_party/rust/rand_isaac/CHANGELOG.md create mode 100644 third_party/rust/rand_isaac/COPYRIGHT create mode 100644 third_party/rust/rand_isaac/Cargo.toml create mode 100644 third_party/rust/rand_isaac/LICENSE-APACHE create mode 100644 third_party/rust/rand_isaac/LICENSE-MIT create mode 100644 third_party/rust/rand_isaac/README.md create mode 100644 third_party/rust/rand_isaac/src/isaac.rs create mode 100644 third_party/rust/rand_isaac/src/isaac64.rs create mode 100644 third_party/rust/rand_isaac/src/isaac_array.rs create mode 100644 third_party/rust/rand_isaac/src/lib.rs create mode 100644 third_party/rust/rand_jitter/.cargo-checksum.json create mode 100644 third_party/rust/rand_jitter/CHANGELOG.md create mode 100644 third_party/rust/rand_jitter/COPYRIGHT create mode 100644 third_party/rust/rand_jitter/Cargo.toml create mode 100644 third_party/rust/rand_jitter/LICENSE-APACHE create mode 100644 third_party/rust/rand_jitter/LICENSE-MIT create mode 100644 third_party/rust/rand_jitter/README.md create mode 100644 third_party/rust/rand_jitter/benches/mod.rs create mode 100644 third_party/rust/rand_jitter/src/dummy_log.rs create mode 100644 third_party/rust/rand_jitter/src/error.rs create mode 100644 third_party/rust/rand_jitter/src/lib.rs create mode 100644 third_party/rust/rand_jitter/src/platform.rs create mode 100644 third_party/rust/rand_jitter/tests/mod.rs create mode 100644 third_party/rust/rand_os/.cargo-checksum.json create mode 100644 third_party/rust/rand_os/CHANGELOG.md create mode 100644 third_party/rust/rand_os/COPYRIGHT create mode 100644 third_party/rust/rand_os/Cargo.toml create mode 100644 third_party/rust/rand_os/LICENSE-APACHE create mode 100644 third_party/rust/rand_os/LICENSE-MIT create mode 100644 third_party/rust/rand_os/README.md create mode 100644 third_party/rust/rand_os/src/cloudabi.rs create mode 100644 third_party/rust/rand_os/src/dragonfly_haiku_emscripten.rs create mode 100644 third_party/rust/rand_os/src/dummy_log.rs create mode 100644 third_party/rust/rand_os/src/freebsd.rs create mode 100644 third_party/rust/rand_os/src/fuchsia.rs create mode 100644 third_party/rust/rand_os/src/lib.rs create mode 100644 third_party/rust/rand_os/src/linux_android.rs create mode 100644 third_party/rust/rand_os/src/macos.rs create mode 100644 third_party/rust/rand_os/src/netbsd.rs create mode 100644 third_party/rust/rand_os/src/openbsd_bitrig.rs create mode 100644 third_party/rust/rand_os/src/random_device.rs create mode 100644 third_party/rust/rand_os/src/redox.rs create mode 100644 third_party/rust/rand_os/src/sgx.rs create mode 100644 third_party/rust/rand_os/src/solarish.rs create mode 100644 third_party/rust/rand_os/src/wasm32_bindgen.rs create mode 100644 third_party/rust/rand_os/src/wasm32_stdweb.rs create mode 100644 third_party/rust/rand_os/src/windows.rs create mode 100644 third_party/rust/rand_os/tests/mod.rs create mode 100644 third_party/rust/rand_pcg/.cargo-checksum.json create mode 100644 third_party/rust/rand_pcg/CHANGELOG.md create mode 100644 third_party/rust/rand_pcg/COPYRIGHT create mode 100644 third_party/rust/rand_pcg/Cargo.toml create mode 100644 third_party/rust/rand_pcg/LICENSE-APACHE create mode 100644 third_party/rust/rand_pcg/LICENSE-MIT create mode 100644 third_party/rust/rand_pcg/README.md create mode 100644 third_party/rust/rand_pcg/build.rs create mode 100644 third_party/rust/rand_pcg/src/lib.rs create mode 100644 third_party/rust/rand_pcg/src/pcg128.rs create mode 100644 third_party/rust/rand_pcg/src/pcg64.rs create mode 100644 third_party/rust/rand_pcg/tests/lcg64xsh32.rs create mode 100644 third_party/rust/rand_pcg/tests/mcg128xsl64.rs create mode 100644 third_party/rust/rand_xorshift/.cargo-checksum.json create mode 100644 third_party/rust/rand_xorshift/CHANGELOG.md create mode 100644 third_party/rust/rand_xorshift/COPYRIGHT create mode 100644 third_party/rust/rand_xorshift/Cargo.toml create mode 100644 third_party/rust/rand_xorshift/LICENSE-APACHE create mode 100644 third_party/rust/rand_xorshift/LICENSE-MIT create mode 100644 third_party/rust/rand_xorshift/README.md create mode 100644 third_party/rust/rand_xorshift/src/lib.rs create mode 100644 third_party/rust/rand_xorshift/tests/mod.rs create mode 100644 third_party/rust/rdrand/.cargo-checksum.json create mode 100644 third_party/rust/rdrand/Cargo.toml create mode 100644 third_party/rust/rdrand/LICENSE create mode 100644 third_party/rust/rdrand/README.mkd create mode 100644 third_party/rust/rdrand/appveyor.yml create mode 100644 third_party/rust/rdrand/benches/rdrand.rs create mode 100644 third_party/rust/rdrand/benches/rdseed.rs create mode 100644 third_party/rust/rdrand/benches/std.rs create mode 100644 third_party/rust/rdrand/src/changelog.rs create mode 100644 third_party/rust/rdrand/src/lib.rs create mode 100644 third_party/rust/sha-1/.cargo-checksum.json create mode 100644 third_party/rust/sha-1/Cargo.toml create mode 100644 third_party/rust/sha-1/LICENSE-APACHE create mode 100644 third_party/rust/sha-1/LICENSE-MIT create mode 100644 third_party/rust/sha-1/benches/lib.rs create mode 100644 third_party/rust/sha-1/examples/sha1sum.rs create mode 100644 third_party/rust/sha-1/src/consts.rs create mode 100644 third_party/rust/sha-1/src/lib.rs create mode 100644 third_party/rust/sha-1/src/utils.rs create mode 100644 third_party/rust/sha-1/tests/data/one_million_a.bin create mode 100644 third_party/rust/sha-1/tests/data/sha1.blb create mode 100644 third_party/rust/sha-1/tests/lib.rs delete mode 100644 third_party/rust/sha1/.cargo-checksum.json delete mode 100644 third_party/rust/sha1/Cargo.toml delete mode 100644 third_party/rust/sha1/README.md delete mode 100644 third_party/rust/sha1/src/lib.rs create mode 100644 third_party/rust/ws/examples/html_chat.rs diff --git a/python/mozbuild/mozbuild/vendor_rust.py b/python/mozbuild/mozbuild/vendor_rust.py index 24689c96b937..fd6982c00a16 100644 --- a/python/mozbuild/mozbuild/vendor_rust.py +++ b/python/mozbuild/mozbuild/vendor_rust.py @@ -165,6 +165,7 @@ Please commit or stash these changes before vendoring, or re-run with `--ignore- 'bindgen', 'fuchsia-zircon', 'fuchsia-zircon-sys', + 'fuchsia-cprng', ] } @@ -172,7 +173,6 @@ Please commit or stash these changes before vendoring, or re-run with `--ignore- # license, but that also need to explicitly mentioned in about:license. RUNTIME_LICENSE_PACKAGE_WHITELIST = { 'BSD-3-Clause': [ - 'sha1', ] } diff --git a/third_party/rust/autocfg/.cargo-checksum.json b/third_party/rust/autocfg/.cargo-checksum.json new file mode 100644 index 000000000000..30e2d81b75fd --- /dev/null +++ b/third_party/rust/autocfg/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"59b541962c15f51087a11d7296e3b69ec6d9b8a8e9e8db949e7629ea28183564","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"27995d58ad5c1145c1a8cd86244ce844886958a35eb2b78c6b772748669999ac","README.md":"d0e320dccace525a2cbcf3bc5d43ac9b7b61ee86b9c9713bf68993c3ad789d0a","examples/integers.rs":"589ff4271566dfa322becddf3e2c7b592e6e0bc97b02892ce75619b7e452e930","examples/paths.rs":"1b30e466b824ce8df7ad0a55334424131d9d2573d6cf9f7d5d50c09c8901d526","examples/traits.rs":"cbee6a3e1f7db60b02ae25b714926517144a77cb492021f492774cf0e1865a9e","examples/versions.rs":"38535e6d9f5bfae0de474a3db79a40e8f5da8ba9334c5ff4c363de9bc99d4d12","src/error.rs":"12de7dafea4a35d1dc2f0fa79bfa038386bbbea72bf083979f4ddf227999eeda","src/lib.rs":"7392068683dc86107bcf8073c81ff8fb7026f5fb98a355a4d47301c5946eeccb","src/tests.rs":"34bdceeffdbdd7f2535a6ed8272482b17325dba044c91bb96f3f8caeec58a83d","src/version.rs":"165324950f2195aaf068c47a4f2f0992b2bf18d8b7f4f17b6b264767523c0e5d"},"package":"a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"} \ No newline at end of file diff --git a/third_party/rust/autocfg/Cargo.toml b/third_party/rust/autocfg/Cargo.toml new file mode 100644 index 000000000000..cf59906f641f --- /dev/null +++ b/third_party/rust/autocfg/Cargo.toml @@ -0,0 +1,24 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "autocfg" +version = "0.1.2" +authors = ["Josh Stone "] +description = "Automatic cfg for Rust compiler features" +readme = "README.md" +keywords = ["rustc", "build", "autoconf"] +categories = ["development-tools::build-utils"] +license = "Apache-2.0/MIT" +repository = "https://github.com/cuviper/autocfg" + +[dependencies] diff --git a/third_party/rust/autocfg/LICENSE-APACHE b/third_party/rust/autocfg/LICENSE-APACHE new file mode 100644 index 000000000000..16fe87b06e80 --- /dev/null +++ b/third_party/rust/autocfg/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/autocfg/LICENSE-MIT b/third_party/rust/autocfg/LICENSE-MIT new file mode 100644 index 000000000000..44fbc4d8b90d --- /dev/null +++ b/third_party/rust/autocfg/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2018 Josh Stone + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/autocfg/README.md b/third_party/rust/autocfg/README.md new file mode 100644 index 000000000000..7295b3f785d4 --- /dev/null +++ b/third_party/rust/autocfg/README.md @@ -0,0 +1,68 @@ +autocfg +======= + +[![autocfg crate](https://img.shields.io/crates/v/autocfg.svg)](https://crates.io/crates/autocfg) +[![autocfg documentation](https://docs.rs/autocfg/badge.svg)](https://docs.rs/autocfg) +![minimum rustc 1.0](https://img.shields.io/badge/rustc-1.0+-red.svg) +[![Travis Status](https://travis-ci.org/cuviper/autocfg.svg?branch=master)](https://travis-ci.org/cuviper/autocfg) + +A Rust library for build scripts to automatically configure code based on +compiler support. Code snippets are dynamically tested to see if the `rustc` +will accept them, rather than hard-coding specific version support. + + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[build-dependencies] +autocfg = "0.1" +``` + +Then use it in your `build.rs` script to detect compiler features. For +example, to test for 128-bit integer support, it might look like: + +```rust +extern crate autocfg; + +fn main() { + let ac = autocfg::new(); + ac.emit_has_type("i128"); + + // (optional) We don't need to rerun for anything external. + autocfg::rerun_path(file!()); +} +``` + +If the type test succeeds, this will write a `cargo:rustc-cfg=has_i128` line +for Cargo, which translates to Rust arguments `--cfg has_i128`. Then in the +rest of your Rust code, you can add `#[cfg(has_i128)]` conditions on code that +should only be used when the compiler supports it. + + +## Release Notes + +- 0.1.2 (2018-01-16) + - Add `rerun_env(ENV)` to print `cargo:rerun-if-env-changed=ENV` + - Add `rerun_path(PATH)` to print `cargo:rerun-if-changed=PATH` + + +## Minimum Rust version policy + +This crate's minimum supported `rustc` version is `1.0.0`. Compatibility is +its entire reason for existence, so this crate will be extremely conservative +about raising this requirement. If this is ever deemed necessary, it will be +treated as a major breaking change for semver purposes. + + +## License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. diff --git a/third_party/rust/autocfg/examples/integers.rs b/third_party/rust/autocfg/examples/integers.rs new file mode 100644 index 000000000000..23d4cba6ee3e --- /dev/null +++ b/third_party/rust/autocfg/examples/integers.rs @@ -0,0 +1,9 @@ +extern crate autocfg; + +fn main() { + // Normally, cargo will set `OUT_DIR` for build scripts. + let ac = autocfg::AutoCfg::with_dir("target").unwrap(); + for i in 3..8 { + ac.emit_has_type(&format!("i{}", 1 << i)); + } +} diff --git a/third_party/rust/autocfg/examples/paths.rs b/third_party/rust/autocfg/examples/paths.rs new file mode 100644 index 000000000000..b7a6ca7a25f7 --- /dev/null +++ b/third_party/rust/autocfg/examples/paths.rs @@ -0,0 +1,22 @@ +extern crate autocfg; + +fn main() { + // Normally, cargo will set `OUT_DIR` for build scripts. + let ac = autocfg::AutoCfg::with_dir("target").unwrap(); + + // since ancient times... + ac.emit_has_path("std::vec::Vec"); + ac.emit_path_cfg("std::vec::Vec", "has_vec"); + + // rustc 1.10.0 + ac.emit_has_path("std::panic::PanicInfo"); + ac.emit_path_cfg("std::panic::PanicInfo", "has_panic_info"); + + // rustc 1.20.0 + ac.emit_has_path("std::mem::ManuallyDrop"); + ac.emit_path_cfg("std::mem::ManuallyDrop", "has_manually_drop"); + + // rustc 1.25.0 + ac.emit_has_path("std::ptr::NonNull"); + ac.emit_path_cfg("std::ptr::NonNull", "has_non_null"); +} diff --git a/third_party/rust/autocfg/examples/traits.rs b/third_party/rust/autocfg/examples/traits.rs new file mode 100644 index 000000000000..c1ca00385cd4 --- /dev/null +++ b/third_party/rust/autocfg/examples/traits.rs @@ -0,0 +1,26 @@ +extern crate autocfg; + +fn main() { + // Normally, cargo will set `OUT_DIR` for build scripts. + let ac = autocfg::AutoCfg::with_dir("target").unwrap(); + + // since ancient times... + ac.emit_has_trait("std::ops::Add"); + ac.emit_trait_cfg("std::ops::Add", "has_ops"); + + // trait parameters have to be provided + ac.emit_has_trait("std::borrow::Borrow"); + ac.emit_trait_cfg("std::borrow::Borrow", "has_borrow"); + + // rustc 1.8.0 + ac.emit_has_trait("std::ops::AddAssign"); + ac.emit_trait_cfg("std::ops::AddAssign", "has_assign_ops"); + + // rustc 1.12.0 + ac.emit_has_trait("std::iter::Sum"); + ac.emit_trait_cfg("std::iter::Sum", "has_sum"); + + // rustc 1.28.0 + ac.emit_has_trait("std::alloc::GlobalAlloc"); + ac.emit_trait_cfg("std::alloc::GlobalAlloc", "has_global_alloc"); +} diff --git a/third_party/rust/autocfg/examples/versions.rs b/third_party/rust/autocfg/examples/versions.rs new file mode 100644 index 000000000000..992919b7c642 --- /dev/null +++ b/third_party/rust/autocfg/examples/versions.rs @@ -0,0 +1,9 @@ +extern crate autocfg; + +fn main() { + // Normally, cargo will set `OUT_DIR` for build scripts. + let ac = autocfg::AutoCfg::with_dir("target").unwrap(); + for i in 0..100 { + ac.emit_rustc_version(1, i); + } +} diff --git a/third_party/rust/autocfg/src/error.rs b/third_party/rust/autocfg/src/error.rs new file mode 100644 index 000000000000..4624835451b0 --- /dev/null +++ b/third_party/rust/autocfg/src/error.rs @@ -0,0 +1,69 @@ +use std::error; +use std::fmt; +use std::io; +use std::num; +use std::str; + +/// A common error type for the `autocfg` crate. +#[derive(Debug)] +pub struct Error { + kind: ErrorKind, +} + +impl error::Error for Error { + fn description(&self) -> &str { + "AutoCfg error" + } + + fn cause(&self) -> Option<&error::Error> { + match self.kind { + ErrorKind::Io(ref e) => Some(e), + ErrorKind::Num(ref e) => Some(e), + ErrorKind::Utf8(ref e) => Some(e), + ErrorKind::Other(_) => None, + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match self.kind { + ErrorKind::Io(ref e) => e.fmt(f), + ErrorKind::Num(ref e) => e.fmt(f), + ErrorKind::Utf8(ref e) => e.fmt(f), + ErrorKind::Other(s) => s.fmt(f), + } + } +} + +#[derive(Debug)] +enum ErrorKind { + Io(io::Error), + Num(num::ParseIntError), + Utf8(str::Utf8Error), + Other(&'static str), +} + +pub fn from_io(e: io::Error) -> Error { + Error { + kind: ErrorKind::Io(e), + } +} + +pub fn from_num(e: num::ParseIntError) -> Error { + Error { + kind: ErrorKind::Num(e), + } +} + +pub fn from_utf8(e: str::Utf8Error) -> Error { + Error { + kind: ErrorKind::Utf8(e), + } +} + +pub fn from_str(s: &'static str) -> Error { + Error { + kind: ErrorKind::Other(s), + } +} diff --git a/third_party/rust/autocfg/src/lib.rs b/third_party/rust/autocfg/src/lib.rs new file mode 100644 index 000000000000..6d372922682e --- /dev/null +++ b/third_party/rust/autocfg/src/lib.rs @@ -0,0 +1,288 @@ +//! A Rust library for build scripts to automatically configure code based on +//! compiler support. Code snippets are dynamically tested to see if the `rustc` +//! will accept them, rather than hard-coding specific version support. +//! +//! +//! ## Usage +//! +//! Add this to your `Cargo.toml`: +//! +//! ```toml +//! [build-dependencies] +//! autocfg = "0.1" +//! ``` +//! +//! Then use it in your `build.rs` script to detect compiler features. For +//! example, to test for 128-bit integer support, it might look like: +//! +//! ```rust +//! extern crate autocfg; +//! +//! fn main() { +//! # // Normally, cargo will set `OUT_DIR` for build scripts. +//! # std::env::set_var("OUT_DIR", "target"); +//! let ac = autocfg::new(); +//! ac.emit_has_type("i128"); +//! +//! // (optional) We don't need to rerun for anything external. +//! autocfg::rerun_path(file!()); +//! } +//! ``` +//! +//! If the type test succeeds, this will write a `cargo:rustc-cfg=has_i128` line +//! for Cargo, which translates to Rust arguments `--cfg has_i128`. Then in the +//! rest of your Rust code, you can add `#[cfg(has_i128)]` conditions on code that +//! should only be used when the compiler supports it. + +#![deny(missing_debug_implementations)] +#![deny(missing_docs)] + +use std::env; +use std::ffi::OsString; +use std::fs; +use std::io::Write; +use std::path::PathBuf; +use std::process::{Command, Stdio}; + +mod error; +pub use error::Error; + +mod version; +use version::Version; + +#[cfg(test)] +mod tests; + +/// Helper to detect compiler features for `cfg` output in build scripts. +#[derive(Clone, Debug)] +pub struct AutoCfg { + out_dir: PathBuf, + rustc: PathBuf, + rustc_version: Version, + target: Option, +} + +/// Writes a config flag for rustc on standard out. +/// +/// This looks like: `cargo:rustc-cfg=CFG` +/// +/// Cargo will use this in arguments to rustc, like `--cfg CFG`. +pub fn emit(cfg: &str) { + println!("cargo:rustc-cfg={}", cfg); +} + +/// Writes a line telling Cargo to rerun the build script if `path` changes. +/// +/// This looks like: `cargo:rerun-if-changed=PATH` +/// +/// This requires at least cargo 0.7.0, corresponding to rustc 1.6.0. Earlier +/// versions of cargo will simply ignore the directive. +pub fn rerun_path(path: &str) { + println!("cargo:rerun-if-changed={}", path); +} + +/// Writes a line telling Cargo to rerun the build script if the environment +/// variable `var` changes. +/// +/// This looks like: `cargo:rerun-if-env-changed=VAR` +/// +/// This requires at least cargo 0.21.0, corresponding to rustc 1.20.0. Earlier +/// versions of cargo will simply ignore the directive. +pub fn rerun_env(var: &str) { + println!("cargo:rerun-if-env-changed={}", var); +} + +/// Create a new `AutoCfg` instance. +/// +/// # Panics +/// +/// Panics if `AutoCfg::new()` returns an error. +pub fn new() -> AutoCfg { + AutoCfg::new().unwrap() +} + +impl AutoCfg { + /// Create a new `AutoCfg` instance. + /// + /// # Common errors + /// + /// - `rustc` can't be executed, from `RUSTC` or in the `PATH`. + /// - The version output from `rustc` can't be parsed. + /// - `OUT_DIR` is not set in the environment, or is not a writable directory. + /// + pub fn new() -> Result { + match env::var_os("OUT_DIR") { + Some(d) => Self::with_dir(d), + None => Err(error::from_str("no OUT_DIR specified!")), + } + } + + /// Create a new `AutoCfg` instance with the specified output directory. + /// + /// # Common errors + /// + /// - `rustc` can't be executed, from `RUSTC` or in the `PATH`. + /// - The version output from `rustc` can't be parsed. + /// - `dir` is not a writable directory. + /// + pub fn with_dir>(dir: T) -> Result { + let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into()); + let rustc: PathBuf = rustc.into(); + let rustc_version = try!(Version::from_rustc(&rustc)); + + // Sanity check the output directory + let dir = dir.into(); + let meta = try!(fs::metadata(&dir).map_err(error::from_io)); + if !meta.is_dir() || meta.permissions().readonly() { + return Err(error::from_str("output path is not a writable directory")); + } + + Ok(AutoCfg { + out_dir: dir, + rustc: rustc, + rustc_version: rustc_version, + target: env::var_os("TARGET"), + }) + } + + /// Test whether the current `rustc` reports a version greater than + /// or equal to "`major`.`minor`". + pub fn probe_rustc_version(&self, major: usize, minor: usize) -> bool { + self.rustc_version >= Version::new(major, minor, 0) + } + + /// Sets a `cfg` value of the form `rustc_major_minor`, like `rustc_1_29`, + /// if the current `rustc` is at least that version. + pub fn emit_rustc_version(&self, major: usize, minor: usize) { + if self.probe_rustc_version(major, minor) { + emit(&format!("rustc_{}_{}", major, minor)); + } + } + + fn probe>(&self, code: T) -> Result { + use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; + + static ID: AtomicUsize = ATOMIC_USIZE_INIT; + + let id = ID.fetch_add(1, Ordering::Relaxed); + let mut command = Command::new(&self.rustc); + command + .arg(format!("--crate-name=probe{}", id)) + .arg("--crate-type=lib") + .arg("--out-dir") + .arg(&self.out_dir) + .arg("--emit=llvm-ir"); + + if let Some(target) = self.target.as_ref() { + command.arg("--target").arg(target); + } + + command.arg("-").stdin(Stdio::piped()); + let mut child = try!(command.spawn().map_err(error::from_io)); + try!( + child + .stdin + .take() + .expect("rustc stdin") + .write_all(code.as_ref()) + .map_err(error::from_io) + ); + + let status = try!(child.wait().map_err(error::from_io)); + Ok(status.success()) + } + + /// Tests whether the given path can be used. + /// + /// The test code is subject to change, but currently looks like: + /// + /// ```ignore + /// pub use PATH; + /// ``` + pub fn probe_path(&self, path: &str) -> bool { + self.probe(format!("pub use {};", path)).unwrap_or(false) + } + + /// Emits a config value `has_PATH` if `probe_path` returns true. + /// + /// Any non-identifier characters in the `path` will be replaced with + /// `_` in the generated config value. + pub fn emit_has_path(&self, path: &str) { + if self.probe_path(path) { + emit(&format!("has_{}", mangle(path))); + } + } + + /// Emits the given `cfg` value if `probe_path` returns true. + pub fn emit_path_cfg(&self, path: &str, cfg: &str) { + if self.probe_path(path) { + emit(cfg); + } + } + + /// Tests whether the given trait can be used. + /// + /// The test code is subject to change, but currently looks like: + /// + /// ```ignore + /// pub trait Probe: TRAIT + Sized {} + /// ``` + pub fn probe_trait(&self, name: &str) -> bool { + self.probe(format!("pub trait Probe: {} + Sized {{}}", name)) + .unwrap_or(false) + } + + /// Emits a config value `has_TRAIT` if `probe_trait` returns true. + /// + /// Any non-identifier characters in the trait `name` will be replaced with + /// `_` in the generated config value. + pub fn emit_has_trait(&self, name: &str) { + if self.probe_trait(name) { + emit(&format!("has_{}", mangle(name))); + } + } + + /// Emits the given `cfg` value if `probe_trait` returns true. + pub fn emit_trait_cfg(&self, name: &str, cfg: &str) { + if self.probe_trait(name) { + emit(cfg); + } + } + + /// Tests whether the given type can be used. + /// + /// The test code is subject to change, but currently looks like: + /// + /// ```ignore + /// pub type Probe = TYPE; + /// ``` + pub fn probe_type(&self, name: &str) -> bool { + self.probe(format!("pub type Probe = {};", name)) + .unwrap_or(false) + } + + /// Emits a config value `has_TYPE` if `probe_type` returns true. + /// + /// Any non-identifier characters in the type `name` will be replaced with + /// `_` in the generated config value. + pub fn emit_has_type(&self, name: &str) { + if self.probe_type(name) { + emit(&format!("has_{}", mangle(name))); + } + } + + /// Emits the given `cfg` value if `probe_type` returns true. + pub fn emit_type_cfg(&self, name: &str, cfg: &str) { + if self.probe_type(name) { + emit(cfg); + } + } +} + +fn mangle(s: &str) -> String { + s.chars() + .map(|c| match c { + 'A'...'Z' | 'a'...'z' | '0'...'9' => c, + _ => '_', + }).collect() +} diff --git a/third_party/rust/autocfg/src/tests.rs b/third_party/rust/autocfg/src/tests.rs new file mode 100644 index 000000000000..ba97ed1e0bc3 --- /dev/null +++ b/third_party/rust/autocfg/src/tests.rs @@ -0,0 +1,57 @@ +use super::AutoCfg; + +#[test] +fn autocfg_version() { + let ac = AutoCfg::with_dir("target").unwrap(); + println!("version: {:?}", ac.rustc_version); + assert!(ac.probe_rustc_version(1, 0)); +} + +#[test] +fn version_cmp() { + use super::version::Version; + let v123 = Version::new(1, 2, 3); + + assert!(Version::new(1, 0, 0) < v123); + assert!(Version::new(1, 2, 2) < v123); + assert!(Version::new(1, 2, 3) == v123); + assert!(Version::new(1, 2, 4) > v123); + assert!(Version::new(1, 10, 0) > v123); + assert!(Version::new(2, 0, 0) > v123); +} + +#[test] +fn probe_add() { + let ac = AutoCfg::with_dir("target").unwrap(); + assert!(ac.probe_path("std::ops::Add")); + assert!(ac.probe_trait("std::ops::Add")); + assert!(ac.probe_trait("std::ops::Add")); + assert!(ac.probe_trait("std::ops::Add")); + assert!(ac.probe_type("std::ops::Add")); +} + +#[test] +fn probe_as_ref() { + let ac = AutoCfg::with_dir("target").unwrap(); + assert!(ac.probe_path("std::convert::AsRef")); + assert!(ac.probe_trait("std::convert::AsRef")); + assert!(ac.probe_type("std::convert::AsRef")); +} + +#[test] +fn probe_i128() { + let ac = AutoCfg::with_dir("target").unwrap(); + let missing = !ac.probe_rustc_version(1, 26); + assert!(missing ^ ac.probe_path("std::i128")); + assert!(missing ^ ac.probe_type("i128")); +} + +#[test] +fn probe_sum() { + let ac = AutoCfg::with_dir("target").unwrap(); + let missing = !ac.probe_rustc_version(1, 12); + assert!(missing ^ ac.probe_path("std::iter::Sum")); + assert!(missing ^ ac.probe_trait("std::iter::Sum")); + assert!(missing ^ ac.probe_trait("std::iter::Sum")); + assert!(missing ^ ac.probe_type("std::iter::Sum")); +} diff --git a/third_party/rust/autocfg/src/version.rs b/third_party/rust/autocfg/src/version.rs new file mode 100644 index 000000000000..67c1851418bf --- /dev/null +++ b/third_party/rust/autocfg/src/version.rs @@ -0,0 +1,62 @@ +use std::path::Path; +use std::process::Command; +use std::str; + +use super::{error, Error}; + +/// A version structure for making relative comparisons. +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Version { + major: usize, + minor: usize, + patch: usize, +} + +impl Version { + /// Creates a `Version` instance for a specific `major.minor.patch` version. + pub fn new(major: usize, minor: usize, patch: usize) -> Self { + Version { + major: major, + minor: minor, + patch: patch, + } + } + + pub fn from_rustc(rustc: &Path) -> Result { + // Get rustc's verbose version + let output = try!( + Command::new(rustc) + .args(&["--version", "--verbose"]) + .output() + .map_err(error::from_io) + ); + if !output.status.success() { + return Err(error::from_str("could not execute rustc")); + } + let output = try!(str::from_utf8(&output.stdout).map_err(error::from_utf8)); + + // Find the release line in the verbose version output. + let release = match output.lines().find(|line| line.starts_with("release: ")) { + Some(line) => &line["release: ".len()..], + None => return Err(error::from_str("could not find rustc release")), + }; + + // Strip off any extra channel info, e.g. "-beta.N", "-nightly" + let version = match release.find('-') { + Some(i) => &release[..i], + None => release, + }; + + // Split the version into semver components. + let mut iter = version.splitn(3, '.'); + let major = try!(iter.next().ok_or(error::from_str("missing major version"))); + let minor = try!(iter.next().ok_or(error::from_str("missing minor version"))); + let patch = try!(iter.next().ok_or(error::from_str("missing patch version"))); + + Ok(Version::new( + try!(major.parse().map_err(error::from_num)), + try!(minor.parse().map_err(error::from_num)), + try!(patch.parse().map_err(error::from_num)), + )) + } +} diff --git a/third_party/rust/cloudabi/.cargo-checksum.json b/third_party/rust/cloudabi/.cargo-checksum.json new file mode 100644 index 000000000000..f79ba6556c18 --- /dev/null +++ b/third_party/rust/cloudabi/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"16ef935056e2aaf48b28c1340a63cc75febaabc901c752da9a3a2edbe081b429","bitflags.rs":"4621173dcf1307094cf240d26955b6f25c2f770dfd4e975ec2728771209006b5","cloudabi.rs":"93e139ba72a04db4934b04a6f21b054757a218a687e0bd2f6ba32514ec8c5f38"},"package":"ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"} \ No newline at end of file diff --git a/third_party/rust/cloudabi/Cargo.toml b/third_party/rust/cloudabi/Cargo.toml new file mode 100644 index 000000000000..ed0daf9de2f7 --- /dev/null +++ b/third_party/rust/cloudabi/Cargo.toml @@ -0,0 +1,31 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "cloudabi" +version = "0.0.3" +authors = ["Nuxi (https://nuxi.nl/) and contributors"] +description = "Low level interface to CloudABI. Contains all syscalls and related types." +homepage = "https://nuxi.nl/cloudabi/" +documentation = "https://docs.rs/cloudabi/" +keywords = ["cloudabi"] +license = "BSD-2-Clause" +repository = "https://github.com/nuxinl/cloudabi" + +[lib] +path = "cloudabi.rs" +[dependencies.bitflags] +version = "1.0" +optional = true + +[features] +default = ["bitflags"] diff --git a/third_party/rust/cloudabi/bitflags.rs b/third_party/rust/cloudabi/bitflags.rs new file mode 100644 index 000000000000..f764cc1df5a5 --- /dev/null +++ b/third_party/rust/cloudabi/bitflags.rs @@ -0,0 +1,51 @@ +// Copyright (c) 2018 Nuxi (https://nuxi.nl/) and contributors. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. + +// Appease Rust's tidy. +// ignore-license + +#[cfg(feature = "bitflags")] +#[macro_use] +extern crate bitflags; + +// Minimal implementation of bitflags! in case we can't depend on the bitflags +// crate. Only implements `bits()` and a `from_bits_truncate()` that doesn't +// actually truncate. +#[cfg(not(feature = "bitflags"))] +macro_rules! bitflags { + ( + $(#[$attr:meta])* + pub struct $name:ident: $type:ty { + $($(#[$const_attr:meta])* const $const:ident = $val:expr;)* + } + ) => { + $(#[$attr])* + #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] + pub struct $name { bits: $type } + impl $name { + $($(#[$const_attr])* pub const $const: $name = $name{ bits: $val };)* + pub fn bits(&self) -> $type { self.bits } + pub fn from_bits_truncate(bits: $type) -> Self { $name{ bits } } + } + } +} diff --git a/third_party/rust/cloudabi/cloudabi.rs b/third_party/rust/cloudabi/cloudabi.rs new file mode 100644 index 000000000000..2909db5098e5 --- /dev/null +++ b/third_party/rust/cloudabi/cloudabi.rs @@ -0,0 +1,2847 @@ +// Copyright (c) 2016-2017 Nuxi (https://nuxi.nl/) and contributors. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// This file is automatically generated. Do not edit. +// +// Source: https://github.com/NuxiNL/cloudabi + +// Appease Rust's tidy. +// ignore-license +// ignore-tidy-linelength + +//! **PLEASE NOTE: This entire crate including this +//! documentation is automatically generated from +//! [`cloudabi.txt`](https://github.com/NuxiNL/cloudabi/blob/master/cloudabi.txt)** +//! +//! # Nuxi CloudABI +//! +//! CloudABI is what you get if you take POSIX, add capability-based +//! security, and remove everything that's incompatible with that. The +//! result is a minimal ABI consisting of only 49 syscalls. +//! +//! CloudABI doesn't have its own kernel, but instead is implemented in existing +//! kernels: FreeBSD has CloudABI support for x86-64 and arm64, and [a patch-set +//! for NetBSD](https://github.com/NuxiNL/netbsd) and [a patch-set for +//! Linux](https://github.com/NuxiNL/linux) are available as well. This means that +//! CloudABI binaries can be executed on different operating systems, without any +//! modification. +//! +//! ## Capability-Based Security +//! +//! Capability-based security means that processes can only perform +//! actions that have no global impact. Processes cannot open files by +//! their absolute path, cannot open network connections, and cannot +//! observe global system state such as the process table. +//! +//! The capabilities of a process are fully determined by its set of open +//! file descriptors (fds). For example, files can only be opened if the +//! process already has a file descriptor to a directory the file is in. +//! +//! Unlike in POSIX, where processes are normally started with file +//! descriptors 0, 1, and 2 reserved for standard input, output, and +//! error, CloudABI does not reserve any file descriptor numbers for +//! specific purposes. +//! +//! In CloudABI, a process depends on its parent process to launch it with +//! the right set of resources, since the process will not be able to open +//! any new resources. For example, a simple static web server would need +//! to be started with a file descriptor to a [TCP +//! listener](https://github.com/NuxiNL/flower), and a file descriptor to +//! the directory for which to serve files. The web server will then be +//! unable to do anything other than reading files in that directory, and +//! process incoming network connections. +//! +//! So, unknown CloudABI binaries can safely be executed without the need +//! for containers, virtual machines, or other sandboxing technologies. +//! +//! Watch [Ed Schouten's Talk at +//! 32C3](https://www.youtube.com/watch?v=3N29vrPoDv8) for more +//! information about what capability-based security for UNIX means. +//! +//! ## Cloudlibc +//! +//! [Cloudlibc](https://github.com/NuxiNL/cloudlibc) is an implementation +//! of the C standard library, without all CloudABI-incompatible +//! functions. For example, Cloudlibc does not have `printf`, but does +//! have `fprintf`. It does not have `open`, but does have `openat`. +//! +//! ## CloudABI-Ports +//! +//! [CloudABI-Ports](https://github.com/NuxiNL/cloudabi-ports) is a +//! collection of ports of commonly used libraries and applications to +//! CloudABI. It contains software such as `zlib`, `libpng`, `boost`, +//! `memcached`, and much more. The software is patched to not depend on +//! any global state, such as files in `/etc` or `/dev`, using `open()`, +//! etc. +//! +//! ## Using CloudABI +//! +//! Instructions for using CloudABI (including kernel modules/patches, +//! toolchain, and ports) are available for several operating systems: +//! +//! - [Arch Linux](https://nuxi.nl/cloudabi/archlinux/) +//! - [Debian, Ubuntu, and other Debian derivatives](https://nuxi.nl/cloudabi/debian/) +//! - [FreeBSD, PC-BSD and DragonFly BSD](https://nuxi.nl/cloudabi/freebsd/) +//! - [Mac OS X](https://nuxi.nl/cloudabi/mac/) +//! - [NetBSD](https://nuxi.nl/cloudabi/netbsd/) +//! +//! ## Specification of the ABI +//! +//! The entire ABI is specified in a a file called +//! [`cloudabi.txt`](https://github.com/NuxiNL/cloudabi/blob/master/cloudabi.txt), +//! from which all +//! [headers](https://github.com/NuxiNL/cloudabi/tree/master/headers) +//! and documentation (including the one you're reading now) is generated. + +#![no_std] +#![allow(non_camel_case_types)] + +include!("bitflags.rs"); + +/// File or memory access pattern advisory information. +#[repr(u8)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub enum advice { + /// The application expects that it will not access the + /// specified data in the near future. + DONTNEED = 1, + /// The application expects to access the specified data + /// once and then not reuse it thereafter. + NOREUSE = 2, + /// The application has no advice to give on its behavior + /// with respect to the specified data. + NORMAL = 3, + /// The application expects to access the specified data + /// in a random order. + RANDOM = 4, + /// The application expects to access the specified data + /// sequentially from lower offsets to higher offsets. + SEQUENTIAL = 5, + /// The application expects to access the specified data + /// in the near future. + WILLNEED = 6, + #[doc(hidden)] _NonExhaustive = -1 as isize as u8, +} + +/// Enumeration describing the kind of value stored in [`auxv`](struct.auxv.html). +#[repr(u32)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub enum auxtype { + /// Base address of the binary argument data provided to + /// [`proc_exec()`](fn.proc_exec.html). + ARGDATA = 256, + /// Length of the binary argument data provided to + /// [`proc_exec()`](fn.proc_exec.html). + ARGDATALEN = 257, + /// Base address at which the executable is placed in + /// memory. + BASE = 7, + /// Base address of a buffer of random data that may be + /// used for non-cryptographic purposes, for example as a + /// canary for stack smashing protection. + CANARY = 258, + /// Length of a buffer of random data that may be used + /// for non-cryptographic purposes, for example as a + /// canary for stack smashing protection. + CANARYLEN = 259, + /// Number of CPUs that the system this process is running + /// on has. + NCPUS = 260, + /// Terminator of the auxiliary vector. + NULL = 0, + /// Smallest memory object size for which individual + /// memory protection controls can be configured. + PAGESZ = 6, + /// Address of the first ELF program header of the + /// executable. + PHDR = 3, + /// Number of ELF program headers of the executable. + PHNUM = 4, + /// Identifier of the process. + /// + /// This environment does not provide any simple numerical + /// process identifiers, for the reason that these are not + /// useful in distributed contexts. Instead, processes are + /// identified by a UUID. + /// + /// This record should point to sixteen bytes of binary + /// data, containing a version 4 UUID (fully random). + PID = 263, + /// Address of the ELF header of the vDSO. + /// + /// The vDSO is a shared library that is mapped in the + /// address space of the process. It provides entry points + /// for every system call supported by the environment, + /// all having a corresponding symbol that is prefixed + /// with `cloudabi_sys_`. System calls should be invoked + /// through these entry points. + /// + /// The first advantage of letting processes call into a + /// vDSO to perform system calls instead of raising + /// hardware traps is that it allows for easy emulation of + /// executables on top of existing operating systems. The + /// second advantage is that in cases where an operating + /// system provides native support for CloudABI executables, + /// it may still implement partial userspace + /// implementations of these system calls to improve + /// performance (e.g., [`clock_time_get()`](fn.clock_time_get.html)). It also provides + /// a more dynamic way of adding, removing or replacing + /// system calls. + SYSINFO_EHDR = 262, + /// Thread ID of the initial thread of the process. + TID = 261, + #[doc(hidden)] _NonExhaustive = -1 as isize as u32, +} + +/// Identifiers for clocks. +#[repr(u32)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub enum clockid { + /// The system-wide monotonic clock, which is defined as a + /// clock measuring real time, whose value cannot be + /// adjusted and which cannot have negative clock jumps. + /// + /// The epoch of this clock is undefined. The absolute + /// time value of this clock therefore has no meaning. + MONOTONIC = 1, + /// The CPU-time clock associated with the current + /// process. + PROCESS_CPUTIME_ID = 2, + /// The system-wide clock measuring real time. Time value + /// zero corresponds with 1970-01-01T00:00:00Z. + REALTIME = 3, + /// The CPU-time clock associated with the current thread. + THREAD_CPUTIME_ID = 4, + #[doc(hidden)] _NonExhaustive = -1 as isize as u32, +} + +/// A userspace condition variable. +#[repr(C)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub struct condvar(pub u32); +/// The condition variable is in its initial state. There +/// are no threads waiting to be woken up. If the +/// condition variable has any other value, the kernel +/// must be called to wake up any sleeping threads. +pub const CONDVAR_HAS_NO_WAITERS: condvar = condvar(0); + +/// Identifier for a device containing a file system. Can be used +/// in combination with [`inode`](struct.inode.html) to uniquely identify a file on the +/// local system. +#[repr(C)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub struct device(pub u64); + +/// A reference to the offset of a directory entry. +#[repr(C)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub struct dircookie(pub u64); +/// Permanent reference to the first directory entry +/// within a directory. +pub const DIRCOOKIE_START: dircookie = dircookie(0); + +/// Error codes returned by system calls. +/// +/// Not all of these error codes are returned by the system calls +/// provided by this environment, but are either used in userspace +/// exclusively or merely provided for alignment with POSIX. +#[repr(u16)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub enum errno { + /// No error occurred. System call completed successfully. + SUCCESS = 0, + /// Argument list too long. + TOOBIG = 1, + /// Permission denied. + ACCES = 2, + /// Address in use. + ADDRINUSE = 3, + /// Address not available. + ADDRNOTAVAIL = 4, + /// Address family not supported. + AFNOSUPPORT = 5, + /// Resource unavailable, or operation would block. + AGAIN = 6, + /// Connection already in progress. + ALREADY = 7, + /// Bad file descriptor. + BADF = 8, + /// Bad message. + BADMSG = 9, + /// Device or resource busy. + BUSY = 10, + /// Operation canceled. + CANCELED = 11, + /// No child processes. + CHILD = 12, + /// Connection aborted. + CONNABORTED = 13, + /// Connection refused. + CONNREFUSED = 14, + /// Connection reset. + CONNRESET = 15, + /// Resource deadlock would occur. + DEADLK = 16, + /// Destination address required. + DESTADDRREQ = 17, + /// Mathematics argument out of domain of function. + DOM = 18, + /// Reserved. + DQUOT = 19, + /// File exists. + EXIST = 20, + /// Bad address. + FAULT = 21, + /// File too large. + FBIG = 22, + /// Host is unreachable. + HOSTUNREACH = 23, + /// Identifier removed. + IDRM = 24, + /// Illegal byte sequence. + ILSEQ = 25, + /// Operation in progress. + INPROGRESS = 26, + /// Interrupted function. + INTR = 27, + /// Invalid argument. + INVAL = 28, + /// I/O error. + IO = 29, + /// Socket is connected. + ISCONN = 30, + /// Is a directory. + ISDIR = 31, + /// Too many levels of symbolic links. + LOOP = 32, + /// File descriptor value too large. + MFILE = 33, + /// Too many links. + MLINK = 34, + /// Message too large. + MSGSIZE = 35, + /// Reserved. + MULTIHOP = 36, + /// Filename too long. + NAMETOOLONG = 37, + /// Network is down. + NETDOWN = 38, + /// Connection aborted by network. + NETRESET = 39, + /// Network unreachable. + NETUNREACH = 40, + /// Too many files open in system. + NFILE = 41, + /// No buffer space available. + NOBUFS = 42, + /// No such device. + NODEV = 43, + /// No such file or directory. + NOENT = 44, + /// Executable file format error. + NOEXEC = 45, + /// No locks available. + NOLCK = 46, + /// Reserved. + NOLINK = 47, + /// Not enough space. + NOMEM = 48, + /// No message of the desired type. + NOMSG = 49, + /// Protocol not available. + NOPROTOOPT = 50, + /// No space left on device. + NOSPC = 51, + /// Function not supported. + NOSYS = 52, + /// The socket is not connected. + NOTCONN = 53, + /// Not a directory or a symbolic link to a directory. + NOTDIR = 54, + /// Directory not empty. + NOTEMPTY = 55, + /// State not recoverable. + NOTRECOVERABLE = 56, + /// Not a socket. + NOTSOCK = 57, + /// Not supported, or operation not supported on socket. + NOTSUP = 58, + /// Inappropriate I/O control operation. + NOTTY = 59, + /// No such device or address. + NXIO = 60, + /// Value too large to be stored in data type. + OVERFLOW = 61, + /// Previous owner died. + OWNERDEAD = 62, + /// Operation not permitted. + PERM = 63, + /// Broken pipe. + PIPE = 64, + /// Protocol error. + PROTO = 65, + /// Protocol not supported. + PROTONOSUPPORT = 66, + /// Protocol wrong type for socket. + PROTOTYPE = 67, + /// Result too large. + RANGE = 68, + /// Read-only file system. + ROFS = 69, + /// Invalid seek. + SPIPE = 70, + /// No such process. + SRCH = 71, + /// Reserved. + STALE = 72, + /// Connection timed out. + TIMEDOUT = 73, + /// Text file busy. + TXTBSY = 74, + /// Cross-device link. + XDEV = 75, + /// Extension: Capabilities insufficient. + NOTCAPABLE = 76, + #[doc(hidden)] _NonExhaustive = -1 as isize as u16, +} + +bitflags! { + /// The state of the file descriptor subscribed to with + /// [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE). + #[repr(C)] + pub struct eventrwflags: u16 { + /// The peer of this socket has closed or disconnected. + const HANGUP = 0x0001; + } +} + +/// Type of a subscription to an event or its occurrence. +#[repr(u8)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub enum eventtype { + /// The time value of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id) + /// has reached timestamp [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout). + CLOCK = 1, + /// Condition variable [`subscription.union.condvar.condvar`](struct.subscription_condvar.html#structfield.condvar) has + /// been woken up and [`subscription.union.condvar.lock`](struct.subscription_condvar.html#structfield.lock) has been + /// acquired for writing. + CONDVAR = 2, + /// File descriptor [`subscription.union.fd_readwrite.fd`](struct.subscription_fd_readwrite.html#structfield.fd) has + /// data available for reading. This event always triggers + /// for regular files. + FD_READ = 3, + /// File descriptor [`subscription.union.fd_readwrite.fd`](struct.subscription_fd_readwrite.html#structfield.fd) has + /// capacity available for writing. This event always + /// triggers for regular files. + FD_WRITE = 4, + /// Lock [`subscription.union.lock.lock`](struct.subscription_lock.html#structfield.lock) has been acquired for + /// reading. + LOCK_RDLOCK = 5, + /// Lock [`subscription.union.lock.lock`](struct.subscription_lock.html#structfield.lock) has been acquired for + /// writing. + LOCK_WRLOCK = 6, + /// The process associated with process descriptor + /// [`subscription.union.proc_terminate.fd`](struct.subscription_proc_terminate.html#structfield.fd) has terminated. + PROC_TERMINATE = 7, + #[doc(hidden)] _NonExhaustive = -1 as isize as u8, +} + +/// Exit code generated by a process when exiting. +pub type exitcode = u32; + +/// A file descriptor number. +/// +/// Unlike on POSIX-compliant systems, none of the file descriptor +/// numbers are reserved for a purpose (e.g., stdin, stdout, +/// stderr). Operating systems are not required to allocate new +/// file descriptors in ascending order. +#[repr(C)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub struct fd(pub u32); +/// Returned to the child process by [`proc_fork()`](fn.proc_fork.html). +pub const PROCESS_CHILD: fd = fd(0xffffffff); +/// Passed to [`mem_map()`](fn.mem_map.html) when creating a mapping to +/// anonymous memory. +pub const MAP_ANON_FD : fd = fd(0xffffffff); + +bitflags! { + /// File descriptor flags. + #[repr(C)] + pub struct fdflags: u16 { + /// Append mode: Data written to the file is always + /// appended to the file's end. + const APPEND = 0x0001; + /// Write according to synchronized I/O data integrity + /// completion. Only the data stored in the file is + /// synchronized. + const DSYNC = 0x0002; + /// Non-blocking mode. + const NONBLOCK = 0x0004; + /// Synchronized read I/O operations. + const RSYNC = 0x0008; + /// Write according to synchronized I/O file integrity + /// completion. In addition to synchronizing the data + /// stored in the file, the system may also synchronously + /// update the file's metadata. + const SYNC = 0x0010; + } +} + +bitflags! { + /// Which file descriptor attributes to adjust. + #[repr(C)] + pub struct fdsflags: u16 { + /// Adjust the file descriptor flags stored in + /// [`fdstat.fs_flags`](struct.fdstat.html#structfield.fs_flags). + const FLAGS = 0x0001; + /// Restrict the rights of the file descriptor to the + /// rights stored in [`fdstat.fs_rights_base`](struct.fdstat.html#structfield.fs_rights_base) and + /// [`fdstat.fs_rights_inheriting`](struct.fdstat.html#structfield.fs_rights_inheriting). + const RIGHTS = 0x0002; + } +} + +/// Relative offset within a file. +pub type filedelta = i64; + +/// Non-negative file size or length of a region within a file. +pub type filesize = u64; + +/// The type of a file descriptor or file. +#[repr(u8)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub enum filetype { + /// The type of the file descriptor or file is unknown or + /// is different from any of the other types specified. + UNKNOWN = 0, + /// The file descriptor or file refers to a block device + /// inode. + BLOCK_DEVICE = 16, + /// The file descriptor or file refers to a character + /// device inode. + CHARACTER_DEVICE = 17, + /// The file descriptor or file refers to a directory + /// inode. + DIRECTORY = 32, + /// The file descriptor refers to a process handle. + PROCESS = 80, + /// The file descriptor or file refers to a regular file + /// inode. + REGULAR_FILE = 96, + /// The file descriptor refers to a shared memory object. + SHARED_MEMORY = 112, + /// The file descriptor or file refers to a datagram + /// socket. + SOCKET_DGRAM = 128, + /// The file descriptor or file refers to a byte-stream + /// socket. + SOCKET_STREAM = 130, + /// The file refers to a symbolic link inode. + SYMBOLIC_LINK = 144, + #[doc(hidden)] _NonExhaustive = -1 as isize as u8, +} + +bitflags! { + /// Which file attributes to adjust. + #[repr(C)] + pub struct fsflags: u16 { + /// Adjust the last data access timestamp to the value + /// stored in [`filestat.st_atim`](struct.filestat.html#structfield.st_atim). + const ATIM = 0x0001; + /// Adjust the last data access timestamp to the time + /// of clock [`REALTIME`](enum.clockid.html#variant.REALTIME). + const ATIM_NOW = 0x0002; + /// Adjust the last data modification timestamp to the + /// value stored in [`filestat.st_mtim`](struct.filestat.html#structfield.st_mtim). + const MTIM = 0x0004; + /// Adjust the last data modification timestamp to the + /// time of clock [`REALTIME`](enum.clockid.html#variant.REALTIME). + const MTIM_NOW = 0x0008; + /// Truncate or extend the file to the size stored in + /// [`filestat.st_size`](struct.filestat.html#structfield.st_size). + const SIZE = 0x0010; + } +} + +/// File serial number that is unique within its file system. +#[repr(C)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub struct inode(pub u64); + +/// Number of hard links to an inode. +pub type linkcount = u32; + +/// A userspace read-recursive readers-writer lock, similar to a +/// Linux futex or a FreeBSD umtx. +#[repr(C)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub struct lock(pub u32); +/// Value indicating that the lock is in its initial +/// unlocked state. +pub const LOCK_UNLOCKED : lock = lock(0x00000000); +/// Bitmask indicating that the lock is write-locked. If +/// set, the lower 30 bits of the lock contain the +/// identifier of the thread that owns the write lock. +/// Otherwise, the lower 30 bits of the lock contain the +/// number of acquired read locks. +pub const LOCK_WRLOCKED : lock = lock(0x40000000); +/// Bitmask indicating that the lock is either read locked +/// or write locked, and that one or more threads have +/// their execution suspended, waiting to acquire the +/// lock. The last owner of the lock must call the +/// kernel to unlock. +/// +/// When the lock is acquired for reading and this bit is +/// set, it means that one or more threads are attempting +/// to acquire this lock for writing. In that case, other +/// threads should only acquire additional read locks if +/// suspending execution would cause a deadlock. It is +/// preferred to suspend execution, as this prevents +/// starvation of writers. +pub const LOCK_KERNEL_MANAGED: lock = lock(0x80000000); +/// Value indicating that the lock is in an incorrect +/// state. A lock cannot be in its initial unlocked state, +/// while also managed by the kernel. +pub const LOCK_BOGUS : lock = lock(0x80000000); + +bitflags! { + /// Flags determining the method of how paths are resolved. + #[repr(C)] + pub struct lookupflags: u32 { + /// As long as the resolved path corresponds to a symbolic + /// link, it is expanded. + const SYMLINK_FOLLOW = 0x00000001; + } +} + +bitflags! { + /// Memory mapping flags. + #[repr(C)] + pub struct mflags: u8 { + /// Instead of mapping the contents of the file provided, + /// create a mapping to anonymous memory. The file + /// descriptor argument must be set to [`MAP_ANON_FD`](constant.MAP_ANON_FD.html), + /// and the offset must be set to zero. + const ANON = 0x01; + /// Require that the mapping is performed at the base + /// address provided. + const FIXED = 0x02; + /// Changes are private. + const PRIVATE = 0x04; + /// Changes are shared. + const SHARED = 0x08; + } +} + +bitflags! { + /// Memory page protection options. + /// + /// This implementation enforces the `W^X` property: Pages cannot be + /// mapped for execution while also mapped for writing. + #[repr(C)] + pub struct mprot: u8 { + /// Page can be executed. + const EXEC = 0x01; + /// Page can be written. + const WRITE = 0x02; + /// Page can be read. + const READ = 0x04; + } +} + +bitflags! { + /// Methods of synchronizing memory with physical storage. + #[repr(C)] + pub struct msflags: u8 { + /// Perform asynchronous writes. + const ASYNC = 0x01; + /// Invalidate cached data. + const INVALIDATE = 0x02; + /// Perform synchronous writes. + const SYNC = 0x04; + } +} + +/// Specifies the number of threads sleeping on a condition +/// variable that should be woken up. +pub type nthreads = u32; + +bitflags! { + /// Open flags used by [`file_open()`](fn.file_open.html). + #[repr(C)] + pub struct oflags: u16 { + /// Create file if it does not exist. + const CREAT = 0x0001; + /// Fail if not a directory. + const DIRECTORY = 0x0002; + /// Fail if file already exists. + const EXCL = 0x0004; + /// Truncate file to size 0. + const TRUNC = 0x0008; + } +} + +bitflags! { + /// Flags provided to [`sock_recv()`](fn.sock_recv.html). + #[repr(C)] + pub struct riflags: u16 { + /// Returns the message without removing it from the + /// socket's receive queue. + const PEEK = 0x0004; + /// On byte-stream sockets, block until the full amount + /// of data can be returned. + const WAITALL = 0x0010; + } +} + +bitflags! { + /// File descriptor rights, determining which actions may be + /// performed. + #[repr(C)] + pub struct rights: u64 { + /// The right to invoke [`fd_datasync()`](fn.fd_datasync.html). + /// + /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to + /// invoke [`file_open()`](fn.file_open.html) with [`DSYNC`](struct.fdflags.html#associatedconstant.DSYNC). + const FD_DATASYNC = 0x0000000000000001; + /// The right to invoke [`fd_read()`](fn.fd_read.html) and [`sock_recv()`](fn.sock_recv.html). + /// + /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, includes the right to + /// invoke [`mem_map()`](fn.mem_map.html) with memory protection option + /// [`READ`](struct.mprot.html#associatedconstant.READ). + /// + /// If [`FD_SEEK`](struct.rights.html#associatedconstant.FD_SEEK) is set, includes the right to invoke + /// [`fd_pread()`](fn.fd_pread.html). + const FD_READ = 0x0000000000000002; + /// The right to invoke [`fd_seek()`](fn.fd_seek.html). This flag implies + /// [`FD_TELL`](struct.rights.html#associatedconstant.FD_TELL). + const FD_SEEK = 0x0000000000000004; + /// The right to invoke [`fd_stat_put()`](fn.fd_stat_put.html) with + /// [`FLAGS`](struct.fdsflags.html#associatedconstant.FLAGS). + const FD_STAT_PUT_FLAGS = 0x0000000000000008; + /// The right to invoke [`fd_sync()`](fn.fd_sync.html). + /// + /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to + /// invoke [`file_open()`](fn.file_open.html) with [`RSYNC`](struct.fdflags.html#associatedconstant.RSYNC) and + /// [`DSYNC`](struct.fdflags.html#associatedconstant.DSYNC). + const FD_SYNC = 0x0000000000000010; + /// The right to invoke [`fd_seek()`](fn.fd_seek.html) in such a way that the + /// file offset remains unaltered (i.e., [`CUR`](enum.whence.html#variant.CUR) with + /// offset zero). + const FD_TELL = 0x0000000000000020; + /// The right to invoke [`fd_write()`](fn.fd_write.html) and [`sock_send()`](fn.sock_send.html). + /// + /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, includes the right to + /// invoke [`mem_map()`](fn.mem_map.html) with memory protection option + /// [`WRITE`](struct.mprot.html#associatedconstant.WRITE). + /// + /// If [`FD_SEEK`](struct.rights.html#associatedconstant.FD_SEEK) is set, includes the right to + /// invoke [`fd_pwrite()`](fn.fd_pwrite.html). + const FD_WRITE = 0x0000000000000040; + /// The right to invoke [`file_advise()`](fn.file_advise.html). + const FILE_ADVISE = 0x0000000000000080; + /// The right to invoke [`file_allocate()`](fn.file_allocate.html). + const FILE_ALLOCATE = 0x0000000000000100; + /// The right to invoke [`file_create()`](fn.file_create.html) with + /// [`DIRECTORY`](enum.filetype.html#variant.DIRECTORY). + const FILE_CREATE_DIRECTORY = 0x0000000000000200; + /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, the right to invoke + /// [`file_open()`](fn.file_open.html) with [`CREAT`](struct.oflags.html#associatedconstant.CREAT). + const FILE_CREATE_FILE = 0x0000000000000400; + /// The right to invoke [`file_link()`](fn.file_link.html) with the file + /// descriptor as the source directory. + const FILE_LINK_SOURCE = 0x0000000000001000; + /// The right to invoke [`file_link()`](fn.file_link.html) with the file + /// descriptor as the target directory. + const FILE_LINK_TARGET = 0x0000000000002000; + /// The right to invoke [`file_open()`](fn.file_open.html). + const FILE_OPEN = 0x0000000000004000; + /// The right to invoke [`file_readdir()`](fn.file_readdir.html). + const FILE_READDIR = 0x0000000000008000; + /// The right to invoke [`file_readlink()`](fn.file_readlink.html). + const FILE_READLINK = 0x0000000000010000; + /// The right to invoke [`file_rename()`](fn.file_rename.html) with the file + /// descriptor as the source directory. + const FILE_RENAME_SOURCE = 0x0000000000020000; + /// The right to invoke [`file_rename()`](fn.file_rename.html) with the file + /// descriptor as the target directory. + const FILE_RENAME_TARGET = 0x0000000000040000; + /// The right to invoke [`file_stat_fget()`](fn.file_stat_fget.html). + const FILE_STAT_FGET = 0x0000000000080000; + /// The right to invoke [`file_stat_fput()`](fn.file_stat_fput.html) with + /// [`SIZE`](struct.fsflags.html#associatedconstant.SIZE). + /// + /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to + /// invoke [`file_open()`](fn.file_open.html) with [`TRUNC`](struct.oflags.html#associatedconstant.TRUNC). + const FILE_STAT_FPUT_SIZE = 0x0000000000100000; + /// The right to invoke [`file_stat_fput()`](fn.file_stat_fput.html) with + /// [`ATIM`](struct.fsflags.html#associatedconstant.ATIM), [`ATIM_NOW`](struct.fsflags.html#associatedconstant.ATIM_NOW), [`MTIM`](struct.fsflags.html#associatedconstant.MTIM), + /// and [`MTIM_NOW`](struct.fsflags.html#associatedconstant.MTIM_NOW). + const FILE_STAT_FPUT_TIMES = 0x0000000000200000; + /// The right to invoke [`file_stat_get()`](fn.file_stat_get.html). + const FILE_STAT_GET = 0x0000000000400000; + /// The right to invoke [`file_stat_put()`](fn.file_stat_put.html) with + /// [`ATIM`](struct.fsflags.html#associatedconstant.ATIM), [`ATIM_NOW`](struct.fsflags.html#associatedconstant.ATIM_NOW), [`MTIM`](struct.fsflags.html#associatedconstant.MTIM), + /// and [`MTIM_NOW`](struct.fsflags.html#associatedconstant.MTIM_NOW). + const FILE_STAT_PUT_TIMES = 0x0000000000800000; + /// The right to invoke [`file_symlink()`](fn.file_symlink.html). + const FILE_SYMLINK = 0x0000000001000000; + /// The right to invoke [`file_unlink()`](fn.file_unlink.html). + const FILE_UNLINK = 0x0000000002000000; + /// The right to invoke [`mem_map()`](fn.mem_map.html) with [`mprot`](struct.mprot.html) set to + /// zero. + const MEM_MAP = 0x0000000004000000; + /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, the right to invoke + /// [`mem_map()`](fn.mem_map.html) with [`EXEC`](struct.mprot.html#associatedconstant.EXEC). + const MEM_MAP_EXEC = 0x0000000008000000; + /// If [`FD_READ`](struct.rights.html#associatedconstant.FD_READ) is set, includes the right to + /// invoke [`poll()`](fn.poll.html) to subscribe to [`FD_READ`](enum.eventtype.html#variant.FD_READ). + /// + /// If [`FD_WRITE`](struct.rights.html#associatedconstant.FD_WRITE) is set, includes the right to + /// invoke [`poll()`](fn.poll.html) to subscribe to [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE). + const POLL_FD_READWRITE = 0x0000000010000000; + /// The right to invoke [`poll()`](fn.poll.html) to subscribe to + /// [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE). + const POLL_PROC_TERMINATE = 0x0000000040000000; + /// The right to invoke [`proc_exec()`](fn.proc_exec.html). + const PROC_EXEC = 0x0000000100000000; + /// The right to invoke [`sock_shutdown()`](fn.sock_shutdown.html). + const SOCK_SHUTDOWN = 0x0000008000000000; + } +} + +bitflags! { + /// Flags returned by [`sock_recv()`](fn.sock_recv.html). + #[repr(C)] + pub struct roflags: u16 { + /// Returned by [`sock_recv()`](fn.sock_recv.html): List of file descriptors + /// has been truncated. + const FDS_TRUNCATED = 0x0001; + /// Returned by [`sock_recv()`](fn.sock_recv.html): Message data has been + /// truncated. + const DATA_TRUNCATED = 0x0008; + } +} + +/// Indicates whether an object is stored in private or shared +/// memory. +#[repr(u8)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub enum scope { + /// The object is stored in private memory. + PRIVATE = 4, + /// The object is stored in shared memory. + SHARED = 8, + #[doc(hidden)] _NonExhaustive = -1 as isize as u8, +} + +bitflags! { + /// Which channels on a socket need to be shut down. + #[repr(C)] + pub struct sdflags: u8 { + /// Disables further receive operations. + const RD = 0x01; + /// Disables further send operations. + const WR = 0x02; + } +} + +bitflags! { + /// Flags provided to [`sock_send()`](fn.sock_send.html). As there are currently no flags + /// defined, it must be set to zero. + #[repr(C)] + pub struct siflags: u16 { + const DEFAULT = 0; + } +} + +/// Signal condition. +#[repr(u8)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub enum signal { + /// Process abort signal. + /// + /// Action: Terminates the process. + ABRT = 1, + /// Alarm clock. + /// + /// Action: Terminates the process. + ALRM = 2, + /// Access to an undefined portion of a memory object. + /// + /// Action: Terminates the process. + BUS = 3, + /// Child process terminated, stopped, or continued. + /// + /// Action: Ignored. + CHLD = 4, + /// Continue executing, if stopped. + /// + /// Action: Continues executing, if stopped. + CONT = 5, + /// Erroneous arithmetic operation. + /// + /// Action: Terminates the process. + FPE = 6, + /// Hangup. + /// + /// Action: Terminates the process. + HUP = 7, + /// Illegal instruction. + /// + /// Action: Terminates the process. + ILL = 8, + /// Terminate interrupt signal. + /// + /// Action: Terminates the process. + INT = 9, + /// Kill. + /// + /// Action: Terminates the process. + KILL = 10, + /// Write on a pipe with no one to read it. + /// + /// Action: Ignored. + PIPE = 11, + /// Terminal quit signal. + /// + /// Action: Terminates the process. + QUIT = 12, + /// Invalid memory reference. + /// + /// Action: Terminates the process. + SEGV = 13, + /// Stop executing. + /// + /// Action: Stops executing. + STOP = 14, + /// Bad system call. + /// + /// Action: Terminates the process. + SYS = 15, + /// Termination signal. + /// + /// Action: Terminates the process. + TERM = 16, + /// Trace/breakpoint trap. + /// + /// Action: Terminates the process. + TRAP = 17, + /// Terminal stop signal. + /// + /// Action: Stops executing. + TSTP = 18, + /// Background process attempting read. + /// + /// Action: Stops executing. + TTIN = 19, + /// Background process attempting write. + /// + /// Action: Stops executing. + TTOU = 20, + /// High bandwidth data is available at a socket. + /// + /// Action: Ignored. + URG = 21, + /// User-defined signal 1. + /// + /// Action: Terminates the process. + USR1 = 22, + /// User-defined signal 2. + /// + /// Action: Terminates the process. + USR2 = 23, + /// Virtual timer expired. + /// + /// Action: Terminates the process. + VTALRM = 24, + /// CPU time limit exceeded. + /// + /// Action: Terminates the process. + XCPU = 25, + /// File size limit exceeded. + /// + /// Action: Terminates the process. + XFSZ = 26, + #[doc(hidden)] _NonExhaustive = -1 as isize as u8, +} + +bitflags! { + /// Flags determining how the timestamp provided in + /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) should be interpreted. + #[repr(C)] + pub struct subclockflags: u16 { + /// If set, treat the timestamp provided in + /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) as an absolute timestamp + /// of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id). + /// + /// If clear, treat the timestamp provided in + /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) relative to the current + /// time value of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id). + const ABSTIME = 0x0001; + } +} + +bitflags! { + /// Flags influencing the method of polling for read or writing on + /// a file descriptor. + #[repr(C)] + pub struct subrwflags: u16 { + /// Deprecated. Must be set by callers and ignored by + /// implementations. + const POLL = 0x0001; + } +} + +/// Unique system-local identifier of a thread. This identifier is +/// only valid during the lifetime of the thread. +/// +/// Threads must be aware of their thread identifier, as it is +/// written it into locks when acquiring them for writing. It is +/// not advised to use these identifiers for any other purpose. +/// +/// As the thread identifier is also stored in [`lock`](struct.lock.html) when +/// [`LOCK_WRLOCKED`](constant.LOCK_WRLOCKED.html) is set, the top two bits of the thread +/// must always be set to zero. +#[repr(C)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub struct tid(pub u32); + +/// Timestamp in nanoseconds. +pub type timestamp = u64; + +bitflags! { + /// Specifies whether files are unlinked or directories are + /// removed. + #[repr(C)] + pub struct ulflags: u8 { + /// If set, removes a directory. Otherwise, unlinks any + /// non-directory file. + const REMOVEDIR = 0x01; + } +} + +/// User-provided value that can be attached to objects that is +/// retained when extracted from the kernel. +pub type userdata = u64; + +/// Relative to which position the offset of the file descriptor +/// should be set. +#[repr(u8)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub enum whence { + /// Seek relative to current position. + CUR = 1, + /// Seek relative to end-of-file. + END = 2, + /// Seek relative to start-of-file. + SET = 3, + #[doc(hidden)] _NonExhaustive = -1 as isize as u8, +} + +/// Auxiliary vector entry. +/// +/// The auxiliary vector is a list of key-value pairs that is +/// provided to the process on startup. Unlike structures, it is +/// extensible, as it is possible to add new records later on. +/// The auxiliary vector is always terminated by an entry having +/// type [`NULL`](enum.auxtype.html#variant.NULL). +/// +/// The auxiliary vector is part of the x86-64 ABI, but is used by +/// this environment on all architectures. +#[repr(C)] +#[derive(Copy, Clone)] +pub struct auxv { + /// The type of the auxiliary vector entry. + pub a_type: auxtype, + pub union: auxv_union +} +/// A union inside `auxv`. +#[repr(C)] +#[derive(Copy, Clone)] +pub union auxv_union { + /// Used when `a_type` is [`ARGDATALEN`](enum.auxtype.html#variant.ARGDATALEN), [`CANARYLEN`](enum.auxtype.html#variant.CANARYLEN), [`NCPUS`](enum.auxtype.html#variant.NCPUS), [`PAGESZ`](enum.auxtype.html#variant.PAGESZ), [`PHNUM`](enum.auxtype.html#variant.PHNUM), or [`TID`](enum.auxtype.html#variant.TID). +/// A numerical value. + pub a_val: usize, + /// Used when `a_type` is [`ARGDATA`](enum.auxtype.html#variant.ARGDATA), [`BASE`](enum.auxtype.html#variant.BASE), [`CANARY`](enum.auxtype.html#variant.CANARY), [`PHDR`](enum.auxtype.html#variant.PHDR), [`PID`](enum.auxtype.html#variant.PID), or [`SYSINFO_EHDR`](enum.auxtype.html#variant.SYSINFO_EHDR). +/// A pointer value. + pub a_ptr: *mut (), +} +#[test] +#[cfg(target_pointer_width = "32")] +fn auxv_layout_test_32() { + assert_eq!(::core::mem::size_of::(), 8); + assert_eq!(::core::mem::align_of::(), 4); + unsafe { + let obj: auxv = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.a_type as *const _ as usize - base, 0); + assert_eq!(&obj.union.a_val as *const _ as usize - base, 4); + assert_eq!(&obj.union.a_ptr as *const _ as usize - base, 4); + } +} +#[test] +#[cfg(target_pointer_width = "64")] +fn auxv_layout_test_64() { + assert_eq!(::core::mem::size_of::(), 16); + assert_eq!(::core::mem::align_of::(), 8); + unsafe { + let obj: auxv = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.a_type as *const _ as usize - base, 0); + assert_eq!(&obj.union.a_val as *const _ as usize - base, 8); + assert_eq!(&obj.union.a_ptr as *const _ as usize - base, 8); + } +} + +/// A region of memory for scatter/gather writes. +#[repr(C)] +#[derive(Copy, Clone)] +pub struct ciovec { + /// The address and length of the buffer to be written. + pub buf: (*const (), usize), +} +#[test] +#[cfg(target_pointer_width = "32")] +fn ciovec_layout_test_32() { + assert_eq!(::core::mem::size_of::(), 8); + assert_eq!(::core::mem::align_of::(), 4); + unsafe { + let obj: ciovec = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.buf.0 as *const _ as usize - base, 0); + assert_eq!(&obj.buf.1 as *const _ as usize - base, 4); + } +} +#[test] +#[cfg(target_pointer_width = "64")] +fn ciovec_layout_test_64() { + assert_eq!(::core::mem::size_of::(), 16); + assert_eq!(::core::mem::align_of::(), 8); + unsafe { + let obj: ciovec = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.buf.0 as *const _ as usize - base, 0); + assert_eq!(&obj.buf.1 as *const _ as usize - base, 8); + } +} + +/// A directory entry. +#[repr(C)] +#[derive(Copy, Clone)] +pub struct dirent { + /// The offset of the next directory entry stored in this + /// directory. + pub d_next: dircookie, + /// The serial number of the file referred to by this + /// directory entry. + pub d_ino: inode, + /// The length of the name of the directory entry. + pub d_namlen: u32, + /// The type of the file referred to by this directory + /// entry. + pub d_type: filetype, +} +#[test] +fn dirent_layout_test() { + assert_eq!(::core::mem::size_of::(), 24); + assert_eq!(::core::mem::align_of::(), 8); + unsafe { + let obj: dirent = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.d_next as *const _ as usize - base, 0); + assert_eq!(&obj.d_ino as *const _ as usize - base, 8); + assert_eq!(&obj.d_namlen as *const _ as usize - base, 16); + assert_eq!(&obj.d_type as *const _ as usize - base, 20); + } +} + +/// An event that occurred. +#[repr(C)] +#[derive(Copy, Clone)] +pub struct event { + /// User-provided value that got attached to + /// [`subscription.userdata`](struct.subscription.html#structfield.userdata). + pub userdata: userdata, + /// If non-zero, an error that occurred while processing + /// the subscription request. + pub error: errno, + /// The type of the event that occurred. + pub type_: eventtype, + pub union: event_union +} +/// A union inside `event`. +#[repr(C)] +#[derive(Copy, Clone)] +pub union event_union { + /// Used when `type_` is [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE). + pub fd_readwrite: event_fd_readwrite, + /// Used when `type_` is [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE). + pub proc_terminate: event_proc_terminate, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct event_fd_readwrite { + /// The number of bytes available + /// for reading or writing. + pub nbytes: filesize, + /// Obsolete. + pub unused: [u8; 4], + /// The state of the file + /// descriptor. + pub flags: eventrwflags, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct event_proc_terminate { + /// Obsolete. + pub unused: [u8; 4], + /// If zero, the process has + /// exited. + /// Otherwise, the signal + /// condition causing it to + /// terminated. + pub signal: signal, + /// If exited, the exit code of + /// the process. + pub exitcode: exitcode, +} +#[test] +fn event_layout_test() { + assert_eq!(::core::mem::size_of::(), 32); + assert_eq!(::core::mem::align_of::(), 8); + unsafe { + let obj: event = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.userdata as *const _ as usize - base, 0); + assert_eq!(&obj.error as *const _ as usize - base, 8); + assert_eq!(&obj.type_ as *const _ as usize - base, 10); + assert_eq!(&obj.union.fd_readwrite.nbytes as *const _ as usize - base, 16); + assert_eq!(&obj.union.fd_readwrite.unused as *const _ as usize - base, 24); + assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 28); + assert_eq!(&obj.union.proc_terminate.unused as *const _ as usize - base, 16); + assert_eq!(&obj.union.proc_terminate.signal as *const _ as usize - base, 20); + assert_eq!(&obj.union.proc_terminate.exitcode as *const _ as usize - base, 24); + } +} + +/// File descriptor attributes. +#[repr(C)] +#[derive(Copy, Clone)] +pub struct fdstat { + /// File type. + pub fs_filetype: filetype, + /// File descriptor flags. + pub fs_flags: fdflags, + /// Rights that apply to this file descriptor. + pub fs_rights_base: rights, + /// Maximum set of rights that can be installed on new + /// file descriptors that are created through this file + /// descriptor, e.g., through [`file_open()`](fn.file_open.html). + pub fs_rights_inheriting: rights, +} +#[test] +fn fdstat_layout_test() { + assert_eq!(::core::mem::size_of::(), 24); + assert_eq!(::core::mem::align_of::(), 8); + unsafe { + let obj: fdstat = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.fs_filetype as *const _ as usize - base, 0); + assert_eq!(&obj.fs_flags as *const _ as usize - base, 2); + assert_eq!(&obj.fs_rights_base as *const _ as usize - base, 8); + assert_eq!(&obj.fs_rights_inheriting as *const _ as usize - base, 16); + } +} + +/// File attributes. +#[repr(C)] +#[derive(Copy, Clone)] +pub struct filestat { + /// Device ID of device containing the file. + pub st_dev: device, + /// File serial number. + pub st_ino: inode, + /// File type. + pub st_filetype: filetype, + /// Number of hard links to the file. + pub st_nlink: linkcount, + /// For regular files, the file size in bytes. For + /// symbolic links, the length in bytes of the pathname + /// contained in the symbolic link. + pub st_size: filesize, + /// Last data access timestamp. + pub st_atim: timestamp, + /// Last data modification timestamp. + pub st_mtim: timestamp, + /// Last file status change timestamp. + pub st_ctim: timestamp, +} +#[test] +fn filestat_layout_test() { + assert_eq!(::core::mem::size_of::(), 56); + assert_eq!(::core::mem::align_of::(), 8); + unsafe { + let obj: filestat = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.st_dev as *const _ as usize - base, 0); + assert_eq!(&obj.st_ino as *const _ as usize - base, 8); + assert_eq!(&obj.st_filetype as *const _ as usize - base, 16); + assert_eq!(&obj.st_nlink as *const _ as usize - base, 20); + assert_eq!(&obj.st_size as *const _ as usize - base, 24); + assert_eq!(&obj.st_atim as *const _ as usize - base, 32); + assert_eq!(&obj.st_mtim as *const _ as usize - base, 40); + assert_eq!(&obj.st_ctim as *const _ as usize - base, 48); + } +} + +/// A region of memory for scatter/gather reads. +#[repr(C)] +#[derive(Copy, Clone)] +pub struct iovec { + /// The address and length of the buffer to be filled. + pub buf: (*mut (), usize), +} +#[test] +#[cfg(target_pointer_width = "32")] +fn iovec_layout_test_32() { + assert_eq!(::core::mem::size_of::(), 8); + assert_eq!(::core::mem::align_of::(), 4); + unsafe { + let obj: iovec = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.buf.0 as *const _ as usize - base, 0); + assert_eq!(&obj.buf.1 as *const _ as usize - base, 4); + } +} +#[test] +#[cfg(target_pointer_width = "64")] +fn iovec_layout_test_64() { + assert_eq!(::core::mem::size_of::(), 16); + assert_eq!(::core::mem::align_of::(), 8); + unsafe { + let obj: iovec = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.buf.0 as *const _ as usize - base, 0); + assert_eq!(&obj.buf.1 as *const _ as usize - base, 8); + } +} + +/// Path lookup properties. +#[repr(C)] +#[derive(Copy, Clone)] +pub struct lookup { + /// The working directory at which the resolution of the + /// path starts. + pub fd: fd, + /// Flags determining the method of how the path is + /// resolved. + pub flags: lookupflags, +} +#[test] +fn lookup_layout_test() { + assert_eq!(::core::mem::size_of::(), 8); + assert_eq!(::core::mem::align_of::(), 4); + unsafe { + let obj: lookup = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.fd as *const _ as usize - base, 0); + assert_eq!(&obj.flags as *const _ as usize - base, 4); + } +} + +/// Entry point for a process (`_start`). +/// +/// **auxv**: +/// The auxiliary vector. See [`auxv`](struct.auxv.html). +pub type processentry = unsafe extern "C" fn( + auxv: *const auxv, +) -> (); + +/// Arguments of [`sock_recv()`](fn.sock_recv.html). +#[repr(C)] +#[derive(Copy, Clone)] +pub struct recv_in { + /// List of scatter/gather vectors where message data + /// should be stored. + pub ri_data: (*const iovec, usize), + /// Buffer where numbers of incoming file descriptors + /// should be stored. + pub ri_fds: (*mut fd, usize), + /// Message flags. + pub ri_flags: riflags, +} +#[test] +#[cfg(target_pointer_width = "32")] +fn recv_in_layout_test_32() { + assert_eq!(::core::mem::size_of::(), 20); + assert_eq!(::core::mem::align_of::(), 4); + unsafe { + let obj: recv_in = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.ri_data.0 as *const _ as usize - base, 0); + assert_eq!(&obj.ri_data.1 as *const _ as usize - base, 4); + assert_eq!(&obj.ri_fds.0 as *const _ as usize - base, 8); + assert_eq!(&obj.ri_fds.1 as *const _ as usize - base, 12); + assert_eq!(&obj.ri_flags as *const _ as usize - base, 16); + } +} +#[test] +#[cfg(target_pointer_width = "64")] +fn recv_in_layout_test_64() { + assert_eq!(::core::mem::size_of::(), 40); + assert_eq!(::core::mem::align_of::(), 8); + unsafe { + let obj: recv_in = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.ri_data.0 as *const _ as usize - base, 0); + assert_eq!(&obj.ri_data.1 as *const _ as usize - base, 8); + assert_eq!(&obj.ri_fds.0 as *const _ as usize - base, 16); + assert_eq!(&obj.ri_fds.1 as *const _ as usize - base, 24); + assert_eq!(&obj.ri_flags as *const _ as usize - base, 32); + } +} + +/// Results of [`sock_recv()`](fn.sock_recv.html). +#[repr(C)] +#[derive(Copy, Clone)] +pub struct recv_out { + /// Number of bytes stored in [`recv_in.ri_data`](struct.recv_in.html#structfield.ri_data). + pub ro_datalen: usize, + /// Number of file descriptors stored in [`recv_in.ri_fds`](struct.recv_in.html#structfield.ri_fds). + pub ro_fdslen: usize, + /// Fields that were used by previous implementations. + pub ro_unused: [u8; 40], + /// Message flags. + pub ro_flags: roflags, +} +#[test] +#[cfg(target_pointer_width = "32")] +fn recv_out_layout_test_32() { + assert_eq!(::core::mem::size_of::(), 52); + assert_eq!(::core::mem::align_of::(), 4); + unsafe { + let obj: recv_out = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.ro_datalen as *const _ as usize - base, 0); + assert_eq!(&obj.ro_fdslen as *const _ as usize - base, 4); + assert_eq!(&obj.ro_unused as *const _ as usize - base, 8); + assert_eq!(&obj.ro_flags as *const _ as usize - base, 48); + } +} +#[test] +#[cfg(target_pointer_width = "64")] +fn recv_out_layout_test_64() { + assert_eq!(::core::mem::size_of::(), 64); + assert_eq!(::core::mem::align_of::(), 8); + unsafe { + let obj: recv_out = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.ro_datalen as *const _ as usize - base, 0); + assert_eq!(&obj.ro_fdslen as *const _ as usize - base, 8); + assert_eq!(&obj.ro_unused as *const _ as usize - base, 16); + assert_eq!(&obj.ro_flags as *const _ as usize - base, 56); + } +} + +/// Arguments of [`sock_send()`](fn.sock_send.html). +#[repr(C)] +#[derive(Copy, Clone)] +pub struct send_in { + /// List of scatter/gather vectors where message data + /// should be retrieved. + pub si_data: (*const ciovec, usize), + /// File descriptors that need to be attached to the + /// message. + pub si_fds: (*const fd, usize), + /// Message flags. + pub si_flags: siflags, +} +#[test] +#[cfg(target_pointer_width = "32")] +fn send_in_layout_test_32() { + assert_eq!(::core::mem::size_of::(), 20); + assert_eq!(::core::mem::align_of::(), 4); + unsafe { + let obj: send_in = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.si_data.0 as *const _ as usize - base, 0); + assert_eq!(&obj.si_data.1 as *const _ as usize - base, 4); + assert_eq!(&obj.si_fds.0 as *const _ as usize - base, 8); + assert_eq!(&obj.si_fds.1 as *const _ as usize - base, 12); + assert_eq!(&obj.si_flags as *const _ as usize - base, 16); + } +} +#[test] +#[cfg(target_pointer_width = "64")] +fn send_in_layout_test_64() { + assert_eq!(::core::mem::size_of::(), 40); + assert_eq!(::core::mem::align_of::(), 8); + unsafe { + let obj: send_in = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.si_data.0 as *const _ as usize - base, 0); + assert_eq!(&obj.si_data.1 as *const _ as usize - base, 8); + assert_eq!(&obj.si_fds.0 as *const _ as usize - base, 16); + assert_eq!(&obj.si_fds.1 as *const _ as usize - base, 24); + assert_eq!(&obj.si_flags as *const _ as usize - base, 32); + } +} + +/// Results of [`sock_send()`](fn.sock_send.html). +#[repr(C)] +#[derive(Copy, Clone)] +pub struct send_out { + /// Number of bytes transmitted. + pub so_datalen: usize, +} +#[test] +#[cfg(target_pointer_width = "32")] +fn send_out_layout_test_32() { + assert_eq!(::core::mem::size_of::(), 4); + assert_eq!(::core::mem::align_of::(), 4); + unsafe { + let obj: send_out = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.so_datalen as *const _ as usize - base, 0); + } +} +#[test] +#[cfg(target_pointer_width = "64")] +fn send_out_layout_test_64() { + assert_eq!(::core::mem::size_of::(), 8); + assert_eq!(::core::mem::align_of::(), 8); + unsafe { + let obj: send_out = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.so_datalen as *const _ as usize - base, 0); + } +} + +/// Subscription to an event. +#[repr(C)] +#[derive(Copy, Clone)] +pub struct subscription { + /// User-provided value that is attached to the + /// subscription in the kernel and returned through + /// [`event.userdata`](struct.event.html#structfield.userdata). + pub userdata: userdata, + /// Used by previous implementations. Ignored. + pub unused: u16, + /// The type of the event to which to subscribe. + /// + /// Currently, [`CONDVAR`](enum.eventtype.html#variant.CONDVAR), + /// [`LOCK_RDLOCK`](enum.eventtype.html#variant.LOCK_RDLOCK), and [`LOCK_WRLOCK`](enum.eventtype.html#variant.LOCK_WRLOCK) + /// must be provided as the first subscription and may + /// only be followed by up to one other subscription, + /// having type [`CLOCK`](enum.eventtype.html#variant.CLOCK). + pub type_: eventtype, + pub union: subscription_union +} +/// A union inside `subscription`. +#[repr(C)] +#[derive(Copy, Clone)] +pub union subscription_union { + /// Used when `type_` is [`CLOCK`](enum.eventtype.html#variant.CLOCK). + pub clock: subscription_clock, + /// Used when `type_` is [`CONDVAR`](enum.eventtype.html#variant.CONDVAR). + pub condvar: subscription_condvar, + /// Used when `type_` is [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE). + pub fd_readwrite: subscription_fd_readwrite, + /// Used when `type_` is [`LOCK_RDLOCK`](enum.eventtype.html#variant.LOCK_RDLOCK) or [`LOCK_WRLOCK`](enum.eventtype.html#variant.LOCK_WRLOCK). + pub lock: subscription_lock, + /// Used when `type_` is [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE). + pub proc_terminate: subscription_proc_terminate, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct subscription_clock { + /// The user-defined unique + /// identifier of the clock. + pub identifier: userdata, + /// The clock against which the + /// timestamp should be compared. + pub clock_id: clockid, + /// The absolute or relative + /// timestamp. + pub timeout: timestamp, + /// The amount of time that the + /// kernel may wait additionally + /// to coalesce with other events. + pub precision: timestamp, + /// Flags specifying whether the + /// timeout is absolute or + /// relative. + pub flags: subclockflags, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct subscription_condvar { + /// The condition variable on + /// which to wait to be woken up. + pub condvar: *mut condvar, + /// The lock that will be + /// released while waiting. + /// + /// The lock will be reacquired + /// for writing when the condition + /// variable triggers. + pub lock: *mut lock, + /// Whether the condition variable + /// is stored in private or shared + /// memory. + pub condvar_scope: scope, + /// Whether the lock is stored in + /// private or shared memory. + pub lock_scope: scope, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct subscription_fd_readwrite { + /// The file descriptor on which + /// to wait for it to become ready + /// for reading or writing. + pub fd: fd, + /// Under which conditions to + /// trigger. + pub flags: subrwflags, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct subscription_lock { + /// The lock that will be acquired + /// for reading or writing. + pub lock: *mut lock, + /// Whether the lock is stored in + /// private or shared memory. + pub lock_scope: scope, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct subscription_proc_terminate { + /// The process descriptor on + /// which to wait for process + /// termination. + pub fd: fd, +} +#[test] +#[cfg(target_pointer_width = "32")] +fn subscription_layout_test_32() { + assert_eq!(::core::mem::size_of::(), 56); + assert_eq!(::core::mem::align_of::(), 8); + unsafe { + let obj: subscription = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.userdata as *const _ as usize - base, 0); + assert_eq!(&obj.unused as *const _ as usize - base, 8); + assert_eq!(&obj.type_ as *const _ as usize - base, 10); + assert_eq!(&obj.union.clock.identifier as *const _ as usize - base, 16); + assert_eq!(&obj.union.clock.clock_id as *const _ as usize - base, 24); + assert_eq!(&obj.union.clock.timeout as *const _ as usize - base, 32); + assert_eq!(&obj.union.clock.precision as *const _ as usize - base, 40); + assert_eq!(&obj.union.clock.flags as *const _ as usize - base, 48); + assert_eq!(&obj.union.condvar.condvar as *const _ as usize - base, 16); + assert_eq!(&obj.union.condvar.lock as *const _ as usize - base, 20); + assert_eq!(&obj.union.condvar.condvar_scope as *const _ as usize - base, 24); + assert_eq!(&obj.union.condvar.lock_scope as *const _ as usize - base, 25); + assert_eq!(&obj.union.fd_readwrite.fd as *const _ as usize - base, 16); + assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 20); + assert_eq!(&obj.union.lock.lock as *const _ as usize - base, 16); + assert_eq!(&obj.union.lock.lock_scope as *const _ as usize - base, 20); + assert_eq!(&obj.union.proc_terminate.fd as *const _ as usize - base, 16); + } +} +#[test] +#[cfg(target_pointer_width = "64")] +fn subscription_layout_test_64() { + assert_eq!(::core::mem::size_of::(), 56); + assert_eq!(::core::mem::align_of::(), 8); + unsafe { + let obj: subscription = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.userdata as *const _ as usize - base, 0); + assert_eq!(&obj.unused as *const _ as usize - base, 8); + assert_eq!(&obj.type_ as *const _ as usize - base, 10); + assert_eq!(&obj.union.clock.identifier as *const _ as usize - base, 16); + assert_eq!(&obj.union.clock.clock_id as *const _ as usize - base, 24); + assert_eq!(&obj.union.clock.timeout as *const _ as usize - base, 32); + assert_eq!(&obj.union.clock.precision as *const _ as usize - base, 40); + assert_eq!(&obj.union.clock.flags as *const _ as usize - base, 48); + assert_eq!(&obj.union.condvar.condvar as *const _ as usize - base, 16); + assert_eq!(&obj.union.condvar.lock as *const _ as usize - base, 24); + assert_eq!(&obj.union.condvar.condvar_scope as *const _ as usize - base, 32); + assert_eq!(&obj.union.condvar.lock_scope as *const _ as usize - base, 33); + assert_eq!(&obj.union.fd_readwrite.fd as *const _ as usize - base, 16); + assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 20); + assert_eq!(&obj.union.lock.lock as *const _ as usize - base, 16); + assert_eq!(&obj.union.lock.lock_scope as *const _ as usize - base, 24); + assert_eq!(&obj.union.proc_terminate.fd as *const _ as usize - base, 16); + } +} + +/// The Thread Control Block (TCB). +/// +/// After a thread begins execution (at program startup or when +/// created through [`thread_create()`](fn.thread_create.html)), the CPU's registers +/// controlling Thread-Local Storage (TLS) will already be +/// initialized. They will point to an area only containing the +/// TCB. +/// +/// If the thread needs space for storing thread-specific +/// variables, the thread may allocate a larger area and adjust +/// the CPU's registers to point to that area instead. However, it +/// does need to make sure that the TCB is copied over to the new +/// TLS area. +/// +/// The purpose of the TCB is that it allows light-weight +/// emulators to store information related to individual threads. +/// For example, it may be used to store a copy of the CPU +/// registers prior emulation, so that TLS for the host system +/// can be restored if needed. +#[repr(C)] +#[derive(Copy, Clone)] +pub struct tcb { + /// Pointer that may be freely assigned by the system. Its + /// value cannot be interpreted by the application. + pub parent: *mut (), +} +#[test] +#[cfg(target_pointer_width = "32")] +fn tcb_layout_test_32() { + assert_eq!(::core::mem::size_of::(), 4); + assert_eq!(::core::mem::align_of::(), 4); + unsafe { + let obj: tcb = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.parent as *const _ as usize - base, 0); + } +} +#[test] +#[cfg(target_pointer_width = "64")] +fn tcb_layout_test_64() { + assert_eq!(::core::mem::size_of::(), 8); + assert_eq!(::core::mem::align_of::(), 8); + unsafe { + let obj: tcb = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.parent as *const _ as usize - base, 0); + } +} + +/// Entry point for additionally created threads. +/// +/// **tid**: +/// Thread ID of the current thread. +/// +/// **aux**: +/// Copy of the value stored in +/// [`threadattr.argument`](struct.threadattr.html#structfield.argument). +pub type threadentry = unsafe extern "C" fn( + tid: tid, + aux: *mut (), +) -> (); + +/// Attributes for thread creation. +#[repr(C)] +#[derive(Copy, Clone)] +pub struct threadattr { + /// Initial program counter value. + pub entry_point: threadentry, + /// Region allocated to serve as stack space. + pub stack: (*mut (), usize), + /// Argument to be forwarded to the entry point function. + pub argument: *mut (), +} +#[test] +#[cfg(target_pointer_width = "32")] +fn threadattr_layout_test_32() { + assert_eq!(::core::mem::size_of::(), 16); + assert_eq!(::core::mem::align_of::(), 4); + unsafe { + let obj: threadattr = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.entry_point as *const _ as usize - base, 0); + assert_eq!(&obj.stack.0 as *const _ as usize - base, 4); + assert_eq!(&obj.stack.1 as *const _ as usize - base, 8); + assert_eq!(&obj.argument as *const _ as usize - base, 12); + } +} +#[test] +#[cfg(target_pointer_width = "64")] +fn threadattr_layout_test_64() { + assert_eq!(::core::mem::size_of::(), 32); + assert_eq!(::core::mem::align_of::(), 8); + unsafe { + let obj: threadattr = ::core::mem::uninitialized(); + let base = &obj as *const _ as usize; + assert_eq!(&obj.entry_point as *const _ as usize - base, 0); + assert_eq!(&obj.stack.0 as *const _ as usize - base, 8); + assert_eq!(&obj.stack.1 as *const _ as usize - base, 16); + assert_eq!(&obj.argument as *const _ as usize - base, 24); + } +} + +/// The table with pointers to all syscall implementations. +#[allow(improper_ctypes)] +extern "C" { + fn cloudabi_sys_clock_res_get(_: clockid, _: *mut timestamp) -> errno; + fn cloudabi_sys_clock_time_get(_: clockid, _: timestamp, _: *mut timestamp) -> errno; + fn cloudabi_sys_condvar_signal(_: *mut condvar, _: scope, _: nthreads) -> errno; + fn cloudabi_sys_fd_close(_: fd) -> errno; + fn cloudabi_sys_fd_create1(_: filetype, _: *mut fd) -> errno; + fn cloudabi_sys_fd_create2(_: filetype, _: *mut fd, _: *mut fd) -> errno; + fn cloudabi_sys_fd_datasync(_: fd) -> errno; + fn cloudabi_sys_fd_dup(_: fd, _: *mut fd) -> errno; + fn cloudabi_sys_fd_pread(_: fd, _: *const iovec, _: usize, _: filesize, _: *mut usize) -> errno; + fn cloudabi_sys_fd_pwrite(_: fd, _: *const ciovec, _: usize, _: filesize, _: *mut usize) -> errno; + fn cloudabi_sys_fd_read(_: fd, _: *const iovec, _: usize, _: *mut usize) -> errno; + fn cloudabi_sys_fd_replace(_: fd, _: fd) -> errno; + fn cloudabi_sys_fd_seek(_: fd, _: filedelta, _: whence, _: *mut filesize) -> errno; + fn cloudabi_sys_fd_stat_get(_: fd, _: *mut fdstat) -> errno; + fn cloudabi_sys_fd_stat_put(_: fd, _: *const fdstat, _: fdsflags) -> errno; + fn cloudabi_sys_fd_sync(_: fd) -> errno; + fn cloudabi_sys_fd_write(_: fd, _: *const ciovec, _: usize, _: *mut usize) -> errno; + fn cloudabi_sys_file_advise(_: fd, _: filesize, _: filesize, _: advice) -> errno; + fn cloudabi_sys_file_allocate(_: fd, _: filesize, _: filesize) -> errno; + fn cloudabi_sys_file_create(_: fd, _: *const u8, _: usize, _: filetype) -> errno; + fn cloudabi_sys_file_link(_: lookup, _: *const u8, _: usize, _: fd, _: *const u8, _: usize) -> errno; + fn cloudabi_sys_file_open(_: lookup, _: *const u8, _: usize, _: oflags, _: *const fdstat, _: *mut fd) -> errno; + fn cloudabi_sys_file_readdir(_: fd, _: *mut (), _: usize, _: dircookie, _: *mut usize) -> errno; + fn cloudabi_sys_file_readlink(_: fd, _: *const u8, _: usize, _: *mut u8, _: usize, _: *mut usize) -> errno; + fn cloudabi_sys_file_rename(_: fd, _: *const u8, _: usize, _: fd, _: *const u8, _: usize) -> errno; + fn cloudabi_sys_file_stat_fget(_: fd, _: *mut filestat) -> errno; + fn cloudabi_sys_file_stat_fput(_: fd, _: *const filestat, _: fsflags) -> errno; + fn cloudabi_sys_file_stat_get(_: lookup, _: *const u8, _: usize, _: *mut filestat) -> errno; + fn cloudabi_sys_file_stat_put(_: lookup, _: *const u8, _: usize, _: *const filestat, _: fsflags) -> errno; + fn cloudabi_sys_file_symlink(_: *const u8, _: usize, _: fd, _: *const u8, _: usize) -> errno; + fn cloudabi_sys_file_unlink(_: fd, _: *const u8, _: usize, _: ulflags) -> errno; + fn cloudabi_sys_lock_unlock(_: *mut lock, _: scope) -> errno; + fn cloudabi_sys_mem_advise(_: *mut (), _: usize, _: advice) -> errno; + fn cloudabi_sys_mem_map(_: *mut (), _: usize, _: mprot, _: mflags, _: fd, _: filesize, _: *mut *mut ()) -> errno; + fn cloudabi_sys_mem_protect(_: *mut (), _: usize, _: mprot) -> errno; + fn cloudabi_sys_mem_sync(_: *mut (), _: usize, _: msflags) -> errno; + fn cloudabi_sys_mem_unmap(_: *mut (), _: usize) -> errno; + fn cloudabi_sys_poll(_: *const subscription, _: *mut event, _: usize, _: *mut usize) -> errno; + fn cloudabi_sys_proc_exec(_: fd, _: *const (), _: usize, _: *const fd, _: usize) -> errno; + fn cloudabi_sys_proc_exit(_: exitcode) -> !; + fn cloudabi_sys_proc_fork(_: *mut fd, _: *mut tid) -> errno; + fn cloudabi_sys_proc_raise(_: signal) -> errno; + fn cloudabi_sys_random_get(_: *mut (), _: usize) -> errno; + fn cloudabi_sys_sock_recv(_: fd, _: *const recv_in, _: *mut recv_out) -> errno; + fn cloudabi_sys_sock_send(_: fd, _: *const send_in, _: *mut send_out) -> errno; + fn cloudabi_sys_sock_shutdown(_: fd, _: sdflags) -> errno; + fn cloudabi_sys_thread_create(_: *mut threadattr, _: *mut tid) -> errno; + fn cloudabi_sys_thread_exit(_: *mut lock, _: scope) -> !; + fn cloudabi_sys_thread_yield() -> errno; +} + +/// Obtains the resolution of a clock. +/// +/// ## Parameters +/// +/// **clock_id**: +/// The clock for which the resolution needs to be +/// returned. +/// +/// **resolution**: +/// The resolution of the clock. +#[inline] +pub unsafe fn clock_res_get(clock_id_: clockid, resolution_: &mut timestamp) -> errno { + cloudabi_sys_clock_res_get(clock_id_, resolution_) +} + +/// Obtains the time value of a clock. +/// +/// ## Parameters +/// +/// **clock_id**: +/// The clock for which the time needs to be +/// returned. +/// +/// **precision**: +/// The maximum lag (exclusive) that the returned +/// time value may have, compared to its actual +/// value. +/// +/// **time**: +/// The time value of the clock. +#[inline] +pub unsafe fn clock_time_get(clock_id_: clockid, precision_: timestamp, time_: &mut timestamp) -> errno { + cloudabi_sys_clock_time_get(clock_id_, precision_, time_) +} + +/// Wakes up threads waiting on a userspace condition variable. +/// +/// If an invocation of this system call causes all waiting +/// threads to be woken up, the value of the condition variable +/// is set to [`CONDVAR_HAS_NO_WAITERS`](constant.CONDVAR_HAS_NO_WAITERS.html). As long as the condition +/// variable is set to this value, it is not needed to invoke this +/// system call. +/// +/// ## Parameters +/// +/// **condvar**: +/// The userspace condition variable that has +/// waiting threads. +/// +/// **scope**: +/// Whether the condition variable is stored in +/// private or shared memory. +/// +/// **nwaiters**: +/// The number of threads that need to be woken +/// up. If it exceeds the number of waiting +/// threads, all threads are woken up. +#[inline] +pub unsafe fn condvar_signal(condvar_: *mut condvar, scope_: scope, nwaiters_: nthreads) -> errno { + cloudabi_sys_condvar_signal(condvar_, scope_, nwaiters_) +} + +/// Closes a file descriptor. +/// +/// ## Parameters +/// +/// **fd**: +/// The file descriptor that needs to be closed. +#[inline] +pub unsafe fn fd_close(fd_: fd) -> errno { + cloudabi_sys_fd_close(fd_) +} + +/// Creates a file descriptor. +/// +/// ## Parameters +/// +/// **type**: +/// Possible values: +/// +/// - [`SHARED_MEMORY`](enum.filetype.html#variant.SHARED_MEMORY): +/// Creates an anonymous shared memory +/// object. +/// +/// **fd**: +/// The file descriptor that has been created. +#[inline] +pub unsafe fn fd_create1(type_: filetype, fd_: &mut fd) -> errno { + cloudabi_sys_fd_create1(type_, fd_) +} + +/// Creates a pair of file descriptors. +/// +/// ## Parameters +/// +/// **type**: +/// Possible values: +/// +/// - [`SOCKET_DGRAM`](enum.filetype.html#variant.SOCKET_DGRAM): +/// Creates a UNIX datagram socket pair. +/// - [`SOCKET_STREAM`](enum.filetype.html#variant.SOCKET_STREAM): +/// Creates a UNIX byte-stream socket +/// pair. +/// +/// **fd1**: +/// The first file descriptor of the pair. +/// +/// **fd2**: +/// The second file descriptor of the pair. +#[inline] +pub unsafe fn fd_create2(type_: filetype, fd1_: &mut fd, fd2_: &mut fd) -> errno { + cloudabi_sys_fd_create2(type_, fd1_, fd2_) +} + +/// Synchronizes the data of a file to disk. +/// +/// ## Parameters +/// +/// **fd**: +/// The file descriptor of the file whose data +/// needs to be synchronized to disk. +#[inline] +pub unsafe fn fd_datasync(fd_: fd) -> errno { + cloudabi_sys_fd_datasync(fd_) +} + +/// Duplicates a file descriptor. +/// +/// ## Parameters +/// +/// **from**: +/// The file descriptor that needs to be +/// duplicated. +/// +/// **fd**: +/// The new file descriptor. +#[inline] +pub unsafe fn fd_dup(from_: fd, fd_: &mut fd) -> errno { + cloudabi_sys_fd_dup(from_, fd_) +} + +/// Reads from a file descriptor, without using and updating the +/// file descriptor's offset. +/// +/// ## Parameters +/// +/// **fd**: +/// The file descriptor from which data should be +/// read. +/// +/// **iovs**: +/// List of scatter/gather vectors where data +/// should be stored. +/// +/// **offset**: +/// The offset within the file at which reading +/// should start. +/// +/// **nread**: +/// The number of bytes read. +#[inline] +pub unsafe fn fd_pread(fd_: fd, iovs_: &[iovec], offset_: filesize, nread_: &mut usize) -> errno { + cloudabi_sys_fd_pread(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nread_) +} + +/// Writes to a file descriptor, without using and updating the +/// file descriptor's offset. +/// +/// ## Parameters +/// +/// **fd**: +/// The file descriptor to which data should be +/// written. +/// +/// **iovs**: +/// List of scatter/gather vectors where data +/// should be retrieved. +/// +/// **offset**: +/// The offset within the file at which writing +/// should start. +/// +/// **nwritten**: +/// The number of bytes written. +#[inline] +pub unsafe fn fd_pwrite(fd_: fd, iovs_: &[ciovec], offset_: filesize, nwritten_: &mut usize) -> errno { + cloudabi_sys_fd_pwrite(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nwritten_) +} + +/// Reads from a file descriptor. +/// +/// ## Parameters +/// +/// **fd**: +/// The file descriptor from which data should be +/// read. +/// +/// **iovs**: +/// List of scatter/gather vectors where data +/// should be stored. +/// +/// **nread**: +/// The number of bytes read. +#[inline] +pub unsafe fn fd_read(fd_: fd, iovs_: &[iovec], nread_: &mut usize) -> errno { + cloudabi_sys_fd_read(fd_, iovs_.as_ptr(), iovs_.len(), nread_) +} + +/// Atomically replaces a file descriptor by a copy of another +/// file descriptor. +/// +/// Due to the strong focus on thread safety, this environment +/// does not provide a mechanism to duplicate a file descriptor to +/// an arbitrary number, like dup2(). This would be prone to race +/// conditions, as an actual file descriptor with the same number +/// could be allocated by a different thread at the same time. +/// +/// This system call provides a way to atomically replace file +/// descriptors, which would disappear if dup2() were to be +/// removed entirely. +/// +/// ## Parameters +/// +/// **from**: +/// The file descriptor that needs to be copied. +/// +/// **to**: +/// The file descriptor that needs to be +/// overwritten. +#[inline] +pub unsafe fn fd_replace(from_: fd, to_: fd) -> errno { + cloudabi_sys_fd_replace(from_, to_) +} + +/// Moves the offset of the file descriptor. +/// +/// ## Parameters +/// +/// **fd**: +/// The file descriptor whose offset has to be +/// moved. +/// +/// **offset**: +/// The number of bytes to move. +/// +/// **whence**: +/// Relative to which position the move should +/// take place. +/// +/// **newoffset**: +/// The new offset of the file descriptor, +/// relative to the start of the file. +#[inline] +pub unsafe fn fd_seek(fd_: fd, offset_: filedelta, whence_: whence, newoffset_: &mut filesize) -> errno { + cloudabi_sys_fd_seek(fd_, offset_, whence_, newoffset_) +} + +/// Gets attributes of a file descriptor. +/// +/// ## Parameters +/// +/// **fd**: +/// The file descriptor whose attributes have to +/// be obtained. +/// +/// **buf**: +/// The buffer where the file descriptor's +/// attributes are stored. +#[inline] +pub unsafe fn fd_stat_get(fd_: fd, buf_: *mut fdstat) -> errno { + cloudabi_sys_fd_stat_get(fd_, buf_) +} + +/// Adjusts attributes of a file descriptor. +/// +/// ## Parameters +/// +/// **fd**: +/// The file descriptor whose attributes have to +/// be adjusted. +/// +/// **buf**: +/// The desired values of the file descriptor +/// attributes that are adjusted. +/// +/// **flags**: +/// A bitmask indicating which attributes have to +/// be adjusted. +#[inline] +pub unsafe fn fd_stat_put(fd_: fd, buf_: *const fdstat, flags_: fdsflags) -> errno { + cloudabi_sys_fd_stat_put(fd_, buf_, flags_) +} + +/// Synchronizes the data and metadata of a file to disk. +/// +/// ## Parameters +/// +/// **fd**: +/// The file descriptor of the file whose data +/// and metadata needs to be synchronized to disk. +#[inline] +pub unsafe fn fd_sync(fd_: fd) -> errno { + cloudabi_sys_fd_sync(fd_) +} + +/// Writes to a file descriptor. +/// +/// ## Parameters +/// +/// **fd**: +/// The file descriptor to which data should be +/// written. +/// +/// **iovs**: +/// List of scatter/gather vectors where data +/// should be retrieved. +/// +/// **nwritten**: +/// The number of bytes written. +#[inline] +pub unsafe fn fd_write(fd_: fd, iovs_: &[ciovec], nwritten_: &mut usize) -> errno { + cloudabi_sys_fd_write(fd_, iovs_.as_ptr(), iovs_.len(), nwritten_) +} + +/// Provides file advisory information on a file descriptor. +/// +/// ## Parameters +/// +/// **fd**: +/// The file descriptor for which to provide file +/// advisory information. +/// +/// **offset**: +/// The offset within the file to which the +/// advisory applies. +/// +/// **len**: +/// The length of the region to which the advisory +/// applies. +/// +/// **advice**: +/// The advice. +#[inline] +pub unsafe fn file_advise(fd_: fd, offset_: filesize, len_: filesize, advice_: advice) -> errno { + cloudabi_sys_file_advise(fd_, offset_, len_, advice_) +} + +/// Forces the allocation of space in a file. +/// +/// ## Parameters +/// +/// **fd**: +/// The file in which the space should be +/// allocated. +/// +/// **offset**: +/// The offset at which the allocation should +/// start. +/// +/// **len**: +/// The length of the area that is allocated. +#[inline] +pub unsafe fn file_allocate(fd_: fd, offset_: filesize, len_: filesize) -> errno { + cloudabi_sys_file_allocate(fd_, offset_, len_) +} + +/// Creates a file of a specified type. +/// +/// ## Parameters +/// +/// **fd**: +/// The working directory at which the resolution +/// of the file to be created starts. +/// +/// **path**: +/// The path at which the file should be created. +/// +/// **type**: +/// Possible values: +/// +/// - [`DIRECTORY`](enum.filetype.html#variant.DIRECTORY): +/// Creates a directory. +#[inline] +pub unsafe fn file_create(fd_: fd, path_: &[u8], type_: filetype) -> errno { + cloudabi_sys_file_create(fd_, path_.as_ptr(), path_.len(), type_) +} + +/// Creates a hard link. +/// +/// ## Parameters +/// +/// **fd1**: +/// The working directory at which the resolution +/// of the source path starts. +/// +/// **path1**: +/// The source path of the file that should be +/// hard linked. +/// +/// **fd2**: +/// The working directory at which the resolution +/// of the destination path starts. +/// +/// **path2**: +/// The destination path at which the hard link +/// should be created. +#[inline] +pub unsafe fn file_link(fd1_: lookup, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno { + cloudabi_sys_file_link(fd1_, path1_.as_ptr(), path1_.len(), fd2_, path2_.as_ptr(), path2_.len()) +} + +/// Opens a file. +/// +/// ## Parameters +/// +/// **dirfd**: +/// The working directory at which the resolution +/// of the file to be opened starts. +/// +/// **path**: +/// The path of the file that should be opened. +/// +/// **oflags**: +/// The method at which the file should be opened. +/// +/// **fds**: +/// [`fdstat.fs_rights_base`](struct.fdstat.html#structfield.fs_rights_base) and +/// [`fdstat.fs_rights_inheriting`](struct.fdstat.html#structfield.fs_rights_inheriting) specify the +/// initial rights of the newly created file +/// descriptor. The operating system is allowed to +/// return a file descriptor with fewer rights +/// than specified, if and only if those rights do +/// not apply to the type of file being opened. +/// +/// [`fdstat.fs_flags`](struct.fdstat.html#structfield.fs_flags) specifies the initial flags +/// of the file descriptor. +/// +/// [`fdstat.fs_filetype`](struct.fdstat.html#structfield.fs_filetype) is ignored. +/// +/// **fd**: +/// The file descriptor of the file that has been +/// opened. +#[inline] +pub unsafe fn file_open(dirfd_: lookup, path_: &[u8], oflags_: oflags, fds_: *const fdstat, fd_: &mut fd) -> errno { + cloudabi_sys_file_open(dirfd_, path_.as_ptr(), path_.len(), oflags_, fds_, fd_) +} + +/// Reads directory entries from a directory. +/// +/// When successful, the contents of the output buffer consist of +/// a sequence of directory entries. Each directory entry consists +/// of a [`dirent`](struct.dirent.html) object, followed by [`dirent.d_namlen`](struct.dirent.html#structfield.d_namlen) bytes +/// holding the name of the directory entry. +/// +/// This system call fills the output buffer as much as possible, +/// potentially truncating the last directory entry. This allows +/// the caller to grow its read buffer size in case it's too small +/// to fit a single large directory entry, or skip the oversized +/// directory entry. +/// +/// ## Parameters +/// +/// **fd**: +/// The directory from which to read the directory +/// entries. +/// +/// **buf**: +/// The buffer where directory entries are stored. +/// +/// **cookie**: +/// The location within the directory to start +/// reading. +/// +/// **bufused**: +/// The number of bytes stored in the read buffer. +/// If less than the size of the read buffer, the +/// end of the directory has been reached. +#[inline] +pub unsafe fn file_readdir(fd_: fd, buf_: &mut [u8], cookie_: dircookie, bufused_: &mut usize) -> errno { + cloudabi_sys_file_readdir(fd_, buf_.as_mut_ptr() as *mut (), buf_.len(), cookie_, bufused_) +} + +/// Reads the contents of a symbolic link. +/// +/// ## Parameters +/// +/// **fd**: +/// The working directory at which the resolution +/// of the path of the symbolic starts. +/// +/// **path**: +/// The path of the symbolic link whose contents +/// should be read. +/// +/// **buf**: +/// The buffer where the contents of the symbolic +/// link should be stored. +/// +/// **bufused**: +/// The number of bytes placed in the buffer. +#[inline] +pub unsafe fn file_readlink(fd_: fd, path_: &[u8], buf_: &mut [u8], bufused_: &mut usize) -> errno { + cloudabi_sys_file_readlink(fd_, path_.as_ptr(), path_.len(), buf_.as_mut_ptr(), buf_.len(), bufused_) +} + +/// Renames a file. +/// +/// ## Parameters +/// +/// **fd1**: +/// The working directory at which the resolution +/// of the source path starts. +/// +/// **path1**: +/// The source path of the file that should be +/// renamed. +/// +/// **fd2**: +/// The working directory at which the resolution +/// of the destination path starts. +/// +/// **path2**: +/// The destination path to which the file should +/// be renamed. +#[inline] +pub unsafe fn file_rename(fd1_: fd, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno { + cloudabi_sys_file_rename(fd1_, path1_.as_ptr(), path1_.len(), fd2_, path2_.as_ptr(), path2_.len()) +} + +/// Gets attributes of a file by file descriptor. +/// +/// ## Parameters +/// +/// **fd**: +/// The file descriptor whose attributes have to +/// be obtained. +/// +/// **buf**: +/// The buffer where the file's attributes are +/// stored. +#[inline] +pub unsafe fn file_stat_fget(fd_: fd, buf_: *mut filestat) -> errno { + cloudabi_sys_file_stat_fget(fd_, buf_) +} + +/// Adjusts attributes of a file by file descriptor. +/// +/// ## Parameters +/// +/// **fd**: +/// The file descriptor whose attributes have to +/// be adjusted. +/// +/// **buf**: +/// The desired values of the file attributes that +/// are adjusted. +/// +/// **flags**: +/// A bitmask indicating which attributes have to +/// be adjusted. +#[inline] +pub unsafe fn file_stat_fput(fd_: fd, buf_: *const filestat, flags_: fsflags) -> errno { + cloudabi_sys_file_stat_fput(fd_, buf_, flags_) +} + +/// Gets attributes of a file by path. +/// +/// ## Parameters +/// +/// **fd**: +/// The working directory at which the resolution +/// of the path whose attributes have to be +/// obtained starts. +/// +/// **path**: +/// The path of the file whose attributes have to +/// be obtained. +/// +/// **buf**: +/// The buffer where the file's attributes are +/// stored. +#[inline] +pub unsafe fn file_stat_get(fd_: lookup, path_: &[u8], buf_: *mut filestat) -> errno { + cloudabi_sys_file_stat_get(fd_, path_.as_ptr(), path_.len(), buf_) +} + +/// Adjusts attributes of a file by path. +/// +/// ## Parameters +/// +/// **fd**: +/// The working directory at which the resolution +/// of the path whose attributes have to be +/// adjusted starts. +/// +/// **path**: +/// The path of the file whose attributes have to +/// be adjusted. +/// +/// **buf**: +/// The desired values of the file attributes that +/// are adjusted. +/// +/// **flags**: +/// A bitmask indicating which attributes have to +/// be adjusted. +#[inline] +pub unsafe fn file_stat_put(fd_: lookup, path_: &[u8], buf_: *const filestat, flags_: fsflags) -> errno { + cloudabi_sys_file_stat_put(fd_, path_.as_ptr(), path_.len(), buf_, flags_) +} + +/// Creates a symbolic link. +/// +/// ## Parameters +/// +/// **path1**: +/// The contents of the symbolic link. +/// +/// **fd**: +/// The working directory at which the resolution +/// of the destination path starts. +/// +/// **path2**: +/// The destination path at which the symbolic +/// link should be created. +#[inline] +pub unsafe fn file_symlink(path1_: &[u8], fd_: fd, path2_: &[u8]) -> errno { + cloudabi_sys_file_symlink(path1_.as_ptr(), path1_.len(), fd_, path2_.as_ptr(), path2_.len()) +} + +/// Unlinks a file, or removes a directory. +/// +/// ## Parameters +/// +/// **fd**: +/// The working directory at which the resolution +/// of the path starts. +/// +/// **path**: +/// The path that needs to be unlinked or removed. +/// +/// **flags**: +/// Possible values: +/// +/// - [`REMOVEDIR`](struct.ulflags.html#associatedconstant.REMOVEDIR): +/// If set, attempt to remove a directory. +/// Otherwise, unlink a file. +#[inline] +pub unsafe fn file_unlink(fd_: fd, path_: &[u8], flags_: ulflags) -> errno { + cloudabi_sys_file_unlink(fd_, path_.as_ptr(), path_.len(), flags_) +} + +/// Unlocks a write-locked userspace lock. +/// +/// If a userspace lock is unlocked while having its +/// [`LOCK_KERNEL_MANAGED`](constant.LOCK_KERNEL_MANAGED.html) flag set, the lock cannot be unlocked in +/// userspace directly. This system call needs to be performed +/// instead, so that any waiting threads can be woken up. +/// +/// To prevent spurious invocations of this system call, the lock +/// must be locked for writing. This prevents other threads from +/// acquiring additional read locks while the system call is in +/// progress. If the lock is acquired for reading, it must first +/// be upgraded to a write lock. +/// +/// ## Parameters +/// +/// **lock**: +/// The userspace lock that is locked for writing +/// by the calling thread. +/// +/// **scope**: +/// Whether the lock is stored in private or +/// shared memory. +#[inline] +pub unsafe fn lock_unlock(lock_: *mut lock, scope_: scope) -> errno { + cloudabi_sys_lock_unlock(lock_, scope_) +} + +/// Provides memory advisory information on a region of memory. +/// +/// ## Parameters +/// +/// **mapping**: +/// The pages for which to provide memory advisory +/// information. +/// +/// **advice**: +/// The advice. +#[inline] +pub unsafe fn mem_advise(mapping_: &mut [u8], advice_: advice) -> errno { + cloudabi_sys_mem_advise(mapping_.as_mut_ptr() as *mut (), mapping_.len(), advice_) +} + +/// Creates a memory mapping, making the contents of a file +/// accessible through memory. +/// +/// ## Parameters +/// +/// **addr**: +/// If [`FIXED`](struct.mflags.html#associatedconstant.FIXED) is set, specifies to which +/// address the file region is mapped. Otherwise, +/// the mapping is performed at an unused +/// location. +/// +/// **len**: +/// The length of the memory mapping to be +/// created. +/// +/// **prot**: +/// Initial memory protection options for the +/// memory mapping. +/// +/// **flags**: +/// Memory mapping flags. +/// +/// **fd**: +/// If [`ANON`](struct.mflags.html#associatedconstant.ANON) is set, this argument must be +/// [`MAP_ANON_FD`](constant.MAP_ANON_FD.html). Otherwise, this argument +/// specifies the file whose contents need to be +/// mapped. +/// +/// **off**: +/// If [`ANON`](struct.mflags.html#associatedconstant.ANON) is set, this argument must be +/// zero. Otherwise, this argument specifies the +/// offset within the file at which the mapping +/// starts. +/// +/// **mem**: +/// The starting address of the memory mapping. +#[inline] +pub unsafe fn mem_map(addr_: *mut (), len_: usize, prot_: mprot, flags_: mflags, fd_: fd, off_: filesize, mem_: &mut *mut ()) -> errno { + cloudabi_sys_mem_map(addr_, len_, prot_, flags_, fd_, off_, mem_) +} + +/// Change the protection of a memory mapping. +/// +/// ## Parameters +/// +/// **mapping**: +/// The pages that need their protection changed. +/// +/// **prot**: +/// New protection options. +#[inline] +pub unsafe fn mem_protect(mapping_: &mut [u8], prot_: mprot) -> errno { + cloudabi_sys_mem_protect(mapping_.as_mut_ptr() as *mut (), mapping_.len(), prot_) +} + +/// Synchronize a region of memory with its physical storage. +/// +/// ## Parameters +/// +/// **mapping**: +/// The pages that need to be synchronized. +/// +/// **flags**: +/// The method of synchronization. +#[inline] +pub unsafe fn mem_sync(mapping_: &mut [u8], flags_: msflags) -> errno { + cloudabi_sys_mem_sync(mapping_.as_mut_ptr() as *mut (), mapping_.len(), flags_) +} + +/// Unmaps a region of memory. +/// +/// ## Parameters +/// +/// **mapping**: +/// The pages that needs to be unmapped. +#[inline] +pub unsafe fn mem_unmap(mapping_: &mut [u8]) -> errno { + cloudabi_sys_mem_unmap(mapping_.as_mut_ptr() as *mut (), mapping_.len()) +} + +/// Concurrently polls for the occurrence of a set of events. +/// +/// ## Parameters +/// +/// **in**: +/// The events to which to subscribe. +/// +/// **out**: +/// The events that have occurred. +/// +/// **nsubscriptions**: +/// Both the number of subscriptions and events. +/// +/// **nevents**: +/// The number of events stored. +#[inline] +pub unsafe fn poll(in_: *const subscription, out_: *mut event, nsubscriptions_: usize, nevents_: &mut usize) -> errno { + cloudabi_sys_poll(in_, out_, nsubscriptions_, nevents_) +} + +/// Replaces the process by a new executable. +/// +/// Process execution in CloudABI differs from POSIX in two ways: +/// handling of arguments and inheritance of file descriptors. +/// +/// CloudABI does not use string command line arguments. Instead, +/// a buffer with binary data is copied into the address space of +/// the new executable. The kernel does not enforce any specific +/// structure to this data, although CloudABI's C library uses it +/// to store a tree structure that is semantically identical to +/// YAML. +/// +/// Due to the strong focus on thread safety, file descriptors +/// aren't inherited through close-on-exec flags. An explicit +/// list of file descriptors that need to be retained needs to be +/// provided. After execution, file descriptors are placed in the +/// order in which they are stored in the array. This not only +/// makes the execution process deterministic. It also prevents +/// potential information disclosures about the layout of the +/// original process. +/// +/// ## Parameters +/// +/// **fd**: +/// A file descriptor of the new executable. +/// +/// **data**: +/// Binary argument data that is passed on to the +/// new executable. +/// +/// **fds**: +/// The layout of the file descriptor table after +/// execution. +#[inline] +pub unsafe fn proc_exec(fd_: fd, data_: &[u8], fds_: &[fd]) -> errno { + cloudabi_sys_proc_exec(fd_, data_.as_ptr() as *const (), data_.len(), fds_.as_ptr(), fds_.len()) +} + +/// Terminates the process normally. +/// +/// ## Parameters +/// +/// **rval**: +/// The exit code returned by the process. The +/// exit code can be obtained by other processes +/// through [`event.union.proc_terminate.exitcode`](struct.event_proc_terminate.html#structfield.exitcode). +#[inline] +pub unsafe fn proc_exit(rval_: exitcode) -> ! { + cloudabi_sys_proc_exit(rval_) +} + +/// Forks the process of the calling thread. +/// +/// After forking, a new process shall be created, having only a +/// copy of the calling thread. The parent process will obtain a +/// process descriptor. When closed, the child process is +/// automatically signaled with [`KILL`](enum.signal.html#variant.KILL). +/// +/// ## Parameters +/// +/// **fd**: +/// In the parent process: the file descriptor +/// number of the process descriptor. +/// +/// In the child process: [`PROCESS_CHILD`](constant.PROCESS_CHILD.html). +/// +/// **tid**: +/// In the parent process: undefined. +/// +/// In the child process: the thread ID of the +/// initial thread of the child process. +#[inline] +pub unsafe fn proc_fork(fd_: &mut fd, tid_: &mut tid) -> errno { + cloudabi_sys_proc_fork(fd_, tid_) +} + +/// Sends a signal to the process of the calling thread. +/// +/// ## Parameters +/// +/// **sig**: +/// The signal condition that should be triggered. +/// If the signal causes the process to terminate, +/// its condition can be obtained by other +/// processes through +/// [`event.union.proc_terminate.signal`](struct.event_proc_terminate.html#structfield.signal). +#[inline] +pub unsafe fn proc_raise(sig_: signal) -> errno { + cloudabi_sys_proc_raise(sig_) +} + +/// Obtains random data from the kernel random number generator. +/// +/// As this interface is not guaranteed to be fast, it is advised +/// that the random data obtained through this system call is used +/// as the seed for a userspace pseudo-random number generator. +/// +/// ## Parameters +/// +/// **buf**: +/// The buffer that needs to be filled with random +/// data. +#[inline] +pub unsafe fn random_get(buf_: &mut [u8]) -> errno { + cloudabi_sys_random_get(buf_.as_mut_ptr() as *mut (), buf_.len()) +} + +/// Receives a message on a socket. +/// +/// ## Parameters +/// +/// **sock**: +/// The socket on which a message should be +/// received. +/// +/// **in**: +/// Input parameters. +/// +/// **out**: +/// Output parameters. +#[inline] +pub unsafe fn sock_recv(sock_: fd, in_: *const recv_in, out_: *mut recv_out) -> errno { + cloudabi_sys_sock_recv(sock_, in_, out_) +} + +/// Sends a message on a socket. +/// +/// ## Parameters +/// +/// **sock**: +/// The socket on which a message should be sent. +/// +/// **in**: +/// Input parameters. +/// +/// **out**: +/// Output parameters. +#[inline] +pub unsafe fn sock_send(sock_: fd, in_: *const send_in, out_: *mut send_out) -> errno { + cloudabi_sys_sock_send(sock_, in_, out_) +} + +/// Shuts down socket send and receive channels. +/// +/// ## Parameters +/// +/// **sock**: +/// The socket that needs its channels shut down. +/// +/// **how**: +/// Which channels on the socket need to be shut +/// down. +#[inline] +pub unsafe fn sock_shutdown(sock_: fd, how_: sdflags) -> errno { + cloudabi_sys_sock_shutdown(sock_, how_) +} + +/// Creates a new thread within the current process. +/// +/// ## Parameters +/// +/// **attr**: +/// The desired attributes of the new thread. +/// +/// **tid**: +/// The thread ID of the new thread. +#[inline] +pub unsafe fn thread_create(attr_: *mut threadattr, tid_: &mut tid) -> errno { + cloudabi_sys_thread_create(attr_, tid_) +} + +/// Terminates the calling thread. +/// +/// This system call can also unlock a single userspace lock +/// after termination, which can be used to implement thread +/// joining. +/// +/// ## Parameters +/// +/// **lock**: +/// Userspace lock that is locked for writing by +/// the calling thread. +/// +/// **scope**: +/// Whether the lock is stored in private or +/// shared memory. +#[inline] +pub unsafe fn thread_exit(lock_: *mut lock, scope_: scope) -> ! { + cloudabi_sys_thread_exit(lock_, scope_) +} + +/// Temporarily yields execution of the calling thread. +#[inline] +pub unsafe fn thread_yield() -> errno { + cloudabi_sys_thread_yield() +} diff --git a/third_party/rust/fuchsia-cprng/.cargo-checksum.json b/third_party/rust/fuchsia-cprng/.cargo-checksum.json new file mode 100644 index 000000000000..d92a5f0d1fd5 --- /dev/null +++ b/third_party/rust/fuchsia-cprng/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"AUTHORS":"f82920a5bcfc71b86c1de4be4cdea8af2009ba9e5735824f95ed5043a03e46f0","Cargo.toml":"bb2497b2907c3af499ce7ac3722dae044968e13409a372b7760150f8a01c74c5","LICENSE":"03b114f53e6587a398931762ee11e2395bfdba252a329940e2c8c9e81813845b","PATENTS":"52beb3ac72a0e7f5060384d16e4e6f91573016448fbff363c0b01a66fe99f547","src/lib.rs":"3d76c35c13203093ddf7ce2a3be5e98d768a8091cd9d99bd083fe8db35364096"},"package":"a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"} \ No newline at end of file diff --git a/third_party/rust/fuchsia-cprng/AUTHORS b/third_party/rust/fuchsia-cprng/AUTHORS new file mode 100644 index 000000000000..61ae3028084a --- /dev/null +++ b/third_party/rust/fuchsia-cprng/AUTHORS @@ -0,0 +1,10 @@ +# This is the list of Fuchsia Authors. + +# Names should be added to this file as one of +# Organization's name +# Individual's name +# Individual's name + +Google Inc. +The Chromium Authors +The Go Authors diff --git a/third_party/rust/fuchsia-cprng/Cargo.toml b/third_party/rust/fuchsia-cprng/Cargo.toml new file mode 100644 index 000000000000..917b430962e6 --- /dev/null +++ b/third_party/rust/fuchsia-cprng/Cargo.toml @@ -0,0 +1,22 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "fuchsia-cprng" +version = "0.1.1" +authors = ["Erick Tryzelaar "] +include = ["src/*.rs", "Cargo.toml", "AUTHORS", "LICENSE", "PATENTS"] +description = "Rust crate for the Fuchsia cryptographically secure pseudorandom number generator" +readme = "README.md" +license-file = "LICENSE" +repository = "https://fuchsia.googlesource.com/fuchsia/+/master/garnet/public/rust/fuchsia-cprng" diff --git a/third_party/rust/sha1/LICENSE b/third_party/rust/fuchsia-cprng/LICENSE similarity index 59% rename from third_party/rust/sha1/LICENSE rename to third_party/rust/fuchsia-cprng/LICENSE index 71134f2e1ad9..87f152cc553a 100644 --- a/third_party/rust/sha1/LICENSE +++ b/third_party/rust/fuchsia-cprng/LICENSE @@ -1,24 +1,18 @@ -Copyright (c) 2014 by Armin Ronacher. - -Copyright (c) 2013 Koka El Kiwi - -Some rights reserved. +Copyright 2019 The Fuchsia Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT diff --git a/third_party/rust/fuchsia-cprng/PATENTS b/third_party/rust/fuchsia-cprng/PATENTS new file mode 100644 index 000000000000..2746e78d1bef --- /dev/null +++ b/third_party/rust/fuchsia-cprng/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Fuchsia project. + +Google hereby grants to you a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this +section) patent license to make, have made, use, offer to sell, sell, +import, transfer, and otherwise run, modify and propagate the contents +of this implementation of Fuchsia, where such license applies only to +those patent claims, both currently owned by Google and acquired in +the future, licensable by Google that are necessarily infringed by +this implementation. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute +or order or agree to the institution of patent litigation or any other +patent enforcement activity against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that this +implementation of Fuchsia constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of +Fuchsia shall terminate as of the date such litigation is filed. diff --git a/third_party/rust/fuchsia-cprng/src/lib.rs b/third_party/rust/fuchsia-cprng/src/lib.rs new file mode 100644 index 000000000000..5074690c9641 --- /dev/null +++ b/third_party/rust/fuchsia-cprng/src/lib.rs @@ -0,0 +1,57 @@ +// Copyright 2019 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +//! Type-safe bindings for the Zircon kernel's CPRNG. + +#![no_std] +#![deny(warnings)] + +/// Draw random bytes from the kernel's CPRNG to fill the given buffer. +/// +/// Wraps the +/// [zx_cprng_draw](https://fuchsia.googlesource.com/fuchsia/+/master/zircon/docs/syscalls/cprng_draw.md) +/// syscall. +pub fn cprng_draw(buffer: &mut [u8]) { + unsafe { zx_cprng_draw(buffer.as_mut_ptr(), buffer.len()) }; +} + +#[link(name = "zircon")] +extern "C" { + fn zx_cprng_draw(buffer: *mut u8, length: usize); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn cprng() { + let mut buffer = [0; 20]; + cprng_draw(&mut buffer); + let mut first_zero = 0; + let mut last_zero = 0; + for _ in 0..30 { + let mut buffer = [0; 20]; + cprng_draw(&mut buffer); + if buffer[0] == 0 { + first_zero += 1; + } + if buffer[19] == 0 { + last_zero += 1; + } + } + assert_ne!(first_zero, 30); + assert_ne!(last_zero, 30); + } + + #[test] + fn cprng_large() { + let mut buffer = [0; 1024]; + cprng_draw(&mut buffer); + + for mut s in buffer.chunks_mut(256) { + cprng_draw(&mut s); + } + } +} diff --git a/third_party/rust/httparse/.cargo-checksum.json b/third_party/rust/httparse/.cargo-checksum.json index 32b979f102ac..6e45afdaaa4b 100644 --- a/third_party/rust/httparse/.cargo-checksum.json +++ b/third_party/rust/httparse/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"ce89721483a37a5e21e4c7c8bd36b64a03067c23b3c6a9569e552a2a0364522e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ad5ce29918424008bdd8c6e7851bb064533456cbb32ec0d0955b2bc9444613d3","README.md":"8777517c90cff609e5a00a46b548f44803a4943cc7430a0ca6ddc4712af8d4ac","benches/parse.rs":"07f7d63b625090f1ccb086679e24c104de450d8733bb517e38a6eda8511e35e3","src/iter.rs":"9782faa1736e7988feceecdd5169f51b8b7926cbcf6611bbef9e018763e3cec8","src/lib.rs":"d95d4de02b19f2f921e13f0f477092d202fe0e707dc007b9bbd05282d7e69ebc"},"package":"af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07"} \ No newline at end of file +{"files":{"Cargo.toml":"2d893bf5d1e9a5445e74c2a7a75b804492245647004155a798f5456e5c0f4712","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ad5ce29918424008bdd8c6e7851bb064533456cbb32ec0d0955b2bc9444613d3","README.md":"b54e1e379daa12d26aadad7c1bef578a3cbcf243f2f229d8b17868c90a384d7d","benches/parse.rs":"caabd31cbcb00172bb7f31a1398dbed27a3bf36b01d69729c3d6fbd9a4008e05","build.rs":"00bab146ec6a10fac91958a06bdd4b7b4d71932e0480b6e84a4248cb339dbe79","src/iter.rs":"3f165be2f0d3bb7e0cbe37cb67560e36e06cdb5921e145446a5985c3580a6b6e","src/lib.rs":"21436cacd3b33b20ad75877e6260f34391a9215ffa6ad2c10ebf1a0c67ac07dc","src/macros.rs":"25de190f894eefb48a6992f9dc3d039d9065f908f381d683f0395d568d992275","src/simd/avx2.rs":"1b27cad7b5c210f8a1283d423ca18372127ea50f5565b9be0b83d2a51a1eb826","src/simd/fallback.rs":"0234cc11459f3225d6e3d329068a01206e39625a538bdc292e0d1beaa06a37e5","src/simd/mod.rs":"c67e118a45da679d41de0d51c2f632f64902083db4be8f636021dbfe08f0f9b4","src/simd/sse42.rs":"373f5bf0596942b9ba4497a8a89975117ec0da6d8b8c2345fe03e0d28e68627f","tests/uri.rs":"92a0dc4cfa8eee2e6b8e9109e2e0062ccb50b9ec8cb4b7c06794dab1a3e68c9c"},"package":"e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83"} \ No newline at end of file diff --git a/third_party/rust/httparse/Cargo.toml b/third_party/rust/httparse/Cargo.toml index 8ad43a634ad0..34e1b3bcf3bb 100644 --- a/third_party/rust/httparse/Cargo.toml +++ b/third_party/rust/httparse/Cargo.toml @@ -12,9 +12,14 @@ [package] name = "httparse" -version = "1.2.3" -authors = ["Sean McArthur "] +version = "1.3.3" +authors = ["Sean McArthur "] +build = "build.rs" description = "A tiny, safe, speedy, zero-copy HTTP/1.x parser." +documentation = "https://docs.rs/httparse" +readme = "README.md" +keywords = ["http", "parser", "no_std"] +categories = ["network-programming", "no-std", "parser-implementations", "web-programming"] license = "MIT/Apache-2.0" repository = "https://github.com/seanmonstar/httparse" [profile.bench] diff --git a/third_party/rust/httparse/README.md b/third_party/rust/httparse/README.md index 17d5c520580e..f786302a4d66 100644 --- a/third_party/rust/httparse/README.md +++ b/third_party/rust/httparse/README.md @@ -2,11 +2,14 @@ [![Build Status](https://travis-ci.org/seanmonstar/httparse.svg?branch=master)](https://travis-ci.org/seanmonstar/httparse) [![Coverage Status](https://coveralls.io/repos/seanmonstar/httparse/badge.svg)](https://coveralls.io/r/seanmonstar/httparse) -[![crates.io](http://meritbadge.herokuapp.com/httparse)](https://crates.io/crates/httparse) +[![crates.io](https://img.shields.io/crates/v/httparse.svg)](https://crates.io/crates/httparse) -A push parser for the HTTP 1.x protocol. Avoids allocations. Fast. +A push parser for the HTTP 1.x protocol. Avoids allocations. No copy. **Fast.** + +Works with `no_std`, simply disable the `std` Cargo feature. [Documentation](https://docs.rs/httparse) +[Changelog](https://github.com/seanmonstar/httparse/releases) ## Usage @@ -15,12 +18,12 @@ let mut headers = [httparse::EMPTY_HEADER; 16]; let mut req = httparse::Request::new(&mut headers); let buf = b"GET /index.html HTTP/1.1\r\nHost"; -assert!(try!(req.parse(buf)).is_partial()); +assert!(req.parse(buf)?.is_partial()); // a partial request, so we try again once we have more data let buf = b"GET /index.html HTTP/1.1\r\nHost: example.domain\r\n\r\n"; -assert!(try!(req.parse(buf)).is_complete()); +assert!(req.parse(buf)?.is_complete()); ``` ## License diff --git a/third_party/rust/httparse/benches/parse.rs b/third_party/rust/httparse/benches/parse.rs index 459abc9bed93..38e8b58507e2 100644 --- a/third_party/rust/httparse/benches/parse.rs +++ b/third_party/rust/httparse/benches/parse.rs @@ -5,6 +5,11 @@ extern crate httparse; extern crate test; +const REQ_SHORT: &'static [u8] = b"\ +GET / HTTP/1.0\r\n\ +Host: example.com\r\n\ +Cookie: session=60; user_id=1\r\n\r\n"; + const REQ: &'static [u8] = b"\ GET /wp-content/uploads/2010/03/hello-kitty-darth-vader-pink.jpg HTTP/1.1\r\n\ Host: www.kittyhell.com\r\n\ @@ -15,9 +20,7 @@ Accept-Encoding: gzip,deflate\r\n\ Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7\r\n\ Keep-Alive: 115\r\n\ Connection: keep-alive\r\n\ -Cookie: wp_ozh_wsa_visits=2; wp_ozh_wsa_visit_lasttime=xxxxxxxxxx; __utma=xxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.x; __utmz=xxxxxxxxx.xxxxxxxxxx.x.x.utmccn=(referral)|utmcsr=reader.livedoor.com|utmcct=/reader/|utmcmd=referral\r\n\r\n"; - - +Cookie: wp_ozh_wsa_visits=2; wp_ozh_wsa_visit_lasttime=xxxxxxxxxx; __utma=xxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.x; __utmz=xxxxxxxxx.xxxxxxxxxx.x.x.utmccn=(referral)|utmcsr=reader.livedoor.com|utmcct=/reader/|utmcmd=referral|padding=under256\r\n\r\n"; #[bench] @@ -68,3 +71,52 @@ fn bench_httparse(b: &mut test::Bencher) { }); b.bytes = REQ.len() as u64; } + +#[bench] +fn bench_pico_short(b: &mut test::Bencher) { + use std::mem; + + #[repr(C)] + #[derive(Clone, Copy)] + struct Header<'a>(&'a [u8], &'a [u8]); + + + #[repr(C)] + struct Headers<'a>(&'a mut [Header<'a>]); + let method = [0i8; 16]; + let path = [0i8; 16]; + let mut minor_version = 0; + let mut h = [Header(&[], &[]); 16]; + let mut h_len = h.len(); + let headers = Headers(&mut h); + let prev_buf_len = 0; + + b.iter(|| { + let ret = unsafe { + pico::ffi::phr_parse_request( + REQ_SHORT.as_ptr() as *const _, + REQ_SHORT.len(), + &mut method.as_ptr(), + &mut 16, + &mut path.as_ptr(), + &mut 16, + &mut minor_version, + mem::transmute::<*mut Header, *mut pico::ffi::phr_header>(headers.0.as_mut_ptr()), + &mut h_len as *mut usize as *mut _, + prev_buf_len + ) + }; + assert_eq!(ret, REQ_SHORT.len() as i32); + }); + b.bytes = REQ_SHORT.len() as u64; +} + +#[bench] +fn bench_httparse_short(b: &mut test::Bencher) { + let mut headers = [httparse::Header{ name: "", value: &[] }; 16]; + let mut req = httparse::Request::new(&mut headers); + b.iter(|| { + assert_eq!(req.parse(REQ_SHORT).unwrap(), httparse::Status::Complete(REQ_SHORT.len())); + }); + b.bytes = REQ_SHORT.len() as u64; +} diff --git a/third_party/rust/httparse/build.rs b/third_party/rust/httparse/build.rs new file mode 100644 index 000000000000..e46dea0d158f --- /dev/null +++ b/third_party/rust/httparse/build.rs @@ -0,0 +1,155 @@ +use std::env; +use std::ffi::OsString; +use std::process::Command; + +fn main() { + let rustc = env::var_os("RUSTC").unwrap_or(OsString::from("rustc")); + let output = Command::new(&rustc) + .arg("--version") + .output() + .expect("failed to check 'rustc --version'") + .stdout; + + let version = String::from_utf8(output) + .expect("rustc version output should be utf-8"); + + enable_new_features(&version); +} + +fn enable_new_features(raw_version: &str) { + let version = match Version::parse(raw_version) { + Ok(version) => version, + Err(err) => { + println!("cargo:warning=failed to parse `rustc --version`: {}", err); + return; + } + }; + + enable_simd(version); +} + +fn enable_simd(version: Version) { + if env::var_os("CARGO_FEATURE_STD").is_none() { + println!("cargo:warning=building for no_std disables httparse SIMD"); + return; + } + + let env_disable = "CARGO_CFG_HTTPARSE_DISABLE_SIMD"; + if env::var_os(env_disable).is_some() { + println!("cargo:warning=detected {} environment variable, disabling SIMD", env_disable); + return; + } + + let min_simd_version = Version { + major: 1, + minor: 27, + patch: 0, + }; + + if version >= min_simd_version { + println!("cargo:rustc-cfg=httparse_simd"); + } + + // cfg(target_feature) isn't stable yet, but CARGO_CFG_TARGET_FEATURE has + // a list... We aren't doing anything unsafe, since the is_x86_feature_detected + // macro still checks in the actual lib, BUT! + // + // By peeking at the list here, we can change up slightly how we do feature + // detection in the lib. If our features aren't in the feature list, we + // stick with a cached runtime detection strategy. + // + // But if the features *are* in the list, we benefit from removing our cache, + // since the compiler will eliminate several branches with its internal + // cfg(target_feature) usage. + + + let env_runtime_only = "CARGO_CFG_HTTPARSE_DISABLE_SIMD_COMPILETIME"; + if env::var_os(env_runtime_only).is_some() { + println!("cargo:warning=detected {} environment variable, using runtime SIMD detection only", env_runtime_only); + return; + } + let feature_list = match env::var_os("CARGO_CFG_TARGET_FEATURE") { + Some(var) => match var.into_string() { + Ok(s) => s, + Err(_) => { + println!("cargo:warning=CARGO_CFG_TARGET_FEATURE was not valid utf-8"); + return; + }, + }, + None => { + println!("cargo:warning=CARGO_CFG_TARGET_FEATURE was not set"); + return + }, + }; + + let mut saw_sse42 = false; + let mut saw_avx2 = false; + + for feature in feature_list.split(',') { + let feature = feature.trim(); + if !saw_sse42 && feature == "sse4.2" { + saw_sse42 = true; + println!("cargo:rustc-cfg=httparse_simd_target_feature_sse42"); + } + + if !saw_avx2 && feature == "avx2" { + saw_avx2 = true; + println!("cargo:rustc-cfg=httparse_simd_target_feature_avx2"); + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] +struct Version { + major: u32, + minor: u32, + patch: u32, +} + +impl Version { + fn parse(mut s: &str) -> Result { + if !s.starts_with("rustc ") { + return Err(format!("unrecognized version string: {}", s)); + } + s = &s["rustc ".len()..]; + + let parts: Vec<&str> = s.split(".").collect(); + if parts.len() < 3 { + return Err(format!("not enough version parts: {:?}", parts)); + } + + let mut num = String::new(); + for c in parts[0].chars() { + if !c.is_digit(10) { + break; + } + num.push(c); + } + let major = try!(num.parse::().map_err(|e| e.to_string())); + + num.clear(); + for c in parts[1].chars() { + if !c.is_digit(10) { + break; + } + num.push(c); + } + let minor = try!(num.parse::().map_err(|e| e.to_string())); + + num.clear(); + for c in parts[2].chars() { + if !c.is_digit(10) { + break; + } + num.push(c); + } + let patch = try!(num.parse::().map_err(|e| e.to_string())); + + Ok(Version { + major: major, + minor: minor, + patch: patch, + }) + } +} + diff --git a/third_party/rust/httparse/src/iter.rs b/third_party/rust/httparse/src/iter.rs index f95b09e1bc77..ca2767a1dfe1 100644 --- a/third_party/rust/httparse/src/iter.rs +++ b/third_party/rust/httparse/src/iter.rs @@ -25,10 +25,18 @@ impl<'a> Bytes<'a> { } #[inline] - pub fn bump(&mut self) { + pub unsafe fn bump(&mut self) { + debug_assert!(self.pos + 1 <= self.slice.len(), "overflow"); self.pos += 1; } + #[allow(unused)] + #[inline] + pub unsafe fn advance(&mut self, n: usize) { + debug_assert!(self.pos + n <= self.slice.len(), "overflow"); + self.pos += n; + } + #[inline] pub fn len(&self) -> usize { self.slice.len() @@ -36,21 +44,22 @@ impl<'a> Bytes<'a> { #[inline] pub fn slice(&mut self) -> &'a [u8] { - self.slice_skip(0) + // not moving position at all, so it's safe + unsafe { + self.slice_skip(0) + } } #[inline] - pub fn slice_skip(&mut self, skip: usize) -> &'a [u8] { + pub unsafe fn slice_skip(&mut self, skip: usize) -> &'a [u8] { debug_assert!(self.pos >= skip); let head_pos = self.pos - skip; - unsafe { - let ptr = self.slice.as_ptr(); - let head = slice::from_raw_parts(ptr, head_pos); - let tail = slice::from_raw_parts(ptr.offset(self.pos as isize), self.slice.len() - self.pos); - self.pos = 0; - self.slice = tail; - head - } + let ptr = self.slice.as_ptr(); + let head = slice::from_raw_parts(ptr, head_pos); + let tail = slice::from_raw_parts(ptr.offset(self.pos as isize), self.slice.len() - self.pos); + self.pos = 0; + self.slice = tail; + head } #[inline] @@ -63,6 +72,13 @@ impl<'a> Bytes<'a> { } } +impl<'a> AsRef<[u8]> for Bytes<'a> { + #[inline] + fn as_ref(&self) -> &[u8] { + &self.slice[self.pos..] + } +} + impl<'a> Iterator for Bytes<'a> { type Item = u8; diff --git a/third_party/rust/httparse/src/lib.rs b/third_party/rust/httparse/src/lib.rs index 95d95c070907..99e9e0995342 100644 --- a/third_party/rust/httparse/src/lib.rs +++ b/third_party/rust/httparse/src/lib.rs @@ -1,6 +1,8 @@ -#![cfg_attr(not(feature = "std"), no_std)] +#![doc(html_root_url = "https://docs.rs/httparse/1.3.3")] +#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(test, deny(warnings))] #![deny(missing_docs)] + //! # httparse //! //! A push library for parsing HTTP/1.x requests and responses. @@ -10,44 +12,25 @@ //! parsing internals use an `Iterator` instead of direct indexing, while //! skipping bounds checks. //! -//! The speed is faster than picohttpparser, when SIMD is not available. -#[cfg(feature = "std")] extern crate std as core; +//! With Rust 1.27.0 or later, support for SIMD is enabled automatically. +//! If building an executable to be run on multiple platforms, and thus +//! not passing `target_feature` or `target_cpu` flags to the compiler, +//! runtime detection can still detect SSE4.2 or AVX2 support to provide +//! massive wins. +//! +//! If compiling for a specific target, remembering to include +//! `-C target_cpu=native` allows the detection to become compile time checks, +//! making it *even* faster. +#[cfg(feature = "std")] +extern crate std as core; use core::{fmt, result, str, slice}; use iter::Bytes; mod iter; - -macro_rules! next { - ($bytes:ident) => ({ - match $bytes.next() { - Some(b) => b, - None => return Ok(Status::Partial) - } - }) -} - -macro_rules! expect { - ($bytes:ident.next() == $pat:pat => $ret:expr) => { - expect!(next!($bytes) => $pat |? $ret) - }; - ($e:expr => $pat:pat |? $ret:expr) => { - match $e { - v@$pat => v, - _ => return $ret - } - }; -} - -macro_rules! complete { - ($e:expr) => { - match try!($e) { - Status::Complete(v) => v, - Status::Partial => return Ok(Status::Partial) - } - } -} +#[macro_use] mod macros; +mod simd; #[inline] fn shrink(slice: &mut &mut [T], len: usize) { @@ -70,10 +53,41 @@ fn shrink(slice: &mut &mut [T], len: usize) { fn is_token(b: u8) -> bool { b > 0x1F && b < 0x7F } -macro_rules! byte_map { - ($($flag:expr,)*) => ([ - $($flag != 0,)* - ]) + +// ASCII codes to accept URI string. +// i.e. A-Z a-z 0-9 !#$%&'*+-._();:@=,/?[]~^ +// TODO: Make a stricter checking for URI string? +static URI_MAP: [bool; 256] = byte_map![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// \0 \n + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// commands + 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// \w ! " # $ % & ' ( ) * + , - . / + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, +// 0 1 2 3 4 5 6 7 8 9 : ; < = > ? + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// @ A B C D E F G H I J K L M N O + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, +// P Q R S T U V W X Y Z [ \ ] ^ _ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// ` a b c d e f g h i j k l m n o + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, +// p q r s t u v w x y z { | } ~ del +// ====== Extended ASCII (aka. obs-text) ====== + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +]; + +#[inline] +fn is_uri_token(b: u8) -> bool { + URI_MAP[b as usize] } static HEADER_NAME_MAP: [bool; 256] = byte_map![ @@ -101,7 +115,7 @@ fn is_header_name_token(b: u8) -> bool { } static HEADER_VALUE_MAP: [bool; 256] = byte_map![ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -125,29 +139,6 @@ fn is_header_value_token(b: u8) -> bool { HEADER_VALUE_MAP[b as usize] } - -macro_rules! space { - ($bytes:ident or $err:expr) => ({ - expect!($bytes.next() == b' ' => Err($err)); - $bytes.slice(); - }) -} - -macro_rules! newline { - ($bytes:ident) => ({ - match next!($bytes) { - b'\r' => { - expect!($bytes.next() == b'\n' => Err(Error::NewLine)); - $bytes.slice(); - }, - b'\n' => { - $bytes.slice(); - }, - _ => return Err(Error::NewLine) - } - }) -} - /// An error in parsing. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum Error { @@ -311,7 +302,7 @@ impl<'h, 'b> Request<'h, 'b> { let mut bytes = Bytes::new(buf); complete!(skip_empty_lines(&mut bytes)); self.method = Some(complete!(parse_token(&mut bytes))); - self.path = Some(complete!(parse_token(&mut bytes))); + self.path = Some(complete!(parse_uri(&mut bytes))); self.version = Some(complete!(parse_version(&mut bytes))); newline!(bytes); @@ -328,11 +319,13 @@ fn skip_empty_lines(bytes: &mut Bytes) -> Result<()> { let b = bytes.peek(); match b { Some(b'\r') => { - bytes.bump(); + // there's `\r`, so it's safe to bump 1 pos + unsafe { bytes.bump() }; expect!(bytes.next() == b'\n' => Err(Error::NewLine)); }, Some(b'\n') => { - bytes.bump(); + // there's `\n`, so it's safe to bump 1 pos + unsafe { bytes.bump(); } }, Some(..) => { bytes.slice(); @@ -396,6 +389,7 @@ impl<'h, 'b> Response<'h, 'b> { }, b'\r' => { expect!(bytes.next() == b'\n' => Err(Error::Status)); + bytes.slice(); self.reason = Some(""); }, b'\n' => self.reason = Some(""), @@ -448,10 +442,21 @@ fn parse_version(bytes: &mut Bytes) -> Result { b'1' => 1, _ => return Err(Error::Version) }; - Ok(Status::Complete(v)) - } else { - Ok(Status::Partial) + return Ok(Status::Complete(v)) } + + // else (but not in `else` because of borrow checker) + + // If there aren't at least 8 bytes, we still want to detect early + // if this is a valid version or not. If it is, we'll return Partial. + expect!(bytes.next() == b'H' => Err(Error::Version)); + expect!(bytes.next() == b'T' => Err(Error::Version)); + expect!(bytes.next() == b'T' => Err(Error::Version)); + expect!(bytes.next() == b'P' => Err(Error::Version)); + expect!(bytes.next() == b'/' => Err(Error::Version)); + expect!(bytes.next() == b'1' => Err(Error::Version)); + expect!(bytes.next() == b'.' => Err(Error::Version)); + Ok(Status::Partial) } /// From [RFC 7230](https://tools.ietf.org/html/rfc7230): @@ -508,6 +513,24 @@ fn parse_token<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> { } } +#[inline] +fn parse_uri<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> { + simd::match_uri_vectored(bytes); + + loop { + let b = next!(bytes); + if b == b' ' { + return Ok(Status::Complete(unsafe { + // all bytes up till `i` must have been `is_token`. + str::from_utf8_unchecked(bytes.slice_skip(1)) + })); + } else if !is_uri_token(b) { + return Err(Error::Token); + } + } +} + + #[inline] fn parse_code(bytes: &mut Bytes) -> Result { let hundreds = expect!(bytes.next() == b'0'...b'9' => Err(Error::Status)); @@ -515,8 +538,8 @@ fn parse_code(bytes: &mut Bytes) -> Result { let ones = expect!(bytes.next() == b'0'...b'9' => Err(Error::Status)); Ok(Status::Complete((hundreds - b'0') as u16 * 100 + - (tens - b'0') as u16 * 10 + - (ones - b'0') as u16)) + (tens - b'0') as u16 * 10 + + (ones - b'0') as u16)) } /// Parse a buffer of bytes as headers. @@ -544,6 +567,7 @@ pub fn parse_headers<'b: 'h, 'h>(src: &'b [u8], mut dst: &'h mut [Header<'b>]) Ok(Status::Complete((pos, dst))) } + #[inline] fn parse_headers_iter<'a, 'b>(headers: &mut &mut [Header<'a>], bytes: &'b mut Bytes<'a>) -> Result { @@ -609,7 +633,7 @@ fn parse_headers_iter<'a, 'b>(headers: &mut &mut [Header<'a>], bytes: &'b mut By // parse value till EOL - + simd::match_header_value_vectored(bytes); macro_rules! check { ($bytes:ident, $i:ident) => ({ @@ -641,17 +665,31 @@ fn parse_headers_iter<'a, 'b>(headers: &mut &mut [Header<'a>], bytes: &'b mut By } //found_ctl - if b == b'\r' { + let value_slice : &[u8] = if b == b'\r' { expect!(bytes.next() == b'\n' => Err(Error::HeaderValue)); count += bytes.pos(); - header.value = bytes.slice_skip(2); + // having just check that `\r\n` exists, it's safe to skip those 2 bytes + unsafe { + bytes.slice_skip(2) + } } else if b == b'\n' { count += bytes.pos(); - header.value = bytes.slice_skip(1); + // having just check that `\r\n` exists, it's safe to skip 1 byte + unsafe { + bytes.slice_skip(1) + } } else { return Err(Error::HeaderValue); + }; + // trim trailing whitespace in the header + if let Some(last_visible) = value_slice.iter().rposition(|b| *b != b' ' && *b != b'\t' ) { + // There is at least one non-whitespace character. + header.value = &value_slice[0..last_visible+1]; + } else { + // There is no non-whitespace character. This can only happen when value_slice is + // empty. + header.value = value_slice; } - } } // drop iter @@ -672,7 +710,7 @@ fn parse_headers_iter<'a, 'b>(headers: &mut &mut [Header<'a>], bytes: &'b mut By /// Ok(httparse::Status::Complete((3, 4)))); /// ``` pub fn parse_chunk_size(buf: &[u8]) - -> result::Result, InvalidChunkSize> { + -> result::Result, InvalidChunkSize> { const RADIX: u64 = 16; let mut bytes = Bytes::new(buf); let mut size = 0; @@ -682,7 +720,7 @@ pub fn parse_chunk_size(buf: &[u8]) loop { let b = next!(bytes); match b { - b'0'...b'9' if in_chunk_size => { + b'0' ... b'9' if in_chunk_size => { if count > 15 { return Err(InvalidChunkSize); } @@ -690,7 +728,7 @@ pub fn parse_chunk_size(buf: &[u8]) size *= RADIX; size += (b - b'0') as u64; }, - b'a'...b'f' if in_chunk_size => { + b'a' ... b'f' if in_chunk_size => { if count > 15 { return Err(InvalidChunkSize); } @@ -698,7 +736,7 @@ pub fn parse_chunk_size(buf: &[u8]) size *= RADIX; size += (b + 10 - b'a') as u64; } - b'A'...b'F' if in_chunk_size => { + b'A' ... b'F' if in_chunk_size => { if count > 15 { return Err(InvalidChunkSize); } @@ -785,6 +823,28 @@ mod tests { } } + req! { + test_request_simple_with_query_params, + b"GET /thing?data=a HTTP/1.1\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/thing?data=a"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 0); + } + } + + req! { + test_request_simple_with_whatwg_query_params, + b"GET /thing?data=a^ HTTP/1.1\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/thing?data=a^"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 0); + } + } + req! { test_request_headers, b"GET / HTTP/1.1\r\nHost: foo.com\r\nCookie: \r\n\r\n", @@ -800,6 +860,63 @@ mod tests { } } + req! { + test_request_headers_optional_whitespace, + b"GET / HTTP/1.1\r\nHost: \tfoo.com\t \r\nCookie: \t \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 2); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"foo.com"); + assert_eq!(req.headers[1].name, "Cookie"); + assert_eq!(req.headers[1].value, b""); + } + } + + req! { + // test the scalar parsing + test_request_header_value_htab_short, + b"GET / HTTP/1.1\r\nUser-Agent: some\tagent\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "User-Agent"); + assert_eq!(req.headers[0].value, b"some\tagent"); + } + } + + req! { + // test the sse42 parsing + test_request_header_value_htab_med, + b"GET / HTTP/1.1\r\nUser-Agent: 1234567890some\tagent\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "User-Agent"); + assert_eq!(req.headers[0].value, b"1234567890some\tagent"); + } + } + + req! { + // test the avx2 parsing + test_request_header_value_htab_long, + b"GET / HTTP/1.1\r\nUser-Agent: 1234567890some\t1234567890agent1234567890\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "User-Agent"); + assert_eq!(req.headers[0].value, &b"1234567890some\t1234567890agent1234567890"[..]); + } + } + req! { test_request_headers_max, b"GET / HTTP/1.1\r\nA: A\r\nB: B\r\nC: C\r\nD: D\r\n\r\n", @@ -829,6 +946,12 @@ mod tests { |_req| {} } + req! { + test_request_partial_version, + b"GET / HTTP/1.", Ok(Status::Partial), + |_req| {} + } + req! { test_request_newlines, b"GET / HTTP/1.1\nHost: foo.bar\n\n", @@ -864,6 +987,14 @@ mod tests { |_r| {} } + + req! { + test_request_with_invalid_but_short_version, + b"GET / HTTP/1!", + Err(::Error::Version), + |_r| {} + } + macro_rules! res { ($name:ident, $buf:expr, |$arg:ident| $body:expr) => ( res! {$name, $buf, Ok(Status::Complete($buf.len())), |$arg| $body } @@ -920,6 +1051,19 @@ mod tests { } } + res! { + test_response_reason_missing_no_space_with_headers, + b"HTTP/1.1 200\r\nFoo: bar\r\n\r\n", + |res| { + assert_eq!(res.version.unwrap(), 1); + assert_eq!(res.code.unwrap(), 200); + assert_eq!(res.reason.unwrap(), ""); + assert_eq!(res.headers.len(), 1); + assert_eq!(res.headers[0].name, "Foo"); + assert_eq!(res.headers[0].value, b"bar"); + } + } + res! { test_response_reason_with_space_and_tab, b"HTTP/1.1 101 Switching Protocols\t\r\n\r\n", diff --git a/third_party/rust/httparse/src/macros.rs b/third_party/rust/httparse/src/macros.rs new file mode 100644 index 000000000000..c6f4ab63f33d --- /dev/null +++ b/third_party/rust/httparse/src/macros.rs @@ -0,0 +1,59 @@ +///! Utility macros + +macro_rules! next { + ($bytes:ident) => ({ + match $bytes.next() { + Some(b) => b, + None => return Ok(Status::Partial) + } + }) +} + +macro_rules! expect { + ($bytes:ident.next() == $pat:pat => $ret:expr) => { + expect!(next!($bytes) => $pat |? $ret) + }; + ($e:expr => $pat:pat |? $ret:expr) => { + match $e { + v@$pat => v, + _ => return $ret + } + }; +} + +macro_rules! complete { + ($e:expr) => { + match try!($e) { + Status::Complete(v) => v, + Status::Partial => return Ok(Status::Partial) + } + } +} + +macro_rules! byte_map { + ($($flag:expr,)*) => ([ + $($flag != 0,)* + ]) +} + +macro_rules! space { + ($bytes:ident or $err:expr) => ({ + expect!($bytes.next() == b' ' => Err($err)); + $bytes.slice(); + }) +} + +macro_rules! newline { + ($bytes:ident) => ({ + match next!($bytes) { + b'\r' => { + expect!($bytes.next() == b'\n' => Err(Error::NewLine)); + $bytes.slice(); + }, + b'\n' => { + $bytes.slice(); + }, + _ => return Err(Error::NewLine) + } + }) +} diff --git a/third_party/rust/httparse/src/simd/avx2.rs b/third_party/rust/httparse/src/simd/avx2.rs new file mode 100644 index 000000000000..368c52c2d8a5 --- /dev/null +++ b/third_party/rust/httparse/src/simd/avx2.rs @@ -0,0 +1,116 @@ +use ::iter::Bytes; + +pub enum Scan { + /// Returned when an implementation finds a noteworthy token. + Found, + /// Returned when an implementation couldn't keep running because the input was too short. + TooShort, +} + + +pub unsafe fn parse_uri_batch_32<'a>(bytes: &mut Bytes<'a>) -> Scan { + while bytes.as_ref().len() >= 32 { + let advance = match_url_char_32_avx(bytes.as_ref()); + bytes.advance(advance); + + if advance != 32 { + return Scan::Found; + } + } + Scan::TooShort +} + +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "avx2")] +#[inline] +#[allow(non_snake_case, overflowing_literals)] +unsafe fn match_url_char_32_avx(buf: &[u8]) -> usize { + debug_assert!(buf.len() >= 32); + + /* + #[cfg(target_arch = "x86")] + use core::arch::x86::*; + #[cfg(target_arch = "x86_64")] + */ + use core::arch::x86_64::*; + + let ptr = buf.as_ptr(); + + let LSH: __m256i = _mm256_set1_epi8(0x0f); + let URI: __m256i = _mm256_setr_epi8( + 0xb8, 0xfc, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0x7c, 0x54, 0x7c, 0xd4, 0x7c, + 0xb8, 0xfc, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0x7c, 0x54, 0x7c, 0xd4, 0x7c, + ); + let ARF: __m256i = _mm256_setr_epi8( + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ); + + let data = _mm256_lddqu_si256(ptr as *const _); + let rbms = _mm256_shuffle_epi8(URI, data); + let cols = _mm256_and_si256(LSH, _mm256_srli_epi16(data, 4)); + let bits = _mm256_and_si256(_mm256_shuffle_epi8(ARF, cols), rbms); + + let v = _mm256_cmpeq_epi8(bits, _mm256_setzero_si256()); + let r = 0xffffffff_00000000 | _mm256_movemask_epi8(v) as u64; + + _tzcnt_u64(r) as usize +} + +#[cfg(target_arch = "x86")] +unsafe fn match_url_char_32_avx(_: &[u8]) -> usize { + unreachable!("AVX2 detection should be disabled for x86"); +} + +pub unsafe fn match_header_value_batch_32(bytes: &mut Bytes) -> Scan { + while bytes.as_ref().len() >= 32 { + let advance = match_header_value_char_32_avx(bytes.as_ref()); + bytes.advance(advance); + + if advance != 32 { + return Scan::Found; + } + } + Scan::TooShort +} + +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "avx2")] +#[inline] +#[allow(non_snake_case)] +unsafe fn match_header_value_char_32_avx(buf: &[u8]) -> usize { + debug_assert!(buf.len() >= 32); + + /* + #[cfg(target_arch = "x86")] + use core::arch::x86::*; + #[cfg(target_arch = "x86_64")] + */ + use core::arch::x86_64::*; + + let ptr = buf.as_ptr(); + + // %x09 %x20-%x7e %x80-%xff + let TAB: __m256i = _mm256_set1_epi8(0x09); + let DEL: __m256i = _mm256_set1_epi8(0x7f); + let LOW: __m256i = _mm256_set1_epi8(0x1f); + + let dat = _mm256_lddqu_si256(ptr as *const _); + let low = _mm256_cmpgt_epi8(dat, LOW); + let tab = _mm256_cmpeq_epi8(dat, TAB); + let del = _mm256_cmpeq_epi8(dat, DEL); + let bit = _mm256_andnot_si256(del, _mm256_or_si256(low, tab)); + let rev = _mm256_cmpeq_epi8(bit, _mm256_setzero_si256()); + let res = 0xffffffff_00000000 | _mm256_movemask_epi8(rev) as u64; + + _tzcnt_u64(res) as usize +} + +#[cfg(target_arch = "x86")] +unsafe fn match_header_value_char_32_avx(_: &[u8]) -> usize { + unreachable!("AVX2 detection should be disabled for x86"); +} diff --git a/third_party/rust/httparse/src/simd/fallback.rs b/third_party/rust/httparse/src/simd/fallback.rs new file mode 100644 index 000000000000..4a79cb997824 --- /dev/null +++ b/third_party/rust/httparse/src/simd/fallback.rs @@ -0,0 +1,8 @@ +use ::iter::Bytes; + +// Fallbacks that do nothing... + +#[inline(always)] +pub fn match_uri_vectored(_: &mut Bytes) {} +#[inline(always)] +pub fn match_header_value_vectored(_: &mut Bytes) {} diff --git a/third_party/rust/httparse/src/simd/mod.rs b/third_party/rust/httparse/src/simd/mod.rs new file mode 100644 index 000000000000..e78034996a2b --- /dev/null +++ b/third_party/rust/httparse/src/simd/mod.rs @@ -0,0 +1,238 @@ +#[cfg(not(all( + httparse_simd, + any( + target_arch = "x86", + target_arch = "x86_64", + ), +)))] +mod fallback; + +#[cfg(not(all( + httparse_simd, + any( + target_arch = "x86", + target_arch = "x86_64", + ), +)))] +pub use self::fallback::*; + +#[cfg(all( + httparse_simd, + any( + target_arch = "x86", + target_arch = "x86_64", + ), +))] +mod sse42; + +#[cfg(all( + httparse_simd, + any( + httparse_simd_target_feature_avx2, + not(httparse_simd_target_feature_sse42), + ), + any( + target_arch = "x86", + target_arch = "x86_64", + ), +))] +mod avx2; + +#[cfg(all( + httparse_simd, + not(any( + httparse_simd_target_feature_sse42, + httparse_simd_target_feature_avx2, + )), + any( + target_arch = "x86", + target_arch = "x86_64", + ), +))] +mod runtime { + //! Runtime detection of simd features. Used when the build script + //! doesn't notice any target features at build time. + //! + //! While `is_x86_feature_detected!` has it's own caching built-in, + //! at least in 1.27.0, the functions don't inline, leaving using it + //! actually *slower* than just using the scalar fallback. + + use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; + + static FEATURE: AtomicUsize = ATOMIC_USIZE_INIT; + + const INIT: usize = 0; + const SSE_42: usize = 1; + const AVX_2: usize = 2; + const AVX_2_AND_SSE_42: usize = 3; + const NONE: usize = ::core::usize::MAX; + + fn detect() -> usize { + let feat = FEATURE.load(Ordering::Relaxed); + if feat == INIT { + if cfg!(target_arch = "x86_64") && is_x86_feature_detected!("avx2") { + if is_x86_feature_detected!("sse4.2") { + FEATURE.store(AVX_2_AND_SSE_42, Ordering::Relaxed); + return AVX_2_AND_SSE_42; + } else { + FEATURE.store(AVX_2, Ordering::Relaxed); + return AVX_2; + } + } else if is_x86_feature_detected!("sse4.2") { + FEATURE.store(SSE_42, Ordering::Relaxed); + return SSE_42; + } else { + FEATURE.store(NONE, Ordering::Relaxed); + } + } + feat + } + + pub fn match_uri_vectored(bytes: &mut ::Bytes) { + unsafe { + match detect() { + SSE_42 => super::sse42::parse_uri_batch_16(bytes), + AVX_2 => { super::avx2::parse_uri_batch_32(bytes); }, + AVX_2_AND_SSE_42 => { + if let super::avx2::Scan::Found = super::avx2::parse_uri_batch_32(bytes) { + return; + } + super::sse42::parse_uri_batch_16(bytes) + }, + _ => () + } + } + + // else do nothing + } + + pub fn match_header_value_vectored(bytes: &mut ::Bytes) { + unsafe { + match detect() { + SSE_42 => super::sse42::match_header_value_batch_16(bytes), + AVX_2 => { super::avx2::match_header_value_batch_32(bytes); }, + AVX_2_AND_SSE_42 => { + if let super::avx2::Scan::Found = super::avx2::match_header_value_batch_32(bytes) { + return; + } + super::sse42::match_header_value_batch_16(bytes) + }, + _ => () + } + } + + // else do nothing + } +} + +#[cfg(all( + httparse_simd, + not(any( + httparse_simd_target_feature_sse42, + httparse_simd_target_feature_avx2, + )), + any( + target_arch = "x86", + target_arch = "x86_64", + ), +))] +pub use self::runtime::*; + +#[cfg(all( + httparse_simd, + httparse_simd_target_feature_sse42, + not(httparse_simd_target_feature_avx2), + any( + target_arch = "x86", + target_arch = "x86_64", + ), +))] +mod sse42_compile_time { + pub fn match_uri_vectored(bytes: &mut ::Bytes) { + if is_x86_feature_detected!("sse4.2") { + unsafe { + super::sse42::parse_uri_batch_16(bytes); + } + } + + // else do nothing + } + + pub fn match_header_value_vectored(bytes: &mut ::Bytes) { + if is_x86_feature_detected!("sse4.2") { + unsafe { + super::sse42::match_header_value_batch_16(bytes); + } + } + + // else do nothing + } +} + +#[cfg(all( + httparse_simd, + httparse_simd_target_feature_sse42, + not(httparse_simd_target_feature_avx2), + any( + target_arch = "x86", + target_arch = "x86_64", + ), +))] +pub use self::sse42_compile_time::*; + +#[cfg(all( + httparse_simd, + httparse_simd_target_feature_avx2, + any( + target_arch = "x86", + target_arch = "x86_64", + ), +))] +mod avx2_compile_time { + pub fn match_uri_vectored(bytes: &mut ::Bytes) { + // do both, since avx2 only works when bytes.len() >= 32 + if cfg!(target_arch = "x86_64") && is_x86_feature_detected!("avx2") { + unsafe { + super::avx2::parse_uri_batch_32(bytes); + } + + } + if is_x86_feature_detected!("sse4.2") { + unsafe { + super::sse42::parse_uri_batch_16(bytes); + } + } + + // else do nothing + } + + pub fn match_header_value_vectored(bytes: &mut ::Bytes) { + // do both, since avx2 only works when bytes.len() >= 32 + if cfg!(target_arch = "x86_64") && is_x86_feature_detected!("avx2") { + let scanned = unsafe { + super::avx2::match_header_value_batch_32(bytes) + }; + + if let super::avx2::Scan::Found = scanned { + return; + } + } + if is_x86_feature_detected!("sse4.2") { + unsafe { + super::sse42::match_header_value_batch_16(bytes); + } + } + + // else do nothing + } +} + +#[cfg(all( + httparse_simd, + httparse_simd_target_feature_avx2, + any( + target_arch = "x86", + target_arch = "x86_64", + ), +))] +pub use self::avx2_compile_time::*; diff --git a/third_party/rust/httparse/src/simd/sse42.rs b/third_party/rust/httparse/src/simd/sse42.rs new file mode 100644 index 000000000000..1770ba9aebc6 --- /dev/null +++ b/third_party/rust/httparse/src/simd/sse42.rs @@ -0,0 +1,84 @@ +use ::iter::Bytes; + +pub unsafe fn parse_uri_batch_16<'a>(bytes: &mut Bytes<'a>) { + while bytes.as_ref().len() >= 16 { + let advance = match_url_char_16_sse(bytes.as_ref()); + bytes.advance(advance); + + if advance != 16 { + break; + } + } +} + +#[target_feature(enable = "sse4.2")] +#[allow(non_snake_case, overflowing_literals)] +unsafe fn match_url_char_16_sse(buf: &[u8]) -> usize { + debug_assert!(buf.len() >= 16); + + #[cfg(target_arch = "x86")] + use core::arch::x86::*; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::*; + + let ptr = buf.as_ptr(); + + let LSH: __m128i = _mm_set1_epi8(0x0f); + let URI: __m128i = _mm_setr_epi8( + 0xb8, 0xfc, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0x7c, 0x54, 0x7c, 0xd4, 0x7c, + ); + let ARF: __m128i = _mm_setr_epi8( + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ); + + let data = _mm_lddqu_si128(ptr as *const _); + let rbms = _mm_shuffle_epi8(URI, data); + let cols = _mm_and_si128(LSH, _mm_srli_epi16(data, 4)); + let bits = _mm_and_si128(_mm_shuffle_epi8(ARF, cols), rbms); + + let v = _mm_cmpeq_epi8(bits, _mm_setzero_si128()); + let r = 0xffff_0000 | _mm_movemask_epi8(v) as u32; + + _tzcnt_u32(r) as usize +} + +pub unsafe fn match_header_value_batch_16(bytes: &mut Bytes) { + while bytes.as_ref().len() >= 16 { + let advance = match_header_value_char_16_sse(bytes.as_ref()); + bytes.advance(advance); + + if advance != 16 { + break; + } + } +} + +#[target_feature(enable = "sse4.2")] +#[allow(non_snake_case)] +unsafe fn match_header_value_char_16_sse(buf: &[u8]) -> usize { + debug_assert!(buf.len() >= 16); + + #[cfg(target_arch = "x86")] + use core::arch::x86::*; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::*; + + let ptr = buf.as_ptr(); + + // %x09 %x20-%x7e %x80-%xff + let TAB: __m128i = _mm_set1_epi8(0x09); + let DEL: __m128i = _mm_set1_epi8(0x7f); + let LOW: __m128i = _mm_set1_epi8(0x1f); + + let dat = _mm_lddqu_si128(ptr as *const _); + let low = _mm_cmpgt_epi8(dat, LOW); + let tab = _mm_cmpeq_epi8(dat, TAB); + let del = _mm_cmpeq_epi8(dat, DEL); + let bit = _mm_andnot_si128(del, _mm_or_si128(low, tab)); + let rev = _mm_cmpeq_epi8(bit, _mm_setzero_si128()); + let res = 0xffff_0000 | _mm_movemask_epi8(rev) as u32; + + _tzcnt_u32(res) as usize +} diff --git a/third_party/rust/httparse/tests/uri.rs b/third_party/rust/httparse/tests/uri.rs new file mode 100644 index 000000000000..78ca72ac8de9 --- /dev/null +++ b/third_party/rust/httparse/tests/uri.rs @@ -0,0 +1,3677 @@ +extern crate httparse; + +use httparse::{Error, Request, Status, EMPTY_HEADER}; + +const NUM_OF_HEADERS: usize = 4; + +macro_rules! req { + ($name:ident, $buf:expr, |$arg:ident| $body:expr) => ( + req! {$name, $buf, Ok(Status::Complete($buf.len())), |$arg| $body } + ); + ($name:ident, $buf:expr, $len:expr, |$arg:ident| $body:expr) => ( + #[test] + fn $name() { + let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS]; + let mut req = Request::new(&mut headers[..]); + let status = req.parse($buf.as_ref()); + assert_eq!(status, $len); + closure(req); + + fn closure($arg: Request) { + $body + } + } + ) +} + +req! { + urltest_001, + b"GET /bar;par?b HTTP/1.1\r\nHost: foo\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/bar;par?b"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"foo"); + } +} + + +req! { + urltest_002, + b"GET /x HTTP/1.1\r\nHost: test\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/x"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"test"); + } +} + + +req! { + urltest_003, + b"GET /x HTTP/1.1\r\nHost: test\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/x"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"test"); + } +} + + +req! { + urltest_004, + b"GET /foo/foo.com HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/foo.com"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_005, + b"GET /foo/:foo.com HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/:foo.com"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_006, + b"GET /foo/foo.com HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/foo.com"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_007, + b"GET foo.com HTTP/1.1\r\nHost: \r\n\r\n", + Err(Error::Version), + |_r| {} +} + + +req! { + urltest_008, + b"GET /%20b%20?%20d%20 HTTP/1.1\r\nHost: f\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/%20b%20?%20d%20"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"f"); + } +} + + +req! { + urltest_009, + b"GET x x HTTP/1.1\r\nHost: \r\n\r\n", + Err(Error::Version), + |_r| {} +} + + +req! { + urltest_010, + b"GET /c HTTP/1.1\r\nHost: f\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/c"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"f"); + } +} + + +req! { + urltest_011, + b"GET /c HTTP/1.1\r\nHost: f\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/c"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"f"); + } +} + + +req! { + urltest_012, + b"GET /c HTTP/1.1\r\nHost: f\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/c"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"f"); + } +} + + +req! { + urltest_013, + b"GET /c HTTP/1.1\r\nHost: f\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/c"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"f"); + } +} + + +req! { + urltest_014, + b"GET /c HTTP/1.1\r\nHost: f\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/c"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"f"); + } +} + + +req! { + urltest_015, + b"GET /foo/bar HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_016, + b"GET /foo/bar HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_017, + b"GET /foo/:foo.com/ HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/:foo.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_018, + b"GET /foo/:foo.com/ HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/:foo.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_019, + b"GET /foo/: HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/:"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_020, + b"GET /foo/:a HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/:a"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_021, + b"GET /foo/:/ HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/:/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_022, + b"GET /foo/:/ HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/:/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_023, + b"GET /foo/: HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/:"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_024, + b"GET /foo/bar HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_025, + b"GET /foo/bar HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_026, + b"GET /foo/bar HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_027, + b"GET /foo/bar HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_028, + b"GET /foo/bar HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_029, + b"GET /foo/:23 HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/:23"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_030, + b"GET /:23 HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/:23"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_031, + b"GET /foo/:: HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/::"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_032, + b"GET /foo/::23 HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/::23"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_033, + b"GET /d HTTP/1.1\r\nHost: c\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/d"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"c"); + } +} + + +req! { + urltest_034, + b"GET /foo/:@c:29 HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/:@c:29"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_035, + b"GET //@ HTTP/1.1\r\nHost: foo.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "//@"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"foo.com"); + } +} + + +req! { + urltest_036, + b"GET /b:c/d@foo.com/ HTTP/1.1\r\nHost: a\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/b:c/d@foo.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"a"); + } +} + + +req! { + urltest_037, + b"GET /bar.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/bar.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_038, + b"GET /////// HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "///////"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_039, + b"GET ///////bar.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "///////bar.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_040, + b"GET //:///// HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "//://///"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_041, + b"GET /foo HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_042, + b"GET /bar HTTP/1.1\r\nHost: foo\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"foo"); + } +} + + +req! { + urltest_043, + b"GET /path;a??e HTTP/1.1\r\nHost: foo\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/path;a??e"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"foo"); + } +} + + +req! { + urltest_044, + b"GET /abcd?efgh?ijkl HTTP/1.1\r\nHost: foo\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/abcd?efgh?ijkl"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"foo"); + } +} + + +req! { + urltest_045, + b"GET /abcd HTTP/1.1\r\nHost: foo\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/abcd"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"foo"); + } +} + + +req! { + urltest_046, + b"GET /foo/[61:24:74]:98 HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/[61:24:74]:98"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_047, + b"GET /foo/[61:27]/:foo HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/[61:27]/:foo"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_048, + b"GET /example.com/ HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_049, + b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_050, + b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_051, + b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_052, + b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_053, + b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_054, + b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_055, + b"GET /foo/example.com/ HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_056, + b"GET example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_057, + b"GET example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_058, + b"GET example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_059, + b"GET example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_060, + b"GET example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_061, + b"GET /a/b/c HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/a/b/c"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_062, + b"GET /a/%20/c HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/a/%20/c"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_063, + b"GET /a%2fc HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/a%2fc"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_064, + b"GET /a/%2f/c HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/a/%2f/c"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_065, + b"GET /foo/bar HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_066, + b"GET text/html,test HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "text/html,test"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_067, + b"GET 1234567890 HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "1234567890"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_068, + b"GET /c:/foo/bar.html HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/c:/foo/bar.html"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_069, + b"GET /c:////foo/bar.html HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/c:////foo/bar.html"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_070, + b"GET /C:/foo/bar HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/C:/foo/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_071, + b"GET /C:/foo/bar HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/C:/foo/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_072, + b"GET /C:/foo/bar HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/C:/foo/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_073, + b"GET /file HTTP/1.1\r\nHost: server\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/file"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"server"); + } +} + + +req! { + urltest_074, + b"GET /file HTTP/1.1\r\nHost: server\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/file"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"server"); + } +} + + +req! { + urltest_075, + b"GET /file HTTP/1.1\r\nHost: server\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/file"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"server"); + } +} + + +req! { + urltest_076, + b"GET /foo/bar.txt HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/bar.txt"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_077, + b"GET /home/me HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/home/me"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_078, + b"GET /test HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_079, + b"GET /test HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_080, + b"GET /tmp/mock/test HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/tmp/mock/test"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_081, + b"GET /tmp/mock/test HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/tmp/mock/test"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_082, + b"GET /foo HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_083, + b"GET /.foo HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/.foo"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_084, + b"GET /foo/ HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_085, + b"GET /foo/ HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_086, + b"GET /foo/ HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_087, + b"GET /foo/ HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_088, + b"GET /foo/..bar HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/..bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_089, + b"GET /foo/ton HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/ton"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_090, + b"GET /a HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/a"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_091, + b"GET /ton HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/ton"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_092, + b"GET /foo/ HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_093, + b"GET /foo/%2e%2 HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/%2e%2"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_094, + b"GET /%2e.bar HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/%2e.bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_095, + b"GET // HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "//"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_096, + b"GET /foo/ HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_097, + b"GET /foo/bar/ HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/bar/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_098, + b"GET /foo HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_099, + b"GET /%20foo HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/%20foo"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_100, + b"GET /foo% HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo%"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_101, + b"GET /foo%2 HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo%2"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_102, + b"GET /foo%2zbar HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo%2zbar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_103, + b"GET /foo%2%C3%82%C2%A9zbar HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo%2%C3%82%C2%A9zbar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_104, + b"GET /foo%41%7a HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo%41%7a"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_105, + b"GET /foo%C2%91%91 HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo%C2%91%91"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_106, + b"GET /foo%00%51 HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo%00%51"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_107, + b"GET /(%28:%3A%29) HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/(%28:%3A%29)"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_108, + b"GET /%3A%3a%3C%3c HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/%3A%3a%3C%3c"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_109, + b"GET /foobar HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foobar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_110, + b"GET //foo//bar HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "//foo//bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_111, + b"GET /%7Ffp3%3Eju%3Dduvgw%3Dd HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/%7Ffp3%3Eju%3Dduvgw%3Dd"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_112, + b"GET /@asdf%40 HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/@asdf%40"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_113, + b"GET /%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_114, + b"GET /%E2%80%A5/foo HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/%E2%80%A5/foo"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_115, + b"GET /%EF%BB%BF/foo HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/%EF%BB%BF/foo"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_116, + b"GET /%E2%80%AE/foo/%E2%80%AD/bar HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/%E2%80%AE/foo/%E2%80%AD/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_117, + b"GET /foo?bar=baz HTTP/1.1\r\nHost: www.google.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo?bar=baz"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"www.google.com"); + } +} + + +req! { + urltest_118, + b"GET /foo?bar=baz HTTP/1.1\r\nHost: www.google.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo?bar=baz"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"www.google.com"); + } +} + + +req! { + urltest_119, + b"GET test HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "test"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_120, + b"GET /foo%2Ehtml HTTP/1.1\r\nHost: www\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo%2Ehtml"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"www"); + } +} + + +req! { + urltest_121, + b"GET /foo/html HTTP/1.1\r\nHost: www\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/html"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"www"); + } +} + + +req! { + urltest_122, + b"GET /foo HTTP/1.1\r\nHost: www.google.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"www.google.com"); + } +} + + +req! { + urltest_123, + b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_124, + b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_125, + b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_126, + b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_127, + b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_128, + b"GET /example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_129, + b"GET example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_130, + b"GET example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_131, + b"GET example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_132, + b"GET example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_133, + b"GET example.com/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "example.com/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_134, + b"GET /test.txt HTTP/1.1\r\nHost: www.example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test.txt"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"www.example.com"); + } +} + + +req! { + urltest_135, + b"GET /test.txt HTTP/1.1\r\nHost: www.example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test.txt"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"www.example.com"); + } +} + + +req! { + urltest_136, + b"GET /test.txt HTTP/1.1\r\nHost: www.example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test.txt"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"www.example.com"); + } +} + + +req! { + urltest_137, + b"GET /test.txt HTTP/1.1\r\nHost: www.example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test.txt"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"www.example.com"); + } +} + + +req! { + urltest_138, + b"GET /aaa/test.txt HTTP/1.1\r\nHost: www.example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/aaa/test.txt"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"www.example.com"); + } +} + + +req! { + urltest_139, + b"GET /test.txt HTTP/1.1\r\nHost: www.example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test.txt"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"www.example.com"); + } +} + + +req! { + urltest_140, + b"GET /%E4%B8%AD/test.txt HTTP/1.1\r\nHost: www.example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/%E4%B8%AD/test.txt"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"www.example.com"); + } +} + + +req! { + urltest_141, + b"GET /... HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/..."); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_142, + b"GET /a HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/a"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_143, + b"GET /%EF%BF%BD?%EF%BF%BD HTTP/1.1\r\nHost: x\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/%EF%BF%BD?%EF%BF%BD"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"x"); + } +} + + +req! { + urltest_144, + b"GET /bar HTTP/1.1\r\nHost: example.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.com"); + } +} + + +req! { + urltest_145, + b"GET test HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "test"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_146, + b"GET x@x.com HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "x@x.com"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_147, + b"GET , HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), ","); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_148, + b"GET blank HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "blank"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_149, + b"GET test?test HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "test?test"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_150, + b"GET /%60%7B%7D?`{} HTTP/1.1\r\nHost: h\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/%60%7B%7D?`{}"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"h"); + } + +} + + +req! { + urltest_151, + b"GET /?%27 HTTP/1.1\r\nHost: host\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/?%27"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"host"); + } +} + + +req! { + urltest_152, + b"GET /?' HTTP/1.1\r\nHost: host\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/?'"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"host"); + } +} + + +req! { + urltest_153, + b"GET /some/path HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/some/path"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_154, + b"GET /smth HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/smth"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_155, + b"GET /some/path HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/some/path"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_156, + b"GET /pa/i HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/pa/i"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_157, + b"GET /i HTTP/1.1\r\nHost: ho\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/i"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"ho"); + } +} + + +req! { + urltest_158, + b"GET /pa/i HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/pa/i"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_159, + b"GET /i HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/i"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_160, + b"GET /i HTTP/1.1\r\nHost: ho\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/i"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"ho"); + } +} + + +req! { + urltest_161, + b"GET /i HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/i"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_162, + b"GET /i HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/i"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_163, + b"GET /i HTTP/1.1\r\nHost: ho\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/i"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"ho"); + } +} + + +req! { + urltest_164, + b"GET /i HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/i"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_165, + b"GET /pa/pa?i HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/pa/pa?i"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_166, + b"GET /pa?i HTTP/1.1\r\nHost: ho\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/pa?i"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"ho"); + } +} + + +req! { + urltest_167, + b"GET /pa/pa?i HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/pa/pa?i"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_168, + b"GET sd HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "sd"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_169, + b"GET sd/sd HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "sd/sd"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_170, + b"GET /pa/pa HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/pa/pa"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_171, + b"GET /pa HTTP/1.1\r\nHost: ho\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/pa"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"ho"); + } +} + + +req! { + urltest_172, + b"GET /pa/pa HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/pa/pa"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_173, + b"GET /x HTTP/1.1\r\nHost: %C3%B1\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/x"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"%C3%B1"); + } +} + + +req! { + urltest_174, + b"GET \\.\\./ HTTP/1.1\r\nHost: \r\n\r\n", + Err(Error::Token), + |_r| {} +} + + +req! { + urltest_175, + b"GET :a@example.net HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), ":a@example.net"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_176, + b"GET %NBD HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "%NBD"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_177, + b"GET %1G HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "%1G"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_178, + b"GET /relative_import.html HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/relative_import.html"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"127.0.0.1"); + } +} + + +req! { + urltest_179, + b"GET /?foo=%7B%22abc%22 HTTP/1.1\r\nHost: facebook.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/?foo=%7B%22abc%22"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"facebook.com"); + } +} + + +req! { + urltest_180, + b"GET /jqueryui@1.2.3 HTTP/1.1\r\nHost: localhost\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/jqueryui@1.2.3"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"localhost"); + } +} + + +req! { + urltest_181, + b"GET /path?query HTTP/1.1\r\nHost: host\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/path?query"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"host"); + } +} + + +req! { + urltest_182, + b"GET /foo/bar?a=b&c=d HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/bar?a=b&c=d"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_183, + b"GET /foo/bar??a=b&c=d HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/bar??a=b&c=d"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_184, + b"GET /foo/bar HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_185, + b"GET /baz?qux HTTP/1.1\r\nHost: foo.bar\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/baz?qux"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"foo.bar"); + } +} + + +req! { + urltest_186, + b"GET /baz?qux HTTP/1.1\r\nHost: foo.bar\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/baz?qux"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"foo.bar"); + } +} + + +req! { + urltest_187, + b"GET /baz?qux HTTP/1.1\r\nHost: foo.bar\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/baz?qux"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"foo.bar"); + } +} + + +req! { + urltest_188, + b"GET /baz?qux HTTP/1.1\r\nHost: foo.bar\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/baz?qux"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"foo.bar"); + } +} + + +req! { + urltest_189, + b"GET /baz?qux HTTP/1.1\r\nHost: foo.bar\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/baz?qux"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"foo.bar"); + } +} + + +req! { + urltest_190, + b"GET /C%3A/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/C%3A/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_191, + b"GET /C%7C/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/C%7C/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_192, + b"GET /C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_193, + b"GET /C:/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/C:/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_194, + b"GET /C:/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/C:/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_195, + b"GET /d: HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/d:"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_196, + b"GET /d:/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/d:/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_197, + b"GET /test?test HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test?test"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_198, + b"GET /test?test HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test?test"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_199, + b"GET /test?x HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test?x"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_200, + b"GET /test?x HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test?x"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_201, + b"GET /test?test HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test?test"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_202, + b"GET /test?test HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test?test"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_203, + b"GET /?fox HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/?fox"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_204, + b"GET /localhost//cat HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/localhost//cat"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_205, + b"GET /localhost//cat HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/localhost//cat"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_206, + b"GET /mouse HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/mouse"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_207, + b"GET /pig HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/pig"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_208, + b"GET /pig HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/pig"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_209, + b"GET /pig HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/pig"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_210, + b"GET /localhost//pig HTTP/1.1\r\nHost: lion\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/localhost//pig"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"lion"); + } +} + + +req! { + urltest_211, + b"GET /rooibos HTTP/1.1\r\nHost: tea\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/rooibos"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"tea"); + } +} + + +req! { + urltest_212, + b"GET /?chai HTTP/1.1\r\nHost: tea\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/?chai"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"tea"); + } +} + + +req! { + urltest_213, + b"GET /C: HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/C:"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_214, + b"GET /C: HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/C:"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_215, + b"GET /C: HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/C:"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_216, + b"GET /C:/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/C:/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_217, + b"GET /C:/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/C:/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_218, + b"GET /C:/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/C:/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_219, + b"GET /dir/C HTTP/1.1\r\nHost: host\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/dir/C"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"host"); + } +} + + +req! { + urltest_220, + b"GET /dir/C|a HTTP/1.1\r\nHost: host\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/dir/C|a"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"host"); + } +} + + +req! { + urltest_221, + b"GET /c:/foo/bar HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/c:/foo/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_222, + b"GET /c:/foo/bar HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/c:/foo/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_223, + b"GET /c:/foo/bar HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/c:/foo/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_224, + b"GET /c:/foo/bar HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/c:/foo/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_225, + b"GET /C:/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/C:/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_226, + b"GET /C:/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/C:/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_227, + b"GET /C:/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/C:/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_228, + b"GET /C:/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/C:/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_229, + b"GET /C:/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/C:/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_230, + b"GET /?q=v HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/?q=v"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_231, + b"GET ?x HTTP/1.1\r\nHost: %C3%B1\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "?x"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"%C3%B1"); + } +} + + +req! { + urltest_232, + b"GET ?x HTTP/1.1\r\nHost: %C3%B1\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "?x"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"%C3%B1"); + } +} + + +req! { + urltest_233, + b"GET // HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "//"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_234, + b"GET //x/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "//x/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_235, + b"GET /someconfig;mode=netascii HTTP/1.1\r\nHost: foobar.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/someconfig;mode=netascii"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"foobar.com"); + } +} + + +req! { + urltest_236, + b"GET /Index.ut2 HTTP/1.1\r\nHost: 10.10.10.10\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/Index.ut2"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"10.10.10.10"); + } +} + + +req! { + urltest_237, + b"GET /0?baz=bam&qux=baz HTTP/1.1\r\nHost: somehost\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/0?baz=bam&qux=baz"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"somehost"); + } +} + + +req! { + urltest_238, + b"GET /sup HTTP/1.1\r\nHost: host\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/sup"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"host"); + } +} + + +req! { + urltest_239, + b"GET /foo/bar.git HTTP/1.1\r\nHost: github.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/bar.git"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"github.com"); + } +} + + +req! { + urltest_240, + b"GET /channel?passwd HTTP/1.1\r\nHost: myserver.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/channel?passwd"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"myserver.com"); + } +} + + +req! { + urltest_241, + b"GET /foo.bar.org?type=TXT HTTP/1.1\r\nHost: fw.example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo.bar.org?type=TXT"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"fw.example.org"); + } +} + + +req! { + urltest_242, + b"GET /ou=People,o=JNDITutorial HTTP/1.1\r\nHost: localhost\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/ou=People,o=JNDITutorial"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"localhost"); + } +} + + +req! { + urltest_243, + b"GET /foo/bar HTTP/1.1\r\nHost: github.com\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/foo/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"github.com"); + } +} + + +req! { + urltest_244, + b"GET ietf:rfc:2648 HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "ietf:rfc:2648"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_245, + b"GET joe@example.org,2001:foo/bar HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "joe@example.org,2001:foo/bar"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_246, + b"GET /path HTTP/1.1\r\nHost: H%4fSt\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/path"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"H%4fSt"); + } +} + + +req! { + urltest_247, + b"GET https://example.com:443/ HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "https://example.com:443/"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_248, + b"GET d3958f5c-0777-0845-9dcf-2cb28783acaf HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "d3958f5c-0777-0845-9dcf-2cb28783acaf"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_249, + b"GET /test?%22 HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test?%22"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_250, + b"GET /test HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_251, + b"GET /test?%3C HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test?%3C"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_252, + b"GET /test?%3E HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test?%3E"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_253, + b"GET /test?%E2%8C%A3 HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test?%E2%8C%A3"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_254, + b"GET /test?%23%23 HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test?%23%23"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_255, + b"GET /test?%GH HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test?%GH"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_256, + b"GET /test?a HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test?a"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_257, + b"GET /test?a HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test?a"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + +req! { + urltest_258, + b"GET /test-a-colon-slash.html HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test-a-colon-slash.html"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_259, + b"GET /test-a-colon-slash-slash.html HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test-a-colon-slash-slash.html"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_260, + b"GET /test-a-colon-slash-b.html HTTP/1.1\r\nHost: \r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test-a-colon-slash-b.html"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b""); + } +} + + +req! { + urltest_261, + b"GET /test-a-colon-slash-slash-b.html HTTP/1.1\r\nHost: b\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test-a-colon-slash-slash-b.html"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"b"); + } +} + + +req! { + urltest_262, + b"GET /test?a HTTP/1.1\r\nHost: example.org\r\n\r\n", + |req| { + assert_eq!(req.method.unwrap(), "GET"); + assert_eq!(req.path.unwrap(), "/test?a"); + assert_eq!(req.version.unwrap(), 1); + assert_eq!(req.headers.len(), 1); + assert_eq!(req.headers[0].name, "Host"); + assert_eq!(req.headers[0].value, b"example.org"); + } +} + + diff --git a/third_party/rust/lazycell/.cargo-checksum.json b/third_party/rust/lazycell/.cargo-checksum.json index e325e80ac076..59ef575fef09 100644 --- a/third_party/rust/lazycell/.cargo-checksum.json +++ b/third_party/rust/lazycell/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"0ac479629dc1cde30432141baf12e6ee347b14bd3cd07a44ea3e645fdb1a0d7c","Cargo.toml":"152d2f4435ce45bd83a0f3842a04c0aed7223f458c843c9ad1cc10ad6f0acca6","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"4d3959aeee87b7924faecca7e7369370a2ac603422e7bb3fea86191b2574899d","README.md":"ea7850a3e9cc388dd40c7e5ea26e08cec788219fc4cd01280ea52cb7382d184f","src/lib.rs":"226ef2985de8085b4edd780578f4cf5e77f58512c566b2fa8462086db8f96e15"},"package":"a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef"} \ No newline at end of file +{"files":{"CHANGELOG.md":"0aa4629e399d08ad3a446366d465449a5e92ba95aac708be76961100a9c7df48","Cargo.toml":"15c8e40c3c9ed8635ed338b633d343702b6f4a90dcd5aa759673d31af401dd0a","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"03f6ccb4e6040abccf12b31551bbbd1800a5069a17950bbd6db850d85744800f","README.md":"c0798b2c9b0d3b9c0da509fdd9001eb2d80e6ed0850d312e36136ac269dbe49f","src/lib.rs":"7ea882864c246d78be6ea3558b92a8a7dd5732f55556cd641efb7a8caf4e64e3"},"package":"b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"} \ No newline at end of file diff --git a/third_party/rust/lazycell/CHANGELOG.md b/third_party/rust/lazycell/CHANGELOG.md index d3b6d78268a2..33f1a7d1b5f1 100644 --- a/third_party/rust/lazycell/CHANGELOG.md +++ b/third_party/rust/lazycell/CHANGELOG.md @@ -1,3 +1,49 @@ + +## v1.2.1 (2018-12-03) + + +#### Features + +* Implement Clone for LazyCell and AtomicLazyCell ([30fe4a8f](https://github.com/indiv0/lazycell/commit/30fe4a8f568059b3c78ed149a810962a676cb2b2)) + + + + +## v1.2.0 (2018-09-19) + + +#### Features + +* add `LazyCell::replace` for infallible access ([a63ffb90](https://github.com/indiv0/lazycell/commit/a63ffb9040a5e0683a9bbf9d3d5ef589f2ca8b7c)) + + + + +## v1.1.0 (2018-09-10) + + +#### Documentation + +* add note regarding LazyCell::borrow_mut ([9d634d1f](https://github.com/indiv0/lazycell/commit/9d634d1fd9a21b7aa075d407bedf9fe77ba8b79f)) +* describe mutability more consistently ([b8078029](https://github.com/indiv0/lazycell/commit/b80780294611e92efddcdd33a701b3049ab5c5eb), closes [#78](https://github.com/indiv0/lazycell/issues/78)) + +#### Improvements + +* add NONE constant for an empty AtomicLazyCell ([31aff0da](https://github.com/indiv0/lazycell/commit/31aff0dacf824841c5f38ef4acf0aa71ec4c36eb), closes [#87](https://github.com/indiv0/lazycell/issues/87)) +* add `LazyCell::borrow_mut_with` and `LazyCell::try_borrow_mut_with` ([fdc6d268](https://github.com/indiv0/lazycell/commit/fdc6d268f0e9a6668768302f45fe2bb4aa9a7c34), closes [#79](https://github.com/indiv0/lazycell/issues/79), [#80](https://github.com/indiv0/lazycell/issues/80)) + + + + +## v1.0.0 (2018-06-06) + + +#### Features + +* Add #![no_std] ([e59f6b55](https://github.com/indiv0/lazycell/commit/e59f6b5531e310d3df26b0eb40b1431937f38096)) + + + ## 0.6.0 (2017-11-25) diff --git a/third_party/rust/lazycell/Cargo.toml b/third_party/rust/lazycell/Cargo.toml index a3b952a8b660..faecd458d288 100644 --- a/third_party/rust/lazycell/Cargo.toml +++ b/third_party/rust/lazycell/Cargo.toml @@ -12,7 +12,7 @@ [package] name = "lazycell" -version = "0.6.0" +version = "1.2.1" authors = ["Alex Crichton ", "Nikita Pekin "] include = ["CHANGELOG.md", "Cargo.toml", "LICENSE-MIT", "LICENSE-APACHE", "README.md", "src/**/*.rs"] description = "A library providing a lazily filled Cell struct" diff --git a/third_party/rust/lazycell/LICENSE-MIT b/third_party/rust/lazycell/LICENSE-MIT index 9a871b84794a..b4cbb4b7eb28 100644 --- a/third_party/rust/lazycell/LICENSE-MIT +++ b/third_party/rust/lazycell/LICENSE-MIT @@ -1,5 +1,5 @@ Original work Copyright (c) 2014 The Rust Project Developers -Modified work Copyright (c) 2016-2017 Nikita Pekin and lazycell contributors +Modified work Copyright (c) 2016-2018 Nikita Pekin and lazycell contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/third_party/rust/lazycell/README.md b/third_party/rust/lazycell/README.md index a1669b7a82fa..4e1dd993f17d 100644 --- a/third_party/rust/lazycell/README.md +++ b/third_party/rust/lazycell/README.md @@ -30,7 +30,7 @@ Add the following to your `Cargo.toml`: ```toml [dependencies] -lazycell = "0.6" +lazycell = "1.2" ``` And in your `lib.rs` or `main.rs`: diff --git a/third_party/rust/lazycell/src/lib.rs b/third_party/rust/lazycell/src/lib.rs index 0137a463ca98..f7f8488a5252 100644 --- a/third_party/rust/lazycell/src/lib.rs +++ b/third_party/rust/lazycell/src/lib.rs @@ -1,5 +1,5 @@ // Original work Copyright (c) 2014 The Rust Project Developers -// Modified work Copyright (c) 2016-2017 Nikita Pekin and the lazycell contributors +// Modified work Copyright (c) 2016-2018 Nikita Pekin and the lazycell contributors // See the README.md file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 { inner: UnsafeCell>, @@ -63,7 +73,7 @@ impl LazyCell { /// /// This function will return `Err(value)` is the cell is already full. pub fn fill(&self, value: T) -> Result<(), T> { - let mut slot = unsafe { &mut *self.inner.get() }; + let slot = unsafe { &mut *self.inner.get() }; if slot.is_some() { return Err(value); } @@ -72,6 +82,20 @@ impl LazyCell { Ok(()) } + /// Put a value into this cell. + /// + /// Note that this function is infallible but requires `&mut self`. By + /// requiring `&mut self` we're guaranteed that no active borrows to this + /// cell can exist so we can always fill in the value. This may not always + /// be usable, however, as `&mut self` may not be possible to borrow. + /// + /// # Return value + /// + /// This function returns the previous value, if any. + pub fn replace(&mut self, value: T) -> Option { + mem::replace(unsafe { &mut *self.inner.get() }, Some(value)) + } + /// Test whether this cell has been previously filled. pub fn filled(&self) -> bool { self.borrow().is_some() @@ -115,6 +139,26 @@ impl LazyCell { self.borrow().unwrap() } + /// Borrows the contents of this `LazyCell` mutably for the duration of the + /// cell itself. + /// + /// If the cell has not yet been filled, the cell is first filled using the + /// function provided. + /// + /// # Panics + /// + /// Panics if the cell becomes filled as a side effect of `f`. + pub fn borrow_mut_with T>(&mut self, f: F) -> &mut T { + if !self.filled() { + let value = f(); + if self.fill(value).is_err() { + panic!("borrow_mut_with: cell was filled by closure") + } + } + + self.borrow_mut().unwrap() + } + /// Same as `borrow_with`, but allows the initializing function to fail. /// /// # Panics @@ -133,8 +177,30 @@ impl LazyCell { Ok(self.borrow().unwrap()) } + /// Same as `borrow_mut_with`, but allows the initializing function to fail. + /// + /// # Panics + /// + /// Panics if the cell becomes filled as a side effect of `f`. + pub fn try_borrow_mut_with(&mut self, f: F) -> Result<&mut T, E> + where F: FnOnce() -> Result + { + if self.filled() { + return Ok(self.borrow_mut().unwrap()); + } + let value = f()?; + if self.fill(value).is_err() { + panic!("try_borrow_mut_with: cell was filled by closure") + } + Ok(self.borrow_mut().unwrap()) + } + /// Consumes this `LazyCell`, returning the underlying value. pub fn into_inner(self) -> Option { + // Rust 1.25 changed UnsafeCell::into_inner() from unsafe to safe + // function. This unsafe can be removed when supporting Rust older than + // 1.25 is not needed. + #[allow(unused_unsafe)] unsafe { self.inner.into_inner() } } } @@ -149,12 +215,23 @@ impl LazyCell { } } +impl Clone for LazyCell { + /// Create a clone of this `LazyCell` + /// + /// If self has not been initialized, returns an uninitialized `LazyCell` + /// otherwise returns a `LazyCell` already initialized with a clone of the + /// contents of self. + fn clone(&self) -> LazyCell { + LazyCell { inner: UnsafeCell::new(self.borrow().map(Clone::clone) ) } + } +} + // Tracks the AtomicLazyCell inner state const NONE: usize = 0; const LOCK: usize = 1; const SOME: usize = 2; -/// A lazily filled `Cell`, with frozen contents. +/// A lazily filled and thread-safe `Cell`, with frozen contents. #[derive(Debug, Default)] pub struct AtomicLazyCell { inner: UnsafeCell>, @@ -162,12 +239,15 @@ pub struct AtomicLazyCell { } impl AtomicLazyCell { + /// An empty `AtomicLazyCell`. + pub const NONE: Self = Self { + inner: UnsafeCell::new(None), + state: AtomicUsize::new(NONE), + }; + /// Creates a new, empty, `AtomicLazyCell`. pub fn new() -> AtomicLazyCell { - AtomicLazyCell { - inner: UnsafeCell::new(None), - state: AtomicUsize::new(NONE), - } + Self::NONE } /// Put a value into this cell. @@ -187,6 +267,24 @@ impl AtomicLazyCell { Ok(()) } + /// Put a value into this cell. + /// + /// Note that this function is infallible but requires `&mut self`. By + /// requiring `&mut self` we're guaranteed that no active borrows to this + /// cell can exist so we can always fill in the value. This may not always + /// be usable, however, as `&mut self` may not be possible to borrow. + /// + /// # Return value + /// + /// This function returns the previous value, if any. + pub fn replace(&mut self, value: T) -> Option { + match mem::replace(self.state.get_mut(), SOME) { + NONE | SOME => {} + _ => panic!("cell in inconsistent state"), + } + mem::replace(unsafe { &mut *self.inner.get() }, Some(value)) + } + /// Test whether this cell has been previously filled. pub fn filled(&self) -> bool { self.state.load(Ordering::Acquire) == SOME @@ -206,6 +304,10 @@ impl AtomicLazyCell { /// Consumes this `LazyCell`, returning the underlying value. pub fn into_inner(self) -> Option { + // Rust 1.25 changed UnsafeCell::into_inner() from unsafe to safe + // function. This unsafe can be removed when supporting Rust older than + // 1.25 is not needed. + #[allow(unused_unsafe)] unsafe { self.inner.into_inner() } } } @@ -223,6 +325,23 @@ impl AtomicLazyCell { } } +impl Clone for AtomicLazyCell { + /// Create a clone of this `AtomicLazyCell` + /// + /// If self has not been initialized, returns an uninitialized `AtomicLazyCell` + /// otherwise returns an `AtomicLazyCell` already initialized with a clone of the + /// contents of self. + fn clone(&self) -> AtomicLazyCell { + self.borrow().map_or( + Self::NONE, + |v| AtomicLazyCell { + inner: UnsafeCell::new(Some(v.clone())), + state: AtomicUsize::new(SOME), + } + ) + } +} + unsafe impl Sync for AtomicLazyCell {} unsafe impl Send for AtomicLazyCell {} @@ -324,6 +443,37 @@ mod tests { }); } + #[test] + fn test_borrow_mut_with() { + let mut lazycell = LazyCell::new(); + + { + let value = lazycell.borrow_mut_with(|| 1); + assert_eq!(&mut 1, value); + *value = 2; + } + assert_eq!(&2, lazycell.borrow().unwrap()); + } + + #[test] + fn test_borrow_mut_with_already_filled() { + let mut lazycell = LazyCell::new(); + lazycell.fill(1).unwrap(); + + let value = lazycell.borrow_mut_with(|| 1); + assert_eq!(&1, value); + } + + #[test] + fn test_borrow_mut_with_not_called_when_filled() { + let mut lazycell = LazyCell::new(); + + lazycell.fill(1).unwrap(); + + let value = lazycell.borrow_mut_with(|| 2); + assert_eq!(&1, value); + } + #[test] fn test_try_borrow_with_ok() { let lazycell = LazyCell::new(); @@ -360,6 +510,32 @@ mod tests { }); } + #[test] + fn test_try_borrow_mut_with_ok() { + let mut lazycell = LazyCell::new(); + { + let result = lazycell.try_borrow_mut_with::<(), _>(|| Ok(1)); + assert_eq!(result, Ok(&mut 1)); + *result.unwrap() = 2; + } + assert_eq!(&mut 2, lazycell.borrow().unwrap()); + } + + #[test] + fn test_try_borrow_mut_with_err() { + let mut lazycell = LazyCell::<()>::new(); + let result = lazycell.try_borrow_mut_with(|| Err(1)); + assert_eq!(result, Err(1)); + } + + #[test] + fn test_try_borrow_mut_with_already_filled() { + let mut lazycell = LazyCell::new(); + lazycell.fill(1).unwrap(); + let result = lazycell.try_borrow_mut_with::<(), _>(|| unreachable!()); + assert_eq!(result, Ok(&mut 1)); + } + #[test] fn test_into_inner() { let lazycell = LazyCell::new(); @@ -411,4 +587,63 @@ mod tests { let value = lazycell.into_inner(); assert_eq!(value, Some(1)); } + + #[test] + fn normal_replace() { + let mut cell = LazyCell::new(); + assert_eq!(cell.fill(1), Ok(())); + assert_eq!(cell.replace(2), Some(1)); + assert_eq!(cell.replace(3), Some(2)); + assert_eq!(cell.borrow(), Some(&3)); + + let mut cell = LazyCell::new(); + assert_eq!(cell.replace(2), None); + } + + #[test] + fn atomic_replace() { + let mut cell = AtomicLazyCell::new(); + assert_eq!(cell.fill(1), Ok(())); + assert_eq!(cell.replace(2), Some(1)); + assert_eq!(cell.replace(3), Some(2)); + assert_eq!(cell.borrow(), Some(&3)); + } + + #[test] + fn clone() { + let mut cell = LazyCell::new(); + let clone1 = cell.clone(); + assert_eq!(clone1.borrow(), None); + assert_eq!(cell.fill(1), Ok(())); + let mut clone2 = cell.clone(); + assert_eq!(clone1.borrow(), None); + assert_eq!(clone2.borrow(), Some(&1)); + assert_eq!(cell.replace(2), Some(1)); + assert_eq!(clone1.borrow(), None); + assert_eq!(clone2.borrow(), Some(&1)); + assert_eq!(clone1.fill(3), Ok(())); + assert_eq!(clone2.replace(4), Some(1)); + assert_eq!(clone1.borrow(), Some(&3)); + assert_eq!(clone2.borrow(), Some(&4)); + assert_eq!(cell.borrow(), Some(&2)); + } + + #[test] + fn clone_atomic() { + let mut cell = AtomicLazyCell::new(); + let clone1 = cell.clone(); + assert_eq!(clone1.borrow(), None); + assert_eq!(cell.fill(1), Ok(())); + let mut clone2 = cell.clone(); + assert_eq!(clone1.borrow(), None); + assert_eq!(clone2.borrow(), Some(&1)); + assert_eq!(cell.replace(2), Some(1)); + assert_eq!(clone1.borrow(), None); + assert_eq!(clone2.borrow(), Some(&1)); + assert_eq!(clone1.fill(3), Ok(())); + assert_eq!(clone2.replace(4), Some(1)); + assert_eq!(clone1.borrow(), Some(&3)); + assert_eq!(clone2.borrow(), Some(&4)); + assert_eq!(cell.borrow(), Some(&2)); + } } diff --git a/third_party/rust/mio-extras/.cargo-checksum.json b/third_party/rust/mio-extras/.cargo-checksum.json new file mode 100644 index 000000000000..77be1f21eac3 --- /dev/null +++ b/third_party/rust/mio-extras/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"9f7efb5e07d7bba6e6db9142f35d8379144d3707eaf767ca41759bbfa91e0422","Cargo.toml":"37ea791a7fee2939e800737d62c2cd3189e6c71b57935de9ae02519b04d4dc4c","LICENSE-APACHE":"406e5cbaa2ad1178c300cf28ac5258e8d0db0de4f061e78db559d30e6f38e25c","LICENSE-MIT":"8aa414e6c821efd8be6bade07368a5d9f51f5cc55718bc54e10a59eb826b8d58","README.md":"337973d4db2bd42559bded991de98bf3929d39df00d5f17221e4b493075f8317","src/channel.rs":"bfc4f386595291418a5975250f12431d4fe92714cf422369e6a7960754719b51","src/lib.rs":"2ed1572d3255208681d017265df7f642eb4898b1c2dace91676935f55e03eb04","src/timer.rs":"2aa0070b4d59f74262c926d5378781896260c2264d06e47aa2fc1cafb6cf104b","test/mod.rs":"aa3afc2582f00e5e2a2e5b87d12eb9810b0eed3248b48abef7094fd8d02d9c41","test/test_poll_channel.rs":"a96f5749438853cb8c0727e304eabfd7f23400802da73938337ab29210787bcd","test/test_timer.rs":"082c48a320f603d8a99f6ed13c0efe7f48638d33222782e85364575ce805c20c"},"package":"46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40"} \ No newline at end of file diff --git a/third_party/rust/mio-extras/CHANGELOG.md b/third_party/rust/mio-extras/CHANGELOG.md new file mode 100644 index 000000000000..eb00eca0ef7e --- /dev/null +++ b/third_party/rust/mio-extras/CHANGELOG.md @@ -0,0 +1,31 @@ +## 2.0.5 (18 Jun 2018) + +* update `lazycell` from 0.6 -> 1.0 + +## 2.0.4 (7 Apr 2018) + +* Bump mio dependency (fixes minimal-versions build) + +## 2.0.3 (28 Dec 2017) + +* update `log` from 0.3 -> 0.4 + +## 2.0.2 + +* More docs tidying. + +## 2.0.1 + +* Another try at documenting the timer interface. + +## 2.0.0 + +* Remove channel implementation details from the API. Specifically, the following are no longer public: + * `ctl_pair()` + * `SenderCtl` + * `ReceiverCtl` +* Document all APIs + +## 1.0.0 + +* Initial release. Essentially identical to [mio-more](https://github.com/carllerche/mio-more). diff --git a/third_party/rust/mio-extras/Cargo.toml b/third_party/rust/mio-extras/Cargo.toml new file mode 100644 index 000000000000..df3156013507 --- /dev/null +++ b/third_party/rust/mio-extras/Cargo.toml @@ -0,0 +1,39 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "mio-extras" +version = "2.0.5" +authors = ["Carl Lerche ", "David Hotham"] +exclude = [".gitignore"] +description = "Extra components for use with Mio" +documentation = "https://docs.rs/mio-extras" +readme = "README.md" +keywords = ["io", "async", "non-blocking"] +categories = ["asynchronous"] +license = "MIT" +repository = "https://github.com/dimbleby/mio-extras" + +[[test]] +name = "test" +path = "test/mod.rs" +[dependencies.lazycell] +version = "1" + +[dependencies.log] +version = "0.4" + +[dependencies.mio] +version = "0.6.14" + +[dependencies.slab] +version = "0.4" diff --git a/third_party/rust/mio-extras/LICENSE-APACHE b/third_party/rust/mio-extras/LICENSE-APACHE new file mode 100644 index 000000000000..a6e8ded65739 --- /dev/null +++ b/third_party/rust/mio-extras/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2017 Mio authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/mio-extras/LICENSE-MIT b/third_party/rust/mio-extras/LICENSE-MIT new file mode 100644 index 000000000000..4cf193e73e5b --- /dev/null +++ b/third_party/rust/mio-extras/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2017 Mio authors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/mio-extras/README.md b/third_party/rust/mio-extras/README.md new file mode 100644 index 000000000000..883969b46119 --- /dev/null +++ b/third_party/rust/mio-extras/README.md @@ -0,0 +1,28 @@ +# mio-extras + +Extra components for use with [Mio](https://github.com/carllerche/mio): + +* a channel that implements `Evented` +* a timer that implements `Evented` + +[![Build Status](https://travis-ci.org/dimbleby/mio-extras.svg?branch=master)](https://travis-ci.org/dimbleby/mio-extras) +[![crates.io](http://meritbadge.herokuapp.com/mio-extras)](https://crates.io/crates/mio-extras) + +[Documentation](https://docs.rs/mio-extras). + + +## History and maintenance + +This repository is forked from [`mio-more`](https://github.com/carllerche/mio-more), which is unmaintained. + +I don't intend to do very much with this except for routine maintenance - bug fixes, updating dependencies, and suchlike. + +However if you have some code that you think belongs here, then by all means raise an issue or open a pull request. + +# License + +`mio-extras` is primarily distributed under the terms of both the MIT license +and the Apache License (Version 2.0), with portions covered by various BSD-like +licenses. + +See LICENSE-APACHE, and LICENSE-MIT for details. diff --git a/third_party/rust/mio-extras/src/channel.rs b/third_party/rust/mio-extras/src/channel.rs new file mode 100644 index 000000000000..9ebc73bb7f63 --- /dev/null +++ b/third_party/rust/mio-extras/src/channel.rs @@ -0,0 +1,431 @@ +//! Thread safe communication channel implementing `Evented` +use lazycell::{AtomicLazyCell, LazyCell}; +use mio::{Evented, Poll, PollOpt, Ready, Registration, SetReadiness, Token}; +use std::any::Any; +use std::error; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::{mpsc, Arc}; +use std::{fmt, io}; + +/// Creates a new asynchronous channel, where the `Receiver` can be registered +/// with `Poll`. +pub fn channel() -> (Sender, Receiver) { + let (tx_ctl, rx_ctl) = ctl_pair(); + let (tx, rx) = mpsc::channel(); + + let tx = Sender { tx, ctl: tx_ctl }; + + let rx = Receiver { rx, ctl: rx_ctl }; + + (tx, rx) +} + +/// Creates a new synchronous, bounded channel where the `Receiver` can be +/// registered with `Poll`. +pub fn sync_channel(bound: usize) -> (SyncSender, Receiver) { + let (tx_ctl, rx_ctl) = ctl_pair(); + let (tx, rx) = mpsc::sync_channel(bound); + + let tx = SyncSender { tx, ctl: tx_ctl }; + + let rx = Receiver { rx, ctl: rx_ctl }; + + (tx, rx) +} + +fn ctl_pair() -> (SenderCtl, ReceiverCtl) { + let inner = Arc::new(Inner { + pending: AtomicUsize::new(0), + senders: AtomicUsize::new(1), + set_readiness: AtomicLazyCell::new(), + }); + + let tx = SenderCtl { + inner: Arc::clone(&inner), + }; + + let rx = ReceiverCtl { + registration: LazyCell::new(), + inner, + }; + + (tx, rx) +} + +/// Tracks messages sent on a channel in order to update readiness. +struct SenderCtl { + inner: Arc, +} + +/// Tracks messages received on a channel in order to track readiness. +struct ReceiverCtl { + registration: LazyCell, + inner: Arc, +} + +/// The sending half of a channel. +pub struct Sender { + tx: mpsc::Sender, + ctl: SenderCtl, +} + +/// The sending half of a synchronous channel. +pub struct SyncSender { + tx: mpsc::SyncSender, + ctl: SenderCtl, +} + +/// The receiving half of a channel. +pub struct Receiver { + rx: mpsc::Receiver, + ctl: ReceiverCtl, +} + +/// An error returned from the `Sender::send` or `SyncSender::send` function. +pub enum SendError { + /// An IO error. + Io(io::Error), + + /// The receiving half of the channel has disconnected. + Disconnected(T), +} + +/// An error returned from the `SyncSender::try_send` function. +pub enum TrySendError { + /// An IO error. + Io(io::Error), + + /// Data could not be sent because it would require the callee to block. + Full(T), + + /// The receiving half of the channel has disconnected. + Disconnected(T), +} + +struct Inner { + // The number of outstanding messages for the receiver to read + pending: AtomicUsize, + // The number of sender handles + senders: AtomicUsize, + // The set readiness handle + set_readiness: AtomicLazyCell, +} + +impl Sender { + /// Attempts to send a value on this channel, returning it back if it could not be sent. + pub fn send(&self, t: T) -> Result<(), SendError> { + self.tx.send(t).map_err(SendError::from).and_then(|_| { + try!(self.ctl.inc()); + Ok(()) + }) + } +} + +impl Clone for Sender { + fn clone(&self) -> Sender { + Sender { + tx: self.tx.clone(), + ctl: self.ctl.clone(), + } + } +} + +impl SyncSender { + /// Sends a value on this synchronous channel. + /// + /// This function will *block* until space in the internal buffer becomes + /// available or a receiver is available to hand off the message to. + pub fn send(&self, t: T) -> Result<(), SendError> { + self.tx.send(t).map_err(From::from).and_then(|_| { + try!(self.ctl.inc()); + Ok(()) + }) + } + + /// Attempts to send a value on this channel without blocking. + /// + /// This method differs from `send` by returning immediately if the channel's + /// buffer is full or no receiver is waiting to acquire some data. + pub fn try_send(&self, t: T) -> Result<(), TrySendError> { + self.tx.try_send(t).map_err(From::from).and_then(|_| { + try!(self.ctl.inc()); + Ok(()) + }) + } +} + +impl Clone for SyncSender { + fn clone(&self) -> SyncSender { + SyncSender { + tx: self.tx.clone(), + ctl: self.ctl.clone(), + } + } +} + +impl Receiver { + /// Attempts to return a pending value on this receiver without blocking. + pub fn try_recv(&self) -> Result { + self.rx.try_recv().and_then(|res| { + let _ = self.ctl.dec(); + Ok(res) + }) + } +} + +impl Evented for Receiver { + fn register( + &self, + poll: &Poll, + token: Token, + interest: Ready, + opts: PollOpt, + ) -> io::Result<()> { + self.ctl.register(poll, token, interest, opts) + } + + fn reregister( + &self, + poll: &Poll, + token: Token, + interest: Ready, + opts: PollOpt, + ) -> io::Result<()> { + self.ctl.reregister(poll, token, interest, opts) + } + + fn deregister(&self, poll: &Poll) -> io::Result<()> { + self.ctl.deregister(poll) + } +} + +/* + * + * ===== SenderCtl / ReceiverCtl ===== + * + */ + +impl SenderCtl { + /// Call to track that a message has been sent + fn inc(&self) -> io::Result<()> { + let cnt = self.inner.pending.fetch_add(1, Ordering::Acquire); + + if 0 == cnt { + // Toggle readiness to readable + if let Some(set_readiness) = self.inner.set_readiness.borrow() { + try!(set_readiness.set_readiness(Ready::readable())); + } + } + + Ok(()) + } +} + +impl Clone for SenderCtl { + fn clone(&self) -> SenderCtl { + self.inner.senders.fetch_add(1, Ordering::Relaxed); + SenderCtl { + inner: Arc::clone(&self.inner), + } + } +} + +impl Drop for SenderCtl { + fn drop(&mut self) { + if self.inner.senders.fetch_sub(1, Ordering::Release) == 1 { + let _ = self.inc(); + } + } +} + +impl ReceiverCtl { + fn dec(&self) -> io::Result<()> { + let first = self.inner.pending.load(Ordering::Acquire); + + if first == 1 { + // Unset readiness + if let Some(set_readiness) = self.inner.set_readiness.borrow() { + try!(set_readiness.set_readiness(Ready::empty())); + } + } + + // Decrement + let second = self.inner.pending.fetch_sub(1, Ordering::AcqRel); + + if first == 1 && second > 1 { + // There are still pending messages. Since readiness was + // previously unset, it must be reset here + if let Some(set_readiness) = self.inner.set_readiness.borrow() { + try!(set_readiness.set_readiness(Ready::readable())); + } + } + + Ok(()) + } +} + +impl Evented for ReceiverCtl { + fn register( + &self, + poll: &Poll, + token: Token, + interest: Ready, + opts: PollOpt, + ) -> io::Result<()> { + if self.registration.borrow().is_some() { + return Err(io::Error::new( + io::ErrorKind::Other, + "receiver already registered", + )); + } + + let (registration, set_readiness) = Registration::new2(); + poll.register(®istration, token, interest, opts)?; + + if self.inner.pending.load(Ordering::Relaxed) > 0 { + // TODO: Don't drop readiness + let _ = set_readiness.set_readiness(Ready::readable()); + } + + self.registration + .fill(registration) + .expect("unexpected state encountered"); + self.inner + .set_readiness + .fill(set_readiness) + .expect("unexpected state encountered"); + + Ok(()) + } + + fn reregister( + &self, + poll: &Poll, + token: Token, + interest: Ready, + opts: PollOpt, + ) -> io::Result<()> { + match self.registration.borrow() { + Some(registration) => poll.reregister(registration, token, interest, opts), + None => Err(io::Error::new( + io::ErrorKind::Other, + "receiver not registered", + )), + } + } + + fn deregister(&self, poll: &Poll) -> io::Result<()> { + match self.registration.borrow() { + Some(registration) => poll.deregister(registration), + None => Err(io::Error::new( + io::ErrorKind::Other, + "receiver not registered", + )), + } + } +} + +/* + * + * ===== Error conversions ===== + * + */ + +impl From> for SendError { + fn from(src: mpsc::SendError) -> SendError { + SendError::Disconnected(src.0) + } +} + +impl From for SendError { + fn from(src: io::Error) -> SendError { + SendError::Io(src) + } +} + +impl From> for TrySendError { + fn from(src: mpsc::TrySendError) -> TrySendError { + match src { + mpsc::TrySendError::Full(v) => TrySendError::Full(v), + mpsc::TrySendError::Disconnected(v) => TrySendError::Disconnected(v), + } + } +} + +impl From> for TrySendError { + fn from(src: mpsc::SendError) -> TrySendError { + TrySendError::Disconnected(src.0) + } +} + +impl From for TrySendError { + fn from(src: io::Error) -> TrySendError { + TrySendError::Io(src) + } +} + +/* + * + * ===== Implement Error, Debug and Display for Errors ===== + * + */ + +impl error::Error for SendError { + fn description(&self) -> &str { + match *self { + SendError::Io(ref io_err) => io_err.description(), + SendError::Disconnected(..) => "Disconnected", + } + } +} + +impl error::Error for TrySendError { + fn description(&self) -> &str { + match *self { + TrySendError::Io(ref io_err) => io_err.description(), + TrySendError::Full(..) => "Full", + TrySendError::Disconnected(..) => "Disconnected", + } + } +} + +impl fmt::Debug for SendError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + format_send_error(self, f) + } +} + +impl fmt::Display for SendError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + format_send_error(self, f) + } +} + +impl fmt::Debug for TrySendError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + format_try_send_error(self, f) + } +} + +impl fmt::Display for TrySendError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + format_try_send_error(self, f) + } +} + +#[inline] +fn format_send_error(e: &SendError, f: &mut fmt::Formatter) -> fmt::Result { + match *e { + SendError::Io(ref io_err) => write!(f, "{}", io_err), + SendError::Disconnected(..) => write!(f, "Disconnected"), + } +} + +#[inline] +fn format_try_send_error(e: &TrySendError, f: &mut fmt::Formatter) -> fmt::Result { + match *e { + TrySendError::Io(ref io_err) => write!(f, "{}", io_err), + TrySendError::Full(..) => write!(f, "Full"), + TrySendError::Disconnected(..) => write!(f, "Disconnected"), + } +} diff --git a/third_party/rust/mio-extras/src/lib.rs b/third_party/rust/mio-extras/src/lib.rs new file mode 100644 index 000000000000..69a000556c04 --- /dev/null +++ b/third_party/rust/mio-extras/src/lib.rs @@ -0,0 +1,33 @@ +//! Extra components for use with Mio. +#![deny(missing_docs)] +extern crate lazycell; +extern crate mio; +extern crate slab; + +#[macro_use] +extern crate log; + +pub mod channel; +pub mod timer; + +// Conversion utilities +mod convert { + use std::time::Duration; + + const NANOS_PER_MILLI: u32 = 1_000_000; + const MILLIS_PER_SEC: u64 = 1_000; + + /// Convert a `Duration` to milliseconds, rounding up and saturating at + /// `u64::MAX`. + /// + /// The saturating is fine because `u64::MAX` milliseconds are still many + /// million years. + pub fn millis(duration: Duration) -> u64 { + // Round up. + let millis = (duration.subsec_nanos() + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI; + duration + .as_secs() + .saturating_mul(MILLIS_PER_SEC) + .saturating_add(u64::from(millis)) + } +} diff --git a/third_party/rust/mio-extras/src/timer.rs b/third_party/rust/mio-extras/src/timer.rs new file mode 100644 index 000000000000..adf8f2774a26 --- /dev/null +++ b/third_party/rust/mio-extras/src/timer.rs @@ -0,0 +1,751 @@ +//! Timer optimized for I/O related operations +use convert; +use lazycell::LazyCell; +use mio::{Evented, Poll, PollOpt, Ready, Registration, SetReadiness, Token}; +use slab::Slab; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; +use std::time::{Duration, Instant}; +use std::{cmp, fmt, io, iter, thread, u64, usize}; + +/// A timer. +/// +/// Typical usage goes like this: +/// +/// * register the timer with a `mio::Poll`. +/// * set a timeout, by calling `Timer::set_timeout`. Here you provide some +/// state to be associated with this timeout. +/// * poll the `Poll`, to learn when a timeout has occurred. +/// * retrieve state associated with the timeout by calling `Timer::poll`. +/// +/// You can omit use of the `Poll` altogether, if you like, and just poll the +/// `Timer` directly. +pub struct Timer { + // Size of each tick in milliseconds + tick_ms: u64, + // Slab of timeout entries + entries: Slab>, + // Timeout wheel. Each tick, the timer will look at the next slot for + // timeouts that match the current tick. + wheel: Vec, + // Tick 0's time instant + start: Instant, + // The current tick + tick: Tick, + // The next entry to possibly timeout + next: Token, + // Masks the target tick to get the slot + mask: u64, + // Set on registration with Poll + inner: LazyCell, +} + +/// Used to create a `Timer`. +pub struct Builder { + // Approximate duration of each tick + tick: Duration, + // Number of slots in the timer wheel + num_slots: usize, + // Max number of timeouts that can be in flight at a given time. + capacity: usize, +} + +/// A timeout, as returned by `Timer::set_timeout`. +/// +/// Use this as the argument to `Timer::cancel_timeout`, to cancel this timeout. +#[derive(Clone, Debug)] +pub struct Timeout { + // Reference into the timer entry slab + token: Token, + // Tick that it should match up with + tick: u64, +} + +struct Inner { + registration: Registration, + set_readiness: SetReadiness, + wakeup_state: WakeupState, + wakeup_thread: thread::JoinHandle<()>, +} + +impl Drop for Inner { + fn drop(&mut self) { + // 1. Set wakeup state to TERMINATE_THREAD + self.wakeup_state.store(TERMINATE_THREAD, Ordering::Release); + // 2. Wake him up + self.wakeup_thread.thread().unpark(); + } +} + +#[derive(Copy, Clone, Debug)] +struct WheelEntry { + next_tick: Tick, + head: Token, +} + +// Doubly linked list of timer entries. Allows for efficient insertion / +// removal of timeouts. +struct Entry { + state: T, + links: EntryLinks, +} + +#[derive(Copy, Clone)] +struct EntryLinks { + tick: Tick, + prev: Token, + next: Token, +} + +type Tick = u64; + +const TICK_MAX: Tick = u64::MAX; + +// Manages communication with wakeup thread +type WakeupState = Arc; + +const TERMINATE_THREAD: usize = 0; +const EMPTY: Token = Token(usize::MAX); + +impl Builder { + /// Set the tick duration. Default is 100ms. + pub fn tick_duration(mut self, duration: Duration) -> Builder { + self.tick = duration; + self + } + + /// Set the number of slots. Default is 256. + pub fn num_slots(mut self, num_slots: usize) -> Builder { + self.num_slots = num_slots; + self + } + + /// Set the capacity. Default is 65536. + pub fn capacity(mut self, capacity: usize) -> Builder { + self.capacity = capacity; + self + } + + /// Build a `Timer` with the parameters set on this `Builder`. + pub fn build(self) -> Timer { + Timer::new( + convert::millis(self.tick), + self.num_slots, + self.capacity, + Instant::now(), + ) + } +} + +impl Default for Builder { + fn default() -> Builder { + Builder { + tick: Duration::from_millis(100), + num_slots: 1 << 8, + capacity: 1 << 16, + } + } +} + +impl Timer { + fn new(tick_ms: u64, num_slots: usize, capacity: usize, start: Instant) -> Timer { + let num_slots = num_slots.next_power_of_two(); + let capacity = capacity.next_power_of_two(); + let mask = (num_slots as u64) - 1; + let wheel = iter::repeat(WheelEntry { + next_tick: TICK_MAX, + head: EMPTY, + }).take(num_slots) + .collect(); + + Timer { + tick_ms, + entries: Slab::with_capacity(capacity), + wheel, + start, + tick: 0, + next: EMPTY, + mask, + inner: LazyCell::new(), + } + } + + /// Set a timeout. + /// + /// When the timeout occurs, the given state becomes available via `poll`. + pub fn set_timeout(&mut self, delay_from_now: Duration, state: T) -> Timeout { + let delay_from_start = self.start.elapsed() + delay_from_now; + self.set_timeout_at(delay_from_start, state) + } + + fn set_timeout_at(&mut self, delay_from_start: Duration, state: T) -> Timeout { + let mut tick = duration_to_tick(delay_from_start, self.tick_ms); + trace!( + "setting timeout; delay={:?}; tick={:?}; current-tick={:?}", + delay_from_start, + tick, + self.tick + ); + + // Always target at least 1 tick in the future + if tick <= self.tick { + tick = self.tick + 1; + } + + self.insert(tick, state) + } + + fn insert(&mut self, tick: Tick, state: T) -> Timeout { + // Get the slot for the requested tick + let slot = (tick & self.mask) as usize; + let curr = self.wheel[slot]; + + // Insert the new entry + let entry = Entry::new(state, tick, curr.head); + let token = Token(self.entries.insert(entry)); + + if curr.head != EMPTY { + // If there was a previous entry, set its prev pointer to the new + // entry + self.entries[curr.head.into()].links.prev = token; + } + + // Update the head slot + self.wheel[slot] = WheelEntry { + next_tick: cmp::min(tick, curr.next_tick), + head: token, + }; + + self.schedule_readiness(tick); + + trace!("inserted timout; slot={}; token={:?}", slot, token); + + // Return the new timeout + Timeout { token, tick } + } + + /// Cancel a timeout. + /// + /// If the timeout has not yet occurred, the return value holds the + /// associated state. + pub fn cancel_timeout(&mut self, timeout: &Timeout) -> Option { + let links = match self.entries.get(timeout.token.into()) { + Some(e) => e.links, + None => return None, + }; + + // Sanity check + if links.tick != timeout.tick { + return None; + } + + self.unlink(&links, timeout.token); + Some(self.entries.remove(timeout.token.into()).state) + } + + /// Poll for an expired timer. + /// + /// The return value holds the state associated with the first expired + /// timer, if any. + pub fn poll(&mut self) -> Option { + let target_tick = current_tick(self.start, self.tick_ms); + self.poll_to(target_tick) + } + + fn poll_to(&mut self, mut target_tick: Tick) -> Option { + trace!( + "tick_to; target_tick={}; current_tick={}", + target_tick, + self.tick + ); + + if target_tick < self.tick { + target_tick = self.tick; + } + + while self.tick <= target_tick { + let curr = self.next; + + trace!("ticking; curr={:?}", curr); + + if curr == EMPTY { + self.tick += 1; + + let slot = self.slot_for(self.tick); + self.next = self.wheel[slot].head; + + // Handle the case when a slot has a single timeout which gets + // canceled before the timeout expires. In this case, the + // slot's head is EMPTY but there is a value for next_tick. Not + // resetting next_tick here causes the timer to get stuck in a + // loop. + if self.next == EMPTY { + self.wheel[slot].next_tick = TICK_MAX; + } + } else { + let slot = self.slot_for(self.tick); + + if curr == self.wheel[slot].head { + self.wheel[slot].next_tick = TICK_MAX; + } + + let links = self.entries[curr.into()].links; + + if links.tick <= self.tick { + trace!("triggering; token={:?}", curr); + + // Unlink will also advance self.next + self.unlink(&links, curr); + + // Remove and return the token + return Some(self.entries.remove(curr.into()).state); + } else { + let next_tick = self.wheel[slot].next_tick; + self.wheel[slot].next_tick = cmp::min(next_tick, links.tick); + self.next = links.next; + } + } + } + + // No more timeouts to poll + if let Some(inner) = self.inner.borrow() { + trace!("unsetting readiness"); + let _ = inner.set_readiness.set_readiness(Ready::empty()); + + if let Some(tick) = self.next_tick() { + self.schedule_readiness(tick); + } + } + + None + } + + fn unlink(&mut self, links: &EntryLinks, token: Token) { + trace!( + "unlinking timeout; slot={}; token={:?}", + self.slot_for(links.tick), + token + ); + + if links.prev == EMPTY { + let slot = self.slot_for(links.tick); + self.wheel[slot].head = links.next; + } else { + self.entries[links.prev.into()].links.next = links.next; + } + + if links.next != EMPTY { + self.entries[links.next.into()].links.prev = links.prev; + + if token == self.next { + self.next = links.next; + } + } else if token == self.next { + self.next = EMPTY; + } + } + + fn schedule_readiness(&self, tick: Tick) { + if let Some(inner) = self.inner.borrow() { + // Coordinate setting readiness w/ the wakeup thread + let mut curr = inner.wakeup_state.load(Ordering::Acquire); + + loop { + if curr as Tick <= tick { + // Nothing to do, wakeup is already scheduled + return; + } + + // Attempt to move the wakeup time forward + trace!("advancing the wakeup time; target={}; curr={}", tick, curr); + let actual = + inner + .wakeup_state + .compare_and_swap(curr, tick as usize, Ordering::Release); + + if actual == curr { + // Signal to the wakeup thread that the wakeup time has + // been changed. + trace!("unparking wakeup thread"); + inner.wakeup_thread.thread().unpark(); + return; + } + + curr = actual; + } + } + } + + // Next tick containing a timeout + fn next_tick(&self) -> Option { + if self.next != EMPTY { + let slot = self.slot_for(self.entries[self.next.into()].links.tick); + + if self.wheel[slot].next_tick == self.tick { + // There is data ready right now + return Some(self.tick); + } + } + + self.wheel.iter().map(|e| e.next_tick).min() + } + + fn slot_for(&self, tick: Tick) -> usize { + (self.mask & tick) as usize + } +} + +impl Default for Timer { + fn default() -> Timer { + Builder::default().build() + } +} + +impl Evented for Timer { + fn register( + &self, + poll: &Poll, + token: Token, + interest: Ready, + opts: PollOpt, + ) -> io::Result<()> { + if self.inner.borrow().is_some() { + return Err(io::Error::new( + io::ErrorKind::Other, + "timer already registered", + )); + } + + let (registration, set_readiness) = Registration::new2(); + poll.register(®istration, token, interest, opts)?; + let wakeup_state = Arc::new(AtomicUsize::new(usize::MAX)); + let thread_handle = spawn_wakeup_thread( + Arc::clone(&wakeup_state), + set_readiness.clone(), + self.start, + self.tick_ms, + ); + + self.inner + .fill(Inner { + registration, + set_readiness, + wakeup_state, + wakeup_thread: thread_handle, + }) + .expect("timer already registered"); + + if let Some(next_tick) = self.next_tick() { + self.schedule_readiness(next_tick); + } + + Ok(()) + } + + fn reregister( + &self, + poll: &Poll, + token: Token, + interest: Ready, + opts: PollOpt, + ) -> io::Result<()> { + match self.inner.borrow() { + Some(inner) => poll.reregister(&inner.registration, token, interest, opts), + None => Err(io::Error::new( + io::ErrorKind::Other, + "receiver not registered", + )), + } + } + + fn deregister(&self, poll: &Poll) -> io::Result<()> { + match self.inner.borrow() { + Some(inner) => poll.deregister(&inner.registration), + None => Err(io::Error::new( + io::ErrorKind::Other, + "receiver not registered", + )), + } + } +} + +impl fmt::Debug for Inner { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("Inner") + .field("registration", &self.registration) + .field("wakeup_state", &self.wakeup_state.load(Ordering::Relaxed)) + .finish() + } +} + +fn spawn_wakeup_thread( + state: WakeupState, + set_readiness: SetReadiness, + start: Instant, + tick_ms: u64, +) -> thread::JoinHandle<()> { + thread::spawn(move || { + let mut sleep_until_tick = state.load(Ordering::Acquire) as Tick; + + loop { + if sleep_until_tick == TERMINATE_THREAD as Tick { + return; + } + + let now_tick = current_tick(start, tick_ms); + + trace!( + "wakeup thread: sleep_until_tick={:?}; now_tick={:?}", + sleep_until_tick, + now_tick + ); + + if now_tick < sleep_until_tick { + // Calling park_timeout with u64::MAX leads to undefined + // behavior in pthread, causing the park to return immediately + // and causing the thread to tightly spin. Instead of u64::MAX + // on large values, simply use a blocking park. + match tick_ms.checked_mul(sleep_until_tick - now_tick) { + Some(sleep_duration) => { + trace!( + "sleeping; tick_ms={}; now_tick={}; sleep_until_tick={}; duration={:?}", + tick_ms, + now_tick, + sleep_until_tick, + sleep_duration + ); + thread::park_timeout(Duration::from_millis(sleep_duration)); + } + None => { + trace!( + "sleeping; tick_ms={}; now_tick={}; blocking sleep", + tick_ms, + now_tick + ); + thread::park(); + } + } + sleep_until_tick = state.load(Ordering::Acquire) as Tick; + } else { + let actual = + state.compare_and_swap(sleep_until_tick as usize, usize::MAX, Ordering::AcqRel) + as Tick; + + if actual == sleep_until_tick { + trace!("setting readiness from wakeup thread"); + let _ = set_readiness.set_readiness(Ready::readable()); + sleep_until_tick = usize::MAX as Tick; + } else { + sleep_until_tick = actual as Tick; + } + } + } + }) +} + +fn duration_to_tick(elapsed: Duration, tick_ms: u64) -> Tick { + // Calculate tick rounding up to the closest one + let elapsed_ms = convert::millis(elapsed); + elapsed_ms.saturating_add(tick_ms / 2) / tick_ms +} + +fn current_tick(start: Instant, tick_ms: u64) -> Tick { + duration_to_tick(start.elapsed(), tick_ms) +} + +impl Entry { + fn new(state: T, tick: u64, next: Token) -> Entry { + Entry { + state, + links: EntryLinks { + tick, + prev: EMPTY, + next, + }, + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use std::time::{Duration, Instant}; + + #[test] + pub fn test_timeout_next_tick() { + let mut t = timer(); + let mut tick; + + t.set_timeout_at(Duration::from_millis(100), "a"); + + tick = ms_to_tick(&t, 50); + assert_eq!(None, t.poll_to(tick)); + + tick = ms_to_tick(&t, 100); + assert_eq!(Some("a"), t.poll_to(tick)); + assert_eq!(None, t.poll_to(tick)); + + tick = ms_to_tick(&t, 150); + assert_eq!(None, t.poll_to(tick)); + + tick = ms_to_tick(&t, 200); + assert_eq!(None, t.poll_to(tick)); + + assert_eq!(count(&t), 0); + } + + #[test] + pub fn test_clearing_timeout() { + let mut t = timer(); + let mut tick; + + let to = t.set_timeout_at(Duration::from_millis(100), "a"); + assert_eq!("a", t.cancel_timeout(&to).unwrap()); + + tick = ms_to_tick(&t, 100); + assert_eq!(None, t.poll_to(tick)); + + tick = ms_to_tick(&t, 200); + assert_eq!(None, t.poll_to(tick)); + + assert_eq!(count(&t), 0); + } + + #[test] + pub fn test_multiple_timeouts_same_tick() { + let mut t = timer(); + let mut tick; + + t.set_timeout_at(Duration::from_millis(100), "a"); + t.set_timeout_at(Duration::from_millis(100), "b"); + + let mut rcv = vec![]; + + tick = ms_to_tick(&t, 100); + rcv.push(t.poll_to(tick).unwrap()); + rcv.push(t.poll_to(tick).unwrap()); + + assert_eq!(None, t.poll_to(tick)); + + rcv.sort(); + assert!(rcv == ["a", "b"], "actual={:?}", rcv); + + tick = ms_to_tick(&t, 200); + assert_eq!(None, t.poll_to(tick)); + + assert_eq!(count(&t), 0); + } + + #[test] + pub fn test_multiple_timeouts_diff_tick() { + let mut t = timer(); + let mut tick; + + t.set_timeout_at(Duration::from_millis(110), "a"); + t.set_timeout_at(Duration::from_millis(220), "b"); + t.set_timeout_at(Duration::from_millis(230), "c"); + t.set_timeout_at(Duration::from_millis(440), "d"); + t.set_timeout_at(Duration::from_millis(560), "e"); + + tick = ms_to_tick(&t, 100); + assert_eq!(Some("a"), t.poll_to(tick)); + assert_eq!(None, t.poll_to(tick)); + + tick = ms_to_tick(&t, 200); + assert_eq!(Some("c"), t.poll_to(tick)); + assert_eq!(Some("b"), t.poll_to(tick)); + assert_eq!(None, t.poll_to(tick)); + + tick = ms_to_tick(&t, 300); + assert_eq!(None, t.poll_to(tick)); + + tick = ms_to_tick(&t, 400); + assert_eq!(Some("d"), t.poll_to(tick)); + assert_eq!(None, t.poll_to(tick)); + + tick = ms_to_tick(&t, 500); + assert_eq!(None, t.poll_to(tick)); + + tick = ms_to_tick(&t, 600); + assert_eq!(Some("e"), t.poll_to(tick)); + assert_eq!(None, t.poll_to(tick)); + } + + #[test] + pub fn test_catching_up() { + let mut t = timer(); + + t.set_timeout_at(Duration::from_millis(110), "a"); + t.set_timeout_at(Duration::from_millis(220), "b"); + t.set_timeout_at(Duration::from_millis(230), "c"); + t.set_timeout_at(Duration::from_millis(440), "d"); + + let tick = ms_to_tick(&t, 600); + assert_eq!(Some("a"), t.poll_to(tick)); + assert_eq!(Some("c"), t.poll_to(tick)); + assert_eq!(Some("b"), t.poll_to(tick)); + assert_eq!(Some("d"), t.poll_to(tick)); + assert_eq!(None, t.poll_to(tick)); + } + + #[test] + pub fn test_timeout_hash_collision() { + let mut t = timer(); + let mut tick; + + t.set_timeout_at(Duration::from_millis(100), "a"); + t.set_timeout_at(Duration::from_millis(100 + TICK * SLOTS as u64), "b"); + + tick = ms_to_tick(&t, 100); + assert_eq!(Some("a"), t.poll_to(tick)); + assert_eq!(1, count(&t)); + + tick = ms_to_tick(&t, 200); + assert_eq!(None, t.poll_to(tick)); + assert_eq!(1, count(&t)); + + tick = ms_to_tick(&t, 100 + TICK * SLOTS as u64); + assert_eq!(Some("b"), t.poll_to(tick)); + assert_eq!(0, count(&t)); + } + + #[test] + pub fn test_clearing_timeout_between_triggers() { + let mut t = timer(); + let mut tick; + + let a = t.set_timeout_at(Duration::from_millis(100), "a"); + let _ = t.set_timeout_at(Duration::from_millis(100), "b"); + let _ = t.set_timeout_at(Duration::from_millis(200), "c"); + + tick = ms_to_tick(&t, 100); + assert_eq!(Some("b"), t.poll_to(tick)); + assert_eq!(2, count(&t)); + + t.cancel_timeout(&a); + assert_eq!(1, count(&t)); + + assert_eq!(None, t.poll_to(tick)); + + tick = ms_to_tick(&t, 200); + assert_eq!(Some("c"), t.poll_to(tick)); + assert_eq!(0, count(&t)); + } + + const TICK: u64 = 100; + const SLOTS: usize = 16; + const CAPACITY: usize = 32; + + fn count(timer: &Timer) -> usize { + timer.entries.len() + } + + fn timer() -> Timer<&'static str> { + Timer::new(TICK, SLOTS, CAPACITY, Instant::now()) + } + + fn ms_to_tick(timer: &Timer, ms: u64) -> u64 { + ms / timer.tick_ms + } + +} diff --git a/third_party/rust/mio-extras/test/mod.rs b/third_party/rust/mio-extras/test/mod.rs new file mode 100644 index 000000000000..217069466acd --- /dev/null +++ b/third_party/rust/mio-extras/test/mod.rs @@ -0,0 +1,45 @@ +extern crate mio; +extern crate mio_extras; + +use mio::event::Event; +use mio::{Events, Poll}; +use std::time::Duration; + +mod test_poll_channel; +mod test_timer; + +pub fn expect_events( + poll: &Poll, + event_buffer: &mut Events, + poll_try_count: usize, + mut expected: Vec, +) { + const MS: u64 = 1_000; + + for _ in 0..poll_try_count { + poll.poll(event_buffer, Some(Duration::from_millis(MS))) + .unwrap(); + for event in event_buffer.iter() { + let pos_opt = match expected.iter().position(|exp_event| { + (event.token() == exp_event.token()) + && event.readiness().contains(exp_event.readiness()) + }) { + Some(x) => Some(x), + None => None, + }; + if let Some(pos) = pos_opt { + expected.remove(pos); + } + } + + if expected.is_empty() { + break; + } + } + + assert!( + expected.is_empty(), + "The following expected events were not found: {:?}", + expected + ); +} diff --git a/third_party/rust/mio-extras/test/test_poll_channel.rs b/third_party/rust/mio-extras/test/test_poll_channel.rs new file mode 100644 index 000000000000..2091f65cb4bc --- /dev/null +++ b/third_party/rust/mio-extras/test/test_poll_channel.rs @@ -0,0 +1,338 @@ +use expect_events; +use mio::event::Event; +use mio::{Events, Poll, PollOpt, Ready, Token}; +use mio_extras::channel; +use std::sync::mpsc::TryRecvError; +use std::thread; +use std::time::Duration; + +#[test] +pub fn test_poll_channel_edge() { + let poll = Poll::new().unwrap(); + let mut events = Events::with_capacity(1024); + let (tx, rx) = channel::channel(); + + poll.register(&rx, Token(123), Ready::readable(), PollOpt::edge()) + .unwrap(); + + // Wait, but nothing should happen + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(0, num); + + // Push the value + tx.send("hello").unwrap(); + + // Polling will contain the event + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(1, num); + + let event = events.iter().next().unwrap(); + assert_eq!(event.token(), Token(123)); + assert_eq!(event.readiness(), Ready::readable()); + + // Poll again and there should be no events + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(0, num); + + // Read the value + assert_eq!("hello", rx.try_recv().unwrap()); + + // Poll again, nothing + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(0, num); + + // Push a value + tx.send("goodbye").unwrap(); + + // Have an event + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(1, num); + + let event = events.iter().next().unwrap(); + assert_eq!(event.token(), Token(123)); + assert_eq!(event.readiness(), Ready::readable()); + + // Read the value + rx.try_recv().unwrap(); + + // Drop the sender half + drop(tx); + + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(1, num); + + let event = events.iter().next().unwrap(); + assert_eq!(event.token(), Token(123)); + assert_eq!(event.readiness(), Ready::readable()); + + match rx.try_recv() { + Err(TryRecvError::Disconnected) => {} + no => panic!("unexpected value {:?}", no), + } +} + +#[test] +pub fn test_poll_channel_oneshot() { + let poll = Poll::new().unwrap(); + let mut events = Events::with_capacity(1024); + let (tx, rx) = channel::channel(); + + poll.register( + &rx, + Token(123), + Ready::readable(), + PollOpt::edge() | PollOpt::oneshot(), + ).unwrap(); + + // Wait, but nothing should happen + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(0, num); + + // Push the value + tx.send("hello").unwrap(); + + // Polling will contain the event + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(1, num); + + let event = events.iter().next().unwrap(); + assert_eq!(event.token(), Token(123)); + assert_eq!(event.readiness(), Ready::readable()); + + // Poll again and there should be no events + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(0, num); + + // Read the value + assert_eq!("hello", rx.try_recv().unwrap()); + + // Poll again, nothing + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(0, num); + + // Push a value + tx.send("goodbye").unwrap(); + + // Poll again, nothing + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(0, num); + + // Reregistering will re-trigger the notification + for _ in 0..3 { + poll.reregister( + &rx, + Token(123), + Ready::readable(), + PollOpt::edge() | PollOpt::oneshot(), + ).unwrap(); + + // Have an event + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(1, num); + + let event = events.iter().next().unwrap(); + assert_eq!(event.token(), Token(123)); + assert_eq!(event.readiness(), Ready::readable()); + } + + // Get the value + assert_eq!("goodbye", rx.try_recv().unwrap()); + + poll.reregister( + &rx, + Token(123), + Ready::readable(), + PollOpt::edge() | PollOpt::oneshot(), + ).unwrap(); + + // Have an event + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(0, num); + + poll.reregister( + &rx, + Token(123), + Ready::readable(), + PollOpt::edge() | PollOpt::oneshot(), + ).unwrap(); + + // Have an event + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(0, num); +} + +#[test] +pub fn test_poll_channel_level() { + let poll = Poll::new().unwrap(); + let mut events = Events::with_capacity(1024); + let (tx, rx) = channel::channel(); + + poll.register(&rx, Token(123), Ready::readable(), PollOpt::level()) + .unwrap(); + + // Wait, but nothing should happen + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(0, num); + + // Push the value + tx.send("hello").unwrap(); + + // Polling will contain the event + for i in 0..5 { + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert!(1 == num, "actually got {} on iteration {}", num, i); + + let event = events.iter().next().unwrap(); + assert_eq!(event.token(), Token(123)); + assert_eq!(event.readiness(), Ready::readable()); + } + + // Read the value + assert_eq!("hello", rx.try_recv().unwrap()); + + // Wait, but nothing should happen + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(0, num); +} + +#[test] +pub fn test_poll_channel_writable() { + let poll = Poll::new().unwrap(); + let mut events = Events::with_capacity(1024); + let (tx, rx) = channel::channel(); + + poll.register(&rx, Token(123), Ready::writable(), PollOpt::edge()) + .unwrap(); + + // Wait, but nothing should happen + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(0, num); + + // Push the value + tx.send("hello").unwrap(); + + // Wait, but nothing should happen + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(0, num); +} + +#[test] +pub fn test_dropping_receive_before_poll() { + let poll = Poll::new().unwrap(); + let mut events = Events::with_capacity(1024); + let (tx, rx) = channel::channel(); + + poll.register(&rx, Token(123), Ready::readable(), PollOpt::edge()) + .unwrap(); + + // Push the value + tx.send("hello").unwrap(); + + // Drop the receive end + drop(rx); + + // Wait, but nothing should happen + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(0, num); +} + +#[test] +pub fn test_mixing_channel_with_socket() { + use mio::net::{TcpListener, TcpStream}; + + let poll = Poll::new().unwrap(); + let mut events = Events::with_capacity(1024); + let (tx, rx) = channel::channel(); + + // Create the listener + let l = TcpListener::bind(&"127.0.0.1:0".parse().unwrap()).unwrap(); + + // Register the listener with `Poll` + poll.register(&l, Token(0), Ready::readable(), PollOpt::edge()) + .unwrap(); + poll.register(&rx, Token(1), Ready::readable(), PollOpt::edge()) + .unwrap(); + + // Push a value onto the channel + tx.send("hello").unwrap(); + + // Connect a TCP socket + let s1 = TcpStream::connect(&l.local_addr().unwrap()).unwrap(); + + // Register the socket + poll.register(&s1, Token(2), Ready::readable(), PollOpt::edge()) + .unwrap(); + + // Sleep a bit to ensure it arrives at dest + thread::sleep(Duration::from_millis(250)); + + expect_events( + &poll, + &mut events, + 2, + vec![ + Event::new(Ready::empty(), Token(0)), + Event::new(Ready::empty(), Token(1)), + ], + ); +} + +#[test] +pub fn test_sending_from_other_thread_while_polling() { + const ITERATIONS: usize = 20; + const THREADS: usize = 5; + + // Make sure to run multiple times + let poll = Poll::new().unwrap(); + let mut events = Events::with_capacity(1024); + + for _ in 0..ITERATIONS { + let (tx, rx) = channel::channel(); + poll.register(&rx, Token(0), Ready::readable(), PollOpt::edge()) + .unwrap(); + + for _ in 0..THREADS { + let tx = tx.clone(); + + thread::spawn(move || { + thread::sleep(Duration::from_millis(50)); + tx.send("ping").unwrap(); + }); + } + + let mut recv = 0; + + while recv < THREADS { + let num = poll.poll(&mut events, None).unwrap(); + + if num != 0 { + assert_eq!(1, num); + assert_eq!(events.iter().next().unwrap().token(), Token(0)); + + while let Ok(_) = rx.try_recv() { + recv += 1; + } + } + } + } +} diff --git a/third_party/rust/mio-extras/test/test_timer.rs b/third_party/rust/mio-extras/test/test_timer.rs new file mode 100644 index 000000000000..a1d0547a6965 --- /dev/null +++ b/third_party/rust/mio-extras/test/test_timer.rs @@ -0,0 +1,304 @@ +use mio::{Events, Poll, PollOpt, Ready, Token}; +use mio_extras::timer::{self, Timer}; + +use std::thread; +use std::time::Duration; + +#[test] +fn test_basic_timer_without_poll() { + let mut timer = Timer::default(); + + // Set the timeout + timer.set_timeout(Duration::from_millis(200), "hello"); + + // Nothing when polled immediately + assert!(timer.poll().is_none()); + + // Wait for the timeout + thread::sleep(Duration::from_millis(250)); + + assert_eq!(Some("hello"), timer.poll()); + assert!(timer.poll().is_none()); +} + +#[test] +fn test_basic_timer_with_poll_edge_set_timeout_after_register() { + let poll = Poll::new().unwrap(); + let mut events = Events::with_capacity(1024); + let mut timer = Timer::default(); + + poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()) + .unwrap(); + timer.set_timeout(Duration::from_millis(200), "hello"); + + let elapsed = elapsed(|| { + let num = poll.poll(&mut events, None).unwrap(); + + assert_eq!(num, 1); + let event = events.iter().next().unwrap(); + assert_eq!(Token(0), event.token()); + assert_eq!(Ready::readable(), event.readiness()); + }); + + assert!(is_about(200, elapsed), "actual={:?}", elapsed); + assert_eq!("hello", timer.poll().unwrap()); + assert_eq!(None, timer.poll()); +} + +#[test] +fn test_basic_timer_with_poll_edge_set_timeout_before_register() { + let poll = Poll::new().unwrap(); + let mut events = Events::with_capacity(1024); + let mut timer = Timer::default(); + + timer.set_timeout(Duration::from_millis(200), "hello"); + poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()) + .unwrap(); + + let elapsed = elapsed(|| { + let num = poll.poll(&mut events, None).unwrap(); + + assert_eq!(num, 1); + let event = events.iter().next().unwrap(); + assert_eq!(Token(0), event.token()); + assert_eq!(Ready::readable(), event.readiness()); + }); + + assert!(is_about(200, elapsed), "actual={:?}", elapsed); + assert_eq!("hello", timer.poll().unwrap()); + assert_eq!(None, timer.poll()); +} + +#[test] +fn test_setting_later_timeout_then_earlier_one() { + let poll = Poll::new().unwrap(); + let mut events = Events::with_capacity(1024); + let mut timer = Timer::default(); + + poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()) + .unwrap(); + + timer.set_timeout(Duration::from_millis(600), "hello"); + timer.set_timeout(Duration::from_millis(200), "world"); + + let elapsed = elapsed(|| { + let num = poll.poll(&mut events, None).unwrap(); + + assert_eq!(num, 1); + let event = events.iter().next().unwrap(); + assert_eq!(Token(0), event.token()); + assert_eq!(Ready::readable(), event.readiness()); + }); + + assert!(is_about(200, elapsed), "actual={:?}", elapsed); + assert_eq!("world", timer.poll().unwrap()); + assert_eq!(None, timer.poll()); + + let elapsed = self::elapsed(|| { + let num = poll.poll(&mut events, None).unwrap(); + + assert_eq!(num, 1); + let event = events.iter().next().unwrap(); + assert_eq!(Token(0), event.token()); + assert_eq!(Ready::readable(), event.readiness()); + }); + + assert!(is_about(400, elapsed), "actual={:?}", elapsed); + assert_eq!("hello", timer.poll().unwrap()); + assert_eq!(None, timer.poll()); +} + +#[test] +fn test_timer_with_looping_wheel() { + let poll = Poll::new().unwrap(); + let mut events = Events::with_capacity(1024); + let mut timer = timer::Builder::default().num_slots(2).build(); + + poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()) + .unwrap(); + + const TOKENS: &[&str] = &["hello", "world", "some", "thing"]; + + for (i, msg) in TOKENS.iter().enumerate() { + timer.set_timeout(Duration::from_millis(500 * (i as u64 + 1)), msg); + } + + for msg in TOKENS { + let elapsed = elapsed(|| { + let num = poll.poll(&mut events, None).unwrap(); + + assert_eq!(num, 1); + let event = events.iter().next().unwrap(); + assert_eq!(Token(0), event.token()); + assert_eq!(Ready::readable(), event.readiness()); + }); + + assert!( + is_about(500, elapsed), + "actual={:?}; msg={:?}", + elapsed, + msg + ); + assert_eq!(Some(msg), timer.poll()); + assert_eq!(None, timer.poll()); + } +} + +#[test] +fn test_edge_without_polling() { + let poll = Poll::new().unwrap(); + let mut events = Events::with_capacity(1024); + let mut timer = Timer::default(); + + poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()) + .unwrap(); + + timer.set_timeout(Duration::from_millis(400), "hello"); + + let ms = elapsed(|| { + let num = poll.poll(&mut events, None).unwrap(); + assert_eq!(num, 1); + let event = events.iter().next().unwrap(); + assert_eq!(Token(0), event.token()); + assert_eq!(Ready::readable(), event.readiness()); + }); + + assert!(is_about(400, ms), "actual={:?}", ms); + + let ms = elapsed(|| { + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(num, 0); + }); + + assert!(is_about(300, ms), "actual={:?}", ms); +} + +#[test] +fn test_level_triggered() { + let poll = Poll::new().unwrap(); + let mut events = Events::with_capacity(1024); + let mut timer = Timer::default(); + + poll.register(&timer, Token(0), Ready::readable(), PollOpt::level()) + .unwrap(); + + timer.set_timeout(Duration::from_millis(400), "hello"); + + let ms = elapsed(|| { + let num = poll.poll(&mut events, None).unwrap(); + assert_eq!(num, 1); + let event = events.iter().next().unwrap(); + assert_eq!(Token(0), event.token()); + assert_eq!(Ready::readable(), event.readiness()); + }); + + assert!(is_about(400, ms), "actual={:?}", ms); + + let ms = elapsed(|| { + let num = poll.poll(&mut events, None).unwrap(); + assert_eq!(num, 1); + let event = events.iter().next().unwrap(); + assert_eq!(Token(0), event.token()); + assert_eq!(Ready::readable(), event.readiness()); + }); + + assert!(is_about(0, ms), "actual={:?}", ms); +} + +#[test] +fn test_edge_oneshot_triggered() { + let poll = Poll::new().unwrap(); + let mut events = Events::with_capacity(1024); + let mut timer = Timer::default(); + + poll.register( + &timer, + Token(0), + Ready::readable(), + PollOpt::edge() | PollOpt::oneshot(), + ).unwrap(); + + timer.set_timeout(Duration::from_millis(200), "hello"); + + let ms = elapsed(|| { + let num = poll.poll(&mut events, None).unwrap(); + assert_eq!(num, 1); + }); + + assert!(is_about(200, ms), "actual={:?}", ms); + + let ms = elapsed(|| { + let num = poll.poll(&mut events, Some(Duration::from_millis(300))) + .unwrap(); + assert_eq!(num, 0); + }); + + assert!(is_about(300, ms), "actual={:?}", ms); + + poll.reregister( + &timer, + Token(0), + Ready::readable(), + PollOpt::edge() | PollOpt::oneshot(), + ).unwrap(); + + let ms = elapsed(|| { + let num = poll.poll(&mut events, None).unwrap(); + assert_eq!(num, 1); + }); + + assert!(is_about(0, ms)); +} + +#[test] +fn test_cancel_timeout() { + use std::time::Instant; + + let mut timer: Timer = Default::default(); + let timeout = timer.set_timeout(Duration::from_millis(200), 1); + timer.cancel_timeout(&timeout); + + let poll = Poll::new().unwrap(); + poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()) + .unwrap(); + + let mut events = Events::with_capacity(16); + + let now = Instant::now(); + let dur = Duration::from_millis(500); + let mut i = 0; + + while Instant::now() - now < dur { + if i > 10 { + panic!("iterated too many times"); + } + + i += 1; + + let elapsed = Instant::now() - now; + + poll.poll(&mut events, Some(dur - elapsed)).unwrap(); + + while let Some(_) = timer.poll() { + panic!("did not expect to receive timeout"); + } + } +} + +fn elapsed(mut f: F) -> u64 { + use std::time::Instant; + + let now = Instant::now(); + + f(); + + let elapsed = now.elapsed(); + elapsed.as_secs() * 1000 + u64::from(elapsed.subsec_nanos() / 1_000_000) +} + +fn is_about(expect: u64, val: u64) -> bool { + const WINDOW: i64 = 200; + + ((expect as i64) - (val as i64)).abs() <= WINDOW +} diff --git a/third_party/rust/mio/.cargo-checksum.json b/third_party/rust/mio/.cargo-checksum.json index 47aa1fd3988b..a18f1067f6fa 100644 --- a/third_party/rust/mio/.cargo-checksum.json +++ b/third_party/rust/mio/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"77d8144016a20f81879755c8b517e1f8d608e84d41d676adfb061aa4a8e6e88a","Cargo.toml":"129c2be1244092de4987999ff9524717da7a0a1e3c6d6de080a48088ec81c3c1","LICENSE":"07919255c7e04793d8ea760d6c2ce32d19f9ff02bdbdde3ce90b1e1880929a9b","README.md":"8095f9f50964ab6f4539d6b6ffb035c8e0601824920946b9f00037844f2fe161","appveyor.yml":"9cf83d26a0bbf81a8349c7f80ca805d2d57a9c5dff1ee7630db504c4aa759c48","benches/bench_poll.rs":"ab1e38ad309d58f4c1924fdef1868fd6b899536959f08d2f33247f057c8962d0","ci/docker/aarch64-linux-android/Dockerfile":"736b09aaeffc0f8b78b5a1026a9a9e28614d1203ec3767f93f739ce835ed3d6c","ci/docker/aarch64-linux-android/accept-licenses.sh":"b425a5561694c3bf065ef10a00f904c2536e63d6b11782e35a567f2808118ef2","ci/docker/aarch64-linux-android/cargo_config":"ef57da8986b41bbca9ca77d2dbceb857185d341dbb3d97a3f95cc680467e4985","ci/docker/aarch64-linux-android/install-ndk.sh":"e9e58a151ba4f71e7c23fca256bebd9b8a5ed1b3161c6154a634870174f33484","ci/docker/aarch64-linux-android/install-sdk.sh":"0a20433259127e6e3f5115b8bf0aaf3b10c9ae758d56ecb2a33006b614283770","ci/docker/arm-linux-androideabi/Dockerfile":"c6f153172df91bc5c7d3a859f8970ce54e1cc5c92ab295c1c9cf91c81a49fd51","ci/docker/arm-linux-androideabi/accept-licenses.sh":"84ad00815f628005ed22c5d6cd14990ebc97812a7163bd275b2877904eddab53","ci/docker/arm-linux-androideabi/cargo_config":"ec54caa043c093c699cfb3a1cc3dc35651039b50e29fb416b43f3f4dbd778397","ci/docker/arm-linux-androideabi/install-ndk.sh":"eef063bb01a16c0f90471dbce1b5a395b53141d7704e15a3c9a1c4fc5e06d4b1","ci/docker/arm-linux-androideabi/install-sdk.sh":"cb6b0155f0d146515a3ea4bdaa50b90936529f843814cba1665cf52cfda8668c","ci/ios/deploy_and_run_on_ios_simulator.rs":"977ed5ee02864e85b5583d61549865c72e70c16e62d5b4d3ea1fe486609c193e","ci/run-docker.sh":"7f6c68dbca93788111170ac4678608957a179e76cfe8c5a51d11dfea1742d7f2","ci/run-ios.sh":"39de59f369ba52a5ca4a343b496396d3797f7e776f615612401254fb385020b3","ci/run.sh":"f496e9d3506aee0c26e00407a2658ada83b736ca50f4b159af219e53c3fe3acf","ci/trust/install.sh":"8b165fc99df296261fcc9cdcbc8b8a177c11c505cdc9255cc19efb66cb0055db","ci/trust/script.sh":"d5d581703524b4b770ad99d5beed4d68733e16497a50b4d0f416115526dae319","src/channel.rs":"92a0dcf00174fface8a50ddfee2f45189730f8c172d874aab49587bd160c4658","src/deprecated/event_loop.rs":"5fccdcba1b3d3012eb6778f8f487279f30f9b9076acb7d41512838b2ba02c5e7","src/deprecated/handler.rs":"13cbc0c193f43a331e125e05d5eddf3712fe86e41a8721186d3672518ef8a9cc","src/deprecated/io.rs":"4948217ffeeba4f508cc89744da5d6af858b4ad7b4be23f927a00df93bdf2984","src/deprecated/mod.rs":"4310471b5a1313dbf53b492769a3031b15353eb269333b7c1a890bc2709def7c","src/deprecated/notify.rs":"8cb108387ebcfb75764e4dd2868d80eb00d793c4b7c867c08cd86ef10b91b023","src/deprecated/unix.rs":"e63eab07061ff9a0798cf0ad05fe276e62c68e685fb188be5872c2921290beb1","src/event_imp.rs":"35e55783c630ecf6e75be30e35b838d57dab0defbd2963429c0bb3fdf96a5686","src/io.rs":"9207ffc93ea744b09bc6872fa4d378d7c75640f9ac38b1fa67b940c7cb5d0ade","src/lib.rs":"45ce57ba07598a256d9c0af03751420ed6f3aa294e33e262a39e13cbde763368","src/net/mod.rs":"340c63a8efe9ee774b7bf8ed8c0f72fc7563e5c4b35f6a8b243f92d366e145a2","src/net/tcp.rs":"034010d098d1fb2e5385fa6fe40e012ee4876338f6e970fb00282472fff44963","src/net/udp.rs":"4400029c4544f9d6c58c5e7fd4699a70e1a6822f4ef4690d33b0573cfb66e17c","src/poll.rs":"55f2c0f685e8f1c4a5fd47f047ddd9a0e47da8bd9dbc8bd40d56781d92ce5c73","src/sys/fuchsia/awakener.rs":"71a4a0083242457b0a96326c69c0f98b23dfdb97be96deb26ee02fa9d1dfb212","src/sys/fuchsia/eventedfd.rs":"bd8f43d2b61cdd6a5d0df9c0dc1cb43e1708140d01a05611055277ed55a33b63","src/sys/fuchsia/handles.rs":"161a69e8a8d7f71326a9c53bcb7685d0a81d184aba8e20da27c64aa27dfd56b2","src/sys/fuchsia/mod.rs":"9d80f1214abc93f48b6b6c12ce5b6cfaddbda592c8f3410564d0237228cae2d0","src/sys/fuchsia/net.rs":"50340191dd9cbe317bd6e6ae0170c03daa9141f15c96782b96484e3d8b8301b1","src/sys/fuchsia/ready.rs":"7e6bb7235c52ab4a2134d36cf982f6a4fd6e18050e737b40ee84c89a10a9faac","src/sys/fuchsia/selector.rs":"f3be7f8d683d43e4a8313246e4cacb9444549bf66ecb2234f0d0f53172043bf5","src/sys/mod.rs":"64bea046e4a9feb1f2e2fb8326452c1be8b9d56cf8794df0af4fbdf565204255","src/sys/unix/awakener.rs":"20a61d8f39b2f2abf4f166a3ed46fa0d79907ddf92758eaddb880c67321db56c","src/sys/unix/dlsym.rs":"559337d1f6c10e6c1172bd3908a9dcfa5a0828b53b04f7ca3a0d926afa85cd63","src/sys/unix/epoll.rs":"e385de7d7716affbaf69ddacedf91c5670f828fb31e826e4bcf0616c80503877","src/sys/unix/eventedfd.rs":"c9c4aefc218e48b90a9f8703923afb0fe60d5316824501e49365e2c64804a1d0","src/sys/unix/io.rs":"a518f09020f821e87bcf9c2ecb4bf501d428619ddfd7b35a26629b614919b14c","src/sys/unix/kqueue.rs":"c852e7358d8f2c247f5ab9c77c1b76631ad4ab0c582af0954c72c7380ba8cc97","src/sys/unix/mod.rs":"62331824b1f5022e372b875faad41a970abb13e63c15e3fae9af948a2b06e4e1","src/sys/unix/ready.rs":"a01240079528ae5443b643ab03d4955501bee17d87b28caf4defb4284dbe38bc","src/sys/unix/tcp.rs":"811f76bf5ee53363b2f957cdf7db4dbcc995b0c3263eab8b9f240b7f03ba5bbe","src/sys/unix/udp.rs":"c51220d49455bee0072a87f1434e03bf51947c80a7f2bae94402dc3475de795f","src/sys/unix/uds.rs":"fabaf91c64a51de45c2e3142932b1da604206efe888d4aa365d795cfe19e5beb","src/sys/windows/awakener.rs":"2d3cdaf8b523675e2f64c5fd81e1197d5255384517b9753b718c5c47acf0cabd","src/sys/windows/buffer_pool.rs":"636f4b7510a507f9985987699ce8ec140b2ed852abb231443ee1486c80759eed","src/sys/windows/from_raw_arc.rs":"659dabdf5037546e3783aacc422992b4248b0ba2ddcce52b149d35bc723550e5","src/sys/windows/mod.rs":"afeec8cd4e3adeaf6ffe68b134ad1b4ba07faa3abae96f6f9a00bbc20ff5f2c5","src/sys/windows/selector.rs":"e971a04e56104dee3271512497e31634eae06ed04029e4637041609efeb9f7d0","src/sys/windows/tcp.rs":"dbba36ef0459b4331f8f3199d8eef8fe16e0ab5b196aadfc3cc0a80097c9011c","src/sys/windows/udp.rs":"1ef869b660bcf89ea6498552474abf8f540946631e14d5b610ca31014cd9045f","src/timer.rs":"aaebc4729dcddd60fe90a46e6ac053a4dcaba705355ea974730fb9d76f5e429f","src/token.rs":"4a56f851709470df2eed803c57c68b0a4b12ea86fa1b8d2c999bec7a85d58ec0","src/udp.rs":"442e620f3ea0cf010497d3ad775debd585f28e79a025993d40471c8e6839dc98","test/benchmark.rs":"d655cd4a79b11555df4d46e929134d73f2e49e174a59f66b98904a6b9a2779e3","test/mod.rs":"556340593d7376ce67f5645064bce48925f5fe8c52e2a89e709220ccac9503be","test/test_battery.rs":"cea7470a896a5bb09cb45c0658bc80f48ab92f07662e95eceb0cfd70065cd84f","test/test_broken_pipe.rs":"1e8352a22a8b3fe170aa8bb942dc4a2ddd0fb5e69374733e6bcfa324481da648","test/test_close_on_drop.rs":"403b5e8477d3f4309c8d1568ed05a57af50393baa228e91cc7a0d29bb77bcbaa","test/test_custom_evented.rs":"02f113cbbbb4c0d09767bc17434b12acf6de1dd6b6ee20106b5f40ce2f0b46ed","test/test_double_register.rs":"f48b1b5aee68f0c3fef8895c8b9f2cf2446e670f3d0e7249ec300067df783617","test/test_echo_server.rs":"c4fadaf9f226e4ac2066369200792bf890bdec09ccd699370c573f960a4eb52b","test/test_fuchsia_handles.rs":"1e4fc0920b4067a4ece7487067af4f6e3f18e8e55b0fd636ccc2d333f8ade70f","test/test_local_addr_ready.rs":"0a9cd42cb43b5afcc139b1def8278f2a24834e40f96c4ea69f05c4f3263f7c65","test/test_multicast.rs":"cbd85c94971c07bd269d72eb80f53a3bcd57075f7acb7475c2d73efb28e816af","test/test_notify.rs":"ee98f24cb72690756b4bff5983c642a251cd253851f7c1c8f1adf29bf2b97287","test/test_oneshot.rs":"3f618c167734b1ce4695691955fb01224c6abf0a1cc1e1db9e01248fb9edbd3c","test/test_poll.rs":"ad450ff65e9ab8108d424b3b8cf4c82847fb9927f12e749f0aee1228bd5db7da","test/test_poll_channel.rs":"8414e7d27e32bec5c8ea0341f4f2708eb64853cfb6d28689deb58d90b1619120","test/test_register_deregister.rs":"c10612421b097d4a8b0a73a0440f11fe1f8c4f34c701255af6da62bf4fa5a08e","test/test_register_multiple_event_loops.rs":"e0f3115ef938ceed2eae47ea1630c7f440a860b69ab57b70507cf8062fc21eb9","test/test_reregister_without_poll.rs":"30ebba86b936bc283575f8f15237bd1f616ea09516bf34912a27ce6c7b5a5559","test/test_smoke.rs":"f1c4c52509537a76975354dbd9a91e16b14e53f8b30171c57ebf59ff4d935bcc","test/test_subprocess_pipe.rs":"324b68e1cb2d43bec204d41064f6873640cf61970718da3703506f0e5ebad31d","test/test_tcp.rs":"dc7e8684e53099b13e0828cddbc0985755d041c8b20408d57fe12d4bb7c28c3f","test/test_tcp_level.rs":"4f7b9615c6b47ccce5787f1e3b0b4f26e56af9b310c9ca687ec2d08126937478","test/test_tick.rs":"e5bbbcad3106da6419147bb0775d0ad5203d90adb1a9ee61de2128d95600bd5c","test/test_timer.rs":"3e1d249f3c1fc57b3c44adb54221eb1b7434ce41f985b8ae46c75abc026701cd","test/test_udp_level.rs":"c47b99cd614d5115fe59ed3afdbe56e0a4bf16884da7f03bab54ba4a513a3893","test/test_udp_socket.rs":"4bccb59ff803ed9acfc61c58b2d6f19fbdf1cf78ec12eba59902582b0a1acaa8","test/test_uds_shutdown.rs":"ea3bfdca353116fc3a55a7fb5156a1c67229b3ff2057cc06d83ed73768436894","test/test_unix_echo_server.rs":"5f39c69f846a6d60d7f0018a62c212be68032211cf653748fba312edb12206b7","test/test_unix_pass_fd.rs":"a8a4f5b9e0acfae22a53192b037cd3c398c43d8514c60e25468bafe1cb9ccd72","test/test_write_then_drop.rs":"2e58df792cd794306d0b9a068a69ff084352545d295aceedb92b67472be7f1b0"},"package":"4fcfcb32d63961fb6f367bfd5d21e4600b92cd310f71f9dca25acae196eb1560"} \ No newline at end of file +{"files":{"CHANGELOG.md":"91a58d86ee2847768f7711c7e6ef7d78cf41f7564acca0a8ceb6e9444fcff96d","Cargo.toml":"562232ecd5a1e7f6a8c048fcaac8894f7b466ab2c2be800fc147d190ff009784","LICENSE":"07919255c7e04793d8ea760d6c2ce32d19f9ff02bdbdde3ce90b1e1880929a9b","README.md":"8095f9f50964ab6f4539d6b6ffb035c8e0601824920946b9f00037844f2fe161","appveyor.yml":"9cf83d26a0bbf81a8349c7f80ca805d2d57a9c5dff1ee7630db504c4aa759c48","benches/bench_poll.rs":"ab1e38ad309d58f4c1924fdef1868fd6b899536959f08d2f33247f057c8962d0","ci/docker/aarch64-linux-android/Dockerfile":"736b09aaeffc0f8b78b5a1026a9a9e28614d1203ec3767f93f739ce835ed3d6c","ci/docker/aarch64-linux-android/accept-licenses.sh":"b425a5561694c3bf065ef10a00f904c2536e63d6b11782e35a567f2808118ef2","ci/docker/aarch64-linux-android/cargo_config":"ef57da8986b41bbca9ca77d2dbceb857185d341dbb3d97a3f95cc680467e4985","ci/docker/aarch64-linux-android/install-ndk.sh":"e9e58a151ba4f71e7c23fca256bebd9b8a5ed1b3161c6154a634870174f33484","ci/docker/aarch64-linux-android/install-sdk.sh":"0a20433259127e6e3f5115b8bf0aaf3b10c9ae758d56ecb2a33006b614283770","ci/docker/arm-linux-androideabi/Dockerfile":"c6f153172df91bc5c7d3a859f8970ce54e1cc5c92ab295c1c9cf91c81a49fd51","ci/docker/arm-linux-androideabi/accept-licenses.sh":"84ad00815f628005ed22c5d6cd14990ebc97812a7163bd275b2877904eddab53","ci/docker/arm-linux-androideabi/cargo_config":"ec54caa043c093c699cfb3a1cc3dc35651039b50e29fb416b43f3f4dbd778397","ci/docker/arm-linux-androideabi/install-ndk.sh":"eef063bb01a16c0f90471dbce1b5a395b53141d7704e15a3c9a1c4fc5e06d4b1","ci/docker/arm-linux-androideabi/install-sdk.sh":"cb6b0155f0d146515a3ea4bdaa50b90936529f843814cba1665cf52cfda8668c","ci/run-docker.sh":"7f6c68dbca93788111170ac4678608957a179e76cfe8c5a51d11dfea1742d7f2","ci/run.sh":"f496e9d3506aee0c26e00407a2658ada83b736ca50f4b159af219e53c3fe3acf","ci/trust/install.sh":"8b165fc99df296261fcc9cdcbc8b8a177c11c505cdc9255cc19efb66cb0055db","ci/trust/script.sh":"d5d581703524b4b770ad99d5beed4d68733e16497a50b4d0f416115526dae319","src/channel.rs":"92a0dcf00174fface8a50ddfee2f45189730f8c172d874aab49587bd160c4658","src/deprecated/event_loop.rs":"5fccdcba1b3d3012eb6778f8f487279f30f9b9076acb7d41512838b2ba02c5e7","src/deprecated/handler.rs":"13cbc0c193f43a331e125e05d5eddf3712fe86e41a8721186d3672518ef8a9cc","src/deprecated/io.rs":"4948217ffeeba4f508cc89744da5d6af858b4ad7b4be23f927a00df93bdf2984","src/deprecated/mod.rs":"4310471b5a1313dbf53b492769a3031b15353eb269333b7c1a890bc2709def7c","src/deprecated/notify.rs":"8cb108387ebcfb75764e4dd2868d80eb00d793c4b7c867c08cd86ef10b91b023","src/deprecated/unix.rs":"e63eab07061ff9a0798cf0ad05fe276e62c68e685fb188be5872c2921290beb1","src/event_imp.rs":"f9a2a8101a9a7a9f405233407e09cd402dc09b904fa551046433474c454b8e40","src/io.rs":"9207ffc93ea744b09bc6872fa4d378d7c75640f9ac38b1fa67b940c7cb5d0ade","src/lib.rs":"124e136a035e2cbf0345a9aaed6b8f49d3420cc9a885080695e1399bf07607dc","src/net/mod.rs":"340c63a8efe9ee774b7bf8ed8c0f72fc7563e5c4b35f6a8b243f92d366e145a2","src/net/tcp.rs":"034010d098d1fb2e5385fa6fe40e012ee4876338f6e970fb00282472fff44963","src/net/udp.rs":"4400029c4544f9d6c58c5e7fd4699a70e1a6822f4ef4690d33b0573cfb66e17c","src/poll.rs":"712fce86993089ce01f32d7026866be8380742ac5552cd2785652bc509cb35bc","src/sys/fuchsia/awakener.rs":"71a4a0083242457b0a96326c69c0f98b23dfdb97be96deb26ee02fa9d1dfb212","src/sys/fuchsia/eventedfd.rs":"bd8f43d2b61cdd6a5d0df9c0dc1cb43e1708140d01a05611055277ed55a33b63","src/sys/fuchsia/handles.rs":"161a69e8a8d7f71326a9c53bcb7685d0a81d184aba8e20da27c64aa27dfd56b2","src/sys/fuchsia/mod.rs":"9d80f1214abc93f48b6b6c12ce5b6cfaddbda592c8f3410564d0237228cae2d0","src/sys/fuchsia/net.rs":"50340191dd9cbe317bd6e6ae0170c03daa9141f15c96782b96484e3d8b8301b1","src/sys/fuchsia/ready.rs":"7e6bb7235c52ab4a2134d36cf982f6a4fd6e18050e737b40ee84c89a10a9faac","src/sys/fuchsia/selector.rs":"f3be7f8d683d43e4a8313246e4cacb9444549bf66ecb2234f0d0f53172043bf5","src/sys/mod.rs":"64bea046e4a9feb1f2e2fb8326452c1be8b9d56cf8794df0af4fbdf565204255","src/sys/unix/awakener.rs":"20a61d8f39b2f2abf4f166a3ed46fa0d79907ddf92758eaddb880c67321db56c","src/sys/unix/dlsym.rs":"559337d1f6c10e6c1172bd3908a9dcfa5a0828b53b04f7ca3a0d926afa85cd63","src/sys/unix/epoll.rs":"d72d1fde44ed1859ec0b29dad9637cba92a199d4457ad2a647f1372be9429742","src/sys/unix/eventedfd.rs":"c9c4aefc218e48b90a9f8703923afb0fe60d5316824501e49365e2c64804a1d0","src/sys/unix/io.rs":"a518f09020f821e87bcf9c2ecb4bf501d428619ddfd7b35a26629b614919b14c","src/sys/unix/kqueue.rs":"c852e7358d8f2c247f5ab9c77c1b76631ad4ab0c582af0954c72c7380ba8cc97","src/sys/unix/mod.rs":"62331824b1f5022e372b875faad41a970abb13e63c15e3fae9af948a2b06e4e1","src/sys/unix/ready.rs":"bf76f97c0dc9dfe870b8e865ea03ebbdfa939494a6fea809ac530d8055a56ec0","src/sys/unix/tcp.rs":"811f76bf5ee53363b2f957cdf7db4dbcc995b0c3263eab8b9f240b7f03ba5bbe","src/sys/unix/udp.rs":"c51220d49455bee0072a87f1434e03bf51947c80a7f2bae94402dc3475de795f","src/sys/unix/uds.rs":"fabaf91c64a51de45c2e3142932b1da604206efe888d4aa365d795cfe19e5beb","src/sys/windows/awakener.rs":"2d3cdaf8b523675e2f64c5fd81e1197d5255384517b9753b718c5c47acf0cabd","src/sys/windows/buffer_pool.rs":"636f4b7510a507f9985987699ce8ec140b2ed852abb231443ee1486c80759eed","src/sys/windows/from_raw_arc.rs":"659dabdf5037546e3783aacc422992b4248b0ba2ddcce52b149d35bc723550e5","src/sys/windows/mod.rs":"afeec8cd4e3adeaf6ffe68b134ad1b4ba07faa3abae96f6f9a00bbc20ff5f2c5","src/sys/windows/selector.rs":"e971a04e56104dee3271512497e31634eae06ed04029e4637041609efeb9f7d0","src/sys/windows/tcp.rs":"dbba36ef0459b4331f8f3199d8eef8fe16e0ab5b196aadfc3cc0a80097c9011c","src/sys/windows/udp.rs":"1ef869b660bcf89ea6498552474abf8f540946631e14d5b610ca31014cd9045f","src/timer.rs":"aaebc4729dcddd60fe90a46e6ac053a4dcaba705355ea974730fb9d76f5e429f","src/token.rs":"4a56f851709470df2eed803c57c68b0a4b12ea86fa1b8d2c999bec7a85d58ec0","src/udp.rs":"442e620f3ea0cf010497d3ad775debd585f28e79a025993d40471c8e6839dc98","test/benchmark.rs":"d655cd4a79b11555df4d46e929134d73f2e49e174a59f66b98904a6b9a2779e3","test/mod.rs":"1a4ff0285b09c9b7433f49388e789c8d003a7137d0778ec0a840b06959c8fc2b","test/test_battery.rs":"cea7470a896a5bb09cb45c0658bc80f48ab92f07662e95eceb0cfd70065cd84f","test/test_broken_pipe.rs":"1e8352a22a8b3fe170aa8bb942dc4a2ddd0fb5e69374733e6bcfa324481da648","test/test_close_on_drop.rs":"403b5e8477d3f4309c8d1568ed05a57af50393baa228e91cc7a0d29bb77bcbaa","test/test_custom_evented.rs":"02f113cbbbb4c0d09767bc17434b12acf6de1dd6b6ee20106b5f40ce2f0b46ed","test/test_double_register.rs":"f48b1b5aee68f0c3fef8895c8b9f2cf2446e670f3d0e7249ec300067df783617","test/test_echo_server.rs":"c4fadaf9f226e4ac2066369200792bf890bdec09ccd699370c573f960a4eb52b","test/test_fuchsia_handles.rs":"1e4fc0920b4067a4ece7487067af4f6e3f18e8e55b0fd636ccc2d333f8ade70f","test/test_local_addr_ready.rs":"0a9cd42cb43b5afcc139b1def8278f2a24834e40f96c4ea69f05c4f3263f7c65","test/test_multicast.rs":"cbd85c94971c07bd269d72eb80f53a3bcd57075f7acb7475c2d73efb28e816af","test/test_notify.rs":"ee98f24cb72690756b4bff5983c642a251cd253851f7c1c8f1adf29bf2b97287","test/test_oneshot.rs":"3f618c167734b1ce4695691955fb01224c6abf0a1cc1e1db9e01248fb9edbd3c","test/test_poll.rs":"ad450ff65e9ab8108d424b3b8cf4c82847fb9927f12e749f0aee1228bd5db7da","test/test_poll_channel.rs":"8414e7d27e32bec5c8ea0341f4f2708eb64853cfb6d28689deb58d90b1619120","test/test_register_deregister.rs":"c10612421b097d4a8b0a73a0440f11fe1f8c4f34c701255af6da62bf4fa5a08e","test/test_register_multiple_event_loops.rs":"e0f3115ef938ceed2eae47ea1630c7f440a860b69ab57b70507cf8062fc21eb9","test/test_reregister_without_poll.rs":"30ebba86b936bc283575f8f15237bd1f616ea09516bf34912a27ce6c7b5a5559","test/test_smoke.rs":"f1c4c52509537a76975354dbd9a91e16b14e53f8b30171c57ebf59ff4d935bcc","test/test_subprocess_pipe.rs":"324b68e1cb2d43bec204d41064f6873640cf61970718da3703506f0e5ebad31d","test/test_tcp.rs":"dc7e8684e53099b13e0828cddbc0985755d041c8b20408d57fe12d4bb7c28c3f","test/test_tcp_level.rs":"4f7b9615c6b47ccce5787f1e3b0b4f26e56af9b310c9ca687ec2d08126937478","test/test_tick.rs":"e5bbbcad3106da6419147bb0775d0ad5203d90adb1a9ee61de2128d95600bd5c","test/test_udp_level.rs":"c47b99cd614d5115fe59ed3afdbe56e0a4bf16884da7f03bab54ba4a513a3893","test/test_udp_socket.rs":"4bccb59ff803ed9acfc61c58b2d6f19fbdf1cf78ec12eba59902582b0a1acaa8","test/test_uds_shutdown.rs":"ea3bfdca353116fc3a55a7fb5156a1c67229b3ff2057cc06d83ed73768436894","test/test_unix_echo_server.rs":"5f39c69f846a6d60d7f0018a62c212be68032211cf653748fba312edb12206b7","test/test_unix_pass_fd.rs":"a8a4f5b9e0acfae22a53192b037cd3c398c43d8514c60e25468bafe1cb9ccd72","test/test_write_then_drop.rs":"2e58df792cd794306d0b9a068a69ff084352545d295aceedb92b67472be7f1b0"},"package":"71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432"} \ No newline at end of file diff --git a/third_party/rust/mio/CHANGELOG.md b/third_party/rust/mio/CHANGELOG.md index 31a6f4bbd037..5ca26f6133ce 100644 --- a/third_party/rust/mio/CHANGELOG.md +++ b/third_party/rust/mio/CHANGELOG.md @@ -1,3 +1,8 @@ +# 0.6.16 (September 5, 2018) + +* Add EPOLLPRI readiness to UnixReady on supported platforms (#867) +* Reduce spurious awaken calls (#875) + # 0.6.15 (July 3, 2018) * Implement `Evented` for containers (#840). diff --git a/third_party/rust/mio/Cargo.toml b/third_party/rust/mio/Cargo.toml index 0b80bfb55723..9211558ac638 100644 --- a/third_party/rust/mio/Cargo.toml +++ b/third_party/rust/mio/Cargo.toml @@ -12,12 +12,12 @@ [package] name = "mio" -version = "0.6.15" +version = "0.6.16" authors = ["Carl Lerche "] exclude = [".gitignore", ".travis.yml", "deploy.sh"] description = "Lightweight non-blocking IO" homepage = "https://github.com/carllerche/mio" -documentation = "https://docs.rs/mio" +documentation = "https://docs.rs/mio/0.6.16/mio/" readme = "README.md" keywords = ["io", "async", "non-blocking"] categories = ["asynchronous"] @@ -31,7 +31,7 @@ path = "test/mod.rs" version = "0.1.1" [dependencies.lazycell] -version = "0.6.0" +version = "1" [dependencies.log] version = "0.4" diff --git a/third_party/rust/mio/ci/ios/deploy_and_run_on_ios_simulator.rs b/third_party/rust/mio/ci/ios/deploy_and_run_on_ios_simulator.rs deleted file mode 100644 index 542d3e9bd443..000000000000 --- a/third_party/rust/mio/ci/ios/deploy_and_run_on_ios_simulator.rs +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// This is a script to deploy and execute a binary on an iOS simulator. -// The primary use of this is to be able to run unit tests on the simulator and -// retrieve the results. -// -// To do this through Cargo instead, use Dinghy -// (https://github.com/snipsco/dinghy): cargo dinghy install, then cargo dinghy -// test. - -use std::env; -use std::fs::{self, File}; -use std::io::Write; -use std::path::Path; -use std::thread; -use std::process::{self, Command, Stdio}; - -macro_rules! t { - ($e:expr) => (match $e { - Ok(e) => e, - Err(e) => panic!("{} failed with: {}", stringify!($e), e), - }) -} - -// Step one: Wrap as an app -fn package_as_simulator_app(crate_name: &str, test_binary_path: &Path) { - println!("Packaging simulator app"); - drop(fs::remove_dir_all("ios_simulator_app")); - t!(fs::create_dir("ios_simulator_app")); - t!(fs::copy(test_binary_path, - Path::new("ios_simulator_app").join(crate_name))); - - let mut f = t!(File::create("ios_simulator_app/Info.plist")); - t!(f.write_all(format!(r#" - - - - - CFBundleExecutable - {} - CFBundleIdentifier - com.rust.unittests - - - "#, crate_name).as_bytes())); -} - -// Step two: Start the iOS simulator -fn start_simulator() { - println!("Looking for iOS simulator"); - let output = t!(Command::new("xcrun").arg("simctl").arg("list").output()); - assert!(output.status.success()); - let mut simulator_exists = false; - let mut simulator_booted = false; - let mut found_rust_sim = false; - let stdout = t!(String::from_utf8(output.stdout)); - for line in stdout.lines() { - if line.contains("rust_ios") { - if found_rust_sim { - panic!("Duplicate rust_ios simulators found. Please \ - double-check xcrun simctl list."); - } - simulator_exists = true; - simulator_booted = line.contains("(Booted)"); - found_rust_sim = true; - } - } - - if simulator_exists == false { - println!("Creating iOS simulator"); - Command::new("xcrun") - .arg("simctl") - .arg("create") - .arg("rust_ios") - .arg("com.apple.CoreSimulator.SimDeviceType.iPhone-SE") - .arg("com.apple.CoreSimulator.SimRuntime.iOS-10-2") - .check_status(); - } else if simulator_booted == true { - println!("Shutting down already-booted simulator"); - Command::new("xcrun") - .arg("simctl") - .arg("shutdown") - .arg("rust_ios") - .check_status(); - } - - println!("Starting iOS simulator"); - // We can't uninstall the app (if present) as that will hang if the - // simulator isn't completely booted; just erase the simulator instead. - Command::new("xcrun").arg("simctl").arg("erase").arg("rust_ios").check_status(); - Command::new("xcrun").arg("simctl").arg("boot").arg("rust_ios").check_status(); -} - -// Step three: Install the app -fn install_app_to_simulator() { - println!("Installing app to simulator"); - Command::new("xcrun") - .arg("simctl") - .arg("install") - .arg("booted") - .arg("ios_simulator_app/") - .check_status(); -} - -// Step four: Run the app -fn run_app_on_simulator() { - use std::io::{self, Read, Write}; - - println!("Running app"); - let mut child = t!(Command::new("xcrun") - .arg("simctl") - .arg("launch") - .arg("--console") - .arg("booted") - .arg("com.rust.unittests") - .arg("--color") - .arg("never") - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn()); - - let stdout = child.stdout.take().unwrap(); - let stderr = child.stderr.take().unwrap(); - - let th = thread::spawn(move || { - let mut out = vec![]; - - for b in stdout.bytes() { - let b = b.unwrap(); - out.push(b); - let out = [b]; - io::stdout().write(&out[..]).unwrap(); - } - - out - }); - - thread::spawn(move || { - for b in stderr.bytes() { - let out = [b.unwrap()]; - io::stderr().write(&out[..]).unwrap(); - } - }); - - println!("Waiting for cmd to finish"); - child.wait().unwrap(); - - println!("Waiting for stdout"); - let stdout = th.join().unwrap(); - let stdout = String::from_utf8_lossy(&stdout); - let passed = stdout.lines() - .find(|l| l.contains("test result")) - .map(|l| l.contains(" 0 failed")) - .unwrap_or(false); - - println!("Shutting down simulator"); - Command::new("xcrun") - .arg("simctl") - .arg("shutdown") - .arg("rust_ios") - .check_status(); - if !passed { - panic!("tests didn't pass"); - } -} - -trait CheckStatus { - fn check_status(&mut self); -} - -impl CheckStatus for Command { - fn check_status(&mut self) { - println!("\trunning: {:?}", self); - assert!(t!(self.status()).success()); - } -} - -fn main() { - let args: Vec = env::args().collect(); - if args.len() != 2 { - println!("Usage: {} ", args[0]); - process::exit(-1); - } - - let test_binary_path = Path::new(&args[1]); - let crate_name = test_binary_path.file_name().unwrap(); - - package_as_simulator_app(crate_name.to_str().unwrap(), test_binary_path); - start_simulator(); - install_app_to_simulator(); - run_app_on_simulator(); -} diff --git a/third_party/rust/mio/ci/run-ios.sh b/third_party/rust/mio/ci/run-ios.sh deleted file mode 100755 index 027c54e126af..000000000000 --- a/third_party/rust/mio/ci/run-ios.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh - -# Builds and runs tests for a particular target passed as an argument to this -# script. - -set -ex - -TARGET=$1 - - -case "$TARGET" in - *-apple-ios) - # Download the iOS test harness - curl -vv -L https://github.com/carllerche/ios-test-harness/releases/download/v0.1.0/libiosharness-$TARGET.a > libiosharness.a; - - # Build the test - cargo rustc --test test --target $TARGET -- \ - -L . \ - -C link-args="-mios-simulator-version-min=7.0 -e _ios_main -liosharness"; - - - # Find the file to run - TEST_FILE="$(find $TARGET/debug -maxdepth 1 -type f -name test-* | head -1)"; - - rustc -O ./ci/ios/deploy_and_run_on_ios_simulator.rs; - ./deploy_and_run_on_ios_simulator $TEST_FILE; - - ;; - - *) - echo "unsupported target $TARGET"; - exit 1; - ;; -esac diff --git a/third_party/rust/mio/src/event_imp.rs b/third_party/rust/mio/src/event_imp.rs index 6c60aad0fe83..07694d9750ec 100644 --- a/third_party/rust/mio/src/event_imp.rs +++ b/third_party/rust/mio/src/event_imp.rs @@ -718,6 +718,8 @@ impl Ready { /// let ready = Ready::empty(); /// assert!(ready.is_empty()); /// ``` + /// + /// [`Poll`]: struct.Poll.html #[inline] pub fn is_empty(&self) -> bool { *self == Ready::empty() diff --git a/third_party/rust/mio/src/lib.rs b/third_party/rust/mio/src/lib.rs index d26628fd50e3..dbd197cafd4e 100644 --- a/third_party/rust/mio/src/lib.rs +++ b/third_party/rust/mio/src/lib.rs @@ -1,3 +1,7 @@ +#![doc(html_root_url = "https://docs.rs/mio/0.6.16")] +#![deny(missing_docs, missing_debug_implementations)] +#![cfg_attr(test, deny(warnings))] + //! A fast, low-level IO library for Rust focusing on non-blocking APIs, event //! notification, and other useful utilities for building high performance IO //! apps. @@ -90,11 +94,6 @@ //! //! ``` -#![doc(html_root_url = "https://docs.rs/mio/0.6.15")] -#![crate_name = "mio"] - -#![deny(warnings, missing_docs, missing_debug_implementations)] - extern crate lazycell; extern crate net2; extern crate iovec; diff --git a/third_party/rust/mio/src/poll.rs b/third_party/rust/mio/src/poll.rs index a2fcf23dfd54..fa3f01165a42 100644 --- a/third_party/rust/mio/src/poll.rs +++ b/third_party/rust/mio/src/poll.rs @@ -695,8 +695,8 @@ impl Poll { /// readiness. `Poll` will only return readiness events for operations /// specified by this argument. /// - /// If a socket is registered with [`readable`] interest and the socket - /// becomes writable, no event will be returned from [`poll`]. + /// If a socket is registered with readable interest and the socket becomes + /// writable, no event will be returned from [`poll`]. /// /// The readiness interest for an `Evented` handle can be changed at any /// time by calling [`reregister`]. @@ -860,7 +860,7 @@ impl Poll { /// /// When an `Evented` handle is deregistered, the `Poll` instance will /// no longer monitor it for readiness state changes. Unlike disabling - /// handles with [`oneshot`], deregistering clears up any internal resources + /// handles with oneshot, deregistering clears up any internal resources /// needed to track the handle. /// /// A handle can be passed back to `register` after it has been @@ -1157,6 +1157,8 @@ impl Poll { if timeout == Some(Duration::from_millis(0)) { // If blocking is not requested, then there is no need to prepare // the queue for sleep + // + // The sleep_marker should be removed by readiness_queue.poll(). } else if self.readiness_queue.prepare_for_sleep() { // The readiness queue is empty. The call to `prepare_for_sleep` // inserts `sleep_marker` into the queue. This signals to any @@ -2116,6 +2118,13 @@ impl ReadinessQueue { // loop where `Poll::poll` will keep dequeuing nodes it enqueues. let mut until = ptr::null_mut(); + if dst.len() == dst.capacity() { + // If `dst` is already full, the readiness queue won't be drained. + // This might result in `sleep_marker` staying in the queue and + // unecessary pipe writes occuring. + self.inner.clear_sleep_marker(); + } + 'outer: while dst.len() < dst.capacity() { // Dequeue a node. If the queue is in an inconsistent state, then @@ -2353,6 +2362,37 @@ impl ReadinessQueueInner { } } + fn clear_sleep_marker(&self) { + let end_marker = self.end_marker(); + let sleep_marker = self.sleep_marker(); + + unsafe { + let tail = *self.tail_readiness.get(); + + if tail != self.sleep_marker() { + return; + } + + // The empty markeer is *not* currently in the readiness queue + // (since the sleep markeris). + self.end_marker.next_readiness.store(ptr::null_mut(), Relaxed); + + let actual = self.head_readiness.compare_and_swap( + sleep_marker, end_marker, AcqRel); + + debug_assert!(actual != end_marker); + + if actual != sleep_marker { + // The readiness queue is not empty, we cannot remove the sleep + // markeer + return; + } + + // Update the tail pointer. + *self.tail_readiness.get() = end_marker; + } + } + /// Must only be called in `poll` or `drop` unsafe fn dequeue_node(&self, until: *mut ReadinessNode) -> Dequeue { // This is the 1024cores.net intrusive MPSC queue [1] "pop" function @@ -2362,6 +2402,10 @@ impl ReadinessQueueInner { if tail == self.end_marker() || tail == self.sleep_marker() || tail == self.closed_marker() { if next.is_null() { + // Make sure the sleep marker is removed (as we are no longer + // sleeping + self.clear_sleep_marker(); + return Dequeue::Empty; } diff --git a/third_party/rust/mio/src/sys/unix/epoll.rs b/third_party/rust/mio/src/sys/unix/epoll.rs index 50b2a14e4906..313ae256dedf 100644 --- a/third_party/rust/mio/src/sys/unix/epoll.rs +++ b/third_party/rust/mio/src/sys/unix/epoll.rs @@ -145,6 +145,11 @@ fn ioevent_to_epoll(interest: Ready, opts: PollOpt) -> u32 { kind |= EPOLLRDHUP; } + + if UnixReady::from(interest).is_priority() { + kind |= EPOLLPRI; + } + if opts.is_edge() { kind |= EPOLLET; } @@ -206,10 +211,14 @@ impl Events { let epoll = event.events as c_int; let mut kind = Ready::empty(); - if (epoll & EPOLLIN) != 0 || (epoll & EPOLLPRI) != 0 { + if (epoll & EPOLLIN) != 0 { kind = kind | Ready::readable(); } + if (epoll & EPOLLPRI) != 0 { + kind = kind | Ready::readable() | UnixReady::priority(); + } + if (epoll & EPOLLOUT) != 0 { kind = kind | Ready::writable(); } diff --git a/third_party/rust/mio/src/sys/unix/ready.rs b/third_party/rust/mio/src/sys/unix/ready.rs index 398fc17ccf21..b57a4d7df563 100644 --- a/third_party/rust/mio/src/sys/unix/ready.rs +++ b/third_party/rust/mio/src/sys/unix/ready.rs @@ -109,6 +109,11 @@ const LIO: usize = 0b100000; #[cfg(not(any(target_os = "freebsd")))] const LIO: usize = 0b000000; + +#[cfg(any(target_os = "linux", target_os = "android", target_os = "solaris"))] +const PRI: usize = ::libc::EPOLLPRI as usize; + + // Export to support `Ready::all` pub const READY_ALL: usize = ERROR | HUP | AIO | LIO; @@ -219,6 +224,28 @@ impl UnixReady { UnixReady(ready_from_usize(LIO)) } + /// Returns a `Ready` representing priority (`EPOLLPRI`) readiness + /// + /// See [`Poll`] for more documentation on polling. + /// + /// # Examples + /// + /// ``` + /// use mio::unix::UnixReady; + /// + /// let ready = UnixReady::priority(); + /// + /// assert!(ready.is_priority()); + /// ``` + /// + /// [`Poll`]: struct.Poll.html + #[inline] + #[cfg(any(target_os = "linux", + target_os = "android", target_os = "solaris"))] + pub fn priority() -> UnixReady { + UnixReady(ready_from_usize(PRI)) + } + /// Returns true if `Ready` contains AIO readiness /// /// See [`Poll`] for more documentation on polling. @@ -323,6 +350,28 @@ impl UnixReady { pub fn is_lio(&self) -> bool { self.contains(ready_from_usize(LIO)) } + + /// Returns true if `Ready` contains priority (`EPOLLPRI`) readiness + /// + /// See [`Poll`] for more documentation on polling. + /// + /// # Examples + /// + /// ``` + /// use mio::unix::UnixReady; + /// + /// let ready = UnixReady::priority(); + /// + /// assert!(ready.is_priority()); + /// ``` + /// + /// [`Poll`]: struct.Poll.html + #[inline] + #[cfg(any(target_os = "linux", + target_os = "android", target_os = "solaris"))] + pub fn is_priority(&self) -> bool { + self.contains(ready_from_usize(PRI)) + } } impl From for UnixReady { @@ -408,7 +457,11 @@ impl fmt::Debug for UnixReady { (UnixReady::error(), "Error"), (UnixReady::hup(), "Hup"), #[allow(deprecated)] - (UnixReady::aio(), "Aio")]; + (UnixReady::aio(), "Aio"), + #[cfg(any(target_os = "linux", + target_os = "android", target_os = "solaris"))] + (UnixReady::priority(), "Priority"), + ]; for &(flag, msg) in &flags { if self.contains(flag) { diff --git a/third_party/rust/mio/test/mod.rs b/third_party/rust/mio/test/mod.rs index 75cda53f4461..5e5b92a49305 100644 --- a/third_party/rust/mio/test/mod.rs +++ b/third_party/rust/mio/test/mod.rs @@ -45,9 +45,6 @@ mod test_tick; // platforms that were supported from before the features were deprecated #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] #[cfg(feature = "with-deprecated")] -mod test_timer; -#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] -#[cfg(feature = "with-deprecated")] mod test_battery; #[cfg(any(target_os = "macos", target_os = "linux"))] diff --git a/third_party/rust/mio/test/test_timer.rs b/third_party/rust/mio/test/test_timer.rs deleted file mode 100644 index 63d7fb53d291..000000000000 --- a/third_party/rust/mio/test/test_timer.rs +++ /dev/null @@ -1,433 +0,0 @@ -use {sleep_ms, TryRead, TryWrite}; -use mio::*; -use mio::deprecated::{EventLoop, Handler}; -use mio::timer::{Timer}; - -use mio::net::{TcpListener, TcpStream}; -use bytes::{Buf, ByteBuf, SliceBuf}; -use localhost; -use std::time::Duration; - -use self::TestState::{Initial, AfterRead}; - -#[test] -fn test_basic_timer_without_poll() { - let mut timer = Timer::default(); - - // Set the timeout - timer.set_timeout(Duration::from_millis(200), "hello").unwrap(); - - // Nothing when polled immediately - assert!(timer.poll().is_none()); - - // Wait for the timeout - sleep_ms(200); - - assert_eq!(Some("hello"), timer.poll()); - assert!(timer.poll().is_none()); -} - -#[test] -fn test_basic_timer_with_poll_edge_set_timeout_after_register() { - let _ = ::env_logger::init(); - - let poll = Poll::new().unwrap(); - let mut events = Events::with_capacity(1024); - let mut timer = Timer::default(); - - poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()).unwrap(); - timer.set_timeout(Duration::from_millis(200), "hello").unwrap(); - - let elapsed = elapsed(|| { - let num = poll.poll(&mut events, None).unwrap(); - - assert_eq!(num, 1); - assert_eq!(Token(0), events.get(0).unwrap().token()); - assert_eq!(Ready::readable(), events.get(0).unwrap().readiness()); - }); - - assert!(is_about(200, elapsed), "actual={:?}", elapsed); - assert_eq!("hello", timer.poll().unwrap()); - assert_eq!(None, timer.poll()); -} - -#[test] -fn test_basic_timer_with_poll_edge_set_timeout_before_register() { - let _ = ::env_logger::init(); - - let poll = Poll::new().unwrap(); - let mut events = Events::with_capacity(1024); - let mut timer = Timer::default(); - - timer.set_timeout(Duration::from_millis(200), "hello").unwrap(); - poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()).unwrap(); - - let elapsed = elapsed(|| { - let num = poll.poll(&mut events, None).unwrap(); - - assert_eq!(num, 1); - assert_eq!(Token(0), events.get(0).unwrap().token()); - assert_eq!(Ready::readable(), events.get(0).unwrap().readiness()); - }); - - assert!(is_about(200, elapsed), "actual={:?}", elapsed); - assert_eq!("hello", timer.poll().unwrap()); - assert_eq!(None, timer.poll()); -} - -#[test] -fn test_setting_later_timeout_then_earlier_one() { - let _ = ::env_logger::init(); - - let poll = Poll::new().unwrap(); - let mut events = Events::with_capacity(1024); - let mut timer = Timer::default(); - - poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()).unwrap(); - - timer.set_timeout(Duration::from_millis(600), "hello").unwrap(); - timer.set_timeout(Duration::from_millis(200), "world").unwrap(); - - let elapsed = elapsed(|| { - let num = poll.poll(&mut events, None).unwrap(); - - assert_eq!(num, 1); - assert_eq!(Token(0), events.get(0).unwrap().token()); - assert_eq!(Ready::readable(), events.get(0).unwrap().readiness()); - }); - - assert!(is_about(200, elapsed), "actual={:?}", elapsed); - assert_eq!("world", timer.poll().unwrap()); - assert_eq!(None, timer.poll()); - - let elapsed = self::elapsed(|| { - let num = poll.poll(&mut events, None).unwrap(); - - assert_eq!(num, 1); - assert_eq!(Token(0), events.get(0).unwrap().token()); - assert_eq!(Ready::readable(), events.get(0).unwrap().readiness()); - }); - - assert!(is_about(400, elapsed), "actual={:?}", elapsed); - assert_eq!("hello", timer.poll().unwrap()); - assert_eq!(None, timer.poll()); -} - -#[test] -fn test_timer_with_looping_wheel() { - let _ = ::env_logger::init(); - - let poll = Poll::new().unwrap(); - let mut events = Events::with_capacity(1024); - let mut timer = timer::Builder::default() - .num_slots(2) - .build(); - - poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()).unwrap(); - - const TOKENS: &'static [ &'static str ] = &[ "hello", "world", "some", "thing" ]; - - for (i, msg) in TOKENS.iter().enumerate() { - timer.set_timeout(Duration::from_millis(500 * (i as u64 + 1)), msg).unwrap(); - } - - for msg in TOKENS { - let elapsed = elapsed(|| { - let num = poll.poll(&mut events, None).unwrap(); - - assert_eq!(num, 1); - assert_eq!(Token(0), events.get(0).unwrap().token()); - assert_eq!(Ready::readable(), events.get(0).unwrap().readiness()); - }); - - assert!(is_about(500, elapsed), "actual={:?}; msg={:?}", elapsed, msg); - assert_eq!(Some(msg), timer.poll()); - assert_eq!(None, timer.poll()); - - } -} - -#[test] -fn test_edge_without_polling() { - let _ = ::env_logger::init(); - - let poll = Poll::new().unwrap(); - let mut events = Events::with_capacity(1024); - let mut timer = Timer::default(); - - poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()).unwrap(); - - timer.set_timeout(Duration::from_millis(400), "hello").unwrap(); - - let ms = elapsed(|| { - let num = poll.poll(&mut events, None).unwrap(); - assert_eq!(num, 1); - assert_eq!(Token(0), events.get(0).unwrap().token()); - assert_eq!(Ready::readable(), events.get(0).unwrap().readiness()); - }); - - assert!(is_about(400, ms), "actual={:?}", ms); - - let ms = elapsed(|| { - let num = poll.poll(&mut events, Some(Duration::from_millis(300))).unwrap(); - assert_eq!(num, 0); - }); - - assert!(is_about(300, ms), "actual={:?}", ms); -} - -#[test] -fn test_level_triggered() { - let _ = ::env_logger::init(); - - let poll = Poll::new().unwrap(); - let mut events = Events::with_capacity(1024); - let mut timer = Timer::default(); - - poll.register(&timer, Token(0), Ready::readable(), PollOpt::level()).unwrap(); - - timer.set_timeout(Duration::from_millis(400), "hello").unwrap(); - - let ms = elapsed(|| { - let num = poll.poll(&mut events, None).unwrap(); - assert_eq!(num, 1); - assert_eq!(Token(0), events.get(0).unwrap().token()); - assert_eq!(Ready::readable(), events.get(0).unwrap().readiness()); - }); - - assert!(is_about(400, ms), "actual={:?}", ms); - - let ms = elapsed(|| { - let num = poll.poll(&mut events, None).unwrap(); - assert_eq!(num, 1); - assert_eq!(Token(0), events.get(0).unwrap().token()); - assert_eq!(Ready::readable(), events.get(0).unwrap().readiness()); - }); - - assert!(is_about(0, ms), "actual={:?}", ms); -} - -#[test] -fn test_edge_oneshot_triggered() { - let _ = ::env_logger::init(); - - let poll = Poll::new().unwrap(); - let mut events = Events::with_capacity(1024); - let mut timer = Timer::default(); - - poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge() | PollOpt::oneshot()).unwrap(); - - timer.set_timeout(Duration::from_millis(200), "hello").unwrap(); - - let ms = elapsed(|| { - let num = poll.poll(&mut events, None).unwrap(); - assert_eq!(num, 1); - }); - - assert!(is_about(200, ms), "actual={:?}", ms); - - let ms = elapsed(|| { - let num = poll.poll(&mut events, Some(Duration::from_millis(300))).unwrap(); - assert_eq!(num, 0); - }); - - assert!(is_about(300, ms), "actual={:?}", ms); - - poll.reregister(&timer, Token(0), Ready::readable(), PollOpt::edge() | PollOpt::oneshot()).unwrap(); - - let ms = elapsed(|| { - let num = poll.poll(&mut events, None).unwrap(); - assert_eq!(num, 1); - }); - - assert!(is_about(0, ms)); -} - -#[test] -fn test_cancel_timeout() { - use std::time::Instant; - - let _ = ::env_logger::init(); - - let mut timer: Timer = Default::default(); - let timeout = timer.set_timeout(Duration::from_millis(200), 1).unwrap(); - timer.cancel_timeout(&timeout); - - let poll = Poll::new().unwrap(); - poll.register(&timer, Token(0), Ready::readable(), PollOpt::edge()).unwrap(); - - let mut events = Events::with_capacity(16); - - let now = Instant::now(); - let dur = Duration::from_millis(500); - let mut i = 0; - - while Instant::now() - now < dur { - if i > 10 { - panic!("iterated too many times"); - } - - i += 1; - - let elapsed = Instant::now() - now; - - poll.poll(&mut events, Some(dur - elapsed)).unwrap(); - - while let Some(_) = timer.poll() { - panic!("did not expect to receive timeout"); - } - } -} - -fn elapsed(mut f: F) -> u64 { - use std::time::Instant; - - let now = Instant::now(); - - f(); - - let elapsed = now.elapsed(); - elapsed.as_secs() * 1000 + (elapsed.subsec_nanos() / 1_000_000) as u64 -} - -fn is_about(expect: u64, val: u64) -> bool { - const WINDOW: i64 = 200; - - ((expect as i64) - (val as i64)).abs() <= WINDOW -} - -/* - * - * ===== OLD TIMER ===== - * - */ - -const SERVER: Token = Token(0); -const CLIENT: Token = Token(1); -const CONN: Token = Token(2); - -#[derive(Debug, PartialEq)] -enum TestState { - Initial, - AfterRead, -} - -struct TestHandler { - srv: TcpListener, - cli: TcpStream, - state: TestState -} - -impl TestHandler { - fn new(srv: TcpListener, cli: TcpStream) -> TestHandler { - TestHandler { - srv: srv, - cli: cli, - state: Initial - } - } - - fn handle_read(&mut self, event_loop: &mut EventLoop, - tok: Token, _events: Ready) { - match tok { - SERVER => { - debug!("server connection ready for accept"); - let conn = self.srv.accept().unwrap().0; - event_loop.register(&conn, CONN, Ready::readable() | Ready::writable(), - PollOpt::edge()).unwrap(); - event_loop.timeout(conn, Duration::from_millis(200)).unwrap(); - - event_loop.reregister(&self.srv, SERVER, Ready::readable(), - PollOpt::edge()).unwrap(); - } - CLIENT => { - debug!("client readable"); - - match self.state { - Initial => self.state = AfterRead, - AfterRead => {} - } - - let mut buf = ByteBuf::mut_with_capacity(2048); - - match self.cli.try_read_buf(&mut buf) { - Ok(Some(0)) => return event_loop.shutdown(), - Ok(n) => { - debug!("read {:?} bytes", n); - assert!(b"zomg" == buf.flip().bytes()); - } - Err(e) => { - debug!("client sock failed to read; err={:?}", e.kind()); - } - } - - event_loop.reregister(&self.cli, CLIENT, - Ready::readable() | Ready::hup(), - PollOpt::edge()).unwrap(); - } - CONN => {} - _ => panic!("received unknown token {:?}", tok), - } - } - - fn handle_write(&mut self, event_loop: &mut EventLoop, - tok: Token, _: Ready) { - match tok { - SERVER => panic!("received writable for token 0"), - CLIENT => debug!("client connected"), - CONN => {} - _ => panic!("received unknown token {:?}", tok), - } - - event_loop.reregister(&self.cli, CLIENT, Ready::readable(), - PollOpt::edge()).unwrap(); - } -} - -impl Handler for TestHandler { - type Timeout = TcpStream; - type Message = (); - - fn ready(&mut self, event_loop: &mut EventLoop, tok: Token, events: Ready) { - if events.is_readable() { - self.handle_read(event_loop, tok, events); - } - - if events.is_writable() { - self.handle_write(event_loop, tok, events); - } - } - - fn timeout(&mut self, _event_loop: &mut EventLoop, mut sock: TcpStream) { - debug!("timeout handler : writing to socket"); - sock.try_write_buf(&mut SliceBuf::wrap(b"zomg")).unwrap().unwrap(); - } -} - -#[test] -pub fn test_old_timer() { - let _ = ::env_logger::init(); - - debug!("Starting TEST_TIMER"); - let mut event_loop = EventLoop::new().unwrap(); - - let addr = localhost(); - - let srv = TcpListener::bind(&addr).unwrap(); - - info!("listening for connections"); - - event_loop.register(&srv, SERVER, Ready::readable() | Ready::writable(), PollOpt::edge()).unwrap(); - - let sock = TcpStream::connect(&addr).unwrap(); - - // Connect to the server - event_loop.register(&sock, CLIENT, Ready::readable() | Ready::writable(), PollOpt::edge()).unwrap(); - - // Init the handler - let mut handler = TestHandler::new(srv, sock); - // Start the event loop - event_loop.run(&mut handler).unwrap(); - - assert!(handler.state == AfterRead, "actual={:?}", handler.state); -} diff --git a/third_party/rust/rand-0.4.3/.cargo-checksum.json b/third_party/rust/rand-0.4.3/.cargo-checksum.json new file mode 100644 index 000000000000..824131b10bc6 --- /dev/null +++ b/third_party/rust/rand-0.4.3/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"460c7dbfdf227b4c725f7da8131fd51a54d0355b3c5804c0d388c70d3c1c49ec","Cargo.toml":"7d29da51fe4bf73964b3b3dea0af88040514569e2d184c9e8eb2f1746d540fb7","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"fb8071c3bc1013107b16ebcb303f31ef614e81440f2d58a46bfb9ff1e311b792","appveyor.yml":"8796156caf7041ef2a43f7a313df21ea639de3f2563b6181bba1096b1c489f1b","benches/bench.rs":"35c4ab609f2a5f5aab6c52c257415258dc0780621b492b5a82bb12d048cab6db","benches/distributions/exponential.rs":"99cb59c013a0b6bb390d34c5649b341fc3b88ea7df0caf2470bdda8798f9fe3d","benches/distributions/gamma.rs":"3533f311e4b55d743c5b01a7eb6529c94fd97726ef6702a6372f914f5f33666b","benches/distributions/mod.rs":"0028f1cb96f61152ed5b49a4fe91227d809ef6d19035592c36032a538af7f95e","benches/distributions/normal.rs":"4e10c18cb583ccb96301ea953c8e0aa9ee3b6662060271d1b8d19ca23364dc6b","benches/generators.rs":"aaa2f1dbfb399df8323d8a5796b92add6210cd5f0f1d916895ffdd81d60f812b","benches/misc.rs":"bd2f7c5a16f0fcb59022d5aeef66ed3c94e89ebf6c06667851dd23d0b1595504","src/distributions/exponential.rs":"103c8412c8a581b71835f1c00e40f6370e7702adf9d499243933a793d132d4e7","src/distributions/gamma.rs":"7a3f85c8daad4e56e334586ddb9fc9d83df3b0699738ed681a6c41e4ed455be9","src/distributions/mod.rs":"7943c4f83721bac816f831cca3b1574b6136932f7b4927aa6101130080ba62c5","src/distributions/normal.rs":"1562b43f80e4d5f83a8deb5af18de5a18dfeeeeda11fefc577da26672b14c949","src/distributions/range.rs":"a72a538d3ec4ed23f8d632aa55fd4793c464f24a5872d04ce8095ddd5db92115","src/distributions/ziggurat_tables.rs":"4eacf94fc352c91c455a6623de6a721e53842e1690f13a5662b6a79c7fbb73de","src/jitter.rs":"befd4b84bf753c107370b5b9498ad49611c220bdae2e4be9ee4398e9fa497042","src/lib.rs":"fbdc5f56ce1a52b15c85b0aa70a555c64be8f65d9f6f90fa0a3555d7862666b4","src/os.rs":"4860f165f68b7c978b0488c75d264cd9aaf54e7e4484036736ee5c4f5b6bd78d","src/prng/chacha.rs":"558007276f9c22933d39e5b8e853f4dd9533e823ed66df8dc1f23ad6925b1d51","src/prng/isaac.rs":"a8a2ee8b38d312663308e3bdf03376e342fd91330655f39144e5bba7392b2a8e","src/prng/isaac64.rs":"f28f7596ccab910db265b42671116abb9d2039fa8a421cbc75312bd0e7715d3a","src/prng/mod.rs":"c1a73450f49e819a20942a5b591f84a08ebb5ac33aa0f65b18ac1dc9a19a3084","src/prng/xorshift.rs":"606c308747293652c868b46dc3cad847d0c3717629c04ba75681c887c7634114","src/rand_impls.rs":"e1f27077fc13d5855bb66235f8ccfb216e116337eb38424d9c30c090e112215c","src/read.rs":"bd0eb508a6b659dc578d546fc2f231484aed80c73cfe8c475e0d65c8d699a769","src/reseeding.rs":"a97b86387b87ea1adc5262ddea480fe735c9c2a86762abaace29119022ac9f6e","src/seq.rs":"76dd58af0f580aed2721c393a5c036322186dc7cb3b4abed33436620c7c49288","utils/ziggurat_tables.py":"a9fc0a2fdae9b5c798c238788f94b720c156e13fd96f2356c409aa533191eb94"},"package":"8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"} \ No newline at end of file diff --git a/third_party/rust/rand-0.4.3/CHANGELOG.md b/third_party/rust/rand-0.4.3/CHANGELOG.md new file mode 100644 index 000000000000..1811b458fb7f --- /dev/null +++ b/third_party/rust/rand-0.4.3/CHANGELOG.md @@ -0,0 +1,269 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## [0.4.3] - 2018-08-16 +### Fixed +- Use correct syscall number for PowerPC (#589) + +## [0.4.2] - 2018-01-05 +### Changed +- Use winapi on Windows +- Update for Fuchsia OS +- Remove dev-dependency on `log` + +## [0.4.1] - 2017-12-17 +### Added +- `no_std` support + +## [0.4.0-pre.0] - 2017-12-11 +### Added +- `JitterRng` added as a high-quality alternative entropy source using the + system timer +- new `seq` module with `sample_iter`, `sample_slice`, etc. +- WASM support via dummy implementations (fail at run-time) +- Additional benchmarks, covering generators and new seq code + +### Changed +- `thread_rng` uses `JitterRng` if seeding from system time fails + (slower but more secure than previous method) + +### Deprecated + - `sample` function deprecated (replaced by `sample_iter`) + +## [0.3.18] - 2017-11-06 +### Changed +- `thread_rng` is seeded from the system time if `OsRng` fails +- `weak_rng` now uses `thread_rng` internally + + +## [0.3.17] - 2017-10-07 +### Changed + - Fuchsia: Magenta was renamed Zircon + +## [0.3.16] - 2017-07-27 +### Added +- Implement Debug for mote non-public types +- implement `Rand` for (i|u)i128 +- Support for Fuchsia + +### Changed +- Add inline attribute to SampleRange::construct_range. + This improves the benchmark for sample in 11% and for shuffle in 16%. +- Use `RtlGenRandom` instead of `CryptGenRandom` + + +## [0.3.15] - 2016-11-26 +### Added +- Add `Rng` trait method `choose_mut` +- Redox support + +### Changed +- Use `arc4rand` for `OsRng` on FreeBSD. +- Use `arc4random(3)` for `OsRng` on OpenBSD. + +### Fixed +- Fix filling buffers 4 GiB or larger with `OsRng::fill_bytes` on Windows + + +## [0.3.14] - 2016-02-13 +### Fixed +- Inline definitions from winapi/advapi32, wich decreases build times + + +## [0.3.13] - 2016-01-09 +### Fixed +- Compatible with Rust 1.7.0-nightly (needed some extra type annotations) + + +## [0.3.12] - 2015-11-09 +### Changed +- Replaced the methods in `next_f32` and `next_f64` with the technique described + Saito & Matsumoto at MCQMC'08. The new method should exhibit a slightly more + uniform distribution. +- Depend on libc 0.2 + +### Fixed +- Fix iterator protocol issue in `rand::sample` + + +## [0.3.11] - 2015-08-31 +### Added +- Implement `Rand` for arrays with n <= 32 + + +## [0.3.10] - 2015-08-17 +### Added +- Support for NaCl platforms + +### Changed +- Allow `Rng` to be `?Sized`, impl for `&mut R` and `Box` where `R: ?Sized + Rng` + + +## [0.3.9] - 2015-06-18 +### Changed +- Use `winapi` for Windows API things + +### Fixed +- Fixed test on stable/nightly +- Fix `getrandom` syscall number for aarch64-unknown-linux-gnu + + +## [0.3.8] - 2015-04-23 +### Changed +- `log` is a dev dependency + +### Fixed +- Fix race condition of atomics in `is_getrandom_available` + + +## [0.3.7] - 2015-04-03 +### Fixed +- Derive Copy/Clone changes + + +## [0.3.6] - 2015-04-02 +### Changed +- Move to stable Rust! + + +## [0.3.5] - 2015-04-01 +### Fixed +- Compatible with Rust master + + +## [0.3.4] - 2015-03-31 +### Added +- Implement Clone for `Weighted` + +### Fixed +- Compatible with Rust master + + +## [0.3.3] - 2015-03-26 +### Fixed +- Fix compile on Windows + + +## [0.3.2] - 2015-03-26 + + +## [0.3.1] - 2015-03-26 +### Fixed +- Fix compile on Windows + + +## [0.3.0] - 2015-03-25 +### Changed +- Update to use log version 0.3.x + + +## [0.2.1] - 2015-03-22 +### Fixed +- Compatible with Rust master +- Fixed iOS compilation + + +## [0.2.0] - 2015-03-06 +### Fixed +- Compatible with Rust master (move from `old_io` to `std::io`) + + +## [0.1.4] - 2015-03-04 +### Fixed +- Compatible with Rust master (use wrapping ops) + + +## [0.1.3] - 2015-02-20 +### Fixed +- Compatible with Rust master + +### Removed +- Removed Copy inplementaions from RNGs + + +## [0.1.2] - 2015-02-03 +### Added +- Imported functionality from `std::rand`, including: + - `StdRng`, `SeedableRng`, `TreadRng`, `weak_rng()` + - `ReaderRng`: A wrapper around any Reader to treat it as an RNG. +- Imported documentation from `std::rand` +- Imported tests from `std::rand` + + +## [0.1.1] - 2015-02-03 +### Added +- Migrate to a cargo-compatible directory structure. + +### Fixed +- Do not use entropy during `gen_weighted_bool(1)` + + +## [Rust 0.12.0] - 2014-10-09 +### Added +- Impl Rand for tuples of arity 11 and 12 +- Include ChaCha pseudorandom generator +- Add `next_f64` and `next_f32` to Rng +- Implement Clone for PRNGs + +### Changed +- Rename `TaskRng` to `ThreadRng` and `task_rng` to `thread_rng` (since a + runtime is removed from Rust). + +### Fixed +- Improved performance of ISAAC and ISAAC64 by 30% and 12 % respectively, by + informing the optimiser that indexing is never out-of-bounds. + +### Removed +- Removed the Deprecated `choose_option` + + +## [Rust 0.11.0] - 2014-07-02 +### Added +- document when to use `OSRng` in cryptographic context, and explain why we use `/dev/urandom` instead of `/dev/random` +- `Rng::gen_iter()` which will return an infinite stream of random values +- `Rng::gen_ascii_chars()` which will return an infinite stream of random ascii characters + +### Changed +- Now only depends on libcore! 2adf5363f88ffe06f6d2ea5c338d1b186d47f4a1 +- Remove `Rng.choose()`, rename `Rng.choose_option()` to `.choose()` +- Rename OSRng to OsRng +- The WeightedChoice structure is no longer built with a `Vec>`, + but rather a `&mut [Weighted]`. This means that the WeightedChoice + structure now has a lifetime associated with it. +- The `sample` method on `Rng` has been moved to a top-level function in the + `rand` module due to its dependence on `Vec`. + +### Removed +- `Rng::gen_vec()` was removed. Previous behavior can be regained with + `rng.gen_iter().take(n).collect()` +- `Rng::gen_ascii_str()` was removed. Previous behavior can be regained with + `rng.gen_ascii_chars().take(n).collect()` +- {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all + relied on being able to use an OSRng for seeding, but this is no longer + available in librand (where these types are defined). To retain the same + functionality, these types now implement the `Rand` trait so they can be + generated with a random seed from another random number generator. This allows + the stdlib to use an OSRng to create seeded instances of these RNGs. +- Rand implementations for `Box` and `@T` were removed. These seemed to be + pretty rare in the codebase, and it allows for librand to not depend on + liballoc. Additionally, other pointer types like Rc and Arc were not + supported. +- Remove a slew of old deprecated functions + + +## [Rust 0.10] - 2014-04-03 +### Changed +- replace `Rng.shuffle's` functionality with `.shuffle_mut` +- bubble up IO errors when creating an OSRng + +### Fixed +- Use `fill()` instead of `read()` +- Rewrite OsRng in Rust for windows + +## [0.10-pre] - 2014-03-02 +### Added +- Seperate `rand` out of the standard library + diff --git a/third_party/rust/rand-0.4.3/Cargo.toml b/third_party/rust/rand-0.4.3/Cargo.toml new file mode 100644 index 000000000000..4f80003e44f3 --- /dev/null +++ b/third_party/rust/rand-0.4.3/Cargo.toml @@ -0,0 +1,39 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand" +version = "0.4.3" +authors = ["The Rust Project Developers"] +description = "Random number generators and other randomness functionality.\n" +homepage = "https://github.com/rust-lang-nursery/rand" +documentation = "https://docs.rs/rand" +readme = "README.md" +keywords = ["random", "rng"] +categories = ["algorithms"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-lang-nursery/rand" + +[features] +alloc = [] +default = ["std"] +i128_support = [] +nightly = ["i128_support"] +std = ["libc"] +[target."cfg(target_os = \"fuchsia\")".dependencies.fuchsia-zircon] +version = "0.3.2" +[target."cfg(unix)".dependencies.libc] +version = "0.2" +optional = true +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["minwindef", "ntsecapi", "profileapi", "winnt"] diff --git a/third_party/rust/rand-0.4.3/LICENSE-APACHE b/third_party/rust/rand-0.4.3/LICENSE-APACHE new file mode 100644 index 000000000000..16fe87b06e80 --- /dev/null +++ b/third_party/rust/rand-0.4.3/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/rand-0.4.3/LICENSE-MIT b/third_party/rust/rand-0.4.3/LICENSE-MIT new file mode 100644 index 000000000000..39d4bdb5acd3 --- /dev/null +++ b/third_party/rust/rand-0.4.3/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/rand-0.4.3/README.md b/third_party/rust/rand-0.4.3/README.md new file mode 100644 index 000000000000..f72bd51a3333 --- /dev/null +++ b/third_party/rust/rand-0.4.3/README.md @@ -0,0 +1,139 @@ +rand +==== + +A Rust library for random number generators and other randomness functionality. + +[![Build Status](https://travis-ci.org/rust-lang-nursery/rand.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/rand) +[![Build status](https://ci.appveyor.com/api/projects/status/rm5c9o33k3jhchbw?svg=true)](https://ci.appveyor.com/project/alexcrichton/rand) + +[Documentation](https://docs.rs/rand) + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +rand = "0.4" +``` + +and this to your crate root: + +```rust +extern crate rand; +``` + +### Versions + +Version `0.4`was released in December 2017. It contains almost no breaking +changes since the `0.3` series, but nevertheless contains some significant +new code, including a new "external" entropy source (`JitterRng`) and `no_std` +support. + +Version `0.5` is in development and contains significant performance +improvements for the ISAAC random number generators. + +## Examples + +There is built-in support for a random number generator (RNG) associated with each thread stored in thread-local storage. This RNG can be accessed via thread_rng, or used implicitly via random. This RNG is normally randomly seeded from an operating-system source of randomness, e.g. /dev/urandom on Unix systems, and will automatically reseed itself from this source after generating 32 KiB of random data. + +```rust +let tuple = rand::random::<(f64, char)>(); +println!("{:?}", tuple) +``` + +```rust +use rand::Rng; + +let mut rng = rand::thread_rng(); +if rng.gen() { // random bool + println!("i32: {}, u32: {}", rng.gen::(), rng.gen::()) +} +``` + +It is also possible to use other RNG types, which have a similar interface. The following uses the "ChaCha" algorithm instead of the default. + +```rust +use rand::{Rng, ChaChaRng}; + +let mut rng = rand::ChaChaRng::new_unseeded(); +println!("i32: {}, u32: {}", rng.gen::(), rng.gen::()) +``` + +## Features + +By default, `rand` is built with all stable features available. The following +optional features are available: + +- `i128_support` enables support for generating `u128` and `i128` values +- `nightly` enables all unstable features (`i128_support`) +- `std` enabled by default; by setting "default-features = false" `no_std` + mode is activated; this removes features depending on `std` functionality: + + - `OsRng` is entirely unavailable + - `JitterRng` code is still present, but a nanosecond timer must be + provided via `JitterRng::new_with_timer` + - Since no external entropy is available, it is not possible to create + generators with fresh seeds (user must provide entropy) + - `thread_rng`, `weak_rng` and `random` are all disabled + - exponential, normal and gamma type distributions are unavailable + since `exp` and `log` functions are not provided in `core` + - any code requiring `Vec` or `Box` +- `alloc` can be used instead of `std` to provide `Vec` and `Box` + +## Testing + +Unfortunately, `cargo test` does not test everything. The following tests are +recommended: + +``` +# Basic tests for rand and sub-crates +cargo test --all + +# Test no_std support (build only since nearly all tests require std) +cargo build --all --no-default-features + +# Test 128-bit support (requires nightly) +cargo test --all --features nightly + +# Benchmarks (requires nightly) +cargo bench +# or just to test the benchmark code: +cargo test --benches +``` + +# `derive(Rand)` + +You can derive the `Rand` trait for your custom type via the `#[derive(Rand)]` +directive. To use this first add this to your Cargo.toml: + +```toml +rand = "0.4" +rand_derive = "0.3" +``` + +Next in your crate: + +```rust +extern crate rand; +#[macro_use] +extern crate rand_derive; + +#[derive(Rand, Debug)] +struct MyStruct { + a: i32, + b: u32, +} + +fn main() { + println!("{:?}", rand::random::()); +} +``` + + +# License + +`rand` is primarily distributed under the terms of both the MIT +license and the Apache License (Version 2.0). + +See LICENSE-APACHE, and LICENSE-MIT for details. diff --git a/third_party/rust/rand/appveyor.yml b/third_party/rust/rand-0.4.3/appveyor.yml similarity index 100% rename from third_party/rust/rand/appveyor.yml rename to third_party/rust/rand-0.4.3/appveyor.yml diff --git a/third_party/rust/rand/benches/bench.rs b/third_party/rust/rand-0.4.3/benches/bench.rs similarity index 100% rename from third_party/rust/rand/benches/bench.rs rename to third_party/rust/rand-0.4.3/benches/bench.rs diff --git a/third_party/rust/rand/benches/distributions/exponential.rs b/third_party/rust/rand-0.4.3/benches/distributions/exponential.rs similarity index 100% rename from third_party/rust/rand/benches/distributions/exponential.rs rename to third_party/rust/rand-0.4.3/benches/distributions/exponential.rs diff --git a/third_party/rust/rand/benches/distributions/gamma.rs b/third_party/rust/rand-0.4.3/benches/distributions/gamma.rs similarity index 100% rename from third_party/rust/rand/benches/distributions/gamma.rs rename to third_party/rust/rand-0.4.3/benches/distributions/gamma.rs diff --git a/third_party/rust/rand/benches/distributions/mod.rs b/third_party/rust/rand-0.4.3/benches/distributions/mod.rs similarity index 100% rename from third_party/rust/rand/benches/distributions/mod.rs rename to third_party/rust/rand-0.4.3/benches/distributions/mod.rs diff --git a/third_party/rust/rand/benches/distributions/normal.rs b/third_party/rust/rand-0.4.3/benches/distributions/normal.rs similarity index 100% rename from third_party/rust/rand/benches/distributions/normal.rs rename to third_party/rust/rand-0.4.3/benches/distributions/normal.rs diff --git a/third_party/rust/rand-0.4.3/benches/generators.rs b/third_party/rust/rand-0.4.3/benches/generators.rs new file mode 100644 index 000000000000..daee7c5fbb5a --- /dev/null +++ b/third_party/rust/rand-0.4.3/benches/generators.rs @@ -0,0 +1,133 @@ +#![feature(test)] + +extern crate test; +extern crate rand; + +const RAND_BENCH_N: u64 = 1000; +const BYTES_LEN: usize = 1024; + +use std::mem::size_of; +use test::{black_box, Bencher}; + +use rand::{Rng, StdRng, OsRng, JitterRng}; +use rand::{XorShiftRng, IsaacRng, Isaac64Rng, ChaChaRng}; + +macro_rules! gen_bytes { + ($fnn:ident, $gen:ident) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng: $gen = OsRng::new().unwrap().gen(); + let mut buf = [0u8; BYTES_LEN]; + b.iter(|| { + for _ in 0..RAND_BENCH_N { + rng.fill_bytes(&mut buf); + black_box(buf); + } + }); + b.bytes = BYTES_LEN as u64 * RAND_BENCH_N; + } + } +} + +macro_rules! gen_bytes_new { + ($fnn:ident, $gen:ident) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = $gen::new().unwrap(); + let mut buf = [0u8; BYTES_LEN]; + b.iter(|| { + for _ in 0..RAND_BENCH_N { + rng.fill_bytes(&mut buf); + black_box(buf); + } + }); + b.bytes = BYTES_LEN as u64 * RAND_BENCH_N; + } + } +} + +gen_bytes!(gen_bytes_xorshift, XorShiftRng); +gen_bytes!(gen_bytes_isaac, IsaacRng); +gen_bytes!(gen_bytes_isaac64, Isaac64Rng); +gen_bytes!(gen_bytes_chacha, ChaChaRng); +gen_bytes_new!(gen_bytes_std, StdRng); +gen_bytes_new!(gen_bytes_os, OsRng); + + +macro_rules! gen_uint { + ($fnn:ident, $ty:ty, $gen:ident) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng: $gen = OsRng::new().unwrap().gen(); + b.iter(|| { + for _ in 0..RAND_BENCH_N { + black_box(rng.gen::<$ty>()); + } + }); + b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; + } + } +} + +macro_rules! gen_uint_new { + ($fnn:ident, $ty:ty, $gen:ident) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = $gen::new().unwrap(); + b.iter(|| { + for _ in 0..RAND_BENCH_N { + black_box(rng.gen::<$ty>()); + } + }); + b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; + } + } +} + +gen_uint!(gen_u32_xorshift, u32, XorShiftRng); +gen_uint!(gen_u32_isaac, u32, IsaacRng); +gen_uint!(gen_u32_isaac64, u32, Isaac64Rng); +gen_uint!(gen_u32_chacha, u32, ChaChaRng); +gen_uint_new!(gen_u32_std, u32, StdRng); +gen_uint_new!(gen_u32_os, u32, OsRng); + +gen_uint!(gen_u64_xorshift, u64, XorShiftRng); +gen_uint!(gen_u64_isaac, u64, IsaacRng); +gen_uint!(gen_u64_isaac64, u64, Isaac64Rng); +gen_uint!(gen_u64_chacha, u64, ChaChaRng); +gen_uint_new!(gen_u64_std, u64, StdRng); +gen_uint_new!(gen_u64_os, u64, OsRng); + +#[bench] +fn gen_u64_jitter(b: &mut Bencher) { + let mut rng = JitterRng::new().unwrap(); + b.iter(|| { + black_box(rng.gen::()); + }); + b.bytes = size_of::() as u64; +} + +macro_rules! init_gen { + ($fnn:ident, $gen:ident) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng: XorShiftRng = OsRng::new().unwrap().gen(); + b.iter(|| { + let r2: $gen = rng.gen(); + black_box(r2); + }); + } + } +} + +init_gen!(init_xorshift, XorShiftRng); +init_gen!(init_isaac, IsaacRng); +init_gen!(init_isaac64, Isaac64Rng); +init_gen!(init_chacha, ChaChaRng); + +#[bench] +fn init_jitter(b: &mut Bencher) { + b.iter(|| { + black_box(JitterRng::new().unwrap()); + }); +} diff --git a/third_party/rust/rand-0.4.3/benches/misc.rs b/third_party/rust/rand-0.4.3/benches/misc.rs new file mode 100644 index 000000000000..425176176626 --- /dev/null +++ b/third_party/rust/rand-0.4.3/benches/misc.rs @@ -0,0 +1,62 @@ +#![feature(test)] + +extern crate test; +extern crate rand; + +use test::{black_box, Bencher}; + +use rand::{Rng, weak_rng}; +use rand::seq::*; + +#[bench] +fn misc_shuffle_100(b: &mut Bencher) { + let mut rng = weak_rng(); + let x : &mut [usize] = &mut [1; 100]; + b.iter(|| { + rng.shuffle(x); + black_box(&x); + }) +} + +#[bench] +fn misc_sample_iter_10_of_100(b: &mut Bencher) { + let mut rng = weak_rng(); + let x : &[usize] = &[1; 100]; + b.iter(|| { + black_box(sample_iter(&mut rng, x, 10).unwrap_or_else(|e| e)); + }) +} + +#[bench] +fn misc_sample_slice_10_of_100(b: &mut Bencher) { + let mut rng = weak_rng(); + let x : &[usize] = &[1; 100]; + b.iter(|| { + black_box(sample_slice(&mut rng, x, 10)); + }) +} + +#[bench] +fn misc_sample_slice_ref_10_of_100(b: &mut Bencher) { + let mut rng = weak_rng(); + let x : &[usize] = &[1; 100]; + b.iter(|| { + black_box(sample_slice_ref(&mut rng, x, 10)); + }) +} + +macro_rules! sample_indices { + ($name:ident, $amount:expr, $length:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut rng = weak_rng(); + b.iter(|| { + black_box(sample_indices(&mut rng, $length, $amount)); + }) + } + } +} + +sample_indices!(misc_sample_indices_10_of_1k, 10, 1000); +sample_indices!(misc_sample_indices_50_of_1k, 50, 1000); +sample_indices!(misc_sample_indices_100_of_1k, 100, 1000); diff --git a/third_party/rust/rand-0.4.3/src/distributions/exponential.rs b/third_party/rust/rand-0.4.3/src/distributions/exponential.rs new file mode 100644 index 000000000000..c3c924c6b7ee --- /dev/null +++ b/third_party/rust/rand-0.4.3/src/distributions/exponential.rs @@ -0,0 +1,124 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The exponential distribution. + +use {Rng, Rand}; +use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample}; + +/// A wrapper around an `f64` to generate Exp(1) random numbers. +/// +/// See `Exp` for the general exponential distribution. +/// +/// Implemented via the ZIGNOR variant[1] of the Ziggurat method. The +/// exact description in the paper was adjusted to use tables for the +/// exponential distribution rather than normal. +/// +/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to +/// Generate Normal Random +/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield +/// College, Oxford +/// +/// # Example +/// +/// ```rust +/// use rand::distributions::exponential::Exp1; +/// +/// let Exp1(x) = rand::random(); +/// println!("{}", x); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Exp1(pub f64); + +// This could be done via `-rng.gen::().ln()` but that is slower. +impl Rand for Exp1 { + #[inline] + fn rand(rng: &mut R) -> Exp1 { + #[inline] + fn pdf(x: f64) -> f64 { + (-x).exp() + } + #[inline] + fn zero_case(rng: &mut R, _u: f64) -> f64 { + ziggurat_tables::ZIG_EXP_R - rng.gen::().ln() + } + + Exp1(ziggurat(rng, false, + &ziggurat_tables::ZIG_EXP_X, + &ziggurat_tables::ZIG_EXP_F, + pdf, zero_case)) + } +} + +/// The exponential distribution `Exp(lambda)`. +/// +/// This distribution has density function: `f(x) = lambda * +/// exp(-lambda * x)` for `x > 0`. +/// +/// # Example +/// +/// ```rust +/// use rand::distributions::{Exp, IndependentSample}; +/// +/// let exp = Exp::new(2.0); +/// let v = exp.ind_sample(&mut rand::thread_rng()); +/// println!("{} is from a Exp(2) distribution", v); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Exp { + /// `lambda` stored as `1/lambda`, since this is what we scale by. + lambda_inverse: f64 +} + +impl Exp { + /// Construct a new `Exp` with the given shape parameter + /// `lambda`. Panics if `lambda <= 0`. + #[inline] + pub fn new(lambda: f64) -> Exp { + assert!(lambda > 0.0, "Exp::new called with `lambda` <= 0"); + Exp { lambda_inverse: 1.0 / lambda } + } +} + +impl Sample for Exp { + fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } +} +impl IndependentSample for Exp { + fn ind_sample(&self, rng: &mut R) -> f64 { + let Exp1(n) = rng.gen::(); + n * self.lambda_inverse + } +} + +#[cfg(test)] +mod test { + use distributions::{Sample, IndependentSample}; + use super::Exp; + + #[test] + fn test_exp() { + let mut exp = Exp::new(10.0); + let mut rng = ::test::rng(); + for _ in 0..1000 { + assert!(exp.sample(&mut rng) >= 0.0); + assert!(exp.ind_sample(&mut rng) >= 0.0); + } + } + #[test] + #[should_panic] + fn test_exp_invalid_lambda_zero() { + Exp::new(0.0); + } + #[test] + #[should_panic] + fn test_exp_invalid_lambda_neg() { + Exp::new(-10.0); + } +} diff --git a/third_party/rust/rand-0.4.3/src/distributions/gamma.rs b/third_party/rust/rand-0.4.3/src/distributions/gamma.rs new file mode 100644 index 000000000000..280649587319 --- /dev/null +++ b/third_party/rust/rand-0.4.3/src/distributions/gamma.rs @@ -0,0 +1,386 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// ignore-lexer-test FIXME #15679 + +//! The Gamma and derived distributions. + +use self::GammaRepr::*; +use self::ChiSquaredRepr::*; + +use {Rng, Open01}; +use super::normal::StandardNormal; +use super::{IndependentSample, Sample, Exp}; + +/// The Gamma distribution `Gamma(shape, scale)` distribution. +/// +/// The density function of this distribution is +/// +/// ```text +/// f(x) = x^(k - 1) * exp(-x / θ) / (Γ(k) * θ^k) +/// ``` +/// +/// where `Γ` is the Gamma function, `k` is the shape and `θ` is the +/// scale and both `k` and `θ` are strictly positive. +/// +/// The algorithm used is that described by Marsaglia & Tsang 2000[1], +/// falling back to directly sampling from an Exponential for `shape +/// == 1`, and using the boosting technique described in [1] for +/// `shape < 1`. +/// +/// # Example +/// +/// ```rust +/// use rand::distributions::{IndependentSample, Gamma}; +/// +/// let gamma = Gamma::new(2.0, 5.0); +/// let v = gamma.ind_sample(&mut rand::thread_rng()); +/// println!("{} is from a Gamma(2, 5) distribution", v); +/// ``` +/// +/// [1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method +/// for Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3 +/// (September 2000), +/// 363-372. DOI:[10.1145/358407.358414](http://doi.acm.org/10.1145/358407.358414) +#[derive(Clone, Copy, Debug)] +pub struct Gamma { + repr: GammaRepr, +} + +#[derive(Clone, Copy, Debug)] +enum GammaRepr { + Large(GammaLargeShape), + One(Exp), + Small(GammaSmallShape) +} + +// These two helpers could be made public, but saving the +// match-on-Gamma-enum branch from using them directly (e.g. if one +// knows that the shape is always > 1) doesn't appear to be much +// faster. + +/// Gamma distribution where the shape parameter is less than 1. +/// +/// Note, samples from this require a compulsory floating-point `pow` +/// call, which makes it significantly slower than sampling from a +/// gamma distribution where the shape parameter is greater than or +/// equal to 1. +/// +/// See `Gamma` for sampling from a Gamma distribution with general +/// shape parameters. +#[derive(Clone, Copy, Debug)] +struct GammaSmallShape { + inv_shape: f64, + large_shape: GammaLargeShape +} + +/// Gamma distribution where the shape parameter is larger than 1. +/// +/// See `Gamma` for sampling from a Gamma distribution with general +/// shape parameters. +#[derive(Clone, Copy, Debug)] +struct GammaLargeShape { + scale: f64, + c: f64, + d: f64 +} + +impl Gamma { + /// Construct an object representing the `Gamma(shape, scale)` + /// distribution. + /// + /// Panics if `shape <= 0` or `scale <= 0`. + #[inline] + pub fn new(shape: f64, scale: f64) -> Gamma { + assert!(shape > 0.0, "Gamma::new called with shape <= 0"); + assert!(scale > 0.0, "Gamma::new called with scale <= 0"); + + let repr = if shape == 1.0 { + One(Exp::new(1.0 / scale)) + } else if shape < 1.0 { + Small(GammaSmallShape::new_raw(shape, scale)) + } else { + Large(GammaLargeShape::new_raw(shape, scale)) + }; + Gamma { repr: repr } + } +} + +impl GammaSmallShape { + fn new_raw(shape: f64, scale: f64) -> GammaSmallShape { + GammaSmallShape { + inv_shape: 1. / shape, + large_shape: GammaLargeShape::new_raw(shape + 1.0, scale) + } + } +} + +impl GammaLargeShape { + fn new_raw(shape: f64, scale: f64) -> GammaLargeShape { + let d = shape - 1. / 3.; + GammaLargeShape { + scale: scale, + c: 1. / (9. * d).sqrt(), + d: d + } + } +} + +impl Sample for Gamma { + fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } +} +impl Sample for GammaSmallShape { + fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } +} +impl Sample for GammaLargeShape { + fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } +} + +impl IndependentSample for Gamma { + fn ind_sample(&self, rng: &mut R) -> f64 { + match self.repr { + Small(ref g) => g.ind_sample(rng), + One(ref g) => g.ind_sample(rng), + Large(ref g) => g.ind_sample(rng), + } + } +} +impl IndependentSample for GammaSmallShape { + fn ind_sample(&self, rng: &mut R) -> f64 { + let Open01(u) = rng.gen::>(); + + self.large_shape.ind_sample(rng) * u.powf(self.inv_shape) + } +} +impl IndependentSample for GammaLargeShape { + fn ind_sample(&self, rng: &mut R) -> f64 { + loop { + let StandardNormal(x) = rng.gen::(); + let v_cbrt = 1.0 + self.c * x; + if v_cbrt <= 0.0 { // a^3 <= 0 iff a <= 0 + continue + } + + let v = v_cbrt * v_cbrt * v_cbrt; + let Open01(u) = rng.gen::>(); + + let x_sqr = x * x; + if u < 1.0 - 0.0331 * x_sqr * x_sqr || + u.ln() < 0.5 * x_sqr + self.d * (1.0 - v + v.ln()) { + return self.d * v * self.scale + } + } + } +} + +/// The chi-squared distribution `χ²(k)`, where `k` is the degrees of +/// freedom. +/// +/// For `k > 0` integral, this distribution is the sum of the squares +/// of `k` independent standard normal random variables. For other +/// `k`, this uses the equivalent characterisation +/// `χ²(k) = Gamma(k/2, 2)`. +/// +/// # Example +/// +/// ```rust +/// use rand::distributions::{ChiSquared, IndependentSample}; +/// +/// let chi = ChiSquared::new(11.0); +/// let v = chi.ind_sample(&mut rand::thread_rng()); +/// println!("{} is from a χ²(11) distribution", v) +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct ChiSquared { + repr: ChiSquaredRepr, +} + +#[derive(Clone, Copy, Debug)] +enum ChiSquaredRepr { + // k == 1, Gamma(alpha, ..) is particularly slow for alpha < 1, + // e.g. when alpha = 1/2 as it would be for this case, so special- + // casing and using the definition of N(0,1)^2 is faster. + DoFExactlyOne, + DoFAnythingElse(Gamma), +} + +impl ChiSquared { + /// Create a new chi-squared distribution with degrees-of-freedom + /// `k`. Panics if `k < 0`. + pub fn new(k: f64) -> ChiSquared { + let repr = if k == 1.0 { + DoFExactlyOne + } else { + assert!(k > 0.0, "ChiSquared::new called with `k` < 0"); + DoFAnythingElse(Gamma::new(0.5 * k, 2.0)) + }; + ChiSquared { repr: repr } + } +} +impl Sample for ChiSquared { + fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } +} +impl IndependentSample for ChiSquared { + fn ind_sample(&self, rng: &mut R) -> f64 { + match self.repr { + DoFExactlyOne => { + // k == 1 => N(0,1)^2 + let StandardNormal(norm) = rng.gen::(); + norm * norm + } + DoFAnythingElse(ref g) => g.ind_sample(rng) + } + } +} + +/// The Fisher F distribution `F(m, n)`. +/// +/// This distribution is equivalent to the ratio of two normalised +/// chi-squared distributions, that is, `F(m,n) = (χ²(m)/m) / +/// (χ²(n)/n)`. +/// +/// # Example +/// +/// ```rust +/// use rand::distributions::{FisherF, IndependentSample}; +/// +/// let f = FisherF::new(2.0, 32.0); +/// let v = f.ind_sample(&mut rand::thread_rng()); +/// println!("{} is from an F(2, 32) distribution", v) +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct FisherF { + numer: ChiSquared, + denom: ChiSquared, + // denom_dof / numer_dof so that this can just be a straight + // multiplication, rather than a division. + dof_ratio: f64, +} + +impl FisherF { + /// Create a new `FisherF` distribution, with the given + /// parameter. Panics if either `m` or `n` are not positive. + pub fn new(m: f64, n: f64) -> FisherF { + assert!(m > 0.0, "FisherF::new called with `m < 0`"); + assert!(n > 0.0, "FisherF::new called with `n < 0`"); + + FisherF { + numer: ChiSquared::new(m), + denom: ChiSquared::new(n), + dof_ratio: n / m + } + } +} +impl Sample for FisherF { + fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } +} +impl IndependentSample for FisherF { + fn ind_sample(&self, rng: &mut R) -> f64 { + self.numer.ind_sample(rng) / self.denom.ind_sample(rng) * self.dof_ratio + } +} + +/// The Student t distribution, `t(nu)`, where `nu` is the degrees of +/// freedom. +/// +/// # Example +/// +/// ```rust +/// use rand::distributions::{StudentT, IndependentSample}; +/// +/// let t = StudentT::new(11.0); +/// let v = t.ind_sample(&mut rand::thread_rng()); +/// println!("{} is from a t(11) distribution", v) +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct StudentT { + chi: ChiSquared, + dof: f64 +} + +impl StudentT { + /// Create a new Student t distribution with `n` degrees of + /// freedom. Panics if `n <= 0`. + pub fn new(n: f64) -> StudentT { + assert!(n > 0.0, "StudentT::new called with `n <= 0`"); + StudentT { + chi: ChiSquared::new(n), + dof: n + } + } +} +impl Sample for StudentT { + fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } +} +impl IndependentSample for StudentT { + fn ind_sample(&self, rng: &mut R) -> f64 { + let StandardNormal(norm) = rng.gen::(); + norm * (self.dof / self.chi.ind_sample(rng)).sqrt() + } +} + +#[cfg(test)] +mod test { + use distributions::{Sample, IndependentSample}; + use super::{ChiSquared, StudentT, FisherF}; + + #[test] + fn test_chi_squared_one() { + let mut chi = ChiSquared::new(1.0); + let mut rng = ::test::rng(); + for _ in 0..1000 { + chi.sample(&mut rng); + chi.ind_sample(&mut rng); + } + } + #[test] + fn test_chi_squared_small() { + let mut chi = ChiSquared::new(0.5); + let mut rng = ::test::rng(); + for _ in 0..1000 { + chi.sample(&mut rng); + chi.ind_sample(&mut rng); + } + } + #[test] + fn test_chi_squared_large() { + let mut chi = ChiSquared::new(30.0); + let mut rng = ::test::rng(); + for _ in 0..1000 { + chi.sample(&mut rng); + chi.ind_sample(&mut rng); + } + } + #[test] + #[should_panic] + fn test_chi_squared_invalid_dof() { + ChiSquared::new(-1.0); + } + + #[test] + fn test_f() { + let mut f = FisherF::new(2.0, 32.0); + let mut rng = ::test::rng(); + for _ in 0..1000 { + f.sample(&mut rng); + f.ind_sample(&mut rng); + } + } + + #[test] + fn test_t() { + let mut t = StudentT::new(11.0); + let mut rng = ::test::rng(); + for _ in 0..1000 { + t.sample(&mut rng); + t.ind_sample(&mut rng); + } + } +} diff --git a/third_party/rust/rand-0.4.3/src/distributions/mod.rs b/third_party/rust/rand-0.4.3/src/distributions/mod.rs new file mode 100644 index 000000000000..5de8efb9c472 --- /dev/null +++ b/third_party/rust/rand-0.4.3/src/distributions/mod.rs @@ -0,0 +1,409 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Sampling from random distributions. +//! +//! This is a generalization of `Rand` to allow parameters to control the +//! exact properties of the generated values, e.g. the mean and standard +//! deviation of a normal distribution. The `Sample` trait is the most +//! general, and allows for generating values that change some state +//! internally. The `IndependentSample` trait is for generating values +//! that do not need to record state. + +use core::marker; + +use {Rng, Rand}; + +pub use self::range::Range; +#[cfg(feature="std")] +pub use self::gamma::{Gamma, ChiSquared, FisherF, StudentT}; +#[cfg(feature="std")] +pub use self::normal::{Normal, LogNormal}; +#[cfg(feature="std")] +pub use self::exponential::Exp; + +pub mod range; +#[cfg(feature="std")] +pub mod gamma; +#[cfg(feature="std")] +pub mod normal; +#[cfg(feature="std")] +pub mod exponential; + +#[cfg(feature="std")] +mod ziggurat_tables; + +/// Types that can be used to create a random instance of `Support`. +pub trait Sample { + /// Generate a random value of `Support`, using `rng` as the + /// source of randomness. + fn sample(&mut self, rng: &mut R) -> Support; +} + +/// `Sample`s that do not require keeping track of state. +/// +/// Since no state is recorded, each sample is (statistically) +/// independent of all others, assuming the `Rng` used has this +/// property. +// FIXME maybe having this separate is overkill (the only reason is to +// take &self rather than &mut self)? or maybe this should be the +// trait called `Sample` and the other should be `DependentSample`. +pub trait IndependentSample: Sample { + /// Generate a random value. + fn ind_sample(&self, &mut R) -> Support; +} + +/// A wrapper for generating types that implement `Rand` via the +/// `Sample` & `IndependentSample` traits. +#[derive(Debug)] +pub struct RandSample { + _marker: marker::PhantomData Sup>, +} + +impl Copy for RandSample {} +impl Clone for RandSample { + fn clone(&self) -> Self { *self } +} + +impl Sample for RandSample { + fn sample(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) } +} + +impl IndependentSample for RandSample { + fn ind_sample(&self, rng: &mut R) -> Sup { + rng.gen() + } +} + +impl RandSample { + pub fn new() -> RandSample { + RandSample { _marker: marker::PhantomData } + } +} + +/// A value with a particular weight for use with `WeightedChoice`. +#[derive(Copy, Clone, Debug)] +pub struct Weighted { + /// The numerical weight of this item + pub weight: u32, + /// The actual item which is being weighted + pub item: T, +} + +/// A distribution that selects from a finite collection of weighted items. +/// +/// Each item has an associated weight that influences how likely it +/// is to be chosen: higher weight is more likely. +/// +/// The `Clone` restriction is a limitation of the `Sample` and +/// `IndependentSample` traits. Note that `&T` is (cheaply) `Clone` for +/// all `T`, as is `u32`, so one can store references or indices into +/// another vector. +/// +/// # Example +/// +/// ```rust +/// use rand::distributions::{Weighted, WeightedChoice, IndependentSample}; +/// +/// let mut items = vec!(Weighted { weight: 2, item: 'a' }, +/// Weighted { weight: 4, item: 'b' }, +/// Weighted { weight: 1, item: 'c' }); +/// let wc = WeightedChoice::new(&mut items); +/// let mut rng = rand::thread_rng(); +/// for _ in 0..16 { +/// // on average prints 'a' 4 times, 'b' 8 and 'c' twice. +/// println!("{}", wc.ind_sample(&mut rng)); +/// } +/// ``` +#[derive(Debug)] +pub struct WeightedChoice<'a, T:'a> { + items: &'a mut [Weighted], + weight_range: Range +} + +impl<'a, T: Clone> WeightedChoice<'a, T> { + /// Create a new `WeightedChoice`. + /// + /// Panics if: + /// + /// - `items` is empty + /// - the total weight is 0 + /// - the total weight is larger than a `u32` can contain. + pub fn new(items: &'a mut [Weighted]) -> WeightedChoice<'a, T> { + // strictly speaking, this is subsumed by the total weight == 0 case + assert!(!items.is_empty(), "WeightedChoice::new called with no items"); + + let mut running_total: u32 = 0; + + // we convert the list from individual weights to cumulative + // weights so we can binary search. This *could* drop elements + // with weight == 0 as an optimisation. + for item in items.iter_mut() { + running_total = match running_total.checked_add(item.weight) { + Some(n) => n, + None => panic!("WeightedChoice::new called with a total weight \ + larger than a u32 can contain") + }; + + item.weight = running_total; + } + assert!(running_total != 0, "WeightedChoice::new called with a total weight of 0"); + + WeightedChoice { + items: items, + // we're likely to be generating numbers in this range + // relatively often, so might as well cache it + weight_range: Range::new(0, running_total) + } + } +} + +impl<'a, T: Clone> Sample for WeightedChoice<'a, T> { + fn sample(&mut self, rng: &mut R) -> T { self.ind_sample(rng) } +} + +impl<'a, T: Clone> IndependentSample for WeightedChoice<'a, T> { + fn ind_sample(&self, rng: &mut R) -> T { + // we want to find the first element that has cumulative + // weight > sample_weight, which we do by binary since the + // cumulative weights of self.items are sorted. + + // choose a weight in [0, total_weight) + let sample_weight = self.weight_range.ind_sample(rng); + + // short circuit when it's the first item + if sample_weight < self.items[0].weight { + return self.items[0].item.clone(); + } + + let mut idx = 0; + let mut modifier = self.items.len(); + + // now we know that every possibility has an element to the + // left, so we can just search for the last element that has + // cumulative weight <= sample_weight, then the next one will + // be "it". (Note that this greatest element will never be the + // last element of the vector, since sample_weight is chosen + // in [0, total_weight) and the cumulative weight of the last + // one is exactly the total weight.) + while modifier > 1 { + let i = idx + modifier / 2; + if self.items[i].weight <= sample_weight { + // we're small, so look to the right, but allow this + // exact element still. + idx = i; + // we need the `/ 2` to round up otherwise we'll drop + // the trailing elements when `modifier` is odd. + modifier += 1; + } else { + // otherwise we're too big, so go left. (i.e. do + // nothing) + } + modifier /= 2; + } + return self.items[idx + 1].item.clone(); + } +} + +/// Sample a random number using the Ziggurat method (specifically the +/// ZIGNOR variant from Doornik 2005). Most of the arguments are +/// directly from the paper: +/// +/// * `rng`: source of randomness +/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0. +/// * `X`: the $x_i$ abscissae. +/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$) +/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$ +/// * `pdf`: the probability density function +/// * `zero_case`: manual sampling from the tail when we chose the +/// bottom box (i.e. i == 0) + +// the perf improvement (25-50%) is definitely worth the extra code +// size from force-inlining. +#[cfg(feature="std")] +#[inline(always)] +fn ziggurat( + rng: &mut R, + symmetric: bool, + x_tab: ziggurat_tables::ZigTable, + f_tab: ziggurat_tables::ZigTable, + mut pdf: P, + mut zero_case: Z) + -> f64 where P: FnMut(f64) -> f64, Z: FnMut(&mut R, f64) -> f64 { + const SCALE: f64 = (1u64 << 53) as f64; + loop { + // reimplement the f64 generation as an optimisation suggested + // by the Doornik paper: we have a lot of precision-space + // (i.e. there are 11 bits of the 64 of a u64 to use after + // creating a f64), so we might as well reuse some to save + // generating a whole extra random number. (Seems to be 15% + // faster.) + // + // This unfortunately misses out on the benefits of direct + // floating point generation if an RNG like dSMFT is + // used. (That is, such RNGs create floats directly, highly + // efficiently and overload next_f32/f64, so by not calling it + // this may be slower than it would be otherwise.) + // FIXME: investigate/optimise for the above. + let bits: u64 = rng.gen(); + let i = (bits & 0xff) as usize; + let f = (bits >> 11) as f64 / SCALE; + + // u is either U(-1, 1) or U(0, 1) depending on if this is a + // symmetric distribution or not. + let u = if symmetric {2.0 * f - 1.0} else {f}; + let x = u * x_tab[i]; + + let test_x = if symmetric { x.abs() } else {x}; + + // algebraically equivalent to |u| < x_tab[i+1]/x_tab[i] (or u < x_tab[i+1]/x_tab[i]) + if test_x < x_tab[i + 1] { + return x; + } + if i == 0 { + return zero_case(rng, u); + } + // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1 + if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.gen::() < pdf(x) { + return x; + } + } +} + +#[cfg(test)] +mod tests { + + use {Rng, Rand}; + use super::{RandSample, WeightedChoice, Weighted, Sample, IndependentSample}; + + #[derive(PartialEq, Debug)] + struct ConstRand(usize); + impl Rand for ConstRand { + fn rand(_: &mut R) -> ConstRand { + ConstRand(0) + } + } + + // 0, 1, 2, 3, ... + struct CountingRng { i: u32 } + impl Rng for CountingRng { + fn next_u32(&mut self) -> u32 { + self.i += 1; + self.i - 1 + } + fn next_u64(&mut self) -> u64 { + self.next_u32() as u64 + } + } + + #[test] + fn test_rand_sample() { + let mut rand_sample = RandSample::::new(); + + assert_eq!(rand_sample.sample(&mut ::test::rng()), ConstRand(0)); + assert_eq!(rand_sample.ind_sample(&mut ::test::rng()), ConstRand(0)); + } + #[test] + fn test_weighted_choice() { + // this makes assumptions about the internal implementation of + // WeightedChoice, specifically: it doesn't reorder the items, + // it doesn't do weird things to the RNG (so 0 maps to 0, 1 to + // 1, internally; modulo a modulo operation). + + macro_rules! t { + ($items:expr, $expected:expr) => {{ + let mut items = $items; + let wc = WeightedChoice::new(&mut items); + let expected = $expected; + + let mut rng = CountingRng { i: 0 }; + + for &val in expected.iter() { + assert_eq!(wc.ind_sample(&mut rng), val) + } + }} + } + + t!(vec!(Weighted { weight: 1, item: 10}), [10]); + + // skip some + t!(vec!(Weighted { weight: 0, item: 20}, + Weighted { weight: 2, item: 21}, + Weighted { weight: 0, item: 22}, + Weighted { weight: 1, item: 23}), + [21,21, 23]); + + // different weights + t!(vec!(Weighted { weight: 4, item: 30}, + Weighted { weight: 3, item: 31}), + [30,30,30,30, 31,31,31]); + + // check that we're binary searching + // correctly with some vectors of odd + // length. + t!(vec!(Weighted { weight: 1, item: 40}, + Weighted { weight: 1, item: 41}, + Weighted { weight: 1, item: 42}, + Weighted { weight: 1, item: 43}, + Weighted { weight: 1, item: 44}), + [40, 41, 42, 43, 44]); + t!(vec!(Weighted { weight: 1, item: 50}, + Weighted { weight: 1, item: 51}, + Weighted { weight: 1, item: 52}, + Weighted { weight: 1, item: 53}, + Weighted { weight: 1, item: 54}, + Weighted { weight: 1, item: 55}, + Weighted { weight: 1, item: 56}), + [50, 51, 52, 53, 54, 55, 56]); + } + + #[test] + fn test_weighted_clone_initialization() { + let initial : Weighted = Weighted {weight: 1, item: 1}; + let clone = initial.clone(); + assert_eq!(initial.weight, clone.weight); + assert_eq!(initial.item, clone.item); + } + + #[test] #[should_panic] + fn test_weighted_clone_change_weight() { + let initial : Weighted = Weighted {weight: 1, item: 1}; + let mut clone = initial.clone(); + clone.weight = 5; + assert_eq!(initial.weight, clone.weight); + } + + #[test] #[should_panic] + fn test_weighted_clone_change_item() { + let initial : Weighted = Weighted {weight: 1, item: 1}; + let mut clone = initial.clone(); + clone.item = 5; + assert_eq!(initial.item, clone.item); + + } + + #[test] #[should_panic] + fn test_weighted_choice_no_items() { + WeightedChoice::::new(&mut []); + } + #[test] #[should_panic] + fn test_weighted_choice_zero_weight() { + WeightedChoice::new(&mut [Weighted { weight: 0, item: 0}, + Weighted { weight: 0, item: 1}]); + } + #[test] #[should_panic] + fn test_weighted_choice_weight_overflows() { + let x = ::std::u32::MAX / 2; // x + x + 2 is the overflow + WeightedChoice::new(&mut [Weighted { weight: x, item: 0 }, + Weighted { weight: 1, item: 1 }, + Weighted { weight: x, item: 2 }, + Weighted { weight: 1, item: 3 }]); + } +} diff --git a/third_party/rust/rand-0.4.3/src/distributions/normal.rs b/third_party/rust/rand-0.4.3/src/distributions/normal.rs new file mode 100644 index 000000000000..280613d8595d --- /dev/null +++ b/third_party/rust/rand-0.4.3/src/distributions/normal.rs @@ -0,0 +1,201 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The normal and derived distributions. + +use {Rng, Rand, Open01}; +use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample}; + +/// A wrapper around an `f64` to generate N(0, 1) random numbers +/// (a.k.a. a standard normal, or Gaussian). +/// +/// See `Normal` for the general normal distribution. +/// +/// Implemented via the ZIGNOR variant[1] of the Ziggurat method. +/// +/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to +/// Generate Normal Random +/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield +/// College, Oxford +/// +/// # Example +/// +/// ```rust +/// use rand::distributions::normal::StandardNormal; +/// +/// let StandardNormal(x) = rand::random(); +/// println!("{}", x); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct StandardNormal(pub f64); + +impl Rand for StandardNormal { + fn rand(rng: &mut R) -> StandardNormal { + #[inline] + fn pdf(x: f64) -> f64 { + (-x*x/2.0).exp() + } + #[inline] + fn zero_case(rng: &mut R, u: f64) -> f64 { + // compute a random number in the tail by hand + + // strange initial conditions, because the loop is not + // do-while, so the condition should be true on the first + // run, they get overwritten anyway (0 < 1, so these are + // good). + let mut x = 1.0f64; + let mut y = 0.0f64; + + while -2.0 * y < x * x { + let Open01(x_) = rng.gen::>(); + let Open01(y_) = rng.gen::>(); + + x = x_.ln() / ziggurat_tables::ZIG_NORM_R; + y = y_.ln(); + } + + if u < 0.0 { x - ziggurat_tables::ZIG_NORM_R } else { ziggurat_tables::ZIG_NORM_R - x } + } + + StandardNormal(ziggurat( + rng, + true, // this is symmetric + &ziggurat_tables::ZIG_NORM_X, + &ziggurat_tables::ZIG_NORM_F, + pdf, zero_case)) + } +} + +/// The normal distribution `N(mean, std_dev**2)`. +/// +/// This uses the ZIGNOR variant of the Ziggurat method, see +/// `StandardNormal` for more details. +/// +/// # Example +/// +/// ```rust +/// use rand::distributions::{Normal, IndependentSample}; +/// +/// // mean 2, standard deviation 3 +/// let normal = Normal::new(2.0, 3.0); +/// let v = normal.ind_sample(&mut rand::thread_rng()); +/// println!("{} is from a N(2, 9) distribution", v) +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Normal { + mean: f64, + std_dev: f64, +} + +impl Normal { + /// Construct a new `Normal` distribution with the given mean and + /// standard deviation. + /// + /// # Panics + /// + /// Panics if `std_dev < 0`. + #[inline] + pub fn new(mean: f64, std_dev: f64) -> Normal { + assert!(std_dev >= 0.0, "Normal::new called with `std_dev` < 0"); + Normal { + mean: mean, + std_dev: std_dev + } + } +} +impl Sample for Normal { + fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } +} +impl IndependentSample for Normal { + fn ind_sample(&self, rng: &mut R) -> f64 { + let StandardNormal(n) = rng.gen::(); + self.mean + self.std_dev * n + } +} + + +/// The log-normal distribution `ln N(mean, std_dev**2)`. +/// +/// If `X` is log-normal distributed, then `ln(X)` is `N(mean, +/// std_dev**2)` distributed. +/// +/// # Example +/// +/// ```rust +/// use rand::distributions::{LogNormal, IndependentSample}; +/// +/// // mean 2, standard deviation 3 +/// let log_normal = LogNormal::new(2.0, 3.0); +/// let v = log_normal.ind_sample(&mut rand::thread_rng()); +/// println!("{} is from an ln N(2, 9) distribution", v) +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct LogNormal { + norm: Normal +} + +impl LogNormal { + /// Construct a new `LogNormal` distribution with the given mean + /// and standard deviation. + /// + /// # Panics + /// + /// Panics if `std_dev < 0`. + #[inline] + pub fn new(mean: f64, std_dev: f64) -> LogNormal { + assert!(std_dev >= 0.0, "LogNormal::new called with `std_dev` < 0"); + LogNormal { norm: Normal::new(mean, std_dev) } + } +} +impl Sample for LogNormal { + fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } +} +impl IndependentSample for LogNormal { + fn ind_sample(&self, rng: &mut R) -> f64 { + self.norm.ind_sample(rng).exp() + } +} + +#[cfg(test)] +mod tests { + use distributions::{Sample, IndependentSample}; + use super::{Normal, LogNormal}; + + #[test] + fn test_normal() { + let mut norm = Normal::new(10.0, 10.0); + let mut rng = ::test::rng(); + for _ in 0..1000 { + norm.sample(&mut rng); + norm.ind_sample(&mut rng); + } + } + #[test] + #[should_panic] + fn test_normal_invalid_sd() { + Normal::new(10.0, -1.0); + } + + + #[test] + fn test_log_normal() { + let mut lnorm = LogNormal::new(10.0, 10.0); + let mut rng = ::test::rng(); + for _ in 0..1000 { + lnorm.sample(&mut rng); + lnorm.ind_sample(&mut rng); + } + } + #[test] + #[should_panic] + fn test_log_normal_invalid_sd() { + LogNormal::new(10.0, -1.0); + } +} diff --git a/third_party/rust/rand/src/distributions/range.rs b/third_party/rust/rand-0.4.3/src/distributions/range.rs similarity index 100% rename from third_party/rust/rand/src/distributions/range.rs rename to third_party/rust/rand-0.4.3/src/distributions/range.rs diff --git a/third_party/rust/rand-0.4.3/src/distributions/ziggurat_tables.rs b/third_party/rust/rand-0.4.3/src/distributions/ziggurat_tables.rs new file mode 100644 index 000000000000..b6de4bf892cd --- /dev/null +++ b/third_party/rust/rand-0.4.3/src/distributions/ziggurat_tables.rs @@ -0,0 +1,280 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tables for distributions which are sampled using the ziggurat +// algorithm. Autogenerated by `ziggurat_tables.py`. + +pub type ZigTable = &'static [f64; 257]; +pub const ZIG_NORM_R: f64 = 3.654152885361008796; +pub static ZIG_NORM_X: [f64; 257] = + [3.910757959537090045, 3.654152885361008796, 3.449278298560964462, 3.320244733839166074, + 3.224575052047029100, 3.147889289517149969, 3.083526132001233044, 3.027837791768635434, + 2.978603279880844834, 2.934366867207854224, 2.894121053612348060, 2.857138730872132548, + 2.822877396825325125, 2.790921174000785765, 2.760944005278822555, 2.732685359042827056, + 2.705933656121858100, 2.680514643284522158, 2.656283037575502437, 2.633116393630324570, + 2.610910518487548515, 2.589575986706995181, 2.569035452680536569, 2.549221550323460761, + 2.530075232158516929, 2.511544441625342294, 2.493583041269680667, 2.476149939669143318, + 2.459208374333311298, 2.442725318198956774, 2.426670984935725972, 2.411018413899685520, + 2.395743119780480601, 2.380822795170626005, 2.366237056715818632, 2.351967227377659952, + 2.337996148795031370, 2.324308018869623016, 2.310888250599850036, 2.297723348901329565, + 2.284800802722946056, 2.272108990226823888, 2.259637095172217780, 2.247375032945807760, + 2.235313384928327984, 2.223443340090905718, 2.211756642882544366, 2.200245546609647995, + 2.188902771624720689, 2.177721467738641614, 2.166695180352645966, 2.155817819875063268, + 2.145083634046203613, 2.134487182844320152, 2.124023315687815661, 2.113687150684933957, + 2.103474055713146829, 2.093379631137050279, 2.083399693996551783, 2.073530263516978778, + 2.063767547809956415, 2.054107931648864849, 2.044547965215732788, 2.035084353727808715, + 2.025713947862032960, 2.016433734904371722, 2.007240830558684852, 1.998132471356564244, + 1.989106007615571325, 1.980158896898598364, 1.971288697931769640, 1.962493064942461896, + 1.953769742382734043, 1.945116560006753925, 1.936531428273758904, 1.928012334050718257, + 1.919557336591228847, 1.911164563769282232, 1.902832208548446369, 1.894558525668710081, + 1.886341828534776388, 1.878180486290977669, 1.870072921069236838, 1.862017605397632281, + 1.854013059758148119, 1.846057850283119750, 1.838150586580728607, 1.830289919680666566, + 1.822474540091783224, 1.814703175964167636, 1.806974591348693426, 1.799287584547580199, + 1.791640986550010028, 1.784033659547276329, 1.776464495522344977, 1.768932414909077933, + 1.761436365316706665, 1.753975320315455111, 1.746548278279492994, 1.739154261283669012, + 1.731792314050707216, 1.724461502945775715, 1.717160915015540690, 1.709889657069006086, + 1.702646854797613907, 1.695431651932238548, 1.688243209434858727, 1.681080704722823338, + 1.673943330923760353, 1.666830296159286684, 1.659740822855789499, 1.652674147080648526, + 1.645629517902360339, 1.638606196773111146, 1.631603456932422036, 1.624620582830568427, + 1.617656869570534228, 1.610711622367333673, 1.603784156023583041, 1.596873794420261339, + 1.589979870021648534, 1.583101723393471438, 1.576238702733332886, 1.569390163412534456, + 1.562555467528439657, 1.555733983466554893, 1.548925085471535512, 1.542128153226347553, + 1.535342571438843118, 1.528567729435024614, 1.521803020758293101, 1.515047842773992404, + 1.508301596278571965, 1.501563685112706548, 1.494833515777718391, 1.488110497054654369, + 1.481394039625375747, 1.474683555695025516, 1.467978458615230908, 1.461278162507407830, + 1.454582081885523293, 1.447889631277669675, 1.441200224845798017, 1.434513276002946425, + 1.427828197027290358, 1.421144398672323117, 1.414461289772464658, 1.407778276843371534, + 1.401094763676202559, 1.394410150925071257, 1.387723835686884621, 1.381035211072741964, + 1.374343665770030531, 1.367648583594317957, 1.360949343030101844, 1.354245316759430606, + 1.347535871177359290, 1.340820365893152122, 1.334098153216083604, 1.327368577624624679, + 1.320630975217730096, 1.313884673146868964, 1.307128989027353860, 1.300363230327433728, + 1.293586693733517645, 1.286798664489786415, 1.279998415710333237, 1.273185207661843732, + 1.266358287014688333, 1.259516886060144225, 1.252660221891297887, 1.245787495544997903, + 1.238897891102027415, 1.231990574742445110, 1.225064693752808020, 1.218119375481726552, + 1.211153726239911244, 1.204166830140560140, 1.197157747875585931, 1.190125515422801650, + 1.183069142678760732, 1.175987612011489825, 1.168879876726833800, 1.161744859441574240, + 1.154581450355851802, 1.147388505416733873, 1.140164844363995789, 1.132909248648336975, + 1.125620459211294389, 1.118297174115062909, 1.110938046009249502, 1.103541679420268151, + 1.096106627847603487, 1.088631390649514197, 1.081114409698889389, 1.073554065787871714, + 1.065948674757506653, 1.058296483326006454, 1.050595664586207123, 1.042844313139370538, + 1.035040439828605274, 1.027181966030751292, 1.019266717460529215, 1.011292417434978441, + 1.003256679539591412, 0.995156999629943084, 0.986990747093846266, 0.978755155288937750, + 0.970447311058864615, 0.962064143217605250, 0.953602409875572654, 0.945058684462571130, + 0.936429340280896860, 0.927710533396234771, 0.918898183643734989, 0.909987953490768997, + 0.900975224455174528, 0.891855070726792376, 0.882622229578910122, 0.873271068082494550, + 0.863795545546826915, 0.854189171001560554, 0.844444954902423661, 0.834555354079518752, + 0.824512208745288633, 0.814306670128064347, 0.803929116982664893, 0.793369058833152785, + 0.782615023299588763, 0.771654424216739354, 0.760473406422083165, 0.749056662009581653, + 0.737387211425838629, 0.725446140901303549, 0.713212285182022732, 0.700661841097584448, + 0.687767892786257717, 0.674499822827436479, 0.660822574234205984, 0.646695714884388928, + 0.632072236375024632, 0.616896989996235545, 0.601104617743940417, 0.584616766093722262, + 0.567338257040473026, 0.549151702313026790, 0.529909720646495108, 0.509423329585933393, + 0.487443966121754335, 0.463634336771763245, 0.437518402186662658, 0.408389134588000746, + 0.375121332850465727, 0.335737519180459465, 0.286174591747260509, 0.215241895913273806, + 0.000000000000000000]; +pub static ZIG_NORM_F: [f64; 257] = + [0.000477467764586655, 0.001260285930498598, 0.002609072746106363, 0.004037972593371872, + 0.005522403299264754, 0.007050875471392110, 0.008616582769422917, 0.010214971439731100, + 0.011842757857943104, 0.013497450601780807, 0.015177088307982072, 0.016880083152595839, + 0.018605121275783350, 0.020351096230109354, 0.022117062707379922, 0.023902203305873237, + 0.025705804008632656, 0.027527235669693315, 0.029365939758230111, 0.031221417192023690, + 0.033093219458688698, 0.034980941461833073, 0.036884215688691151, 0.038802707404656918, + 0.040736110656078753, 0.042684144916619378, 0.044646552251446536, 0.046623094902089664, + 0.048613553216035145, 0.050617723861121788, 0.052635418276973649, 0.054666461325077916, + 0.056710690106399467, 0.058767952921137984, 0.060838108349751806, 0.062921024437977854, + 0.065016577971470438, 0.067124653828023989, 0.069245144397250269, 0.071377949059141965, + 0.073522973714240991, 0.075680130359194964, 0.077849336702372207, 0.080030515814947509, + 0.082223595813495684, 0.084428509570654661, 0.086645194450867782, 0.088873592068594229, + 0.091113648066700734, 0.093365311913026619, 0.095628536713353335, 0.097903279039215627, + 0.100189498769172020, 0.102487158942306270, 0.104796225622867056, 0.107116667775072880, + 0.109448457147210021, 0.111791568164245583, 0.114145977828255210, 0.116511665626037014, + 0.118888613443345698, 0.121276805485235437, 0.123676228202051403, 0.126086870220650349, + 0.128508722280473636, 0.130941777174128166, 0.133386029692162844, 0.135841476571757352, + 0.138308116449064322, 0.140785949814968309, 0.143274978974047118, 0.145775208006537926, + 0.148286642733128721, 0.150809290682410169, 0.153343161060837674, 0.155888264725064563, + 0.158444614156520225, 0.161012223438117663, 0.163591108232982951, 0.166181285765110071, + 0.168782774801850333, 0.171395595638155623, 0.174019770082499359, 0.176655321444406654, + 0.179302274523530397, 0.181960655600216487, 0.184630492427504539, 0.187311814224516926, + 0.190004651671193070, 0.192709036904328807, 0.195425003514885592, 0.198152586546538112, + 0.200891822495431333, 0.203642749311121501, 0.206405406398679298, 0.209179834621935651, + 0.211966076307852941, 0.214764175252008499, 0.217574176725178370, 0.220396127481011589, + 0.223230075764789593, 0.226076071323264877, 0.228934165415577484, 0.231804410825248525, + 0.234686861873252689, 0.237581574432173676, 0.240488605941449107, 0.243408015423711988, + 0.246339863502238771, 0.249284212419516704, 0.252241126056943765, 0.255210669955677150, + 0.258192911338648023, 0.261187919133763713, 0.264195763998317568, 0.267216518344631837, + 0.270250256366959984, 0.273297054069675804, 0.276356989296781264, 0.279430141762765316, + 0.282516593084849388, 0.285616426816658109, 0.288729728483353931, 0.291856585618280984, + 0.294997087801162572, 0.298151326697901342, 0.301319396102034120, 0.304501391977896274, + 0.307697412505553769, 0.310907558127563710, 0.314131931597630143, 0.317370638031222396, + 0.320623784958230129, 0.323891482377732021, 0.327173842814958593, 0.330470981380537099, + 0.333783015832108509, 0.337110066638412809, 0.340452257045945450, 0.343809713148291340, + 0.347182563958251478, 0.350570941482881204, 0.353974980801569250, 0.357394820147290515, + 0.360830600991175754, 0.364282468130549597, 0.367750569780596226, 0.371235057669821344, + 0.374736087139491414, 0.378253817247238111, 0.381788410875031348, 0.385340034841733958, + 0.388908860020464597, 0.392495061461010764, 0.396098818517547080, 0.399720314981931668, + 0.403359739222868885, 0.407017284331247953, 0.410693148271983222, 0.414387534042706784, + 0.418100649839684591, 0.421832709231353298, 0.425583931339900579, 0.429354541031341519, + 0.433144769114574058, 0.436954852549929273, 0.440785034667769915, 0.444635565397727750, + 0.448506701509214067, 0.452398706863882505, 0.456311852680773566, 0.460246417814923481, + 0.464202689050278838, 0.468180961407822172, 0.472181538469883255, 0.476204732721683788, + 0.480250865911249714, 0.484320269428911598, 0.488413284707712059, 0.492530263646148658, + 0.496671569054796314, 0.500837575128482149, 0.505028667945828791, 0.509245245998136142, + 0.513487720749743026, 0.517756517232200619, 0.522052074674794864, 0.526374847174186700, + 0.530725304406193921, 0.535103932383019565, 0.539511234259544614, 0.543947731192649941, + 0.548413963257921133, 0.552910490428519918, 0.557437893621486324, 0.561996775817277916, + 0.566587763258951771, 0.571211506738074970, 0.575868682975210544, 0.580559996103683473, + 0.585286179266300333, 0.590047996335791969, 0.594846243770991268, 0.599681752622167719, + 0.604555390700549533, 0.609468064928895381, 0.614420723892076803, 0.619414360609039205, + 0.624450015550274240, 0.629528779928128279, 0.634651799290960050, 0.639820277456438991, + 0.645035480824251883, 0.650298743114294586, 0.655611470583224665, 0.660975147780241357, + 0.666391343912380640, 0.671861719900766374, 0.677388036222513090, 0.682972161648791376, + 0.688616083008527058, 0.694321916130032579, 0.700091918140490099, 0.705928501336797409, + 0.711834248882358467, 0.717811932634901395, 0.723864533472881599, 0.729995264565802437, + 0.736207598131266683, 0.742505296344636245, 0.748892447223726720, 0.755373506511754500, + 0.761953346841546475, 0.768637315803334831, 0.775431304986138326, 0.782341832659861902, + 0.789376143571198563, 0.796542330428254619, 0.803849483176389490, 0.811307874318219935, + 0.818929191609414797, 0.826726833952094231, 0.834716292992930375, 0.842915653118441077, + 0.851346258465123684, 0.860033621203008636, 0.869008688043793165, 0.878309655816146839, + 0.887984660763399880, 0.898095921906304051, 0.908726440060562912, 0.919991505048360247, + 0.932060075968990209, 0.945198953453078028, 0.959879091812415930, 0.977101701282731328, + 1.000000000000000000]; +pub const ZIG_EXP_R: f64 = 7.697117470131050077; +pub static ZIG_EXP_X: [f64; 257] = + [8.697117470131052741, 7.697117470131050077, 6.941033629377212577, 6.478378493832569696, + 6.144164665772472667, 5.882144315795399869, 5.666410167454033697, 5.482890627526062488, + 5.323090505754398016, 5.181487281301500047, 5.054288489981304089, 4.938777085901250530, + 4.832939741025112035, 4.735242996601741083, 4.644491885420085175, 4.559737061707351380, + 4.480211746528421912, 4.405287693473573185, 4.334443680317273007, 4.267242480277365857, + 4.203313713735184365, 4.142340865664051464, 4.084051310408297830, 4.028208544647936762, + 3.974606066673788796, 3.923062500135489739, 3.873417670399509127, 3.825529418522336744, + 3.779270992411667862, 3.734528894039797375, 3.691201090237418825, 3.649195515760853770, + 3.608428813128909507, 3.568825265648337020, 3.530315889129343354, 3.492837654774059608, + 3.456332821132760191, 3.420748357251119920, 3.386035442460300970, 3.352149030900109405, + 3.319047470970748037, 3.286692171599068679, 3.255047308570449882, 3.224079565286264160, + 3.193757903212240290, 3.164053358025972873, 3.134938858084440394, 3.106389062339824481, + 3.078380215254090224, 3.050890016615455114, 3.023897504455676621, 2.997382949516130601, + 2.971327759921089662, 2.945714394895045718, 2.920526286512740821, 2.895747768600141825, + 2.871364012015536371, 2.847360965635188812, 2.823725302450035279, 2.800444370250737780, + 2.777506146439756574, 2.754899196562344610, 2.732612636194700073, 2.710636095867928752, + 2.688959688741803689, 2.667573980773266573, 2.646469963151809157, 2.625639026797788489, + 2.605072938740835564, 2.584763820214140750, 2.564704126316905253, 2.544886627111869970, + 2.525304390037828028, 2.505950763528594027, 2.486819361740209455, 2.467904050297364815, + 2.449198932978249754, 2.430698339264419694, 2.412396812688870629, 2.394289099921457886, + 2.376370140536140596, 2.358635057409337321, 2.341079147703034380, 2.323697874390196372, + 2.306486858283579799, 2.289441870532269441, 2.272558825553154804, 2.255833774367219213, + 2.239262898312909034, 2.222842503111036816, 2.206569013257663858, 2.190438966723220027, + 2.174449009937774679, 2.158595893043885994, 2.142876465399842001, 2.127287671317368289, + 2.111826546019042183, 2.096490211801715020, 2.081275874393225145, 2.066180819490575526, + 2.051202409468584786, 2.036338080248769611, 2.021585338318926173, 2.006941757894518563, + 1.992404978213576650, 1.977972700957360441, 1.963642687789548313, 1.949412758007184943, + 1.935280786297051359, 1.921244700591528076, 1.907302480018387536, 1.893452152939308242, + 1.879691795072211180, 1.866019527692827973, 1.852433515911175554, 1.838931967018879954, + 1.825513128903519799, 1.812175288526390649, 1.798916770460290859, 1.785735935484126014, + 1.772631179231305643, 1.759600930889074766, 1.746643651946074405, 1.733757834985571566, + 1.720942002521935299, 1.708194705878057773, 1.695514524101537912, 1.682900062917553896, + 1.670349953716452118, 1.657862852574172763, 1.645437439303723659, 1.633072416535991334, + 1.620766508828257901, 1.608518461798858379, 1.596327041286483395, 1.584191032532688892, + 1.572109239386229707, 1.560080483527888084, 1.548103603714513499, 1.536177455041032092, + 1.524300908219226258, 1.512472848872117082, 1.500692176842816750, 1.488957805516746058, + 1.477268661156133867, 1.465623682245745352, 1.454021818848793446, 1.442462031972012504, + 1.430943292938879674, 1.419464582769983219, 1.408024891569535697, 1.396623217917042137, + 1.385258568263121992, 1.373929956328490576, 1.362636402505086775, 1.351376933258335189, + 1.340150580529504643, 1.328956381137116560, 1.317793376176324749, 1.306660610415174117, + 1.295557131686601027, 1.284481990275012642, 1.273434238296241139, 1.262412929069615330, + 1.251417116480852521, 1.240445854334406572, 1.229498195693849105, 1.218573192208790124, + 1.207669893426761121, 1.196787346088403092, 1.185924593404202199, 1.175080674310911677, + 1.164254622705678921, 1.153445466655774743, 1.142652227581672841, 1.131873919411078511, + 1.121109547701330200, 1.110358108727411031, 1.099618588532597308, 1.088889961938546813, + 1.078171191511372307, 1.067461226479967662, 1.056759001602551429, 1.046063435977044209, + 1.035373431790528542, 1.024687873002617211, 1.014005623957096480, 1.003325527915696735, + 0.992646405507275897, 0.981967053085062602, 0.971286240983903260, 0.960602711668666509, + 0.949915177764075969, 0.939222319955262286, 0.928522784747210395, 0.917815182070044311, + 0.907098082715690257, 0.896370015589889935, 0.885629464761751528, 0.874874866291025066, + 0.864104604811004484, 0.853317009842373353, 0.842510351810368485, 0.831682837734273206, + 0.820832606554411814, 0.809957724057418282, 0.799056177355487174, 0.788125868869492430, + 0.777164609759129710, 0.766170112735434672, 0.755139984181982249, 0.744071715500508102, + 0.732962673584365398, 0.721810090308756203, 0.710611050909655040, 0.699362481103231959, + 0.688061132773747808, 0.676703568029522584, 0.665286141392677943, 0.653804979847664947, + 0.642255960424536365, 0.630634684933490286, 0.618936451394876075, 0.607156221620300030, + 0.595288584291502887, 0.583327712748769489, 0.571267316532588332, 0.559100585511540626, + 0.546820125163310577, 0.534417881237165604, 0.521885051592135052, 0.509211982443654398, + 0.496388045518671162, 0.483401491653461857, 0.470239275082169006, 0.456886840931420235, + 0.443327866073552401, 0.429543940225410703, 0.415514169600356364, 0.401214678896277765, + 0.386617977941119573, 0.371692145329917234, 0.356399760258393816, 0.340696481064849122, + 0.324529117016909452, 0.307832954674932158, 0.290527955491230394, 0.272513185478464703, + 0.253658363385912022, 0.233790483059674731, 0.212671510630966620, 0.189958689622431842, + 0.165127622564187282, 0.137304980940012589, 0.104838507565818778, 0.063852163815001570, + 0.000000000000000000]; +pub static ZIG_EXP_F: [f64; 257] = + [0.000167066692307963, 0.000454134353841497, 0.000967269282327174, 0.001536299780301573, + 0.002145967743718907, 0.002788798793574076, 0.003460264777836904, 0.004157295120833797, + 0.004877655983542396, 0.005619642207205489, 0.006381905937319183, 0.007163353183634991, + 0.007963077438017043, 0.008780314985808977, 0.009614413642502212, 0.010464810181029981, + 0.011331013597834600, 0.012212592426255378, 0.013109164931254991, 0.014020391403181943, + 0.014945968011691148, 0.015885621839973156, 0.016839106826039941, 0.017806200410911355, + 0.018786700744696024, 0.019780424338009740, 0.020787204072578114, 0.021806887504283581, + 0.022839335406385240, 0.023884420511558174, 0.024942026419731787, 0.026012046645134221, + 0.027094383780955803, 0.028188948763978646, 0.029295660224637411, 0.030414443910466622, + 0.031545232172893622, 0.032687963508959555, 0.033842582150874358, 0.035009037697397431, + 0.036187284781931443, 0.037377282772959382, 0.038578995503074871, 0.039792391023374139, + 0.041017441380414840, 0.042254122413316254, 0.043502413568888197, 0.044762297732943289, + 0.046033761076175184, 0.047316792913181561, 0.048611385573379504, 0.049917534282706379, + 0.051235237055126281, 0.052564494593071685, 0.053905310196046080, 0.055257689676697030, + 0.056621641283742870, 0.057997175631200659, 0.059384305633420280, 0.060783046445479660, + 0.062193415408541036, 0.063615431999807376, 0.065049117786753805, 0.066494496385339816, + 0.067951593421936643, 0.069420436498728783, 0.070901055162371843, 0.072393480875708752, + 0.073897746992364746, 0.075413888734058410, 0.076941943170480517, 0.078481949201606435, + 0.080033947542319905, 0.081597980709237419, 0.083174093009632397, 0.084762330532368146, + 0.086362741140756927, 0.087975374467270231, 0.089600281910032886, 0.091237516631040197, + 0.092887133556043569, 0.094549189376055873, 0.096223742550432825, 0.097910853311492213, + 0.099610583670637132, 0.101322997425953631, 0.103048160171257702, 0.104786139306570145, + 0.106537004050001632, 0.108300825451033755, 0.110077676405185357, 0.111867631670056283, + 0.113670767882744286, 0.115487163578633506, 0.117316899211555525, 0.119160057175327641, + 0.121016721826674792, 0.122886979509545108, 0.124770918580830933, 0.126668629437510671, + 0.128580204545228199, 0.130505738468330773, 0.132445327901387494, 0.134399071702213602, + 0.136367070926428829, 0.138349428863580176, 0.140346251074862399, 0.142357645432472146, + 0.144383722160634720, 0.146424593878344889, 0.148480375643866735, 0.150551185001039839, + 0.152637142027442801, 0.154738369384468027, 0.156854992369365148, 0.158987138969314129, + 0.161134939917591952, 0.163298528751901734, 0.165478041874935922, 0.167673618617250081, + 0.169885401302527550, 0.172113535315319977, 0.174358169171353411, 0.176619454590494829, + 0.178897546572478278, 0.181192603475496261, 0.183504787097767436, 0.185834262762197083, + 0.188181199404254262, 0.190545769663195363, 0.192928149976771296, 0.195328520679563189, + 0.197747066105098818, 0.200183974691911210, 0.202639439093708962, 0.205113656293837654, + 0.207606827724221982, 0.210119159388988230, 0.212650861992978224, 0.215202151075378628, + 0.217773247148700472, 0.220364375843359439, 0.222975768058120111, 0.225607660116683956, + 0.228260293930716618, 0.230933917169627356, 0.233628783437433291, 0.236345152457059560, + 0.239083290262449094, 0.241843469398877131, 0.244625969131892024, 0.247431075665327543, + 0.250259082368862240, 0.253110290015629402, 0.255985007030415324, 0.258883549749016173, + 0.261806242689362922, 0.264753418835062149, 0.267725419932044739, 0.270722596799059967, + 0.273745309652802915, 0.276793928448517301, 0.279868833236972869, 0.282970414538780746, + 0.286099073737076826, 0.289255223489677693, 0.292439288161892630, 0.295651704281261252, + 0.298892921015581847, 0.302163400675693528, 0.305463619244590256, 0.308794066934560185, + 0.312155248774179606, 0.315547685227128949, 0.318971912844957239, 0.322428484956089223, + 0.325917972393556354, 0.329440964264136438, 0.332998068761809096, 0.336589914028677717, + 0.340217149066780189, 0.343880444704502575, 0.347580494621637148, 0.351318016437483449, + 0.355093752866787626, 0.358908472948750001, 0.362762973354817997, 0.366658079781514379, + 0.370594648435146223, 0.374573567615902381, 0.378595759409581067, 0.382662181496010056, + 0.386773829084137932, 0.390931736984797384, 0.395136981833290435, 0.399390684475231350, + 0.403694012530530555, 0.408048183152032673, 0.412454465997161457, 0.416914186433003209, + 0.421428728997616908, 0.425999541143034677, 0.430628137288459167, 0.435316103215636907, + 0.440065100842354173, 0.444876873414548846, 0.449753251162755330, 0.454696157474615836, + 0.459707615642138023, 0.464789756250426511, 0.469944825283960310, 0.475175193037377708, + 0.480483363930454543, 0.485871987341885248, 0.491343869594032867, 0.496901987241549881, + 0.502549501841348056, 0.508289776410643213, 0.514126393814748894, 0.520063177368233931, + 0.526104213983620062, 0.532253880263043655, 0.538516872002862246, 0.544898237672440056, + 0.551403416540641733, 0.558038282262587892, 0.564809192912400615, 0.571723048664826150, + 0.578787358602845359, 0.586010318477268366, 0.593400901691733762, 0.600968966365232560, + 0.608725382079622346, 0.616682180915207878, 0.624852738703666200, 0.633251994214366398, + 0.641896716427266423, 0.650805833414571433, 0.660000841079000145, 0.669506316731925177, + 0.679350572264765806, 0.689566496117078431, 0.700192655082788606, 0.711274760805076456, + 0.722867659593572465, 0.735038092431424039, 0.747868621985195658, 0.761463388849896838, + 0.775956852040116218, 0.791527636972496285, 0.808421651523009044, 0.826993296643051101, + 0.847785500623990496, 0.871704332381204705, 0.900469929925747703, 0.938143680862176477, + 1.000000000000000000]; diff --git a/third_party/rust/rand/src/jitter.rs b/third_party/rust/rand-0.4.3/src/jitter.rs similarity index 100% rename from third_party/rust/rand/src/jitter.rs rename to third_party/rust/rand-0.4.3/src/jitter.rs diff --git a/third_party/rust/rand-0.4.3/src/lib.rs b/third_party/rust/rand-0.4.3/src/lib.rs new file mode 100644 index 000000000000..7b22dd45de7e --- /dev/null +++ b/third_party/rust/rand-0.4.3/src/lib.rs @@ -0,0 +1,1214 @@ +// Copyright 2013-2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Utilities for random number generation +//! +//! The key functions are `random()` and `Rng::gen()`. These are polymorphic and +//! so can be used to generate any type that implements `Rand`. Type inference +//! means that often a simple call to `rand::random()` or `rng.gen()` will +//! suffice, but sometimes an annotation is required, e.g. +//! `rand::random::()`. +//! +//! See the `distributions` submodule for sampling random numbers from +//! distributions like normal and exponential. +//! +//! # Usage +//! +//! This crate is [on crates.io](https://crates.io/crates/rand) and can be +//! used by adding `rand` to the dependencies in your project's `Cargo.toml`. +//! +//! ```toml +//! [dependencies] +//! rand = "0.4" +//! ``` +//! +//! and this to your crate root: +//! +//! ```rust +//! extern crate rand; +//! ``` +//! +//! # Thread-local RNG +//! +//! There is built-in support for a RNG associated with each thread stored +//! in thread-local storage. This RNG can be accessed via `thread_rng`, or +//! used implicitly via `random`. This RNG is normally randomly seeded +//! from an operating-system source of randomness, e.g. `/dev/urandom` on +//! Unix systems, and will automatically reseed itself from this source +//! after generating 32 KiB of random data. +//! +//! # Cryptographic security +//! +//! An application that requires an entropy source for cryptographic purposes +//! must use `OsRng`, which reads randomness from the source that the operating +//! system provides (e.g. `/dev/urandom` on Unixes or `CryptGenRandom()` on +//! Windows). +//! The other random number generators provided by this module are not suitable +//! for such purposes. +//! +//! *Note*: many Unix systems provide `/dev/random` as well as `/dev/urandom`. +//! This module uses `/dev/urandom` for the following reasons: +//! +//! - On Linux, `/dev/random` may block if entropy pool is empty; +//! `/dev/urandom` will not block. This does not mean that `/dev/random` +//! provides better output than `/dev/urandom`; the kernel internally runs a +//! cryptographically secure pseudorandom number generator (CSPRNG) based on +//! entropy pool for random number generation, so the "quality" of +//! `/dev/random` is not better than `/dev/urandom` in most cases. However, +//! this means that `/dev/urandom` can yield somewhat predictable randomness +//! if the entropy pool is very small, such as immediately after first +//! booting. Linux 3.17 added the `getrandom(2)` system call which solves +//! the issue: it blocks if entropy pool is not initialized yet, but it does +//! not block once initialized. `OsRng` tries to use `getrandom(2)` if +//! available, and use `/dev/urandom` fallback if not. If an application +//! does not have `getrandom` and likely to be run soon after first booting, +//! or on a system with very few entropy sources, one should consider using +//! `/dev/random` via `ReadRng`. +//! - On some systems (e.g. FreeBSD, OpenBSD and Mac OS X) there is no +//! difference between the two sources. (Also note that, on some systems +//! e.g. FreeBSD, both `/dev/random` and `/dev/urandom` may block once if +//! the CSPRNG has not seeded yet.) +//! +//! # Examples +//! +//! ```rust +//! use rand::Rng; +//! +//! let mut rng = rand::thread_rng(); +//! if rng.gen() { // random bool +//! println!("i32: {}, u32: {}", rng.gen::(), rng.gen::()) +//! } +//! ``` +//! +//! ```rust +//! let tuple = rand::random::<(f64, char)>(); +//! println!("{:?}", tuple) +//! ``` +//! +//! ## Monte Carlo estimation of Ï€ +//! +//! For this example, imagine we have a square with sides of length 2 and a unit +//! circle, both centered at the origin. Since the area of a unit circle is Ï€, +//! we have: +//! +//! ```text +//! (area of unit circle) / (area of square) = Ï€ / 4 +//! ``` +//! +//! So if we sample many points randomly from the square, roughly Ï€ / 4 of them +//! should be inside the circle. +//! +//! We can use the above fact to estimate the value of Ï€: pick many points in +//! the square at random, calculate the fraction that fall within the circle, +//! and multiply this fraction by 4. +//! +//! ``` +//! use rand::distributions::{IndependentSample, Range}; +//! +//! fn main() { +//! let between = Range::new(-1f64, 1.); +//! let mut rng = rand::thread_rng(); +//! +//! let total = 1_000_000; +//! let mut in_circle = 0; +//! +//! for _ in 0..total { +//! let a = between.ind_sample(&mut rng); +//! let b = between.ind_sample(&mut rng); +//! if a*a + b*b <= 1. { +//! in_circle += 1; +//! } +//! } +//! +//! // prints something close to 3.14159... +//! println!("{}", 4. * (in_circle as f64) / (total as f64)); +//! } +//! ``` +//! +//! ## Monty Hall Problem +//! +//! This is a simulation of the [Monty Hall Problem][]: +//! +//! > Suppose you're on a game show, and you're given the choice of three doors: +//! > Behind one door is a car; behind the others, goats. You pick a door, say +//! > No. 1, and the host, who knows what's behind the doors, opens another +//! > door, say No. 3, which has a goat. He then says to you, "Do you want to +//! > pick door No. 2?" Is it to your advantage to switch your choice? +//! +//! The rather unintuitive answer is that you will have a 2/3 chance of winning +//! if you switch and a 1/3 chance of winning if you don't, so it's better to +//! switch. +//! +//! This program will simulate the game show and with large enough simulation +//! steps it will indeed confirm that it is better to switch. +//! +//! [Monty Hall Problem]: http://en.wikipedia.org/wiki/Monty_Hall_problem +//! +//! ``` +//! use rand::Rng; +//! use rand::distributions::{IndependentSample, Range}; +//! +//! struct SimulationResult { +//! win: bool, +//! switch: bool, +//! } +//! +//! // Run a single simulation of the Monty Hall problem. +//! fn simulate(random_door: &Range, rng: &mut R) +//! -> SimulationResult { +//! let car = random_door.ind_sample(rng); +//! +//! // This is our initial choice +//! let mut choice = random_door.ind_sample(rng); +//! +//! // The game host opens a door +//! let open = game_host_open(car, choice, rng); +//! +//! // Shall we switch? +//! let switch = rng.gen(); +//! if switch { +//! choice = switch_door(choice, open); +//! } +//! +//! SimulationResult { win: choice == car, switch: switch } +//! } +//! +//! // Returns the door the game host opens given our choice and knowledge of +//! // where the car is. The game host will never open the door with the car. +//! fn game_host_open(car: u32, choice: u32, rng: &mut R) -> u32 { +//! let choices = free_doors(&[car, choice]); +//! rand::seq::sample_slice(rng, &choices, 1)[0] +//! } +//! +//! // Returns the door we switch to, given our current choice and +//! // the open door. There will only be one valid door. +//! fn switch_door(choice: u32, open: u32) -> u32 { +//! free_doors(&[choice, open])[0] +//! } +//! +//! fn free_doors(blocked: &[u32]) -> Vec { +//! (0..3).filter(|x| !blocked.contains(x)).collect() +//! } +//! +//! fn main() { +//! // The estimation will be more accurate with more simulations +//! let num_simulations = 10000; +//! +//! let mut rng = rand::thread_rng(); +//! let random_door = Range::new(0, 3); +//! +//! let (mut switch_wins, mut switch_losses) = (0, 0); +//! let (mut keep_wins, mut keep_losses) = (0, 0); +//! +//! println!("Running {} simulations...", num_simulations); +//! for _ in 0..num_simulations { +//! let result = simulate(&random_door, &mut rng); +//! +//! match (result.win, result.switch) { +//! (true, true) => switch_wins += 1, +//! (true, false) => keep_wins += 1, +//! (false, true) => switch_losses += 1, +//! (false, false) => keep_losses += 1, +//! } +//! } +//! +//! let total_switches = switch_wins + switch_losses; +//! let total_keeps = keep_wins + keep_losses; +//! +//! println!("Switched door {} times with {} wins and {} losses", +//! total_switches, switch_wins, switch_losses); +//! +//! println!("Kept our choice {} times with {} wins and {} losses", +//! total_keeps, keep_wins, keep_losses); +//! +//! // With a large number of simulations, the values should converge to +//! // 0.667 and 0.333 respectively. +//! println!("Estimated chance to win if we switch: {}", +//! switch_wins as f32 / total_switches as f32); +//! println!("Estimated chance to win if we don't: {}", +//! keep_wins as f32 / total_keeps as f32); +//! } +//! ``` + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://docs.rs/rand/0.4")] + +#![deny(missing_debug_implementations)] + +#![cfg_attr(not(feature="std"), no_std)] +#![cfg_attr(all(feature="alloc", not(feature="std")), feature(alloc))] +#![cfg_attr(feature = "i128_support", feature(i128_type, i128))] + +#[cfg(feature="std")] extern crate std as core; +#[cfg(all(feature = "alloc", not(feature="std")))] extern crate alloc; + +use core::marker; +use core::mem; +#[cfg(feature="std")] use std::cell::RefCell; +#[cfg(feature="std")] use std::io; +#[cfg(feature="std")] use std::rc::Rc; + +// external rngs +pub use jitter::JitterRng; +#[cfg(feature="std")] pub use os::OsRng; + +// pseudo rngs +pub use isaac::{IsaacRng, Isaac64Rng}; +pub use chacha::ChaChaRng; +pub use prng::XorShiftRng; + +// local use declarations +#[cfg(target_pointer_width = "32")] +use prng::IsaacRng as IsaacWordRng; +#[cfg(target_pointer_width = "64")] +use prng::Isaac64Rng as IsaacWordRng; + +use distributions::{Range, IndependentSample}; +use distributions::range::SampleRange; + +// public modules +pub mod distributions; +pub mod jitter; +#[cfg(feature="std")] pub mod os; +#[cfg(feature="std")] pub mod read; +pub mod reseeding; +#[cfg(any(feature="std", feature = "alloc"))] pub mod seq; + +// These tiny modules are here to avoid API breakage, probably only temporarily +pub mod chacha { + //! The ChaCha random number generator. + pub use prng::ChaChaRng; +} +pub mod isaac { + //! The ISAAC random number generator. + pub use prng::{IsaacRng, Isaac64Rng}; +} + +// private modules +mod rand_impls; +mod prng; + + +/// A type that can be randomly generated using an `Rng`. +/// +/// ## Built-in Implementations +/// +/// This crate implements `Rand` for various primitive types. Assuming the +/// provided `Rng` is well-behaved, these implementations generate values with +/// the following ranges and distributions: +/// +/// * Integers (`i32`, `u32`, `isize`, `usize`, etc.): Uniformly distributed +/// over all values of the type. +/// * `char`: Uniformly distributed over all Unicode scalar values, i.e. all +/// code points in the range `0...0x10_FFFF`, except for the range +/// `0xD800...0xDFFF` (the surrogate code points). This includes +/// unassigned/reserved code points. +/// * `bool`: Generates `false` or `true`, each with probability 0.5. +/// * Floating point types (`f32` and `f64`): Uniformly distributed in the +/// half-open range `[0, 1)`. (The [`Open01`], [`Closed01`], [`Exp1`], and +/// [`StandardNormal`] wrapper types produce floating point numbers with +/// alternative ranges or distributions.) +/// +/// [`Open01`]: struct.Open01.html +/// [`Closed01`]: struct.Closed01.html +/// [`Exp1`]: distributions/exponential/struct.Exp1.html +/// [`StandardNormal`]: distributions/normal/struct.StandardNormal.html +/// +/// The following aggregate types also implement `Rand` as long as their +/// component types implement it: +/// +/// * Tuples and arrays: Each element of the tuple or array is generated +/// independently, using its own `Rand` implementation. +/// * `Option`: Returns `None` with probability 0.5; otherwise generates a +/// random `T` and returns `Some(T)`. +pub trait Rand : Sized { + /// Generates a random instance of this type using the specified source of + /// randomness. + fn rand(rng: &mut R) -> Self; +} + +/// A random number generator. +pub trait Rng { + /// Return the next random u32. + /// + /// This rarely needs to be called directly, prefer `r.gen()` to + /// `r.next_u32()`. + // FIXME #rust-lang/rfcs#628: Should be implemented in terms of next_u64 + fn next_u32(&mut self) -> u32; + + /// Return the next random u64. + /// + /// By default this is implemented in terms of `next_u32`. An + /// implementation of this trait must provide at least one of + /// these two methods. Similarly to `next_u32`, this rarely needs + /// to be called directly, prefer `r.gen()` to `r.next_u64()`. + fn next_u64(&mut self) -> u64 { + ((self.next_u32() as u64) << 32) | (self.next_u32() as u64) + } + + /// Return the next random f32 selected from the half-open + /// interval `[0, 1)`. + /// + /// This uses a technique described by Saito and Matsumoto at + /// MCQMC'08. Given that the IEEE floating point numbers are + /// uniformly distributed over [1,2), we generate a number in + /// this range and then offset it onto the range [0,1). Our + /// choice of bits (masking v. shifting) is arbitrary and + /// should be immaterial for high quality generators. For low + /// quality generators (ex. LCG), prefer bitshifting due to + /// correlation between sequential low order bits. + /// + /// See: + /// A PRNG specialized in double precision floating point numbers using + /// an affine transition + /// + /// * + /// * + /// + /// By default this is implemented in terms of `next_u32`, but a + /// random number generator which can generate numbers satisfying + /// the requirements directly can overload this for performance. + /// It is required that the return value lies in `[0, 1)`. + /// + /// See `Closed01` for the closed interval `[0,1]`, and + /// `Open01` for the open interval `(0,1)`. + fn next_f32(&mut self) -> f32 { + const UPPER_MASK: u32 = 0x3F800000; + const LOWER_MASK: u32 = 0x7FFFFF; + let tmp = UPPER_MASK | (self.next_u32() & LOWER_MASK); + let result: f32 = unsafe { mem::transmute(tmp) }; + result - 1.0 + } + + /// Return the next random f64 selected from the half-open + /// interval `[0, 1)`. + /// + /// By default this is implemented in terms of `next_u64`, but a + /// random number generator which can generate numbers satisfying + /// the requirements directly can overload this for performance. + /// It is required that the return value lies in `[0, 1)`. + /// + /// See `Closed01` for the closed interval `[0,1]`, and + /// `Open01` for the open interval `(0,1)`. + fn next_f64(&mut self) -> f64 { + const UPPER_MASK: u64 = 0x3FF0000000000000; + const LOWER_MASK: u64 = 0xFFFFFFFFFFFFF; + let tmp = UPPER_MASK | (self.next_u64() & LOWER_MASK); + let result: f64 = unsafe { mem::transmute(tmp) }; + result - 1.0 + } + + /// Fill `dest` with random data. + /// + /// This has a default implementation in terms of `next_u64` and + /// `next_u32`, but should be overridden by implementations that + /// offer a more efficient solution than just calling those + /// methods repeatedly. + /// + /// This method does *not* have a requirement to bear any fixed + /// relationship to the other methods, for example, it does *not* + /// have to result in the same output as progressively filling + /// `dest` with `self.gen::()`, and any such behaviour should + /// not be relied upon. + /// + /// This method should guarantee that `dest` is entirely filled + /// with new data, and may panic if this is impossible + /// (e.g. reading past the end of a file that is being used as the + /// source of randomness). + /// + /// # Example + /// + /// ```rust + /// use rand::{thread_rng, Rng}; + /// + /// let mut v = [0u8; 13579]; + /// thread_rng().fill_bytes(&mut v); + /// println!("{:?}", &v[..]); + /// ``` + fn fill_bytes(&mut self, dest: &mut [u8]) { + // this could, in theory, be done by transmuting dest to a + // [u64], but this is (1) likely to be undefined behaviour for + // LLVM, (2) has to be very careful about alignment concerns, + // (3) adds more `unsafe` that needs to be checked, (4) + // probably doesn't give much performance gain if + // optimisations are on. + let mut count = 0; + let mut num = 0; + for byte in dest.iter_mut() { + if count == 0 { + // we could micro-optimise here by generating a u32 if + // we only need a few more bytes to fill the vector + // (i.e. at most 4). + num = self.next_u64(); + count = 8; + } + + *byte = (num & 0xff) as u8; + num >>= 8; + count -= 1; + } + } + + /// Return a random value of a `Rand` type. + /// + /// # Example + /// + /// ```rust + /// use rand::{thread_rng, Rng}; + /// + /// let mut rng = thread_rng(); + /// let x: u32 = rng.gen(); + /// println!("{}", x); + /// println!("{:?}", rng.gen::<(f64, bool)>()); + /// ``` + #[inline(always)] + fn gen(&mut self) -> T where Self: Sized { + Rand::rand(self) + } + + /// Return an iterator that will yield an infinite number of randomly + /// generated items. + /// + /// # Example + /// + /// ``` + /// use rand::{thread_rng, Rng}; + /// + /// let mut rng = thread_rng(); + /// let x = rng.gen_iter::().take(10).collect::>(); + /// println!("{:?}", x); + /// println!("{:?}", rng.gen_iter::<(f64, bool)>().take(5) + /// .collect::>()); + /// ``` + fn gen_iter<'a, T: Rand>(&'a mut self) -> Generator<'a, T, Self> where Self: Sized { + Generator { rng: self, _marker: marker::PhantomData } + } + + /// Generate a random value in the range [`low`, `high`). + /// + /// This is a convenience wrapper around + /// `distributions::Range`. If this function will be called + /// repeatedly with the same arguments, one should use `Range`, as + /// that will amortize the computations that allow for perfect + /// uniformity, as they only happen on initialization. + /// + /// # Panics + /// + /// Panics if `low >= high`. + /// + /// # Example + /// + /// ```rust + /// use rand::{thread_rng, Rng}; + /// + /// let mut rng = thread_rng(); + /// let n: u32 = rng.gen_range(0, 10); + /// println!("{}", n); + /// let m: f64 = rng.gen_range(-40.0f64, 1.3e5f64); + /// println!("{}", m); + /// ``` + fn gen_range(&mut self, low: T, high: T) -> T where Self: Sized { + assert!(low < high, "Rng.gen_range called with low >= high"); + Range::new(low, high).ind_sample(self) + } + + /// Return a bool with a 1 in n chance of true + /// + /// # Example + /// + /// ```rust + /// use rand::{thread_rng, Rng}; + /// + /// let mut rng = thread_rng(); + /// println!("{}", rng.gen_weighted_bool(3)); + /// ``` + fn gen_weighted_bool(&mut self, n: u32) -> bool where Self: Sized { + n <= 1 || self.gen_range(0, n) == 0 + } + + /// Return an iterator of random characters from the set A-Z,a-z,0-9. + /// + /// # Example + /// + /// ```rust + /// use rand::{thread_rng, Rng}; + /// + /// let s: String = thread_rng().gen_ascii_chars().take(10).collect(); + /// println!("{}", s); + /// ``` + fn gen_ascii_chars<'a>(&'a mut self) -> AsciiGenerator<'a, Self> where Self: Sized { + AsciiGenerator { rng: self } + } + + /// Return a random element from `values`. + /// + /// Return `None` if `values` is empty. + /// + /// # Example + /// + /// ``` + /// use rand::{thread_rng, Rng}; + /// + /// let choices = [1, 2, 4, 8, 16, 32]; + /// let mut rng = thread_rng(); + /// println!("{:?}", rng.choose(&choices)); + /// assert_eq!(rng.choose(&choices[..0]), None); + /// ``` + fn choose<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T> where Self: Sized { + if values.is_empty() { + None + } else { + Some(&values[self.gen_range(0, values.len())]) + } + } + + /// Return a mutable pointer to a random element from `values`. + /// + /// Return `None` if `values` is empty. + fn choose_mut<'a, T>(&mut self, values: &'a mut [T]) -> Option<&'a mut T> where Self: Sized { + if values.is_empty() { + None + } else { + let len = values.len(); + Some(&mut values[self.gen_range(0, len)]) + } + } + + /// Shuffle a mutable slice in place. + /// + /// This applies Durstenfeld's algorithm for the [Fisher–Yates shuffle](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm) + /// which produces an unbiased permutation. + /// + /// # Example + /// + /// ```rust + /// use rand::{thread_rng, Rng}; + /// + /// let mut rng = thread_rng(); + /// let mut y = [1, 2, 3]; + /// rng.shuffle(&mut y); + /// println!("{:?}", y); + /// rng.shuffle(&mut y); + /// println!("{:?}", y); + /// ``` + fn shuffle(&mut self, values: &mut [T]) where Self: Sized { + let mut i = values.len(); + while i >= 2 { + // invariant: elements with index >= i have been locked in place. + i -= 1; + // lock element i in place. + values.swap(i, self.gen_range(0, i + 1)); + } + } +} + +impl<'a, R: ?Sized> Rng for &'a mut R where R: Rng { + fn next_u32(&mut self) -> u32 { + (**self).next_u32() + } + + fn next_u64(&mut self) -> u64 { + (**self).next_u64() + } + + fn next_f32(&mut self) -> f32 { + (**self).next_f32() + } + + fn next_f64(&mut self) -> f64 { + (**self).next_f64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + (**self).fill_bytes(dest) + } +} + +#[cfg(feature="std")] +impl Rng for Box where R: Rng { + fn next_u32(&mut self) -> u32 { + (**self).next_u32() + } + + fn next_u64(&mut self) -> u64 { + (**self).next_u64() + } + + fn next_f32(&mut self) -> f32 { + (**self).next_f32() + } + + fn next_f64(&mut self) -> f64 { + (**self).next_f64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + (**self).fill_bytes(dest) + } +} + +/// Iterator which will generate a stream of random items. +/// +/// This iterator is created via the [`gen_iter`] method on [`Rng`]. +/// +/// [`gen_iter`]: trait.Rng.html#method.gen_iter +/// [`Rng`]: trait.Rng.html +#[derive(Debug)] +pub struct Generator<'a, T, R:'a> { + rng: &'a mut R, + _marker: marker::PhantomData T>, +} + +impl<'a, T: Rand, R: Rng> Iterator for Generator<'a, T, R> { + type Item = T; + + fn next(&mut self) -> Option { + Some(self.rng.gen()) + } +} + +/// Iterator which will continuously generate random ascii characters. +/// +/// This iterator is created via the [`gen_ascii_chars`] method on [`Rng`]. +/// +/// [`gen_ascii_chars`]: trait.Rng.html#method.gen_ascii_chars +/// [`Rng`]: trait.Rng.html +#[derive(Debug)] +pub struct AsciiGenerator<'a, R:'a> { + rng: &'a mut R, +} + +impl<'a, R: Rng> Iterator for AsciiGenerator<'a, R> { + type Item = char; + + fn next(&mut self) -> Option { + const GEN_ASCII_STR_CHARSET: &'static [u8] = + b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ + abcdefghijklmnopqrstuvwxyz\ + 0123456789"; + Some(*self.rng.choose(GEN_ASCII_STR_CHARSET).unwrap() as char) + } +} + +/// A random number generator that can be explicitly seeded to produce +/// the same stream of randomness multiple times. +pub trait SeedableRng: Rng { + /// Reseed an RNG with the given seed. + /// + /// # Example + /// + /// ```rust + /// use rand::{Rng, SeedableRng, StdRng}; + /// + /// let seed: &[_] = &[1, 2, 3, 4]; + /// let mut rng: StdRng = SeedableRng::from_seed(seed); + /// println!("{}", rng.gen::()); + /// rng.reseed(&[5, 6, 7, 8]); + /// println!("{}", rng.gen::()); + /// ``` + fn reseed(&mut self, Seed); + + /// Create a new RNG with the given seed. + /// + /// # Example + /// + /// ```rust + /// use rand::{Rng, SeedableRng, StdRng}; + /// + /// let seed: &[_] = &[1, 2, 3, 4]; + /// let mut rng: StdRng = SeedableRng::from_seed(seed); + /// println!("{}", rng.gen::()); + /// ``` + fn from_seed(seed: Seed) -> Self; +} + +/// A wrapper for generating floating point numbers uniformly in the +/// open interval `(0,1)` (not including either endpoint). +/// +/// Use `Closed01` for the closed interval `[0,1]`, and the default +/// `Rand` implementation for `f32` and `f64` for the half-open +/// `[0,1)`. +/// +/// # Example +/// ```rust +/// use rand::{random, Open01}; +/// +/// let Open01(val) = random::>(); +/// println!("f32 from (0,1): {}", val); +/// ``` +#[derive(Debug)] +pub struct Open01(pub F); + +/// A wrapper for generating floating point numbers uniformly in the +/// closed interval `[0,1]` (including both endpoints). +/// +/// Use `Open01` for the closed interval `(0,1)`, and the default +/// `Rand` implementation of `f32` and `f64` for the half-open +/// `[0,1)`. +/// +/// # Example +/// +/// ```rust +/// use rand::{random, Closed01}; +/// +/// let Closed01(val) = random::>(); +/// println!("f32 from [0,1]: {}", val); +/// ``` +#[derive(Debug)] +pub struct Closed01(pub F); + +/// The standard RNG. This is designed to be efficient on the current +/// platform. +#[derive(Copy, Clone, Debug)] +pub struct StdRng { + rng: IsaacWordRng, +} + +impl StdRng { + /// Create a randomly seeded instance of `StdRng`. + /// + /// This is a very expensive operation as it has to read + /// randomness from the operating system and use this in an + /// expensive seeding operation. If one is only generating a small + /// number of random numbers, or doesn't need the utmost speed for + /// generating each number, `thread_rng` and/or `random` may be more + /// appropriate. + /// + /// Reading the randomness from the OS may fail, and any error is + /// propagated via the `io::Result` return value. + #[cfg(feature="std")] + pub fn new() -> io::Result { + match OsRng::new() { + Ok(mut r) => Ok(StdRng { rng: r.gen() }), + Err(e1) => { + match JitterRng::new() { + Ok(mut r) => Ok(StdRng { rng: r.gen() }), + Err(_) => { + Err(e1) + } + } + } + } + } +} + +impl Rng for StdRng { + #[inline] + fn next_u32(&mut self) -> u32 { + self.rng.next_u32() + } + + #[inline] + fn next_u64(&mut self) -> u64 { + self.rng.next_u64() + } +} + +impl<'a> SeedableRng<&'a [usize]> for StdRng { + fn reseed(&mut self, seed: &'a [usize]) { + // the internal RNG can just be seeded from the above + // randomness. + self.rng.reseed(unsafe {mem::transmute(seed)}) + } + + fn from_seed(seed: &'a [usize]) -> StdRng { + StdRng { rng: SeedableRng::from_seed(unsafe {mem::transmute(seed)}) } + } +} + +/// Create a weak random number generator with a default algorithm and seed. +/// +/// It returns the fastest `Rng` algorithm currently available in Rust without +/// consideration for cryptography or security. If you require a specifically +/// seeded `Rng` for consistency over time you should pick one algorithm and +/// create the `Rng` yourself. +/// +/// This will seed the generator with randomness from thread_rng. +#[cfg(feature="std")] +pub fn weak_rng() -> XorShiftRng { + thread_rng().gen() +} + +/// Controls how the thread-local RNG is reseeded. +#[cfg(feature="std")] +#[derive(Debug)] +struct ThreadRngReseeder; + +#[cfg(feature="std")] +impl reseeding::Reseeder for ThreadRngReseeder { + fn reseed(&mut self, rng: &mut StdRng) { + match StdRng::new() { + Ok(r) => *rng = r, + Err(e) => panic!("No entropy available: {}", e), + } + } +} +#[cfg(feature="std")] +const THREAD_RNG_RESEED_THRESHOLD: u64 = 32_768; +#[cfg(feature="std")] +type ThreadRngInner = reseeding::ReseedingRng; + +/// The thread-local RNG. +#[cfg(feature="std")] +#[derive(Clone, Debug)] +pub struct ThreadRng { + rng: Rc>, +} + +/// Retrieve the lazily-initialized thread-local random number +/// generator, seeded by the system. Intended to be used in method +/// chaining style, e.g. `thread_rng().gen::()`. +/// +/// After generating a certain amount of randomness, the RNG will reseed itself +/// from the operating system or, if the operating system RNG returns an error, +/// a seed based on the current system time. +/// +/// The internal RNG used is platform and architecture dependent, even +/// if the operating system random number generator is rigged to give +/// the same sequence always. If absolute consistency is required, +/// explicitly select an RNG, e.g. `IsaacRng` or `Isaac64Rng`. +#[cfg(feature="std")] +pub fn thread_rng() -> ThreadRng { + // used to make space in TLS for a random number generator + thread_local!(static THREAD_RNG_KEY: Rc> = { + let r = match StdRng::new() { + Ok(r) => r, + Err(e) => panic!("No entropy available: {}", e), + }; + let rng = reseeding::ReseedingRng::new(r, + THREAD_RNG_RESEED_THRESHOLD, + ThreadRngReseeder); + Rc::new(RefCell::new(rng)) + }); + + ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) } +} + +#[cfg(feature="std")] +impl Rng for ThreadRng { + fn next_u32(&mut self) -> u32 { + self.rng.borrow_mut().next_u32() + } + + fn next_u64(&mut self) -> u64 { + self.rng.borrow_mut().next_u64() + } + + #[inline] + fn fill_bytes(&mut self, bytes: &mut [u8]) { + self.rng.borrow_mut().fill_bytes(bytes) + } +} + +/// Generates a random value using the thread-local random number generator. +/// +/// `random()` can generate various types of random things, and so may require +/// type hinting to generate the specific type you want. +/// +/// This function uses the thread local random number generator. This means +/// that if you're calling `random()` in a loop, caching the generator can +/// increase performance. An example is shown below. +/// +/// # Examples +/// +/// ``` +/// let x = rand::random::(); +/// println!("{}", x); +/// +/// let y = rand::random::(); +/// println!("{}", y); +/// +/// if rand::random() { // generates a boolean +/// println!("Better lucky than good!"); +/// } +/// ``` +/// +/// Caching the thread local random number generator: +/// +/// ``` +/// use rand::Rng; +/// +/// let mut v = vec![1, 2, 3]; +/// +/// for x in v.iter_mut() { +/// *x = rand::random() +/// } +/// +/// // can be made faster by caching thread_rng +/// +/// let mut rng = rand::thread_rng(); +/// +/// for x in v.iter_mut() { +/// *x = rng.gen(); +/// } +/// ``` +#[cfg(feature="std")] +#[inline] +pub fn random() -> T { + thread_rng().gen() +} + +/// DEPRECATED: use `seq::sample_iter` instead. +/// +/// Randomly sample up to `amount` elements from a finite iterator. +/// The order of elements in the sample is not random. +/// +/// # Example +/// +/// ```rust +/// use rand::{thread_rng, sample}; +/// +/// let mut rng = thread_rng(); +/// let sample = sample(&mut rng, 1..100, 5); +/// println!("{:?}", sample); +/// ``` +#[cfg(feature="std")] +#[inline(always)] +#[deprecated(since="0.4.0", note="renamed to seq::sample_iter")] +pub fn sample(rng: &mut R, iterable: I, amount: usize) -> Vec + where I: IntoIterator, + R: Rng, +{ + // the legacy sample didn't care whether amount was met + seq::sample_iter(rng, iterable, amount) + .unwrap_or_else(|e| e) +} + +#[cfg(test)] +mod test { + use super::{Rng, thread_rng, random, SeedableRng, StdRng, weak_rng}; + use std::iter::repeat; + + pub struct MyRng { inner: R } + + impl Rng for MyRng { + fn next_u32(&mut self) -> u32 { + fn next(t: &mut T) -> u32 { + t.next_u32() + } + next(&mut self.inner) + } + } + + pub fn rng() -> MyRng<::ThreadRng> { + MyRng { inner: ::thread_rng() } + } + + struct ConstRng { i: u64 } + impl Rng for ConstRng { + fn next_u32(&mut self) -> u32 { self.i as u32 } + fn next_u64(&mut self) -> u64 { self.i } + + // no fill_bytes on purpose + } + + pub fn iter_eq(i: I, j: J) -> bool + where I: IntoIterator, + J: IntoIterator, + I::Item: Eq + { + // make sure the iterators have equal length + let mut i = i.into_iter(); + let mut j = j.into_iter(); + loop { + match (i.next(), j.next()) { + (Some(ref ei), Some(ref ej)) if ei == ej => { } + (None, None) => return true, + _ => return false, + } + } + } + + #[test] + fn test_fill_bytes_default() { + let mut r = ConstRng { i: 0x11_22_33_44_55_66_77_88 }; + + // check every remainder mod 8, both in small and big vectors. + let lengths = [0, 1, 2, 3, 4, 5, 6, 7, + 80, 81, 82, 83, 84, 85, 86, 87]; + for &n in lengths.iter() { + let mut v = repeat(0u8).take(n).collect::>(); + r.fill_bytes(&mut v); + + // use this to get nicer error messages. + for (i, &byte) in v.iter().enumerate() { + if byte == 0 { + panic!("byte {} of {} is zero", i, n) + } + } + } + } + + #[test] + fn test_gen_range() { + let mut r = thread_rng(); + for _ in 0..1000 { + let a = r.gen_range(-3, 42); + assert!(a >= -3 && a < 42); + assert_eq!(r.gen_range(0, 1), 0); + assert_eq!(r.gen_range(-12, -11), -12); + } + + for _ in 0..1000 { + let a = r.gen_range(10, 42); + assert!(a >= 10 && a < 42); + assert_eq!(r.gen_range(0, 1), 0); + assert_eq!(r.gen_range(3_000_000, 3_000_001), 3_000_000); + } + + } + + #[test] + #[should_panic] + fn test_gen_range_panic_int() { + let mut r = thread_rng(); + r.gen_range(5, -2); + } + + #[test] + #[should_panic] + fn test_gen_range_panic_usize() { + let mut r = thread_rng(); + r.gen_range(5, 2); + } + + #[test] + fn test_gen_weighted_bool() { + let mut r = thread_rng(); + assert_eq!(r.gen_weighted_bool(0), true); + assert_eq!(r.gen_weighted_bool(1), true); + } + + #[test] + fn test_gen_ascii_str() { + let mut r = thread_rng(); + assert_eq!(r.gen_ascii_chars().take(0).count(), 0); + assert_eq!(r.gen_ascii_chars().take(10).count(), 10); + assert_eq!(r.gen_ascii_chars().take(16).count(), 16); + } + + #[test] + fn test_gen_vec() { + let mut r = thread_rng(); + assert_eq!(r.gen_iter::().take(0).count(), 0); + assert_eq!(r.gen_iter::().take(10).count(), 10); + assert_eq!(r.gen_iter::().take(16).count(), 16); + } + + #[test] + fn test_choose() { + let mut r = thread_rng(); + assert_eq!(r.choose(&[1, 1, 1]).map(|&x|x), Some(1)); + + let v: &[isize] = &[]; + assert_eq!(r.choose(v), None); + } + + #[test] + fn test_shuffle() { + let mut r = thread_rng(); + let empty: &mut [isize] = &mut []; + r.shuffle(empty); + let mut one = [1]; + r.shuffle(&mut one); + let b: &[_] = &[1]; + assert_eq!(one, b); + + let mut two = [1, 2]; + r.shuffle(&mut two); + assert!(two == [1, 2] || two == [2, 1]); + + let mut x = [1, 1, 1]; + r.shuffle(&mut x); + let b: &[_] = &[1, 1, 1]; + assert_eq!(x, b); + } + + #[test] + fn test_thread_rng() { + let mut r = thread_rng(); + r.gen::(); + let mut v = [1, 1, 1]; + r.shuffle(&mut v); + let b: &[_] = &[1, 1, 1]; + assert_eq!(v, b); + assert_eq!(r.gen_range(0, 1), 0); + } + + #[test] + fn test_rng_trait_object() { + let mut rng = thread_rng(); + { + let mut r = &mut rng as &mut Rng; + r.next_u32(); + (&mut r).gen::(); + let mut v = [1, 1, 1]; + (&mut r).shuffle(&mut v); + let b: &[_] = &[1, 1, 1]; + assert_eq!(v, b); + assert_eq!((&mut r).gen_range(0, 1), 0); + } + { + let mut r = Box::new(rng) as Box; + r.next_u32(); + r.gen::(); + let mut v = [1, 1, 1]; + r.shuffle(&mut v); + let b: &[_] = &[1, 1, 1]; + assert_eq!(v, b); + assert_eq!(r.gen_range(0, 1), 0); + } + } + + #[test] + fn test_random() { + // not sure how to test this aside from just getting some values + let _n : usize = random(); + let _f : f32 = random(); + let _o : Option> = random(); + let _many : ((), + (usize, + isize, + Option<(u32, (bool,))>), + (u8, i8, u16, i16, u32, i32, u64, i64), + (f32, (f64, (f64,)))) = random(); + } + + #[test] + fn test_std_rng_seeded() { + let s = thread_rng().gen_iter::().take(256).collect::>(); + let mut ra: StdRng = SeedableRng::from_seed(&s[..]); + let mut rb: StdRng = SeedableRng::from_seed(&s[..]); + assert!(iter_eq(ra.gen_ascii_chars().take(100), + rb.gen_ascii_chars().take(100))); + } + + #[test] + fn test_std_rng_reseed() { + let s = thread_rng().gen_iter::().take(256).collect::>(); + let mut r: StdRng = SeedableRng::from_seed(&s[..]); + let string1 = r.gen_ascii_chars().take(100).collect::(); + + r.reseed(&s); + + let string2 = r.gen_ascii_chars().take(100).collect::(); + assert_eq!(string1, string2); + } + + #[test] + fn test_weak_rng() { + let s = weak_rng().gen_iter::().take(256).collect::>(); + let mut ra: StdRng = SeedableRng::from_seed(&s[..]); + let mut rb: StdRng = SeedableRng::from_seed(&s[..]); + assert!(iter_eq(ra.gen_ascii_chars().take(100), + rb.gen_ascii_chars().take(100))); + } +} diff --git a/third_party/rust/rand/src/os.rs b/third_party/rust/rand-0.4.3/src/os.rs similarity index 100% rename from third_party/rust/rand/src/os.rs rename to third_party/rust/rand-0.4.3/src/os.rs diff --git a/third_party/rust/rand/src/prng/chacha.rs b/third_party/rust/rand-0.4.3/src/prng/chacha.rs similarity index 100% rename from third_party/rust/rand/src/prng/chacha.rs rename to third_party/rust/rand-0.4.3/src/prng/chacha.rs diff --git a/third_party/rust/rand/src/prng/isaac.rs b/third_party/rust/rand-0.4.3/src/prng/isaac.rs similarity index 100% rename from third_party/rust/rand/src/prng/isaac.rs rename to third_party/rust/rand-0.4.3/src/prng/isaac.rs diff --git a/third_party/rust/rand/src/prng/isaac64.rs b/third_party/rust/rand-0.4.3/src/prng/isaac64.rs similarity index 100% rename from third_party/rust/rand/src/prng/isaac64.rs rename to third_party/rust/rand-0.4.3/src/prng/isaac64.rs diff --git a/third_party/rust/rand-0.4.3/src/prng/mod.rs b/third_party/rust/rand-0.4.3/src/prng/mod.rs new file mode 100644 index 000000000000..ed3e01886495 --- /dev/null +++ b/third_party/rust/rand-0.4.3/src/prng/mod.rs @@ -0,0 +1,51 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Pseudo random number generators are algorithms to produce *apparently +//! random* numbers deterministically, and usually fairly quickly. +//! +//! So long as the algorithm is computationally secure, is initialised with +//! sufficient entropy (i.e. unknown by an attacker), and its internal state is +//! also protected (unknown to an attacker), the output will also be +//! *computationally secure*. Computationally Secure Pseudo Random Number +//! Generators (CSPRNGs) are thus suitable sources of random numbers for +//! cryptography. There are a couple of gotchas here, however. First, the seed +//! used for initialisation must be unknown. Usually this should be provided by +//! the operating system and should usually be secure, however this may not +//! always be the case (especially soon after startup). Second, user-space +//! memory may be vulnerable, for example when written to swap space, and after +//! forking a child process should reinitialise any user-space PRNGs. For this +//! reason it may be preferable to source random numbers directly from the OS +//! for cryptographic applications. +//! +//! PRNGs are also widely used for non-cryptographic uses: randomised +//! algorithms, simulations, games. In these applications it is usually not +//! important for numbers to be cryptographically *unguessable*, but even +//! distribution and independence from other samples (from the point of view +//! of someone unaware of the algorithm used, at least) may still be important. +//! Good PRNGs should satisfy these properties, but do not take them for +//! granted; Wikipedia's article on +//! [Pseudorandom number generators](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) +//! provides some background on this topic. +//! +//! Care should be taken when seeding (initialising) PRNGs. Some PRNGs have +//! short periods for some seeds. If one PRNG is seeded from another using the +//! same algorithm, it is possible that both will yield the same sequence of +//! values (with some lag). + +mod chacha; +mod isaac; +mod isaac64; +mod xorshift; + +pub use self::chacha::ChaChaRng; +pub use self::isaac::IsaacRng; +pub use self::isaac64::Isaac64Rng; +pub use self::xorshift::XorShiftRng; diff --git a/third_party/rust/rand/src/prng/xorshift.rs b/third_party/rust/rand-0.4.3/src/prng/xorshift.rs similarity index 100% rename from third_party/rust/rand/src/prng/xorshift.rs rename to third_party/rust/rand-0.4.3/src/prng/xorshift.rs diff --git a/third_party/rust/rand/src/rand_impls.rs b/third_party/rust/rand-0.4.3/src/rand_impls.rs similarity index 100% rename from third_party/rust/rand/src/rand_impls.rs rename to third_party/rust/rand-0.4.3/src/rand_impls.rs diff --git a/third_party/rust/rand/src/read.rs b/third_party/rust/rand-0.4.3/src/read.rs similarity index 100% rename from third_party/rust/rand/src/read.rs rename to third_party/rust/rand-0.4.3/src/read.rs diff --git a/third_party/rust/rand/src/reseeding.rs b/third_party/rust/rand-0.4.3/src/reseeding.rs similarity index 100% rename from third_party/rust/rand/src/reseeding.rs rename to third_party/rust/rand-0.4.3/src/reseeding.rs diff --git a/third_party/rust/rand/src/seq.rs b/third_party/rust/rand-0.4.3/src/seq.rs similarity index 100% rename from third_party/rust/rand/src/seq.rs rename to third_party/rust/rand-0.4.3/src/seq.rs diff --git a/third_party/rust/rand/utils/ziggurat_tables.py b/third_party/rust/rand-0.4.3/utils/ziggurat_tables.py similarity index 100% rename from third_party/rust/rand/utils/ziggurat_tables.py rename to third_party/rust/rand-0.4.3/utils/ziggurat_tables.py diff --git a/third_party/rust/rand/.cargo-checksum.json b/third_party/rust/rand/.cargo-checksum.json index 824131b10bc6..875021e1835d 100644 --- a/third_party/rust/rand/.cargo-checksum.json +++ b/third_party/rust/rand/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"460c7dbfdf227b4c725f7da8131fd51a54d0355b3c5804c0d388c70d3c1c49ec","Cargo.toml":"7d29da51fe4bf73964b3b3dea0af88040514569e2d184c9e8eb2f1746d540fb7","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"fb8071c3bc1013107b16ebcb303f31ef614e81440f2d58a46bfb9ff1e311b792","appveyor.yml":"8796156caf7041ef2a43f7a313df21ea639de3f2563b6181bba1096b1c489f1b","benches/bench.rs":"35c4ab609f2a5f5aab6c52c257415258dc0780621b492b5a82bb12d048cab6db","benches/distributions/exponential.rs":"99cb59c013a0b6bb390d34c5649b341fc3b88ea7df0caf2470bdda8798f9fe3d","benches/distributions/gamma.rs":"3533f311e4b55d743c5b01a7eb6529c94fd97726ef6702a6372f914f5f33666b","benches/distributions/mod.rs":"0028f1cb96f61152ed5b49a4fe91227d809ef6d19035592c36032a538af7f95e","benches/distributions/normal.rs":"4e10c18cb583ccb96301ea953c8e0aa9ee3b6662060271d1b8d19ca23364dc6b","benches/generators.rs":"aaa2f1dbfb399df8323d8a5796b92add6210cd5f0f1d916895ffdd81d60f812b","benches/misc.rs":"bd2f7c5a16f0fcb59022d5aeef66ed3c94e89ebf6c06667851dd23d0b1595504","src/distributions/exponential.rs":"103c8412c8a581b71835f1c00e40f6370e7702adf9d499243933a793d132d4e7","src/distributions/gamma.rs":"7a3f85c8daad4e56e334586ddb9fc9d83df3b0699738ed681a6c41e4ed455be9","src/distributions/mod.rs":"7943c4f83721bac816f831cca3b1574b6136932f7b4927aa6101130080ba62c5","src/distributions/normal.rs":"1562b43f80e4d5f83a8deb5af18de5a18dfeeeeda11fefc577da26672b14c949","src/distributions/range.rs":"a72a538d3ec4ed23f8d632aa55fd4793c464f24a5872d04ce8095ddd5db92115","src/distributions/ziggurat_tables.rs":"4eacf94fc352c91c455a6623de6a721e53842e1690f13a5662b6a79c7fbb73de","src/jitter.rs":"befd4b84bf753c107370b5b9498ad49611c220bdae2e4be9ee4398e9fa497042","src/lib.rs":"fbdc5f56ce1a52b15c85b0aa70a555c64be8f65d9f6f90fa0a3555d7862666b4","src/os.rs":"4860f165f68b7c978b0488c75d264cd9aaf54e7e4484036736ee5c4f5b6bd78d","src/prng/chacha.rs":"558007276f9c22933d39e5b8e853f4dd9533e823ed66df8dc1f23ad6925b1d51","src/prng/isaac.rs":"a8a2ee8b38d312663308e3bdf03376e342fd91330655f39144e5bba7392b2a8e","src/prng/isaac64.rs":"f28f7596ccab910db265b42671116abb9d2039fa8a421cbc75312bd0e7715d3a","src/prng/mod.rs":"c1a73450f49e819a20942a5b591f84a08ebb5ac33aa0f65b18ac1dc9a19a3084","src/prng/xorshift.rs":"606c308747293652c868b46dc3cad847d0c3717629c04ba75681c887c7634114","src/rand_impls.rs":"e1f27077fc13d5855bb66235f8ccfb216e116337eb38424d9c30c090e112215c","src/read.rs":"bd0eb508a6b659dc578d546fc2f231484aed80c73cfe8c475e0d65c8d699a769","src/reseeding.rs":"a97b86387b87ea1adc5262ddea480fe735c9c2a86762abaace29119022ac9f6e","src/seq.rs":"76dd58af0f580aed2721c393a5c036322186dc7cb3b4abed33436620c7c49288","utils/ziggurat_tables.py":"a9fc0a2fdae9b5c798c238788f94b720c156e13fd96f2356c409aa533191eb94"},"package":"8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"} \ No newline at end of file +{"files":{"CHANGELOG.md":"ddc101ef9368ef83c21ea9e43064307b1c59b0698b78f59ea01cba32c0ef55bf","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.toml":"54c97aa3fc80f7482358b32df3fb96dbd63a4b52fb7f2eb06f1707cda7d15f09","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"d442009fc242a0670f6e7a418862c67514e2c544a43c88b24cb7f37695b8ae38","benches/distributions.rs":"fea4337cd3eb6eaa7bb3250bb04b084290a2b081d3f4679510f3e1dab9c9506b","benches/generators.rs":"19286f1022041bca7e9f83ff615534397565246d5cd26c53abcaeaebebad6773","benches/misc.rs":"c0302e0d9ab973ba4463506d90f89f903104b2a42fc11247be2056a2e1cb561f","benches/seq.rs":"188043fe02640c3936da7634517d0bc0bbdbf685739c52d2ec51a95f238aa347","build.rs":"00d4e7d3521f631913001cfaeb5c97f9dab8b550346046deb2683b962a99e9b3","examples/monte-carlo.rs":"2161c9c1ed90af6b72a5b05b6650d5fce6a983873c29c99798957099cd7a5153","examples/monty-hall.rs":"6a1921868c41d4c130a6b098632f2c127d2446ac6a73aeea10b79b845df1cbbc","src/deprecated.rs":"da2a39dfc440a09bdcdf5af93842dce0fbbc179e5e7146dc94ea861c244bf4c5","src/distributions/bernoulli.rs":"02526bdc24fe17f390505779fb38a441c6a1792c1f7e6093d8b86e143bf9e07e","src/distributions/binomial.rs":"5e2cd6ebc0a5411a4af26ff07d05dd30ae91fc47852cd29757b370ce496074b6","src/distributions/cauchy.rs":"b49d4abd1d861e9f9e9a27444680ea0e24779a6a263dce07c400cf43bab9363c","src/distributions/dirichlet.rs":"b6c0273216a05d32ab21320c11f46f80bc6a6173c93f7aa63fd397927fa365fb","src/distributions/exponential.rs":"7e8a98b63a271714c1f982dd15bc21626593691eaa92c7a76bd59af7b37a56a2","src/distributions/float.rs":"6e1e15b47f9efd282a0e7d140c141d35ece4ebbb748ce7ead620782dc492e88f","src/distributions/gamma.rs":"c922a1b7b2f20ee5a7f5241a252b8b947ab998a88a747df488380211b865f9a6","src/distributions/integer.rs":"b615123a814b118f8bc0563cd7615eec7ee171223bf8100416fb7d22e350c8d7","src/distributions/mod.rs":"6824a6a461d84aef22646d6c3ac8af5d2b5dfc90f09d537be2112fde98a9a8ea","src/distributions/normal.rs":"fe5df9d00ff4038ef6e1f6ca22971547aaec57887c700a511806da01bb4a2f17","src/distributions/other.rs":"44abe480bdc2000ca91a9d41c04e3d5fff2b08e81dfc9168d82c90ddc5cbf616","src/distributions/pareto.rs":"8a9d0f6a7b7221c5716f92b4b65dc19954c146eaeeddcc0b9533d01e2b7414ff","src/distributions/poisson.rs":"918f36d9f7b6c9c4a249b49138cf4df5e1498dd894e3856c21d2f82b83d33e53","src/distributions/triangular.rs":"5a3927b4f1306686591c6d6f3df01d774a5dbf9ec2450ee2f3ce6a71b54f744d","src/distributions/uniform.rs":"9536012592e978cda4e72cd936f21b9986704468de531fbe873f25f763afa4da","src/distributions/unit_circle.rs":"007815186a3696a3d835e9004f51e52402557a7cda09219a0ade13122578e1bd","src/distributions/unit_sphere.rs":"24b8dea60bee580378713477235ddac5e8da07e4f9ceb610fe655ec82390abaf","src/distributions/utils.rs":"68a8257290fdbbd1e72c77e55f21aab4420c6ff168ffb82f7cabc3ad815f4803","src/distributions/weibull.rs":"7678c47145bbb8455fb34326e59d05c2564d427b9c13d5d32435119fd37b5eeb","src/distributions/weighted.rs":"2c98d09ed15d204687efce857129742f905e50e96ba0518122a742f3b47753df","src/distributions/ziggurat_tables.rs":"6368acec20801c703ae76dd1e08983793732c5ac221c491f85d719ef75448b6d","src/lib.rs":"5a7c48d633e75c6d9f2598651ac7b754b3b34fec4212bdc50358a0abbc4ffc62","src/prelude.rs":"36f87f720c1ce0c9d0041872b0498e016b5578b96ba4f6152765ac5084d3b5da","src/prng/mod.rs":"e38182ca652acd0f9348e70e6896e2143b11e9cdcdb34fc78ad13b150dbd7da9","src/rngs/adapter/mod.rs":"e8f37aed72eaebc7dff20787f194e3a74da3e824e2b92a6839b7e6f01fcd911c","src/rngs/adapter/read.rs":"f9502c774607b5c3e62b87ea58698db258486b7c0dbb9b01559e3c18b468bb34","src/rngs/adapter/reseeding.rs":"0ce93bd0f00da429459bca7081346bddea85735bf2d617bcde92708907016a0d","src/rngs/entropy.rs":"cd89359f7891e955245279e4848c37733c508a8cf126eee34f2361a228014f4e","src/rngs/mock.rs":"ef812949b98e4f2eea3e62f8b3ee56edaeffc99d17625337efc882b7b2b19f4b","src/rngs/mod.rs":"440870d8066f1fbeb5d3b178bbf62d899f565d3cbc99c9b179ae4bca81b45a4f","src/rngs/small.rs":"eb942851fe2c2ce11eb0fe179efdfe2889dfc9bc72398bddbdfa327882935dd9","src/rngs/std.rs":"8420c2c32f312b2400ed23afdd9019632c2dd61bb5bd935d6d73bacbcbb9a5b2","src/rngs/thread.rs":"82ef4cf043d16d1d3e6f0037b269f817b133833240f866cd8a7b6e82d3c279ff","src/seq/index.rs":"384500a66361d21531db1380474066fa0bafb672ff7c9db00208b30a94664511","src/seq/mod.rs":"5a9938dc2ac75f393b54267abced2c5f7fbba4ffbdeb6ecdc80afe618c28fea6","tests/uniformity.rs":"0b774361f7db445bd910ad2cbac71207d01ace6881b8d501f4ff01bffd16cd68"},"package":"6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"} \ No newline at end of file diff --git a/third_party/rust/rand/CHANGELOG.md b/third_party/rust/rand/CHANGELOG.md index 1811b458fb7f..955e872b0934 100644 --- a/third_party/rust/rand/CHANGELOG.md +++ b/third_party/rust/rand/CHANGELOG.md @@ -2,22 +2,262 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) -and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +A [separate changelog is kept for rand_core](rand_core/CHANGELOG.md). + +You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.html) useful. + + +## [0.6.5] - 2019-01-28 +### Crates +- Update `rand_core` to 0.4 (#703) +- Move `JitterRng` to its own crate (#685) +- Add a warm-bindgen test crate (#696) + +### Platforms +- Fuchsia: Replaced fuchsia-zircon with fuchsia-cprng + +### Doc +- Use RFC 1946 for doc links (#691) +- Fix some doc links and notes (#711) + +## [0.6.4] - 2019-01-08 +### Fixes +- Move wasm-bindgen shims to correct crate (#686) +- Make `wasm32-unknown-unknown` compile but fail at run-time if missing bindingsg (#686) + +## [0.6.3] - 2019-01-04 +### Fixes +- Make the `std` feature require the optional `rand_os` dependency (#675) +- Re-export the optional WASM dependencies of `rand_os` from `rand` to avoid breakage (#674) + +## [0.6.2] - 2019-01-04 +### Additions +- Add `Default` for `ThreadRng` (#657) +- Move `rngs::OsRng` to `rand_os` sub-crate; clean up code; use as dependency (#643) ##BLOCKER## +- Add `rand_xoshiro` sub-crate, plus benchmarks (#642, #668) + +### Fixes +- Fix bias in `UniformInt::sample_single` (#662) +- Use `autocfg` instead of `rustc_version` for rustc version detection (#664) +- Disable `i128` and `u128` if the `target_os` is `emscripten` (#671: work-around Emscripten limitation) +- CI fixes (#660, #671) + +### Optimisations +- Optimise memory usage of `UnitCircle` and `UnitSphereSurface` distributions (no PR) + +## [0.6.1] - 2018-11-22 +- Support sampling `Duration` also for `no_std` (only since Rust 1.25) (#649) +- Disable default features of `libc` (#647) + +## [0.6.0] - 2018-11-14 + +### Project organisation +- Rand has moved from [rust-lang-nursery](https://github.com/rust-lang-nursery/rand) + to [rust-random](https://github.com/rust-random/rand)! (#578) +- Created [The Rust Random Book](https://rust-random.github.io/book/) + ([source](https://github.com/rust-random/book)) +- Update copyright and licence notices (#591, #611) +- Migrate policy documentation from the wiki (#544) + +### Platforms +- Add fork protection on Unix (#466) +- Added support for wasm-bindgen. (#541, #559, #562, #600) +- Enable `OsRng` for powerpc64, sparc and sparc64 (#609) +- Use `syscall` from `libc` on Linux instead of redefining it (#629) + +### RNGs +- Switch `SmallRng` to use PCG (#623) +- Implement `Pcg32` and `Pcg64Mcg` generators (#632) +- Move ISAAC RNGs to a dedicated crate (#551) +- Move Xorshift RNG to its own crate (#557) +- Move ChaCha and HC128 RNGs to dedicated crates (#607, #636) +- Remove usage of `Rc` from `ThreadRng` (#615) + +### Sampling and distributions +- Implement `Rng.gen_ratio()` and `Bernoulli::new_ratio()` (#491) +- Make `Uniform` strictly respect `f32` / `f64` high/low bounds (#477) +- Allow `gen_range` and `Uniform` to work on non-`Copy` types (#506) +- `Uniform` supports inclusive ranges: `Uniform::from(a..=b)`. This is + automatically enabled for Rust >= 1.27. (#566) +- Implement `TrustedLen` and `FusedIterator` for `DistIter` (#620) + +#### New distributions +- Add the `Dirichlet` distribution (#485) +- Added sampling from the unit sphere and circle. (#567) +- Implement the triangular distribution (#575) +- Implement the Weibull distribution (#576) +- Implement the Beta distribution (#574) + +#### Optimisations + +- Optimise `Bernoulli::new` (#500) +- Optimise `char` sampling (#519) +- Optimise sampling of `std::time::Duration` (#583) + +### Sequences +- Redesign the `seq` module (#483, #515) +- Add `WeightedIndex` and `choose_weighted` (#518, #547) +- Optimised and changed return type of the `sample_indices` function. (#479) +- Use `Iterator::size_hint()` to speed up `IteratorRandom::choose` (#593) + +### SIMD +- Support for generating SIMD types (#523, #542, #561, #630) + +### Other +- Revise CI scripts (#632, #635) +- Remove functionality already deprecated in 0.5 (#499) +- Support for `i128` and `u128` is automatically enabled for Rust >= 1.26. This + renders the `i128_support` feature obsolete. It still exists for backwards + compatibility but does not have any effect. This breaks programs using Rand + with `i128_support` on nightlies older than Rust 1.26. (#571) + + +## [0.5.5] - 2018-08-07 +### Documentation +- Fix links in documentation (#582) + + +## [0.5.4] - 2018-07-11 +### Platform support +- Make `OsRng` work via WASM/stdweb for WebWorkers + + +## [0.5.3] - 2018-06-26 +### Platform support +- OpenBSD, Bitrig: fix compilation (broken in 0.5.1) (#530) + + +## [0.5.2] - 2018-06-18 +### Platform support +- Hide `OsRng` and `JitterRng` on unsupported platforms (#512; fixes #503). + + +## [0.5.1] - 2018-06-08 + +### New distributions +- Added Cauchy distribution. (#474, #486) +- Added Pareto distribution. (#495) + +### Platform support and `OsRng` +- Remove blanket Unix implementation. (#484) +- Remove Wasm unimplemented stub. (#484) +- Dragonfly BSD: read from `/dev/random`. (#484) +- Bitrig: use `getentropy` like OpenBSD. (#484) +- Solaris: (untested) use `getrandom` if available, otherwise `/dev/random`. (#484) +- Emscripten, `stdweb`: split the read up in chunks. (#484) +- Emscripten, Haiku: don't do an extra blocking read from `/dev/random`. (#484) +- Linux, NetBSD, Solaris: read in blocking mode on first use in `fill_bytes`. (#484) +- Fuchsia, CloudABI: fix compilation (broken in Rand 0.5). (#484) + + +## [0.5.0] - 2018-05-21 + +### Crate features and organisation +- Minimum Rust version update: 1.22.0. (#239) +- Create a separate `rand_core` crate. (#288) +- Deprecate `rand_derive`. (#256) +- Add `prelude` (and module reorganisation). (#435) +- Add `log` feature. Logging is now available in `JitterRng`, `OsRng`, `EntropyRng` and `ReseedingRng`. (#246) +- Add `serde1` feature for some PRNGs. (#189) +- `stdweb` feature for `OsRng` support on WASM via stdweb. (#272, #336) + +### `Rng` trait +- Split `Rng` in `RngCore` and `Rng` extension trait. + `next_u32`, `next_u64` and `fill_bytes` are now part of `RngCore`. (#265) +- Add `Rng::sample`. (#256) +- Deprecate `Rng::gen_weighted_bool`. (#308) +- Add `Rng::gen_bool`. (#308) +- Remove `Rng::next_f32` and `Rng::next_f64`. (#273) +- Add optimized `Rng::fill` and `Rng::try_fill` methods. (#247) +- Deprecate `Rng::gen_iter`. (#286) +- Deprecate `Rng::gen_ascii_chars`. (#279) + +### `rand_core` crate +- `rand` now depends on new `rand_core` crate (#288) +- `RngCore` and `SeedableRng` are now part of `rand_core`. (#288) +- Add modules to help implementing RNGs `impl` and `le`. (#209, #228) +- Add `Error` and `ErrorKind`. (#225) +- Add `CryptoRng` marker trait. (#273) +- Add `BlockRngCore` trait. (#281) +- Add `BlockRng` and `BlockRng64` wrappers to help implementations. (#281, #325) +- Revise the `SeedableRng` trait. (#233) +- Remove default implementations for `RngCore::next_u64` and `RngCore::fill_bytes`. (#288) +- Add `RngCore::try_fill_bytes`. (#225) + +### Other traits and types +- Add `FromEntropy` trait. (#233, #375) +- Add `SmallRng` wrapper. (#296) +- Rewrite `ReseedingRng` to only work with `BlockRngCore` (substantial performance improvement). (#281) +- Deprecate `weak_rng`. Use `SmallRng` instead. (#296) +- Deprecate `AsciiGenerator`. (#279) + +### Random number generators +- Switch `StdRng` and `thread_rng` to HC-128. (#277) +- `StdRng` must now be created with `from_entropy` instead of `new` +- Change `thread_rng` reseeding threshold to 32 MiB. (#277) +- PRNGs no longer implement `Copy`. (#209) +- `Debug` implementations no longer show internals. (#209) +- Implement `Clone` for `ReseedingRng`, `JitterRng`, OsRng`. (#383, #384) +- Implement serialization for `XorShiftRng`, `IsaacRng` and `Isaac64Rng` under the `serde1` feature. (#189) +- Implement `BlockRngCore` for `ChaChaCore` and `Hc128Core`. (#281) +- All PRNGs are now portable across big- and little-endian architectures. (#209) +- `Isaac64Rng::next_u32` no longer throws away half the results. (#209) +- Add `IsaacRng::new_from_u64` and `Isaac64Rng::new_from_u64`. (#209) +- Add the HC-128 CSPRNG `Hc128Rng`. (#210) +- Change ChaCha20 to have 64-bit counter and 64-bit stream. (#349) +- Changes to `JitterRng` to get its size down from 2112 to 24 bytes. (#251) +- Various performance improvements to all PRNGs. + +### Platform support and `OsRng` +- Add support for CloudABI. (#224) +- Remove support for NaCl. (#225) +- WASM support for `OsRng` via stdweb, behind the `stdweb` feature. (#272, #336) +- Use `getrandom` on more platforms for Linux, and on Android. (#338) +- Use the `SecRandomCopyBytes` interface on macOS. (#322) +- On systems that do not have a syscall interface, only keep a single file descriptor open for `OsRng`. (#239) +- On Unix, first try a single read from `/dev/random`, then `/dev/urandom`. (#338) +- Better error handling and reporting in `OsRng` (using new error type). (#225) +- `OsRng` now uses non-blocking when available. (#225) +- Add `EntropyRng`, which provides `OsRng`, but has `JitterRng` as a fallback. (#235) + +### Distributions +- New `Distribution` trait. (#256) +- Add `Distribution::sample_iter` and `Rng::::sample_iter`. (#361) +- Deprecate `Rand`, `Sample` and `IndependentSample` traits. (#256) +- Add a `Standard` distribution (replaces most `Rand` implementations). (#256) +- Add `Binomial` and `Poisson` distributions. (#96) +- Add `Bernoulli` dsitribution. (#411) +- Add `Alphanumeric` distribution. (#279) +- Remove `Closed01` distribution, add `OpenClosed01`. (#274, #420) +- Rework `Range` type, making it possible to implement it for user types. (#274) +- Rename `Range` to `Uniform`. (#395) +- Add `Uniform::new_inclusive` for inclusive ranges. (#274) +- Use widening multiply method for much faster integer range reduction. (#274) +- `Standard` distribution for `char` uses `Uniform` internally. (#274) +- `Standard` distribution for `bool` uses sign test. (#274) +- Implement `Standard` distribution for `Wrapping`. (#436) +- Implement `Uniform` distribution for `Duration`. (#427) + ## [0.4.3] - 2018-08-16 ### Fixed - Use correct syscall number for PowerPC (#589) -## [0.4.2] - 2018-01-05 + +## [0.4.2] - 2018-01-06 ### Changed -- Use winapi on Windows +- Use `winapi` on Windows - Update for Fuchsia OS - Remove dev-dependency on `log` + ## [0.4.1] - 2017-12-17 ### Added - `no_std` support + ## [0.4.0-pre.0] - 2017-12-11 ### Added - `JitterRng` added as a high-quality alternative entropy source using the @@ -33,6 +273,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Deprecated - `sample` function deprecated (replaced by `sample_iter`) + +## [0.3.20] - 2018-01-06 +### Changed +- Remove dev-dependency on `log` +- Update `fuchsia-zircon` dependency to 0.3.2 + + +## [0.3.19] - 2017-12-27 +### Changed +- Require `log <= 0.3.8` for dev builds +- Update `fuchsia-zircon` dependency to 0.3 +- Fix broken links in docs (to unblock compiler docs testing CI) + + ## [0.3.18] - 2017-11-06 ### Changed - `thread_rng` is seeded from the system time if `OsRng` fails @@ -181,7 +435,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Compatible with Rust master ### Removed -- Removed Copy inplementaions from RNGs +- Removed Copy implementations from RNGs ## [0.1.2] - 2015-02-03 @@ -227,7 +481,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - `Rng::gen_ascii_chars()` which will return an infinite stream of random ascii characters ### Changed -- Now only depends on libcore! 2adf5363f88ffe06f6d2ea5c338d1b186d47f4a1 +- Now only depends on libcore! - Remove `Rng.choose()`, rename `Rng.choose_option()` to `.choose()` - Rename OSRng to OsRng - The WeightedChoice structure is no longer built with a `Vec>`, @@ -266,4 +520,3 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [0.10-pre] - 2014-03-02 ### Added - Seperate `rand` out of the standard library - diff --git a/third_party/rust/rand/COPYRIGHT b/third_party/rust/rand/COPYRIGHT new file mode 100644 index 000000000000..468d907caf99 --- /dev/null +++ b/third_party/rust/rand/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 or + or the MIT license + or , at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/third_party/rust/rand/Cargo.toml b/third_party/rust/rand/Cargo.toml index 4f80003e44f3..fc0313afa4ba 100644 --- a/third_party/rust/rand/Cargo.toml +++ b/third_party/rust/rand/Cargo.toml @@ -12,28 +12,79 @@ [package] name = "rand" -version = "0.4.3" -authors = ["The Rust Project Developers"] +version = "0.6.5" +authors = ["The Rand Project Developers", "The Rust Project Developers"] +build = "build.rs" +exclude = ["/utils/*", "/.travis.yml", "/appveyor.yml", ".gitignore"] description = "Random number generators and other randomness functionality.\n" -homepage = "https://github.com/rust-lang-nursery/rand" -documentation = "https://docs.rs/rand" +homepage = "https://crates.io/crates/rand" +documentation = "https://rust-random.github.io/rand" readme = "README.md" keywords = ["random", "rng"] -categories = ["algorithms"] +categories = ["algorithms", "no-std"] license = "MIT/Apache-2.0" -repository = "https://github.com/rust-lang-nursery/rand" +repository = "https://github.com/rust-random/rand" +[package.metadata.docs.rs] +all-features = true +[dependencies.log] +version = "0.4" +optional = true + +[dependencies.packed_simd] +version = "0.3" +features = ["into_bits"] +optional = true + +[dependencies.rand_chacha] +version = "0.1" + +[dependencies.rand_core] +version = "0.4" + +[dependencies.rand_hc] +version = "0.1" + +[dependencies.rand_isaac] +version = "0.1" + +[dependencies.rand_jitter] +version = "0.1" + +[dependencies.rand_os] +version = "0.1" +optional = true + +[dependencies.rand_pcg] +version = "0.1" + +[dependencies.rand_xorshift] +version = "0.1" +[dev-dependencies.average] +version = "0.9.2" + +[dev-dependencies.rand_xoshiro] +version = "0.1" +[build-dependencies.autocfg] +version = "0.1" [features] -alloc = [] +alloc = ["rand_core/alloc"] default = ["std"] i128_support = [] -nightly = ["i128_support"] -std = ["libc"] -[target."cfg(target_os = \"fuchsia\")".dependencies.fuchsia-zircon] -version = "0.3.2" +nightly = ["simd_support"] +serde1 = ["rand_core/serde1", "rand_isaac/serde1", "rand_xorshift/serde1"] +simd_support = ["packed_simd"] +std = ["rand_core/std", "alloc", "rand_os", "rand_jitter/std"] +stdweb = ["rand_os/stdweb"] +wasm-bindgen = ["rand_os/wasm-bindgen"] [target."cfg(unix)".dependencies.libc] version = "0.2" -optional = true +default-features = false [target."cfg(windows)".dependencies.winapi] version = "0.3" features = ["minwindef", "ntsecapi", "profileapi", "winnt"] +[badges.appveyor] +repository = "rust-random/rand" + +[badges.travis-ci] +repository = "rust-random/rand" diff --git a/third_party/rust/rand/LICENSE-APACHE b/third_party/rust/rand/LICENSE-APACHE index 16fe87b06e80..17d74680f8cf 100644 --- a/third_party/rust/rand/LICENSE-APACHE +++ b/third_party/rust/rand/LICENSE-APACHE @@ -1,6 +1,6 @@ Apache License Version 2.0, January 2004 - http://www.apache.org/licenses/ + https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -192,7 +192,7 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/third_party/rust/rand/LICENSE-MIT b/third_party/rust/rand/LICENSE-MIT index 39d4bdb5acd3..d93b5baf341d 100644 --- a/third_party/rust/rand/LICENSE-MIT +++ b/third_party/rust/rand/LICENSE-MIT @@ -1,3 +1,4 @@ +Copyright 2018 Developers of the Rand project Copyright (c) 2014 The Rust Project Developers Permission is hereby granted, free of charge, to any diff --git a/third_party/rust/rand/README.md b/third_party/rust/rand/README.md index f72bd51a3333..314a57fd60cf 100644 --- a/third_party/rust/rand/README.md +++ b/third_party/rust/rand/README.md @@ -1,12 +1,28 @@ -rand -==== +# Rand -A Rust library for random number generators and other randomness functionality. +[![Build Status](https://travis-ci.org/rust-random/rand.svg?branch=master)](https://travis-ci.org/rust-random/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Crate](https://img.shields.io/crates/v/rand.svg)](https://crates.io/crates/rand) +[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) +[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand) +[![API](https://docs.rs/rand/badge.svg)](https://docs.rs/rand) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) -[![Build Status](https://travis-ci.org/rust-lang-nursery/rand.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/rand) -[![Build status](https://ci.appveyor.com/api/projects/status/rm5c9o33k3jhchbw?svg=true)](https://ci.appveyor.com/project/alexcrichton/rand) +A Rust library for random number generation. + +Rand provides utilities to generate random numbers, to convert them to useful +types and distributions, and some randomness-related algorithms. + +The core random number generation traits of Rand live in the [rand_core]( +https://crates.io/crates/rand_core) crate but are also exposed here; RNG +implementations should prefer to use `rand_core` while most other users should +depend on `rand`. + +Documentation: +- [The Rust Rand Book](https://rust-random.github.io/book) +- [API reference (master)](https://rust-random.github.io/rand) +- [API reference (docs.rs)](https://docs.rs/rand) -[Documentation](https://docs.rs/rand) ## Usage @@ -14,126 +30,93 @@ Add this to your `Cargo.toml`: ```toml [dependencies] -rand = "0.4" +rand = "0.6" ``` -and this to your crate root: +To get started using Rand, see [The Book](https://rust-random.github.io/book). -```rust -extern crate rand; -``` -### Versions +## Versions -Version `0.4`was released in December 2017. It contains almost no breaking -changes since the `0.3` series, but nevertheless contains some significant -new code, including a new "external" entropy source (`JitterRng`) and `no_std` -support. +The Rand lib is not yet stable, however we are careful to limit breaking changes +and warn via deprecation wherever possible. Patch versions never introduce +breaking changes. The following minor versions are supported: -Version `0.5` is in development and contains significant performance -improvements for the ISAAC random number generators. +- Version 0.6 was released in November 2018, redesigning the `seq` module, + moving most PRNGs to external crates, and many small changes. +- Version 0.5 was released in May 2018, as a major reorganisation + (introducing `RngCore` and `rand_core`, and deprecating `Rand` and the + previous distribution traits). +- Version 0.4 was released in December 2017, but contained almost no breaking + changes from the 0.3 series. -## Examples +A detailed [changelog](CHANGELOG.md) is available. -There is built-in support for a random number generator (RNG) associated with each thread stored in thread-local storage. This RNG can be accessed via thread_rng, or used implicitly via random. This RNG is normally randomly seeded from an operating-system source of randomness, e.g. /dev/urandom on Unix systems, and will automatically reseed itself from this source after generating 32 KiB of random data. +When upgrading to the next minor series (especially 0.4 → 0.5), we recommend +reading the [Upgrade Guide](https://rust-random.github.io/book/update.html). -```rust -let tuple = rand::random::<(f64, char)>(); -println!("{:?}", tuple) -``` +### Rust version requirements -```rust -use rand::Rng; +Since version 0.5, Rand requires **Rustc version 1.22 or greater**. +Rand 0.4 and 0.3 (since approx. June 2017) require Rustc version 1.15 or +greater. Subsets of the Rand code may work with older Rust versions, but this +is not supported. -let mut rng = rand::thread_rng(); -if rng.gen() { // random bool - println!("i32: {}, u32: {}", rng.gen::(), rng.gen::()) -} -``` +Travis CI always has a build with a pinned version of Rustc matching the oldest +supported Rust release. The current policy is that this can be updated in any +Rand release if required, but the change must be noted in the changelog. -It is also possible to use other RNG types, which have a similar interface. The following uses the "ChaCha" algorithm instead of the default. +To avoid bumping the required version unnecessarily, we use a `build.rs` script +to auto-detect the compiler version and enable certain features or change code +paths automatically. Since this makes it easy to unintentionally make use of +features requiring a more recent Rust version, we recommend testing with a +pinned version of Rustc if you require compatibility with a specific version. -```rust -use rand::{Rng, ChaChaRng}; +## Crate Features -let mut rng = rand::ChaChaRng::new_unseeded(); -println!("i32: {}, u32: {}", rng.gen::(), rng.gen::()) -``` +Rand is built with the `std` and `rand_os` features enabled by default: -## Features +- `std` enables functionality dependent on the `std` lib and implies `alloc` + and `rand_os` +- `rand_os` enables the `rand_os` crate, `rngs::OsRng` and enables its usage; + the continued existance of this feature is not guaranteed so users are + encouraged to specify `std` instead -By default, `rand` is built with all stable features available. The following -optional features are available: +The following optional features are available: -- `i128_support` enables support for generating `u128` and `i128` values -- `nightly` enables all unstable features (`i128_support`) -- `std` enabled by default; by setting "default-features = false" `no_std` - mode is activated; this removes features depending on `std` functionality: - - - `OsRng` is entirely unavailable - - `JitterRng` code is still present, but a nanosecond timer must be - provided via `JitterRng::new_with_timer` - - Since no external entropy is available, it is not possible to create - generators with fresh seeds (user must provide entropy) - - `thread_rng`, `weak_rng` and `random` are all disabled - - exponential, normal and gamma type distributions are unavailable - since `exp` and `log` functions are not provided in `core` - - any code requiring `Vec` or `Box` -- `alloc` can be used instead of `std` to provide `Vec` and `Box` +- `alloc` can be used instead of `std` to provide `Vec` and `Box`. +- `log` enables some logging via the `log` crate. +- `nightly` enables all unstable features (`simd_support`). +- `serde1` enables serialization for some types, via Serde version 1. +- `simd_support` enables uniform sampling of SIMD types (integers and floats). +- `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`] -## Testing +[`wasm-bindgen`]: https://github.com/rustwasm/wasm-bindgen -Unfortunately, `cargo test` does not test everything. The following tests are -recommended: +`no_std` mode is activated by setting `default-features = false`; this removes +functionality depending on `std`: -``` -# Basic tests for rand and sub-crates -cargo test --all - -# Test no_std support (build only since nearly all tests require std) -cargo build --all --no-default-features - -# Test 128-bit support (requires nightly) -cargo test --all --features nightly - -# Benchmarks (requires nightly) -cargo bench -# or just to test the benchmark code: -cargo test --benches -``` - -# `derive(Rand)` - -You can derive the `Rand` trait for your custom type via the `#[derive(Rand)]` -directive. To use this first add this to your Cargo.toml: - -```toml -rand = "0.4" -rand_derive = "0.3" -``` - -Next in your crate: - -```rust -extern crate rand; -#[macro_use] -extern crate rand_derive; - -#[derive(Rand, Debug)] -struct MyStruct { - a: i32, - b: u32, -} - -fn main() { - println!("{:?}", rand::random::()); -} -``` +- `thread_rng()`, and `random()` are not available, as they require thread-local + storage and an entropy source. +- `OsRng` and `EntropyRng` are unavailable. +- `JitterRng` code is still present, but a nanosecond timer must be provided via + `JitterRng::new_with_timer` +- Since no external entropy is available, it is not possible to create + generators with fresh seeds using the `FromEntropy` trait (user must provide + a seed). +- Several non-linear distributions distributions are unavailable since `exp` + and `log` functions are not provided in `core`. +- Large parts of the `seq`-uence module are unavailable, unless the `alloc` + feature is used (several APIs and many implementations require `Vec`). # License -`rand` is primarily distributed under the terms of both the MIT -license and the Apache License (Version 2.0). +Rand is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). -See LICENSE-APACHE, and LICENSE-MIT for details. +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/third_party/rust/rand/benches/distributions.rs b/third_party/rust/rand/benches/distributions.rs new file mode 100644 index 000000000000..069a82856a54 --- /dev/null +++ b/third_party/rust/rand/benches/distributions.rs @@ -0,0 +1,259 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(test)] + +extern crate test; +extern crate rand; + +const RAND_BENCH_N: u64 = 1000; + +use std::mem::size_of; +use test::Bencher; +use std::time::Duration; + +use rand::{Rng, FromEntropy}; +use rand::rngs::SmallRng; +use rand::distributions::*; + +macro_rules! distr_int { + ($fnn:ident, $ty:ty, $distr:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = SmallRng::from_entropy(); + let distr = $distr; + + b.iter(|| { + let mut accum = 0 as $ty; + for _ in 0..::RAND_BENCH_N { + let x: $ty = distr.sample(&mut rng); + accum = accum.wrapping_add(x); + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N; + } + } +} + +macro_rules! distr_float { + ($fnn:ident, $ty:ty, $distr:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = SmallRng::from_entropy(); + let distr = $distr; + + b.iter(|| { + let mut accum = 0.0; + for _ in 0..::RAND_BENCH_N { + let x: $ty = distr.sample(&mut rng); + accum += x; + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N; + } + } +} + +macro_rules! distr_duration { + ($fnn:ident, $distr:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = SmallRng::from_entropy(); + let distr = $distr; + + b.iter(|| { + let mut accum = Duration::new(0, 0); + for _ in 0..::RAND_BENCH_N { + let x: Duration = distr.sample(&mut rng); + accum = accum.checked_add(x).unwrap_or(Duration::new(u64::max_value(), 999_999_999)); + } + accum + }); + b.bytes = size_of::() as u64 * ::RAND_BENCH_N; + } + } +} + +macro_rules! distr { + ($fnn:ident, $ty:ty, $distr:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = SmallRng::from_entropy(); + let distr = $distr; + + b.iter(|| { + let mut accum = 0u32; + for _ in 0..::RAND_BENCH_N { + let x: $ty = distr.sample(&mut rng); + accum = accum.wrapping_add(x as u32); + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N; + } + } +} + +macro_rules! distr_arr { + ($fnn:ident, $ty:ty, $distr:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = SmallRng::from_entropy(); + let distr = $distr; + + b.iter(|| { + let mut accum = 0u32; + for _ in 0..::RAND_BENCH_N { + let x: $ty = distr.sample(&mut rng); + accum = accum.wrapping_add(x[0] as u32); + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N; + } + } +} + +// uniform +distr_int!(distr_uniform_i8, i8, Uniform::new(20i8, 100)); +distr_int!(distr_uniform_i16, i16, Uniform::new(-500i16, 2000)); +distr_int!(distr_uniform_i32, i32, Uniform::new(-200_000_000i32, 800_000_000)); +distr_int!(distr_uniform_i64, i64, Uniform::new(3i64, 123_456_789_123)); +distr_int!(distr_uniform_i128, i128, Uniform::new(-123_456_789_123i128, 123_456_789_123_456_789)); + +distr_float!(distr_uniform_f32, f32, Uniform::new(2.26f32, 2.319)); +distr_float!(distr_uniform_f64, f64, Uniform::new(2.26f64, 2.319)); + +const LARGE_SEC: u64 = u64::max_value() / 1000; + +distr_duration!(distr_uniform_duration_largest, + Uniform::new_inclusive(Duration::new(0, 0), Duration::new(u64::max_value(), 999_999_999)) +); +distr_duration!(distr_uniform_duration_large, + Uniform::new(Duration::new(0, 0), Duration::new(LARGE_SEC, 1_000_000_000 / 2)) +); +distr_duration!(distr_uniform_duration_one, + Uniform::new(Duration::new(0, 0), Duration::new(1, 0)) +); +distr_duration!(distr_uniform_duration_variety, + Uniform::new(Duration::new(10000, 423423), Duration::new(200000, 6969954)) +); +distr_duration!(distr_uniform_duration_edge, + Uniform::new_inclusive(Duration::new(LARGE_SEC, 999_999_999), Duration::new(LARGE_SEC + 1, 1)) +); + + +// standard +distr_int!(distr_standard_i8, i8, Standard); +distr_int!(distr_standard_i16, i16, Standard); +distr_int!(distr_standard_i32, i32, Standard); +distr_int!(distr_standard_i64, i64, Standard); +distr_int!(distr_standard_i128, i128, Standard); + +distr!(distr_standard_bool, bool, Standard); +distr!(distr_standard_alphanumeric, char, Alphanumeric); +distr!(distr_standard_codepoint, char, Standard); + +distr_float!(distr_standard_f32, f32, Standard); +distr_float!(distr_standard_f64, f64, Standard); +distr_float!(distr_open01_f32, f32, Open01); +distr_float!(distr_open01_f64, f64, Open01); +distr_float!(distr_openclosed01_f32, f32, OpenClosed01); +distr_float!(distr_openclosed01_f64, f64, OpenClosed01); + +// distributions +distr_float!(distr_exp, f64, Exp::new(1.23 * 4.56)); +distr_float!(distr_normal, f64, Normal::new(-1.23, 4.56)); +distr_float!(distr_log_normal, f64, LogNormal::new(-1.23, 4.56)); +distr_float!(distr_gamma_large_shape, f64, Gamma::new(10., 1.0)); +distr_float!(distr_gamma_small_shape, f64, Gamma::new(0.1, 1.0)); +distr_float!(distr_cauchy, f64, Cauchy::new(4.2, 6.9)); +distr_int!(distr_binomial, u64, Binomial::new(20, 0.7)); +distr_int!(distr_poisson, u64, Poisson::new(4.0)); +distr!(distr_bernoulli, bool, Bernoulli::new(0.18)); +distr_arr!(distr_circle, [f64; 2], UnitCircle::new()); +distr_arr!(distr_sphere_surface, [f64; 3], UnitSphereSurface::new()); + +// Weighted +distr_int!(distr_weighted_i8, usize, WeightedIndex::new(&[1i8, 2, 3, 4, 12, 0, 2, 1]).unwrap()); +distr_int!(distr_weighted_u32, usize, WeightedIndex::new(&[1u32, 2, 3, 4, 12, 0, 2, 1]).unwrap()); +distr_int!(distr_weighted_f64, usize, WeightedIndex::new(&[1.0f64, 0.001, 1.0/3.0, 4.01, 0.0, 3.3, 22.0, 0.001]).unwrap()); +distr_int!(distr_weighted_large_set, usize, WeightedIndex::new((0..10000).rev().chain(1..10001)).unwrap()); + +// construct and sample from a range +macro_rules! gen_range_int { + ($fnn:ident, $ty:ident, $low:expr, $high:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = SmallRng::from_entropy(); + + b.iter(|| { + let mut high = $high; + let mut accum: $ty = 0; + for _ in 0..::RAND_BENCH_N { + accum = accum.wrapping_add(rng.gen_range($low, high)); + // force recalculation of range each time + high = high.wrapping_add(1) & std::$ty::MAX; + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N; + } + } +} + +gen_range_int!(gen_range_i8, i8, -20i8, 100); +gen_range_int!(gen_range_i16, i16, -500i16, 2000); +gen_range_int!(gen_range_i32, i32, -200_000_000i32, 800_000_000); +gen_range_int!(gen_range_i64, i64, 3i64, 123_456_789_123); +gen_range_int!(gen_range_i128, i128, -12345678901234i128, 123_456_789_123_456_789); + +// construct and sample from a floating-point range +macro_rules! gen_range_float { + ($fnn:ident, $ty:ident, $low:expr, $high:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = SmallRng::from_entropy(); + + b.iter(|| { + let mut high = $high; + let mut low = $low; + let mut accum: $ty = 0.0; + for _ in 0..::RAND_BENCH_N { + accum += rng.gen_range(low, high); + // force recalculation of range each time + low += 0.9; + high += 1.1; + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N; + } + } +} + +gen_range_float!(gen_range_f32, f32, -20000.0f32, 100000.0); +gen_range_float!(gen_range_f64, f64, 123.456f64, 7890.12); + +#[bench] +fn dist_iter(b: &mut Bencher) { + let mut rng = SmallRng::from_entropy(); + let distr = Normal::new(-2.71828, 3.14159); + let mut iter = distr.sample_iter(&mut rng); + + b.iter(|| { + let mut accum = 0.0; + for _ in 0..::RAND_BENCH_N { + accum += iter.next().unwrap(); + } + accum + }); + b.bytes = size_of::() as u64 * ::RAND_BENCH_N; +} diff --git a/third_party/rust/rand/benches/generators.rs b/third_party/rust/rand/benches/generators.rs index daee7c5fbb5a..a6e3a423202a 100644 --- a/third_party/rust/rand/benches/generators.rs +++ b/third_party/rust/rand/benches/generators.rs @@ -1,7 +1,21 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + #![feature(test)] extern crate test; extern crate rand; +extern crate rand_isaac; +extern crate rand_chacha; +extern crate rand_hc; +extern crate rand_pcg; +extern crate rand_xorshift; +extern crate rand_xoshiro; const RAND_BENCH_N: u64 = 1000; const BYTES_LEN: usize = 1024; @@ -9,14 +23,23 @@ const BYTES_LEN: usize = 1024; use std::mem::size_of; use test::{black_box, Bencher}; -use rand::{Rng, StdRng, OsRng, JitterRng}; -use rand::{XorShiftRng, IsaacRng, Isaac64Rng, ChaChaRng}; +use rand::prelude::*; +use rand::rngs::adapter::ReseedingRng; +use rand::rngs::{OsRng, JitterRng, EntropyRng}; +use rand_isaac::{IsaacRng, Isaac64Rng}; +use rand_chacha::ChaChaRng; +use rand_hc::{Hc128Rng, Hc128Core}; +use rand_pcg::{Lcg64Xsh32, Mcg128Xsl64}; +use rand_xorshift::XorShiftRng; +use rand_xoshiro::{Xoshiro256StarStar, Xoshiro256Plus, Xoshiro128StarStar, + Xoshiro128Plus, Xoroshiro128StarStar, Xoroshiro128Plus, SplitMix64, + Xoroshiro64StarStar, Xoroshiro64Star}; macro_rules! gen_bytes { - ($fnn:ident, $gen:ident) => { + ($fnn:ident, $gen:expr) => { #[bench] fn $fnn(b: &mut Bencher) { - let mut rng: $gen = OsRng::new().unwrap().gen(); + let mut rng = $gen; let mut buf = [0u8; BYTES_LEN]; b.iter(|| { for _ in 0..RAND_BENCH_N { @@ -29,80 +52,90 @@ macro_rules! gen_bytes { } } -macro_rules! gen_bytes_new { - ($fnn:ident, $gen:ident) => { - #[bench] - fn $fnn(b: &mut Bencher) { - let mut rng = $gen::new().unwrap(); - let mut buf = [0u8; BYTES_LEN]; - b.iter(|| { - for _ in 0..RAND_BENCH_N { - rng.fill_bytes(&mut buf); - black_box(buf); - } - }); - b.bytes = BYTES_LEN as u64 * RAND_BENCH_N; - } - } -} - -gen_bytes!(gen_bytes_xorshift, XorShiftRng); -gen_bytes!(gen_bytes_isaac, IsaacRng); -gen_bytes!(gen_bytes_isaac64, Isaac64Rng); -gen_bytes!(gen_bytes_chacha, ChaChaRng); -gen_bytes_new!(gen_bytes_std, StdRng); -gen_bytes_new!(gen_bytes_os, OsRng); - +gen_bytes!(gen_bytes_xorshift, XorShiftRng::from_entropy()); +gen_bytes!(gen_bytes_xoshiro256starstar, Xoshiro256StarStar::from_entropy()); +gen_bytes!(gen_bytes_xoshiro256plus, Xoshiro256Plus::from_entropy()); +gen_bytes!(gen_bytes_xoshiro128starstar, Xoshiro128StarStar::from_entropy()); +gen_bytes!(gen_bytes_xoshiro128plus, Xoshiro128Plus::from_entropy()); +gen_bytes!(gen_bytes_xoroshiro128starstar, Xoroshiro128StarStar::from_entropy()); +gen_bytes!(gen_bytes_xoroshiro128plus, Xoroshiro128Plus::from_entropy()); +gen_bytes!(gen_bytes_xoroshiro64starstar, Xoroshiro64StarStar::from_entropy()); +gen_bytes!(gen_bytes_xoroshiro64star, Xoroshiro64Star::from_entropy()); +gen_bytes!(gen_bytes_splitmix64, SplitMix64::from_entropy()); +gen_bytes!(gen_bytes_lcg64_xsh32, Lcg64Xsh32::from_entropy()); +gen_bytes!(gen_bytes_mcg128_xsh64, Mcg128Xsl64::from_entropy()); +gen_bytes!(gen_bytes_chacha20, ChaChaRng::from_entropy()); +gen_bytes!(gen_bytes_hc128, Hc128Rng::from_entropy()); +gen_bytes!(gen_bytes_isaac, IsaacRng::from_entropy()); +gen_bytes!(gen_bytes_isaac64, Isaac64Rng::from_entropy()); +gen_bytes!(gen_bytes_std, StdRng::from_entropy()); +gen_bytes!(gen_bytes_small, SmallRng::from_entropy()); +gen_bytes!(gen_bytes_os, OsRng::new().unwrap()); macro_rules! gen_uint { - ($fnn:ident, $ty:ty, $gen:ident) => { + ($fnn:ident, $ty:ty, $gen:expr) => { #[bench] fn $fnn(b: &mut Bencher) { - let mut rng: $gen = OsRng::new().unwrap().gen(); + let mut rng = $gen; b.iter(|| { + let mut accum: $ty = 0; for _ in 0..RAND_BENCH_N { - black_box(rng.gen::<$ty>()); + accum = accum.wrapping_add(rng.gen::<$ty>()); } + accum }); b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; } } } -macro_rules! gen_uint_new { - ($fnn:ident, $ty:ty, $gen:ident) => { - #[bench] - fn $fnn(b: &mut Bencher) { - let mut rng = $gen::new().unwrap(); - b.iter(|| { - for _ in 0..RAND_BENCH_N { - black_box(rng.gen::<$ty>()); - } - }); - b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; - } - } -} +gen_uint!(gen_u32_xorshift, u32, XorShiftRng::from_entropy()); +gen_uint!(gen_u32_xoshiro256starstar, u32, Xoshiro256StarStar::from_entropy()); +gen_uint!(gen_u32_xoshiro256plus, u32, Xoshiro256Plus::from_entropy()); +gen_uint!(gen_u32_xoshiro128starstar, u32, Xoshiro128StarStar::from_entropy()); +gen_uint!(gen_u32_xoshiro128plus, u32, Xoshiro128Plus::from_entropy()); +gen_uint!(gen_u32_xoroshiro128starstar, u32, Xoroshiro128StarStar::from_entropy()); +gen_uint!(gen_u32_xoroshiro128plus, u32, Xoroshiro128Plus::from_entropy()); +gen_uint!(gen_u32_xoroshiro64starstar, u32, Xoroshiro64StarStar::from_entropy()); +gen_uint!(gen_u32_xoroshiro64star, u32, Xoroshiro64Star::from_entropy()); +gen_uint!(gen_u32_splitmix64, u32, SplitMix64::from_entropy()); +gen_uint!(gen_u32_lcg64_xsh32, u32, Lcg64Xsh32::from_entropy()); +gen_uint!(gen_u32_mcg128_xsh64, u32, Mcg128Xsl64::from_entropy()); +gen_uint!(gen_u32_chacha20, u32, ChaChaRng::from_entropy()); +gen_uint!(gen_u32_hc128, u32, Hc128Rng::from_entropy()); +gen_uint!(gen_u32_isaac, u32, IsaacRng::from_entropy()); +gen_uint!(gen_u32_isaac64, u32, Isaac64Rng::from_entropy()); +gen_uint!(gen_u32_std, u32, StdRng::from_entropy()); +gen_uint!(gen_u32_small, u32, SmallRng::from_entropy()); +gen_uint!(gen_u32_os, u32, OsRng::new().unwrap()); -gen_uint!(gen_u32_xorshift, u32, XorShiftRng); -gen_uint!(gen_u32_isaac, u32, IsaacRng); -gen_uint!(gen_u32_isaac64, u32, Isaac64Rng); -gen_uint!(gen_u32_chacha, u32, ChaChaRng); -gen_uint_new!(gen_u32_std, u32, StdRng); -gen_uint_new!(gen_u32_os, u32, OsRng); - -gen_uint!(gen_u64_xorshift, u64, XorShiftRng); -gen_uint!(gen_u64_isaac, u64, IsaacRng); -gen_uint!(gen_u64_isaac64, u64, Isaac64Rng); -gen_uint!(gen_u64_chacha, u64, ChaChaRng); -gen_uint_new!(gen_u64_std, u64, StdRng); -gen_uint_new!(gen_u64_os, u64, OsRng); +gen_uint!(gen_u64_xorshift, u64, XorShiftRng::from_entropy()); +gen_uint!(gen_u64_xoshiro256starstar, u64, Xoshiro256StarStar::from_entropy()); +gen_uint!(gen_u64_xoshiro256plus, u64, Xoshiro256Plus::from_entropy()); +gen_uint!(gen_u64_xoshiro128starstar, u64, Xoshiro128StarStar::from_entropy()); +gen_uint!(gen_u64_xoshiro128plus, u64, Xoshiro128Plus::from_entropy()); +gen_uint!(gen_u64_xoroshiro128starstar, u64, Xoroshiro128StarStar::from_entropy()); +gen_uint!(gen_u64_xoroshiro128plus, u64, Xoroshiro128Plus::from_entropy()); +gen_uint!(gen_u64_xoroshiro64starstar, u64, Xoroshiro64StarStar::from_entropy()); +gen_uint!(gen_u64_xoroshiro64star, u64, Xoroshiro64Star::from_entropy()); +gen_uint!(gen_u64_splitmix64, u64, SplitMix64::from_entropy()); +gen_uint!(gen_u64_lcg64_xsh32, u64, Lcg64Xsh32::from_entropy()); +gen_uint!(gen_u64_mcg128_xsh64, u64, Mcg128Xsl64::from_entropy()); +gen_uint!(gen_u64_chacha20, u64, ChaChaRng::from_entropy()); +gen_uint!(gen_u64_hc128, u64, Hc128Rng::from_entropy()); +gen_uint!(gen_u64_isaac, u64, IsaacRng::from_entropy()); +gen_uint!(gen_u64_isaac64, u64, Isaac64Rng::from_entropy()); +gen_uint!(gen_u64_std, u64, StdRng::from_entropy()); +gen_uint!(gen_u64_small, u64, SmallRng::from_entropy()); +gen_uint!(gen_u64_os, u64, OsRng::new().unwrap()); +// Do not test JitterRng like the others by running it RAND_BENCH_N times per, +// measurement, because it is way too slow. Only run it once. #[bench] fn gen_u64_jitter(b: &mut Bencher) { let mut rng = JitterRng::new().unwrap(); b.iter(|| { - black_box(rng.gen::()); + rng.gen::() }); b.bytes = size_of::() as u64; } @@ -111,16 +144,28 @@ macro_rules! init_gen { ($fnn:ident, $gen:ident) => { #[bench] fn $fnn(b: &mut Bencher) { - let mut rng: XorShiftRng = OsRng::new().unwrap().gen(); + let mut rng = XorShiftRng::from_entropy(); b.iter(|| { - let r2: $gen = rng.gen(); - black_box(r2); + let r2 = $gen::from_rng(&mut rng).unwrap(); + r2 }); } } } init_gen!(init_xorshift, XorShiftRng); +init_gen!(init_xoshiro256starstar, Xoshiro256StarStar); +init_gen!(init_xoshiro256plus, Xoshiro256Plus); +init_gen!(init_xoshiro128starstar, Xoshiro128StarStar); +init_gen!(init_xoshiro128plus, Xoshiro128Plus); +init_gen!(init_xoroshiro128starstar, Xoroshiro128StarStar); +init_gen!(init_xoroshiro128plus, Xoroshiro128Plus); +init_gen!(init_xoroshiro64starstar, Xoroshiro64StarStar); +init_gen!(init_xoroshiro64star, Xoroshiro64Star); +init_gen!(init_splitmix64, SplitMix64); +init_gen!(init_lcg64_xsh32, Lcg64Xsh32); +init_gen!(init_mcg128_xsh64, Mcg128Xsl64); +init_gen!(init_hc128, Hc128Rng); init_gen!(init_isaac, IsaacRng); init_gen!(init_isaac64, Isaac64Rng); init_gen!(init_chacha, ChaChaRng); @@ -128,6 +173,68 @@ init_gen!(init_chacha, ChaChaRng); #[bench] fn init_jitter(b: &mut Bencher) { b.iter(|| { - black_box(JitterRng::new().unwrap()); + JitterRng::new().unwrap() }); } + + +const RESEEDING_THRESHOLD: u64 = 1024*1024*1024; // something high enough to get + // deterministic measurements + +#[bench] +fn reseeding_hc128_bytes(b: &mut Bencher) { + let mut rng = ReseedingRng::new(Hc128Core::from_entropy(), + RESEEDING_THRESHOLD, + EntropyRng::new()); + let mut buf = [0u8; BYTES_LEN]; + b.iter(|| { + for _ in 0..RAND_BENCH_N { + rng.fill_bytes(&mut buf); + black_box(buf); + } + }); + b.bytes = BYTES_LEN as u64 * RAND_BENCH_N; +} + +macro_rules! reseeding_uint { + ($fnn:ident, $ty:ty) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = ReseedingRng::new(Hc128Core::from_entropy(), + RESEEDING_THRESHOLD, + EntropyRng::new()); + b.iter(|| { + let mut accum: $ty = 0; + for _ in 0..RAND_BENCH_N { + accum = accum.wrapping_add(rng.gen::<$ty>()); + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; + } + } +} + +reseeding_uint!(reseeding_hc128_u32, u32); +reseeding_uint!(reseeding_hc128_u64, u64); + + +macro_rules! threadrng_uint { + ($fnn:ident, $ty:ty) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = thread_rng(); + b.iter(|| { + let mut accum: $ty = 0; + for _ in 0..RAND_BENCH_N { + accum = accum.wrapping_add(rng.gen::<$ty>()); + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; + } + } +} + +threadrng_uint!(thread_rng_u32, u32); +threadrng_uint!(thread_rng_u64, u64); diff --git a/third_party/rust/rand/benches/misc.rs b/third_party/rust/rand/benches/misc.rs index 425176176626..8fb3a832f229 100644 --- a/third_party/rust/rand/benches/misc.rs +++ b/third_party/rust/rand/benches/misc.rs @@ -1,62 +1,160 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + #![feature(test)] extern crate test; extern crate rand; -use test::{black_box, Bencher}; +const RAND_BENCH_N: u64 = 1000; -use rand::{Rng, weak_rng}; -use rand::seq::*; +use test::Bencher; + +use rand::prelude::*; #[bench] -fn misc_shuffle_100(b: &mut Bencher) { - let mut rng = weak_rng(); - let x : &mut [usize] = &mut [1; 100]; +fn misc_gen_bool_const(b: &mut Bencher) { + let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap(); b.iter(|| { - rng.shuffle(x); - black_box(&x); + let mut accum = true; + for _ in 0..::RAND_BENCH_N { + accum ^= rng.gen_bool(0.18); + } + accum }) } #[bench] -fn misc_sample_iter_10_of_100(b: &mut Bencher) { - let mut rng = weak_rng(); - let x : &[usize] = &[1; 100]; +fn misc_gen_bool_var(b: &mut Bencher) { + let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap(); b.iter(|| { - black_box(sample_iter(&mut rng, x, 10).unwrap_or_else(|e| e)); + let mut accum = true; + let mut p = 0.18; + for _ in 0..::RAND_BENCH_N { + accum ^= rng.gen_bool(p); + p += 0.0001; + } + accum }) } #[bench] -fn misc_sample_slice_10_of_100(b: &mut Bencher) { - let mut rng = weak_rng(); - let x : &[usize] = &[1; 100]; +fn misc_gen_ratio_const(b: &mut Bencher) { + let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap(); b.iter(|| { - black_box(sample_slice(&mut rng, x, 10)); + let mut accum = true; + for _ in 0..::RAND_BENCH_N { + accum ^= rng.gen_ratio(2, 3); + } + accum }) } #[bench] -fn misc_sample_slice_ref_10_of_100(b: &mut Bencher) { - let mut rng = weak_rng(); - let x : &[usize] = &[1; 100]; +fn misc_gen_ratio_var(b: &mut Bencher) { + let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap(); b.iter(|| { - black_box(sample_slice_ref(&mut rng, x, 10)); + let mut accum = true; + for i in 2..(::RAND_BENCH_N as u32 + 2) { + accum ^= rng.gen_ratio(i, i + 1); + } + accum }) } -macro_rules! sample_indices { - ($name:ident, $amount:expr, $length:expr) => { +#[bench] +fn misc_bernoulli_const(b: &mut Bencher) { + let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + let d = rand::distributions::Bernoulli::new(0.18); + let mut accum = true; + for _ in 0..::RAND_BENCH_N { + accum ^= rng.sample(d); + } + accum + }) +} + +#[bench] +fn misc_bernoulli_var(b: &mut Bencher) { + let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + let mut accum = true; + let mut p = 0.18; + for _ in 0..::RAND_BENCH_N { + let d = rand::distributions::Bernoulli::new(p); + accum ^= rng.sample(d); + p += 0.0001; + } + accum + }) +} + +macro_rules! sample_binomial { + ($name:ident, $n:expr, $p:expr) => { #[bench] fn $name(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + let (n, p) = ($n, $p); b.iter(|| { - black_box(sample_indices(&mut rng, $length, $amount)); + let d = rand::distributions::Binomial::new(n, p); + rng.sample(d) }) } } } -sample_indices!(misc_sample_indices_10_of_1k, 10, 1000); -sample_indices!(misc_sample_indices_50_of_1k, 50, 1000); -sample_indices!(misc_sample_indices_100_of_1k, 100, 1000); +sample_binomial!(misc_binomial_1, 1, 0.9); +sample_binomial!(misc_binomial_10, 10, 0.9); +sample_binomial!(misc_binomial_100, 100, 0.99); +sample_binomial!(misc_binomial_1000, 1000, 0.01); +sample_binomial!(misc_binomial_1e12, 1000_000_000_000, 0.2); + +#[bench] +fn gen_1k_iter_repeat(b: &mut Bencher) { + use std::iter; + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + let v: Vec = iter::repeat(()).map(|()| rng.gen()).take(128).collect(); + v + }); + b.bytes = 1024; +} + +#[bench] +fn gen_1k_sample_iter(b: &mut Bencher) { + use rand::distributions::{Distribution, Standard}; + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + let v: Vec = Standard.sample_iter(&mut rng).take(128).collect(); + v + }); + b.bytes = 1024; +} + +#[bench] +fn gen_1k_gen_array(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + // max supported array length is 32! + let v: [[u64; 32]; 4] = rng.gen(); + v + }); + b.bytes = 1024; +} + +#[bench] +fn gen_1k_fill(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + let mut buf = [0u64; 128]; + b.iter(|| { + rng.fill(&mut buf[..]); + buf + }); + b.bytes = 1024; +} diff --git a/third_party/rust/rand/benches/seq.rs b/third_party/rust/rand/benches/seq.rs new file mode 100644 index 000000000000..0ca3398f2e67 --- /dev/null +++ b/third_party/rust/rand/benches/seq.rs @@ -0,0 +1,174 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(test)] +#![allow(non_snake_case)] + +extern crate test; +extern crate rand; + +use test::Bencher; + +use rand::prelude::*; +use rand::seq::*; +use std::mem::size_of; + +const RAND_BENCH_N: u64 = 1000; + +#[bench] +fn seq_shuffle_100(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let x : &mut [usize] = &mut [1; 100]; + b.iter(|| { + x.shuffle(&mut rng); + x[0] + }) +} + +#[bench] +fn seq_slice_choose_1_of_1000(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let x : &mut [usize] = &mut [1; 1000]; + for i in 0..1000 { + x[i] = i; + } + b.iter(|| { + let mut s = 0; + for _ in 0..RAND_BENCH_N { + s += x.choose(&mut rng).unwrap(); + } + s + }); + b.bytes = size_of::() as u64 * ::RAND_BENCH_N; +} + +macro_rules! seq_slice_choose_multiple { + ($name:ident, $amount:expr, $length:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let x : &[i32] = &[$amount; $length]; + let mut result = [0i32; $amount]; + b.iter(|| { + // Collect full result to prevent unwanted shortcuts getting + // first element (in case sample_indices returns an iterator). + for (slot, sample) in result.iter_mut().zip( + x.choose_multiple(&mut rng, $amount)) { + *slot = *sample; + } + result[$amount-1] + }) + } + } +} + +seq_slice_choose_multiple!(seq_slice_choose_multiple_1_of_1000, 1, 1000); +seq_slice_choose_multiple!(seq_slice_choose_multiple_950_of_1000, 950, 1000); +seq_slice_choose_multiple!(seq_slice_choose_multiple_10_of_100, 10, 100); +seq_slice_choose_multiple!(seq_slice_choose_multiple_90_of_100, 90, 100); + +#[bench] +fn seq_iter_choose_from_1000(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let x : &mut [usize] = &mut [1; 1000]; + for i in 0..1000 { + x[i] = i; + } + b.iter(|| { + let mut s = 0; + for _ in 0..RAND_BENCH_N { + s += x.iter().choose(&mut rng).unwrap(); + } + s + }); + b.bytes = size_of::() as u64 * ::RAND_BENCH_N; +} + +#[derive(Clone)] +struct UnhintedIterator { + iter: I, +} +impl Iterator for UnhintedIterator { + type Item = I::Item; + fn next(&mut self) -> Option { + self.iter.next() + } +} + +#[derive(Clone)] +struct WindowHintedIterator { + iter: I, + window_size: usize, +} +impl Iterator for WindowHintedIterator { + type Item = I::Item; + fn next(&mut self) -> Option { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + (std::cmp::min(self.iter.len(), self.window_size), None) + } +} + +#[bench] +fn seq_iter_unhinted_choose_from_1000(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let x : &[usize] = &[1; 1000]; + b.iter(|| { + UnhintedIterator { iter: x.iter() }.choose(&mut rng).unwrap() + }) +} + +#[bench] +fn seq_iter_window_hinted_choose_from_1000(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let x : &[usize] = &[1; 1000]; + b.iter(|| { + WindowHintedIterator { iter: x.iter(), window_size: 7 }.choose(&mut rng) + }) +} + +#[bench] +fn seq_iter_choose_multiple_10_of_100(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let x : &[usize] = &[1; 100]; + b.iter(|| { + x.iter().cloned().choose_multiple(&mut rng, 10) + }) +} + +#[bench] +fn seq_iter_choose_multiple_fill_10_of_100(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let x : &[usize] = &[1; 100]; + let mut buf = [0; 10]; + b.iter(|| { + x.iter().cloned().choose_multiple_fill(&mut rng, &mut buf) + }) +} + +macro_rules! sample_indices { + ($name:ident, $fn:ident, $amount:expr, $length:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + b.iter(|| { + index::$fn(&mut rng, $length, $amount) + }) + } + } +} + +sample_indices!(misc_sample_indices_1_of_1k, sample, 1, 1000); +sample_indices!(misc_sample_indices_10_of_1k, sample, 10, 1000); +sample_indices!(misc_sample_indices_100_of_1k, sample, 100, 1000); +sample_indices!(misc_sample_indices_100_of_1M, sample, 100, 1000_000); +sample_indices!(misc_sample_indices_100_of_1G, sample, 100, 1000_000_000); +sample_indices!(misc_sample_indices_200_of_1G, sample, 200, 1000_000_000); +sample_indices!(misc_sample_indices_400_of_1G, sample, 400, 1000_000_000); +sample_indices!(misc_sample_indices_600_of_1G, sample, 600, 1000_000_000); diff --git a/third_party/rust/rand/build.rs b/third_party/rust/rand/build.rs new file mode 100644 index 000000000000..a554ad9875e5 --- /dev/null +++ b/third_party/rust/rand/build.rs @@ -0,0 +1,10 @@ +extern crate autocfg; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + let ac = autocfg::new(); + ac.emit_rustc_version(1, 25); + ac.emit_rustc_version(1, 26); + ac.emit_rustc_version(1, 27); +} diff --git a/third_party/rust/rand/examples/monte-carlo.rs b/third_party/rust/rand/examples/monte-carlo.rs new file mode 100644 index 000000000000..916299686103 --- /dev/null +++ b/third_party/rust/rand/examples/monte-carlo.rs @@ -0,0 +1,51 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013-2018 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! # Monte Carlo estimation of Ï€ +//! +//! Imagine that we have a square with sides of length 2 and a unit circle +//! (radius = 1), both centered at the origin. The areas are: +//! +//! ```text +//! area of circle = Ï€r² = Ï€ * r * r = Ï€ +//! area of square = 2² = 4 +//! ``` +//! +//! The circle is entirely within the square, so if we sample many points +//! randomly from the square, roughly Ï€ / 4 of them should be inside the circle. +//! +//! We can use the above fact to estimate the value of Ï€: pick many points in +//! the square at random, calculate the fraction that fall within the circle, +//! and multiply this fraction by 4. + +#![cfg(feature="std")] + + +extern crate rand; + +use rand::distributions::{Distribution, Uniform}; + +fn main() { + let range = Uniform::new(-1.0f64, 1.0); + let mut rng = rand::thread_rng(); + + let total = 1_000_000; + let mut in_circle = 0; + + for _ in 0..total { + let a = range.sample(&mut rng); + let b = range.sample(&mut rng); + if a*a + b*b <= 1.0 { + in_circle += 1; + } + } + + // prints something close to 3.14159... + println!("Ï€ is approximately {}", 4. * (in_circle as f64) / (total as f64)); +} diff --git a/third_party/rust/rand/examples/monty-hall.rs b/third_party/rust/rand/examples/monty-hall.rs new file mode 100644 index 000000000000..0932c5efb518 --- /dev/null +++ b/third_party/rust/rand/examples/monty-hall.rs @@ -0,0 +1,116 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013-2018 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! ## Monty Hall Problem +//! +//! This is a simulation of the [Monty Hall Problem][]: +//! +//! > Suppose you're on a game show, and you're given the choice of three doors: +//! > Behind one door is a car; behind the others, goats. You pick a door, say +//! > No. 1, and the host, who knows what's behind the doors, opens another +//! > door, say No. 3, which has a goat. He then says to you, "Do you want to +//! > pick door No. 2?" Is it to your advantage to switch your choice? +//! +//! The rather unintuitive answer is that you will have a 2/3 chance of winning +//! if you switch and a 1/3 chance of winning if you don't, so it's better to +//! switch. +//! +//! This program will simulate the game show and with large enough simulation +//! steps it will indeed confirm that it is better to switch. +//! +//! [Monty Hall Problem]: https://en.wikipedia.org/wiki/Monty_Hall_problem + +#![cfg(feature="std")] + + +extern crate rand; + +use rand::Rng; +use rand::distributions::{Distribution, Uniform}; + +struct SimulationResult { + win: bool, + switch: bool, +} + +// Run a single simulation of the Monty Hall problem. +fn simulate(random_door: &Uniform, rng: &mut R) + -> SimulationResult { + let car = random_door.sample(rng); + + // This is our initial choice + let mut choice = random_door.sample(rng); + + // The game host opens a door + let open = game_host_open(car, choice, rng); + + // Shall we switch? + let switch = rng.gen(); + if switch { + choice = switch_door(choice, open); + } + + SimulationResult { win: choice == car, switch } +} + +// Returns the door the game host opens given our choice and knowledge of +// where the car is. The game host will never open the door with the car. +fn game_host_open(car: u32, choice: u32, rng: &mut R) -> u32 { + use rand::seq::SliceRandom; + *free_doors(&[car, choice]).choose(rng).unwrap() +} + +// Returns the door we switch to, given our current choice and +// the open door. There will only be one valid door. +fn switch_door(choice: u32, open: u32) -> u32 { + free_doors(&[choice, open])[0] +} + +fn free_doors(blocked: &[u32]) -> Vec { + (0..3).filter(|x| !blocked.contains(x)).collect() +} + +fn main() { + // The estimation will be more accurate with more simulations + let num_simulations = 10000; + + let mut rng = rand::thread_rng(); + let random_door = Uniform::new(0u32, 3); + + let (mut switch_wins, mut switch_losses) = (0, 0); + let (mut keep_wins, mut keep_losses) = (0, 0); + + println!("Running {} simulations...", num_simulations); + for _ in 0..num_simulations { + let result = simulate(&random_door, &mut rng); + + match (result.win, result.switch) { + (true, true) => switch_wins += 1, + (true, false) => keep_wins += 1, + (false, true) => switch_losses += 1, + (false, false) => keep_losses += 1, + } + } + + let total_switches = switch_wins + switch_losses; + let total_keeps = keep_wins + keep_losses; + + println!("Switched door {} times with {} wins and {} losses", + total_switches, switch_wins, switch_losses); + + println!("Kept our choice {} times with {} wins and {} losses", + total_keeps, keep_wins, keep_losses); + + // With a large number of simulations, the values should converge to + // 0.667 and 0.333 respectively. + println!("Estimated chance to win if we switch: {}", + switch_wins as f32 / total_switches as f32); + println!("Estimated chance to win if we don't: {}", + keep_wins as f32 / total_keeps as f32); +} diff --git a/third_party/rust/rand/src/deprecated.rs b/third_party/rust/rand/src/deprecated.rs new file mode 100644 index 000000000000..88eb09fce1f9 --- /dev/null +++ b/third_party/rust/rand/src/deprecated.rs @@ -0,0 +1,544 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Deprecated re-exports (we can't add deprecation warnings otherwise) + +#![allow(deprecated)] + +use rngs; +use {RngCore, CryptoRng, SeedableRng, Error}; +use rand_core::block::BlockRngCore; +use rand_isaac; +use rand_chacha; +use rand_hc; + +#[cfg(feature="std")] +use std::io::Read; + +#[derive(Clone, Debug)] +#[deprecated(since="0.6.0", + note="import from rand_isaac crate instead, or use the newer Hc128Rng")] +pub struct IsaacRng(rand_isaac::IsaacRng); + +impl RngCore for IsaacRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for IsaacRng { + type Seed = ::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + IsaacRng(rand_isaac::IsaacRng::from_seed(seed)) + } + + fn from_rng(rng: R) -> Result { + rand_isaac::IsaacRng::from_rng(rng).map(IsaacRng) + } +} + +impl IsaacRng { + pub fn new_from_u64(seed: u64) -> Self { + IsaacRng(rand_isaac::IsaacRng::new_from_u64(seed)) + } +} + + +#[derive(Clone, Debug)] +#[deprecated(since="0.6.0", + note="import from rand_isaac crate instead, or use newer Hc128Rng")] +pub struct Isaac64Rng(rand_isaac::Isaac64Rng); + +impl RngCore for Isaac64Rng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for Isaac64Rng { + type Seed = ::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + Isaac64Rng(rand_isaac::Isaac64Rng::from_seed(seed)) + } + + fn from_rng(rng: R) -> Result { + rand_isaac::Isaac64Rng::from_rng(rng).map(Isaac64Rng) + } +} + +impl Isaac64Rng { + pub fn new_from_u64(seed: u64) -> Self { + Isaac64Rng(rand_isaac::Isaac64Rng::new_from_u64(seed)) + } +} + + +#[derive(Clone, Debug)] +#[deprecated(since="0.6.0", note="import from rand_chacha crate instead")] +pub struct ChaChaRng(rand_chacha::ChaChaRng); + +impl RngCore for ChaChaRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for ChaChaRng { + type Seed = ::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + ChaChaRng(rand_chacha::ChaChaRng::from_seed(seed)) + } + + fn from_rng(rng: R) -> Result { + rand_chacha::ChaChaRng::from_rng(rng).map(ChaChaRng) + } +} + +impl ChaChaRng { + #[cfg(all(rustc_1_26, not(target_os = "emscripten")))] + pub fn get_word_pos(&self) -> u128 { + self.0.get_word_pos() + } + + #[cfg(all(rustc_1_26, not(target_os = "emscripten")))] + pub fn set_word_pos(&mut self, word_offset: u128) { + self.0.set_word_pos(word_offset) + } + + pub fn set_stream(&mut self, stream: u64) { + self.0.set_stream(stream) + } +} + +impl CryptoRng for ChaChaRng {} + + +#[derive(Clone, Debug)] +#[deprecated(since="0.6.0", note="import from rand_hc crate instead")] +pub struct Hc128Rng(rand_hc::Hc128Rng); + +impl RngCore for Hc128Rng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for Hc128Rng { + type Seed = ::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + Hc128Rng(rand_hc::Hc128Rng::from_seed(seed)) + } + + fn from_rng(rng: R) -> Result { + rand_hc::Hc128Rng::from_rng(rng).map(Hc128Rng) + } +} + +impl CryptoRng for Hc128Rng {} + + +#[derive(Clone, Debug)] +#[deprecated(since="0.6.0", note="import from rand_xorshift crate instead")] +pub struct XorShiftRng(::rand_xorshift::XorShiftRng); + +impl RngCore for XorShiftRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for XorShiftRng { + type Seed = <::rand_xorshift::XorShiftRng as SeedableRng>::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + XorShiftRng(::rand_xorshift::XorShiftRng::from_seed(seed)) + } + + fn from_rng(rng: R) -> Result { + ::rand_xorshift::XorShiftRng::from_rng(rng).map(XorShiftRng) + } +} + + +#[derive(Clone, Debug)] +#[deprecated(since="0.6.0", + note="import with rand::prelude::* or rand::rngs::StdRng instead")] +pub struct StdRng(rngs::StdRng); + +impl RngCore for StdRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for StdRng { + type Seed = ::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + StdRng(rngs::StdRng::from_seed(seed)) + } + + fn from_rng(rng: R) -> Result { + rngs::StdRng::from_rng(rng).map(StdRng) + } +} + +impl CryptoRng for StdRng {} + + +#[cfg(feature="rand_os")] +#[derive(Clone, Debug)] +#[deprecated(since="0.6.0", note="import with rand::rngs::OsRng instead")] +pub struct OsRng(rngs::OsRng); + +#[cfg(feature="rand_os")] +impl RngCore for OsRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +#[cfg(feature="rand_os")] +impl OsRng { + pub fn new() -> Result { + rngs::OsRng::new().map(OsRng) + } +} + +#[cfg(feature="rand_os")] +impl CryptoRng for OsRng {} + + +#[cfg(feature="std")] +#[derive(Debug)] +#[deprecated(since="0.6.0", note="import with rand::rngs::EntropyRng instead")] +pub struct EntropyRng(rngs::EntropyRng); + +#[cfg(feature="std")] +impl RngCore for EntropyRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +#[cfg(feature="std")] +impl EntropyRng { + pub fn new() -> Self { + EntropyRng(rngs::EntropyRng::new()) + } +} + +#[cfg(feature="std")] +impl Default for EntropyRng { + fn default() -> Self { + EntropyRng::new() + } +} + +#[cfg(feature="std")] +impl CryptoRng for EntropyRng {} + + +#[derive(Clone, Debug)] +#[deprecated(since="0.6.0", note="import with rand::rngs::JitterRng instead")] +pub struct JitterRng(rngs::JitterRng); + +impl RngCore for JitterRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl JitterRng { + #[cfg(all(feature="std", not(target_arch = "wasm32")))] + pub fn new() -> Result { + rngs::JitterRng::new().map(JitterRng) + } + + pub fn new_with_timer(timer: fn() -> u64) -> JitterRng { + JitterRng(rngs::JitterRng::new_with_timer(timer)) + } + + pub fn set_rounds(&mut self, rounds: u8) { + self.0.set_rounds(rounds) + } + + pub fn test_timer(&mut self) -> Result { + self.0.test_timer() + } + + #[cfg(feature="std")] + pub fn timer_stats(&mut self, var_rounds: bool) -> i64 { + self.0.timer_stats(var_rounds) + } +} + +impl CryptoRng for JitterRng {} + + +#[cfg(feature="std")] +#[derive(Clone, Debug)] +#[deprecated(since="0.6.0", + note="import with rand::prelude::* or rand::rngs::ThreadRng instead")] +pub struct ThreadRng(rngs::ThreadRng); + +#[cfg(feature="std")] +impl RngCore for ThreadRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +#[cfg(feature="std")] +impl CryptoRng for ThreadRng {} + + +#[cfg(feature="std")] +#[derive(Debug)] +#[deprecated(since="0.6.0", note="import with rand::rngs::adapter::ReadRng instead")] +pub struct ReadRng(rngs::adapter::ReadRng); + +#[cfg(feature="std")] +impl RngCore for ReadRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +#[cfg(feature="std")] +impl ReadRng { + pub fn new(r: R) -> ReadRng { + ReadRng(rngs::adapter::ReadRng::new(r)) + } +} + + +#[derive(Clone, Debug)] +pub struct ReseedingRng(rngs::adapter::ReseedingRng) +where R: BlockRngCore + SeedableRng, + Rsdr: RngCore; + +impl RngCore for ReseedingRng +where R: BlockRngCore + SeedableRng, + ::Results: AsRef<[u32]> + AsMut<[u32]> +{ + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl ReseedingRng +where R: BlockRngCore + SeedableRng, + Rsdr: RngCore +{ + pub fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self { + ReseedingRng(rngs::adapter::ReseedingRng::new(rng, threshold, reseeder)) + } + + pub fn reseed(&mut self) -> Result<(), Error> { + self.0.reseed() + } +} + +impl CryptoRng for ReseedingRng +where R: BlockRngCore + SeedableRng + CryptoRng, + Rsdr: RngCore + CryptoRng {} diff --git a/third_party/rust/rand/src/distributions/bernoulli.rs b/third_party/rust/rand/src/distributions/bernoulli.rs new file mode 100644 index 000000000000..f49618c67d57 --- /dev/null +++ b/third_party/rust/rand/src/distributions/bernoulli.rs @@ -0,0 +1,165 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The Bernoulli distribution. + +use Rng; +use distributions::Distribution; + +/// The Bernoulli distribution. +/// +/// This is a special case of the Binomial distribution where `n = 1`. +/// +/// # Example +/// +/// ```rust +/// use rand::distributions::{Bernoulli, Distribution}; +/// +/// let d = Bernoulli::new(0.3); +/// let v = d.sample(&mut rand::thread_rng()); +/// println!("{} is from a Bernoulli distribution", v); +/// ``` +/// +/// # Precision +/// +/// This `Bernoulli` distribution uses 64 bits from the RNG (a `u64`), +/// so only probabilities that are multiples of 2-64 can be +/// represented. +#[derive(Clone, Copy, Debug)] +pub struct Bernoulli { + /// Probability of success, relative to the maximal integer. + p_int: u64, +} + +// To sample from the Bernoulli distribution we use a method that compares a +// random `u64` value `v < (p * 2^64)`. +// +// If `p == 1.0`, the integer `v` to compare against can not represented as a +// `u64`. We manually set it to `u64::MAX` instead (2^64 - 1 instead of 2^64). +// Note that value of `p < 1.0` can never result in `u64::MAX`, because an +// `f64` only has 53 bits of precision, and the next largest value of `p` will +// result in `2^64 - 2048`. +// +// Also there is a 100% theoretical concern: if someone consistenly wants to +// generate `true` using the Bernoulli distribution (i.e. by using a probability +// of `1.0`), just using `u64::MAX` is not enough. On average it would return +// false once every 2^64 iterations. Some people apparently care about this +// case. +// +// That is why we special-case `u64::MAX` to always return `true`, without using +// the RNG, and pay the performance price for all uses that *are* reasonable. +// Luckily, if `new()` and `sample` are close, the compiler can optimize out the +// extra check. +const ALWAYS_TRUE: u64 = ::core::u64::MAX; + +// This is just `2.0.powi(64)`, but written this way because it is not available +// in `no_std` mode. +const SCALE: f64 = 2.0 * (1u64 << 63) as f64; + +impl Bernoulli { + /// Construct a new `Bernoulli` with the given probability of success `p`. + /// + /// # Panics + /// + /// If `p < 0` or `p > 1`. + /// + /// # Precision + /// + /// For `p = 1.0`, the resulting distribution will always generate true. + /// For `p = 0.0`, the resulting distribution will always generate false. + /// + /// This method is accurate for any input `p` in the range `[0, 1]` which is + /// a multiple of 2-64. (Note that not all multiples of + /// 2-64 in `[0, 1]` can be represented as a `f64`.) + #[inline] + pub fn new(p: f64) -> Bernoulli { + if p < 0.0 || p >= 1.0 { + if p == 1.0 { return Bernoulli { p_int: ALWAYS_TRUE } } + panic!("Bernoulli::new not called with 0.0 <= p <= 1.0"); + } + Bernoulli { p_int: (p * SCALE) as u64 } + } + + /// Construct a new `Bernoulli` with the probability of success of + /// `numerator`-in-`denominator`. I.e. `new_ratio(2, 3)` will return + /// a `Bernoulli` with a 2-in-3 chance, or about 67%, of returning `true`. + /// + /// If `numerator == denominator` then the returned `Bernoulli` will always + /// return `true`. If `numerator == 0` it will always return `false`. + /// + /// # Panics + /// + /// If `denominator == 0` or `numerator > denominator`. + /// + #[inline] + pub fn from_ratio(numerator: u32, denominator: u32) -> Bernoulli { + assert!(numerator <= denominator); + if numerator == denominator { + return Bernoulli { p_int: ::core::u64::MAX } + } + let p_int = ((numerator as f64 / denominator as f64) * SCALE) as u64; + Bernoulli { p_int } + } +} + +impl Distribution for Bernoulli { + #[inline] + fn sample(&self, rng: &mut R) -> bool { + // Make sure to always return true for p = 1.0. + if self.p_int == ALWAYS_TRUE { return true; } + let v: u64 = rng.gen(); + v < self.p_int + } +} + +#[cfg(test)] +mod test { + use Rng; + use distributions::Distribution; + use super::Bernoulli; + + #[test] + fn test_trivial() { + let mut r = ::test::rng(1); + let always_false = Bernoulli::new(0.0); + let always_true = Bernoulli::new(1.0); + for _ in 0..5 { + assert_eq!(r.sample::(&always_false), false); + assert_eq!(r.sample::(&always_true), true); + assert_eq!(Distribution::::sample(&always_false, &mut r), false); + assert_eq!(Distribution::::sample(&always_true, &mut r), true); + } + } + + #[test] + fn test_average() { + const P: f64 = 0.3; + const NUM: u32 = 3; + const DENOM: u32 = 10; + let d1 = Bernoulli::new(P); + let d2 = Bernoulli::from_ratio(NUM, DENOM); + const N: u32 = 100_000; + + let mut sum1: u32 = 0; + let mut sum2: u32 = 0; + let mut rng = ::test::rng(2); + for _ in 0..N { + if d1.sample(&mut rng) { + sum1 += 1; + } + if d2.sample(&mut rng) { + sum2 += 1; + } + } + let avg1 = (sum1 as f64) / (N as f64); + assert!((avg1 - P).abs() < 5e-3); + + let avg2 = (sum2 as f64) / (N as f64); + assert!((avg2 - (NUM as f64)/(DENOM as f64)).abs() < 5e-3); + } +} diff --git a/third_party/rust/rand/src/distributions/binomial.rs b/third_party/rust/rand/src/distributions/binomial.rs new file mode 100644 index 000000000000..2df393e53ab1 --- /dev/null +++ b/third_party/rust/rand/src/distributions/binomial.rs @@ -0,0 +1,177 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2016-2017 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The binomial distribution. + +use Rng; +use distributions::{Distribution, Bernoulli, Cauchy}; +use distributions::utils::log_gamma; + +/// The binomial distribution `Binomial(n, p)`. +/// +/// This distribution has density function: +/// `f(k) = n!/(k! (n-k)!) p^k (1-p)^(n-k)` for `k >= 0`. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Binomial, Distribution}; +/// +/// let bin = Binomial::new(20, 0.3); +/// let v = bin.sample(&mut rand::thread_rng()); +/// println!("{} is from a binomial distribution", v); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Binomial { + /// Number of trials. + n: u64, + /// Probability of success. + p: f64, +} + +impl Binomial { + /// Construct a new `Binomial` with the given shape parameters `n` (number + /// of trials) and `p` (probability of success). + /// + /// Panics if `p < 0` or `p > 1`. + pub fn new(n: u64, p: f64) -> Binomial { + assert!(p >= 0.0, "Binomial::new called with p < 0"); + assert!(p <= 1.0, "Binomial::new called with p > 1"); + Binomial { n, p } + } +} + +impl Distribution for Binomial { + fn sample(&self, rng: &mut R) -> u64 { + // Handle these values directly. + if self.p == 0.0 { + return 0; + } else if self.p == 1.0 { + return self.n; + } + + // For low n, it is faster to sample directly. For both methods, + // performance is independent of p. On Intel Haswell CPU this method + // appears to be faster for approx n < 300. + if self.n < 300 { + let mut result = 0; + let d = Bernoulli::new(self.p); + for _ in 0 .. self.n { + result += rng.sample(d) as u32; + } + return result as u64; + } + + // binomial distribution is symmetrical with respect to p -> 1-p, k -> n-k + // switch p so that it is less than 0.5 - this allows for lower expected values + // we will just invert the result at the end + let p = if self.p <= 0.5 { + self.p + } else { + 1.0 - self.p + }; + + // prepare some cached values + let float_n = self.n as f64; + let ln_fact_n = log_gamma(float_n + 1.0); + let pc = 1.0 - p; + let log_p = p.ln(); + let log_pc = pc.ln(); + let expected = self.n as f64 * p; + let sq = (expected * (2.0 * pc)).sqrt(); + + let mut lresult; + + // we use the Cauchy distribution as the comparison distribution + // f(x) ~ 1/(1+x^2) + let cauchy = Cauchy::new(0.0, 1.0); + loop { + let mut comp_dev: f64; + loop { + // draw from the Cauchy distribution + comp_dev = rng.sample(cauchy); + // shift the peak of the comparison ditribution + lresult = expected + sq * comp_dev; + // repeat the drawing until we are in the range of possible values + if lresult >= 0.0 && lresult < float_n + 1.0 { + break; + } + } + + // the result should be discrete + lresult = lresult.floor(); + + let log_binomial_dist = ln_fact_n - log_gamma(lresult+1.0) - + log_gamma(float_n - lresult + 1.0) + lresult*log_p + (float_n - lresult)*log_pc; + // this is the binomial probability divided by the comparison probability + // we will generate a uniform random value and if it is larger than this, + // we interpret it as a value falling out of the distribution and repeat + let comparison_coeff = (log_binomial_dist.exp() * sq) * (1.2 * (1.0 + comp_dev*comp_dev)); + + if comparison_coeff >= rng.gen() { + break; + } + } + + // invert the result for p < 0.5 + if p != self.p { + self.n - lresult as u64 + } else { + lresult as u64 + } + } +} + +#[cfg(test)] +mod test { + use Rng; + use distributions::Distribution; + use super::Binomial; + + fn test_binomial_mean_and_variance(n: u64, p: f64, rng: &mut R) { + let binomial = Binomial::new(n, p); + + let expected_mean = n as f64 * p; + let expected_variance = n as f64 * p * (1.0 - p); + + let mut results = [0.0; 1000]; + for i in results.iter_mut() { *i = binomial.sample(rng) as f64; } + + let mean = results.iter().sum::() / results.len() as f64; + assert!((mean as f64 - expected_mean).abs() < expected_mean / 50.0); + + let variance = + results.iter().map(|x| (x - mean) * (x - mean)).sum::() + / results.len() as f64; + assert!((variance - expected_variance).abs() < expected_variance / 10.0); + } + + #[test] + fn test_binomial() { + let mut rng = ::test::rng(351); + test_binomial_mean_and_variance(150, 0.1, &mut rng); + test_binomial_mean_and_variance(70, 0.6, &mut rng); + test_binomial_mean_and_variance(40, 0.5, &mut rng); + test_binomial_mean_and_variance(20, 0.7, &mut rng); + test_binomial_mean_and_variance(20, 0.5, &mut rng); + } + + #[test] + fn test_binomial_end_points() { + let mut rng = ::test::rng(352); + assert_eq!(rng.sample(Binomial::new(20, 0.0)), 0); + assert_eq!(rng.sample(Binomial::new(20, 1.0)), 20); + } + + #[test] + #[should_panic] + fn test_binomial_invalid_lambda_neg() { + Binomial::new(20, -10.0); + } +} diff --git a/third_party/rust/rand/src/distributions/cauchy.rs b/third_party/rust/rand/src/distributions/cauchy.rs new file mode 100644 index 000000000000..feef015a3413 --- /dev/null +++ b/third_party/rust/rand/src/distributions/cauchy.rs @@ -0,0 +1,115 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2016-2017 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The Cauchy distribution. + +use Rng; +use distributions::Distribution; +use std::f64::consts::PI; + +/// The Cauchy distribution `Cauchy(median, scale)`. +/// +/// This distribution has a density function: +/// `f(x) = 1 / (pi * scale * (1 + ((x - median) / scale)^2))` +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Cauchy, Distribution}; +/// +/// let cau = Cauchy::new(2.0, 5.0); +/// let v = cau.sample(&mut rand::thread_rng()); +/// println!("{} is from a Cauchy(2, 5) distribution", v); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Cauchy { + median: f64, + scale: f64 +} + +impl Cauchy { + /// Construct a new `Cauchy` with the given shape parameters + /// `median` the peak location and `scale` the scale factor. + /// Panics if `scale <= 0`. + pub fn new(median: f64, scale: f64) -> Cauchy { + assert!(scale > 0.0, "Cauchy::new called with scale factor <= 0"); + Cauchy { + median, + scale + } + } +} + +impl Distribution for Cauchy { + fn sample(&self, rng: &mut R) -> f64 { + // sample from [0, 1) + let x = rng.gen::(); + // get standard cauchy random number + // note that Ï€/2 is not exactly representable, even if x=0.5 the result is finite + let comp_dev = (PI * x).tan(); + // shift and scale according to parameters + let result = self.median + self.scale * comp_dev; + result + } +} + +#[cfg(test)] +mod test { + use distributions::Distribution; + use super::Cauchy; + + fn median(mut numbers: &mut [f64]) -> f64 { + sort(&mut numbers); + let mid = numbers.len() / 2; + numbers[mid] + } + + fn sort(numbers: &mut [f64]) { + numbers.sort_by(|a, b| a.partial_cmp(b).unwrap()); + } + + #[test] + fn test_cauchy_median() { + let cauchy = Cauchy::new(10.0, 5.0); + let mut rng = ::test::rng(123); + let mut numbers: [f64; 1000] = [0.0; 1000]; + for i in 0..1000 { + numbers[i] = cauchy.sample(&mut rng); + } + let median = median(&mut numbers); + println!("Cauchy median: {}", median); + assert!((median - 10.0).abs() < 0.5); // not 100% certain, but probable enough + } + + #[test] + fn test_cauchy_mean() { + let cauchy = Cauchy::new(10.0, 5.0); + let mut rng = ::test::rng(123); + let mut sum = 0.0; + for _ in 0..1000 { + sum += cauchy.sample(&mut rng); + } + let mean = sum / 1000.0; + println!("Cauchy mean: {}", mean); + // for a Cauchy distribution the mean should not converge + assert!((mean - 10.0).abs() > 0.5); // not 100% certain, but probable enough + } + + #[test] + #[should_panic] + fn test_cauchy_invalid_scale_zero() { + Cauchy::new(0.0, 0.0); + } + + #[test] + #[should_panic] + fn test_cauchy_invalid_scale_neg() { + Cauchy::new(0.0, -10.0); + } +} diff --git a/third_party/rust/rand/src/distributions/dirichlet.rs b/third_party/rust/rand/src/distributions/dirichlet.rs new file mode 100644 index 000000000000..19384b82de7f --- /dev/null +++ b/third_party/rust/rand/src/distributions/dirichlet.rs @@ -0,0 +1,137 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The dirichlet distribution. + +use Rng; +use distributions::Distribution; +use distributions::gamma::Gamma; + +/// The dirichelet distribution `Dirichlet(alpha)`. +/// +/// The Dirichlet distribution is a family of continuous multivariate +/// probability distributions parameterized by a vector alpha of positive reals. +/// It is a multivariate generalization of the beta distribution. +/// +/// # Example +/// +/// ``` +/// use rand::prelude::*; +/// use rand::distributions::Dirichlet; +/// +/// let dirichlet = Dirichlet::new(vec![1.0, 2.0, 3.0]); +/// let samples = dirichlet.sample(&mut rand::thread_rng()); +/// println!("{:?} is from a Dirichlet([1.0, 2.0, 3.0]) distribution", samples); +/// ``` + +#[derive(Clone, Debug)] +pub struct Dirichlet { + /// Concentration parameters (alpha) + alpha: Vec, +} + +impl Dirichlet { + /// Construct a new `Dirichlet` with the given alpha parameter `alpha`. + /// + /// # Panics + /// - if `alpha.len() < 2` + /// + #[inline] + pub fn new>>(alpha: V) -> Dirichlet { + let a = alpha.into(); + assert!(a.len() > 1); + for i in 0..a.len() { + assert!(a[i] > 0.0); + } + + Dirichlet { alpha: a } + } + + /// Construct a new `Dirichlet` with the given shape parameter `alpha` and `size`. + /// + /// # Panics + /// - if `alpha <= 0.0` + /// - if `size < 2` + /// + #[inline] + pub fn new_with_param(alpha: f64, size: usize) -> Dirichlet { + assert!(alpha > 0.0); + assert!(size > 1); + Dirichlet { + alpha: vec![alpha; size], + } + } +} + +impl Distribution> for Dirichlet { + fn sample(&self, rng: &mut R) -> Vec { + let n = self.alpha.len(); + let mut samples = vec![0.0f64; n]; + let mut sum = 0.0f64; + + for i in 0..n { + let g = Gamma::new(self.alpha[i], 1.0); + samples[i] = g.sample(rng); + sum += samples[i]; + } + let invacc = 1.0 / sum; + for i in 0..n { + samples[i] *= invacc; + } + samples + } +} + +#[cfg(test)] +mod test { + use super::Dirichlet; + use distributions::Distribution; + + #[test] + fn test_dirichlet() { + let d = Dirichlet::new(vec![1.0, 2.0, 3.0]); + let mut rng = ::test::rng(221); + let samples = d.sample(&mut rng); + let _: Vec = samples + .into_iter() + .map(|x| { + assert!(x > 0.0); + x + }) + .collect(); + } + + #[test] + fn test_dirichlet_with_param() { + let alpha = 0.5f64; + let size = 2; + let d = Dirichlet::new_with_param(alpha, size); + let mut rng = ::test::rng(221); + let samples = d.sample(&mut rng); + let _: Vec = samples + .into_iter() + .map(|x| { + assert!(x > 0.0); + x + }) + .collect(); + } + + #[test] + #[should_panic] + fn test_dirichlet_invalid_length() { + Dirichlet::new_with_param(0.5f64, 1); + } + + #[test] + #[should_panic] + fn test_dirichlet_invalid_alpha() { + Dirichlet::new_with_param(0.0f64, 2); + } +} diff --git a/third_party/rust/rand/src/distributions/exponential.rs b/third_party/rust/rand/src/distributions/exponential.rs index c3c924c6b7ee..76752a60e3d7 100644 --- a/third_party/rust/rand/src/distributions/exponential.rs +++ b/third_party/rust/rand/src/distributions/exponential.rs @@ -1,74 +1,78 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. +// Copyright 2018 Developers of the Rand project. +// Copyright 2013 The Rust Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license -// , at your +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! The exponential distribution. -use {Rng, Rand}; -use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample}; +use {Rng}; +use distributions::{ziggurat_tables, Distribution}; +use distributions::utils::ziggurat; -/// A wrapper around an `f64` to generate Exp(1) random numbers. +/// Samples floating-point numbers according to the exponential distribution, +/// with rate parameter `λ = 1`. This is equivalent to `Exp::new(1.0)` or +/// sampling with `-rng.gen::().ln()`, but faster. /// /// See `Exp` for the general exponential distribution. /// -/// Implemented via the ZIGNOR variant[1] of the Ziggurat method. The -/// exact description in the paper was adjusted to use tables for the -/// exponential distribution rather than normal. +/// Implemented via the ZIGNOR variant[^1] of the Ziggurat method. The exact +/// description in the paper was adjusted to use tables for the exponential +/// distribution rather than normal. /// -/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to -/// Generate Normal Random -/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield -/// College, Oxford +/// [^1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to +/// Generate Normal Random Samples*]( +/// https://www.doornik.com/research/ziggurat.pdf). +/// Nuffield College, Oxford /// /// # Example +/// ``` +/// use rand::prelude::*; +/// use rand::distributions::Exp1; /// -/// ```rust -/// use rand::distributions::exponential::Exp1; -/// -/// let Exp1(x) = rand::random(); -/// println!("{}", x); +/// let val: f64 = SmallRng::from_entropy().sample(Exp1); +/// println!("{}", val); /// ``` #[derive(Clone, Copy, Debug)] -pub struct Exp1(pub f64); +pub struct Exp1; // This could be done via `-rng.gen::().ln()` but that is slower. -impl Rand for Exp1 { +impl Distribution for Exp1 { #[inline] - fn rand(rng: &mut R) -> Exp1 { + fn sample(&self, rng: &mut R) -> f64 { #[inline] fn pdf(x: f64) -> f64 { (-x).exp() } #[inline] - fn zero_case(rng: &mut R, _u: f64) -> f64 { + fn zero_case(rng: &mut R, _u: f64) -> f64 { ziggurat_tables::ZIG_EXP_R - rng.gen::().ln() } - Exp1(ziggurat(rng, false, - &ziggurat_tables::ZIG_EXP_X, - &ziggurat_tables::ZIG_EXP_F, - pdf, zero_case)) + ziggurat(rng, false, + &ziggurat_tables::ZIG_EXP_X, + &ziggurat_tables::ZIG_EXP_F, + pdf, zero_case) } } /// The exponential distribution `Exp(lambda)`. /// -/// This distribution has density function: `f(x) = lambda * -/// exp(-lambda * x)` for `x > 0`. +/// This distribution has density function: `f(x) = lambda * exp(-lambda * x)` +/// for `x > 0`. +/// +/// Note that [`Exp1`][crate::distributions::Exp1] is an optimised implementation for `lambda = 1`. /// /// # Example /// -/// ```rust -/// use rand::distributions::{Exp, IndependentSample}; +/// ``` +/// use rand::distributions::{Exp, Distribution}; /// /// let exp = Exp::new(2.0); -/// let v = exp.ind_sample(&mut rand::thread_rng()); +/// let v = exp.sample(&mut rand::thread_rng()); /// println!("{} is from a Exp(2) distribution", v); /// ``` #[derive(Clone, Copy, Debug)] @@ -87,28 +91,24 @@ impl Exp { } } -impl Sample for Exp { - fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } -} -impl IndependentSample for Exp { - fn ind_sample(&self, rng: &mut R) -> f64 { - let Exp1(n) = rng.gen::(); +impl Distribution for Exp { + fn sample(&self, rng: &mut R) -> f64 { + let n: f64 = rng.sample(Exp1); n * self.lambda_inverse } } #[cfg(test)] mod test { - use distributions::{Sample, IndependentSample}; + use distributions::Distribution; use super::Exp; #[test] fn test_exp() { - let mut exp = Exp::new(10.0); - let mut rng = ::test::rng(); + let exp = Exp::new(10.0); + let mut rng = ::test::rng(221); for _ in 0..1000 { assert!(exp.sample(&mut rng) >= 0.0); - assert!(exp.ind_sample(&mut rng) >= 0.0); } } #[test] diff --git a/third_party/rust/rand/src/distributions/float.rs b/third_party/rust/rand/src/distributions/float.rs new file mode 100644 index 000000000000..0dd5caa4a8b8 --- /dev/null +++ b/third_party/rust/rand/src/distributions/float.rs @@ -0,0 +1,259 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Basic floating-point number distributions + +use core::mem; +use Rng; +use distributions::{Distribution, Standard}; +use distributions::utils::FloatSIMDUtils; +#[cfg(feature="simd_support")] +use packed_simd::*; + +/// A distribution to sample floating point numbers uniformly in the half-open +/// interval `(0, 1]`, i.e. including 1 but not 0. +/// +/// All values that can be generated are of the form `n * ε/2`. For `f32` +/// the 23 most significant random bits of a `u32` are used and for `f64` the +/// 53 most significant bits of a `u64` are used. The conversion uses the +/// multiplicative method. +/// +/// See also: [`Standard`] which samples from `[0, 1)`, [`Open01`] +/// which samples from `(0, 1)` and [`Uniform`] which samples from arbitrary +/// ranges. +/// +/// # Example +/// ``` +/// use rand::{thread_rng, Rng}; +/// use rand::distributions::OpenClosed01; +/// +/// let val: f32 = thread_rng().sample(OpenClosed01); +/// println!("f32 from (0, 1): {}", val); +/// ``` +/// +/// [`Standard`]: crate::distributions::Standard +/// [`Open01`]: crate::distributions::Open01 +/// [`Uniform`]: crate::distributions::uniform::Uniform +#[derive(Clone, Copy, Debug)] +pub struct OpenClosed01; + +/// A distribution to sample floating point numbers uniformly in the open +/// interval `(0, 1)`, i.e. not including either endpoint. +/// +/// All values that can be generated are of the form `n * ε + ε/2`. For `f32` +/// the 22 most significant random bits of an `u32` are used, for `f64` 52 from +/// an `u64`. The conversion uses a transmute-based method. +/// +/// See also: [`Standard`] which samples from `[0, 1)`, [`OpenClosed01`] +/// which samples from `(0, 1]` and [`Uniform`] which samples from arbitrary +/// ranges. +/// +/// # Example +/// ``` +/// use rand::{thread_rng, Rng}; +/// use rand::distributions::Open01; +/// +/// let val: f32 = thread_rng().sample(Open01); +/// println!("f32 from (0, 1): {}", val); +/// ``` +/// +/// [`Standard`]: crate::distributions::Standard +/// [`OpenClosed01`]: crate::distributions::OpenClosed01 +/// [`Uniform`]: crate::distributions::uniform::Uniform +#[derive(Clone, Copy, Debug)] +pub struct Open01; + + +pub(crate) trait IntoFloat { + type F; + + /// Helper method to combine the fraction and a contant exponent into a + /// float. + /// + /// Only the least significant bits of `self` may be set, 23 for `f32` and + /// 52 for `f64`. + /// The resulting value will fall in a range that depends on the exponent. + /// As an example the range with exponent 0 will be + /// [20..21), which is [1..2). + fn into_float_with_exponent(self, exponent: i32) -> Self::F; +} + +macro_rules! float_impls { + ($ty:ident, $uty:ident, $f_scalar:ident, $u_scalar:ty, + $fraction_bits:expr, $exponent_bias:expr) => { + impl IntoFloat for $uty { + type F = $ty; + #[inline(always)] + fn into_float_with_exponent(self, exponent: i32) -> $ty { + // The exponent is encoded using an offset-binary representation + let exponent_bits: $u_scalar = + (($exponent_bias + exponent) as $u_scalar) << $fraction_bits; + // TODO: use from_bits when min compiler > 1.25 (see #545) + // $ty::from_bits(self | exponent_bits) + unsafe{ mem::transmute(self | exponent_bits) } + } + } + + impl Distribution<$ty> for Standard { + fn sample(&self, rng: &mut R) -> $ty { + // Multiply-based method; 24/53 random bits; [0, 1) interval. + // We use the most significant bits because for simple RNGs + // those are usually more random. + let float_size = mem::size_of::<$f_scalar>() as u32 * 8; + let precision = $fraction_bits + 1; + let scale = 1.0 / ((1 as $u_scalar << precision) as $f_scalar); + + let value: $uty = rng.gen(); + let value = value >> (float_size - precision); + scale * $ty::cast_from_int(value) + } + } + + impl Distribution<$ty> for OpenClosed01 { + fn sample(&self, rng: &mut R) -> $ty { + // Multiply-based method; 24/53 random bits; (0, 1] interval. + // We use the most significant bits because for simple RNGs + // those are usually more random. + let float_size = mem::size_of::<$f_scalar>() as u32 * 8; + let precision = $fraction_bits + 1; + let scale = 1.0 / ((1 as $u_scalar << precision) as $f_scalar); + + let value: $uty = rng.gen(); + let value = value >> (float_size - precision); + // Add 1 to shift up; will not overflow because of right-shift: + scale * $ty::cast_from_int(value + 1) + } + } + + impl Distribution<$ty> for Open01 { + fn sample(&self, rng: &mut R) -> $ty { + // Transmute-based method; 23/52 random bits; (0, 1) interval. + // We use the most significant bits because for simple RNGs + // those are usually more random. + use core::$f_scalar::EPSILON; + let float_size = mem::size_of::<$f_scalar>() as u32 * 8; + + let value: $uty = rng.gen(); + let fraction = value >> (float_size - $fraction_bits); + fraction.into_float_with_exponent(0) - (1.0 - EPSILON / 2.0) + } + } + } +} + +float_impls! { f32, u32, f32, u32, 23, 127 } +float_impls! { f64, u64, f64, u64, 52, 1023 } + +#[cfg(feature="simd_support")] +float_impls! { f32x2, u32x2, f32, u32, 23, 127 } +#[cfg(feature="simd_support")] +float_impls! { f32x4, u32x4, f32, u32, 23, 127 } +#[cfg(feature="simd_support")] +float_impls! { f32x8, u32x8, f32, u32, 23, 127 } +#[cfg(feature="simd_support")] +float_impls! { f32x16, u32x16, f32, u32, 23, 127 } + +#[cfg(feature="simd_support")] +float_impls! { f64x2, u64x2, f64, u64, 52, 1023 } +#[cfg(feature="simd_support")] +float_impls! { f64x4, u64x4, f64, u64, 52, 1023 } +#[cfg(feature="simd_support")] +float_impls! { f64x8, u64x8, f64, u64, 52, 1023 } + + +#[cfg(test)] +mod tests { + use Rng; + use distributions::{Open01, OpenClosed01}; + use rngs::mock::StepRng; + #[cfg(feature="simd_support")] + use packed_simd::*; + + const EPSILON32: f32 = ::core::f32::EPSILON; + const EPSILON64: f64 = ::core::f64::EPSILON; + + macro_rules! test_f32 { + ($fnn:ident, $ty:ident, $ZERO:expr, $EPSILON:expr) => { + #[test] + fn $fnn() { + // Standard + let mut zeros = StepRng::new(0, 0); + assert_eq!(zeros.gen::<$ty>(), $ZERO); + let mut one = StepRng::new(1 << 8 | 1 << (8 + 32), 0); + assert_eq!(one.gen::<$ty>(), $EPSILON / 2.0); + let mut max = StepRng::new(!0, 0); + assert_eq!(max.gen::<$ty>(), 1.0 - $EPSILON / 2.0); + + // OpenClosed01 + let mut zeros = StepRng::new(0, 0); + assert_eq!(zeros.sample::<$ty, _>(OpenClosed01), + 0.0 + $EPSILON / 2.0); + let mut one = StepRng::new(1 << 8 | 1 << (8 + 32), 0); + assert_eq!(one.sample::<$ty, _>(OpenClosed01), $EPSILON); + let mut max = StepRng::new(!0, 0); + assert_eq!(max.sample::<$ty, _>(OpenClosed01), $ZERO + 1.0); + + // Open01 + let mut zeros = StepRng::new(0, 0); + assert_eq!(zeros.sample::<$ty, _>(Open01), 0.0 + $EPSILON / 2.0); + let mut one = StepRng::new(1 << 9 | 1 << (9 + 32), 0); + assert_eq!(one.sample::<$ty, _>(Open01), $EPSILON / 2.0 * 3.0); + let mut max = StepRng::new(!0, 0); + assert_eq!(max.sample::<$ty, _>(Open01), 1.0 - $EPSILON / 2.0); + } + } + } + test_f32! { f32_edge_cases, f32, 0.0, EPSILON32 } + #[cfg(feature="simd_support")] + test_f32! { f32x2_edge_cases, f32x2, f32x2::splat(0.0), f32x2::splat(EPSILON32) } + #[cfg(feature="simd_support")] + test_f32! { f32x4_edge_cases, f32x4, f32x4::splat(0.0), f32x4::splat(EPSILON32) } + #[cfg(feature="simd_support")] + test_f32! { f32x8_edge_cases, f32x8, f32x8::splat(0.0), f32x8::splat(EPSILON32) } + #[cfg(feature="simd_support")] + test_f32! { f32x16_edge_cases, f32x16, f32x16::splat(0.0), f32x16::splat(EPSILON32) } + + macro_rules! test_f64 { + ($fnn:ident, $ty:ident, $ZERO:expr, $EPSILON:expr) => { + #[test] + fn $fnn() { + // Standard + let mut zeros = StepRng::new(0, 0); + assert_eq!(zeros.gen::<$ty>(), $ZERO); + let mut one = StepRng::new(1 << 11, 0); + assert_eq!(one.gen::<$ty>(), $EPSILON / 2.0); + let mut max = StepRng::new(!0, 0); + assert_eq!(max.gen::<$ty>(), 1.0 - $EPSILON / 2.0); + + // OpenClosed01 + let mut zeros = StepRng::new(0, 0); + assert_eq!(zeros.sample::<$ty, _>(OpenClosed01), + 0.0 + $EPSILON / 2.0); + let mut one = StepRng::new(1 << 11, 0); + assert_eq!(one.sample::<$ty, _>(OpenClosed01), $EPSILON); + let mut max = StepRng::new(!0, 0); + assert_eq!(max.sample::<$ty, _>(OpenClosed01), $ZERO + 1.0); + + // Open01 + let mut zeros = StepRng::new(0, 0); + assert_eq!(zeros.sample::<$ty, _>(Open01), 0.0 + $EPSILON / 2.0); + let mut one = StepRng::new(1 << 12, 0); + assert_eq!(one.sample::<$ty, _>(Open01), $EPSILON / 2.0 * 3.0); + let mut max = StepRng::new(!0, 0); + assert_eq!(max.sample::<$ty, _>(Open01), 1.0 - $EPSILON / 2.0); + } + } + } + test_f64! { f64_edge_cases, f64, 0.0, EPSILON64 } + #[cfg(feature="simd_support")] + test_f64! { f64x2_edge_cases, f64x2, f64x2::splat(0.0), f64x2::splat(EPSILON64) } + #[cfg(feature="simd_support")] + test_f64! { f64x4_edge_cases, f64x4, f64x4::splat(0.0), f64x4::splat(EPSILON64) } + #[cfg(feature="simd_support")] + test_f64! { f64x8_edge_cases, f64x8, f64x8::splat(0.0), f64x8::splat(EPSILON64) } +} diff --git a/third_party/rust/rand/src/distributions/gamma.rs b/third_party/rust/rand/src/distributions/gamma.rs index 280649587319..43ac2bc15247 100644 --- a/third_party/rust/rand/src/distributions/gamma.rs +++ b/third_party/rust/rand/src/distributions/gamma.rs @@ -1,23 +1,20 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. +// Copyright 2018 Developers of the Rand project. +// Copyright 2013 The Rust Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license -// , at your +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -// -// ignore-lexer-test FIXME #15679 //! The Gamma and derived distributions. use self::GammaRepr::*; use self::ChiSquaredRepr::*; -use {Rng, Open01}; -use super::normal::StandardNormal; -use super::{IndependentSample, Sample, Exp}; +use Rng; +use distributions::normal::StandardNormal; +use distributions::{Distribution, Exp, Open01}; /// The Gamma distribution `Gamma(shape, scale)` distribution. /// @@ -30,25 +27,25 @@ use super::{IndependentSample, Sample, Exp}; /// where `Γ` is the Gamma function, `k` is the shape and `θ` is the /// scale and both `k` and `θ` are strictly positive. /// -/// The algorithm used is that described by Marsaglia & Tsang 2000[1], +/// The algorithm used is that described by Marsaglia & Tsang 2000[^1], /// falling back to directly sampling from an Exponential for `shape -/// == 1`, and using the boosting technique described in [1] for +/// == 1`, and using the boosting technique described in that paper for /// `shape < 1`. /// /// # Example /// -/// ```rust -/// use rand::distributions::{IndependentSample, Gamma}; +/// ``` +/// use rand::distributions::{Distribution, Gamma}; /// /// let gamma = Gamma::new(2.0, 5.0); -/// let v = gamma.ind_sample(&mut rand::thread_rng()); +/// let v = gamma.sample(&mut rand::thread_rng()); /// println!("{} is from a Gamma(2, 5) distribution", v); /// ``` /// -/// [1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method -/// for Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3 -/// (September 2000), -/// 363-372. DOI:[10.1145/358407.358414](http://doi.acm.org/10.1145/358407.358414) +/// [^1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method for +/// Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3 +/// (September 2000), 363-372. +/// DOI:[10.1145/358407.358414](https://doi.acm.org/10.1145/358407.358414) #[derive(Clone, Copy, Debug)] pub struct Gamma { repr: GammaRepr, @@ -109,7 +106,7 @@ impl Gamma { } else { Large(GammaLargeShape::new_raw(shape, scale)) }; - Gamma { repr: repr } + Gamma { repr } } } @@ -126,50 +123,40 @@ impl GammaLargeShape { fn new_raw(shape: f64, scale: f64) -> GammaLargeShape { let d = shape - 1. / 3.; GammaLargeShape { - scale: scale, + scale, c: 1. / (9. * d).sqrt(), - d: d + d } } } -impl Sample for Gamma { - fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } -} -impl Sample for GammaSmallShape { - fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } -} -impl Sample for GammaLargeShape { - fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } -} - -impl IndependentSample for Gamma { - fn ind_sample(&self, rng: &mut R) -> f64 { +impl Distribution for Gamma { + fn sample(&self, rng: &mut R) -> f64 { match self.repr { - Small(ref g) => g.ind_sample(rng), - One(ref g) => g.ind_sample(rng), - Large(ref g) => g.ind_sample(rng), + Small(ref g) => g.sample(rng), + One(ref g) => g.sample(rng), + Large(ref g) => g.sample(rng), } } } -impl IndependentSample for GammaSmallShape { - fn ind_sample(&self, rng: &mut R) -> f64 { - let Open01(u) = rng.gen::>(); +impl Distribution for GammaSmallShape { + fn sample(&self, rng: &mut R) -> f64 { + let u: f64 = rng.sample(Open01); - self.large_shape.ind_sample(rng) * u.powf(self.inv_shape) + self.large_shape.sample(rng) * u.powf(self.inv_shape) } } -impl IndependentSample for GammaLargeShape { - fn ind_sample(&self, rng: &mut R) -> f64 { +impl Distribution for GammaLargeShape { + fn sample(&self, rng: &mut R) -> f64 { loop { - let StandardNormal(x) = rng.gen::(); + let x = rng.sample(StandardNormal); let v_cbrt = 1.0 + self.c * x; if v_cbrt <= 0.0 { // a^3 <= 0 iff a <= 0 continue } let v = v_cbrt * v_cbrt * v_cbrt; - let Open01(u) = rng.gen::>(); + let u: f64 = rng.sample(Open01); let x_sqr = x * x; if u < 1.0 - 0.0331 * x_sqr * x_sqr || @@ -190,11 +177,11 @@ impl IndependentSample for GammaLargeShape { /// /// # Example /// -/// ```rust -/// use rand::distributions::{ChiSquared, IndependentSample}; +/// ``` +/// use rand::distributions::{ChiSquared, Distribution}; /// /// let chi = ChiSquared::new(11.0); -/// let v = chi.ind_sample(&mut rand::thread_rng()); +/// let v = chi.sample(&mut rand::thread_rng()); /// println!("{} is from a χ²(11) distribution", v) /// ``` #[derive(Clone, Copy, Debug)] @@ -221,21 +208,18 @@ impl ChiSquared { assert!(k > 0.0, "ChiSquared::new called with `k` < 0"); DoFAnythingElse(Gamma::new(0.5 * k, 2.0)) }; - ChiSquared { repr: repr } + ChiSquared { repr } } } -impl Sample for ChiSquared { - fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } -} -impl IndependentSample for ChiSquared { - fn ind_sample(&self, rng: &mut R) -> f64 { +impl Distribution for ChiSquared { + fn sample(&self, rng: &mut R) -> f64 { match self.repr { DoFExactlyOne => { // k == 1 => N(0,1)^2 - let StandardNormal(norm) = rng.gen::(); + let norm = rng.sample(StandardNormal); norm * norm } - DoFAnythingElse(ref g) => g.ind_sample(rng) + DoFAnythingElse(ref g) => g.sample(rng) } } } @@ -248,11 +232,11 @@ impl IndependentSample for ChiSquared { /// /// # Example /// -/// ```rust -/// use rand::distributions::{FisherF, IndependentSample}; +/// ``` +/// use rand::distributions::{FisherF, Distribution}; /// /// let f = FisherF::new(2.0, 32.0); -/// let v = f.ind_sample(&mut rand::thread_rng()); +/// let v = f.sample(&mut rand::thread_rng()); /// println!("{} is from an F(2, 32) distribution", v) /// ``` #[derive(Clone, Copy, Debug)] @@ -278,12 +262,9 @@ impl FisherF { } } } -impl Sample for FisherF { - fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } -} -impl IndependentSample for FisherF { - fn ind_sample(&self, rng: &mut R) -> f64 { - self.numer.ind_sample(rng) / self.denom.ind_sample(rng) * self.dof_ratio +impl Distribution for FisherF { + fn sample(&self, rng: &mut R) -> f64 { + self.numer.sample(rng) / self.denom.sample(rng) * self.dof_ratio } } @@ -292,11 +273,11 @@ impl IndependentSample for FisherF { /// /// # Example /// -/// ```rust -/// use rand::distributions::{StudentT, IndependentSample}; +/// ``` +/// use rand::distributions::{StudentT, Distribution}; /// /// let t = StudentT::new(11.0); -/// let v = t.ind_sample(&mut rand::thread_rng()); +/// let v = t.sample(&mut rand::thread_rng()); /// println!("{} is from a t(11) distribution", v) /// ``` #[derive(Clone, Copy, Debug)] @@ -316,46 +297,79 @@ impl StudentT { } } } -impl Sample for StudentT { - fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } +impl Distribution for StudentT { + fn sample(&self, rng: &mut R) -> f64 { + let norm = rng.sample(StandardNormal); + norm * (self.dof / self.chi.sample(rng)).sqrt() + } } -impl IndependentSample for StudentT { - fn ind_sample(&self, rng: &mut R) -> f64 { - let StandardNormal(norm) = rng.gen::(); - norm * (self.dof / self.chi.ind_sample(rng)).sqrt() + +/// The Beta distribution with shape parameters `alpha` and `beta`. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Distribution, Beta}; +/// +/// let beta = Beta::new(2.0, 5.0); +/// let v = beta.sample(&mut rand::thread_rng()); +/// println!("{} is from a Beta(2, 5) distribution", v); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Beta { + gamma_a: Gamma, + gamma_b: Gamma, +} + +impl Beta { + /// Construct an object representing the `Beta(alpha, beta)` + /// distribution. + /// + /// Panics if `shape <= 0` or `scale <= 0`. + pub fn new(alpha: f64, beta: f64) -> Beta { + assert!((alpha > 0.) & (beta > 0.)); + Beta { + gamma_a: Gamma::new(alpha, 1.), + gamma_b: Gamma::new(beta, 1.), + } + } +} + +impl Distribution for Beta { + fn sample(&self, rng: &mut R) -> f64 { + let x = self.gamma_a.sample(rng); + let y = self.gamma_b.sample(rng); + x / (x + y) } } #[cfg(test)] mod test { - use distributions::{Sample, IndependentSample}; - use super::{ChiSquared, StudentT, FisherF}; + use distributions::Distribution; + use super::{Beta, ChiSquared, StudentT, FisherF}; #[test] fn test_chi_squared_one() { - let mut chi = ChiSquared::new(1.0); - let mut rng = ::test::rng(); + let chi = ChiSquared::new(1.0); + let mut rng = ::test::rng(201); for _ in 0..1000 { chi.sample(&mut rng); - chi.ind_sample(&mut rng); } } #[test] fn test_chi_squared_small() { - let mut chi = ChiSquared::new(0.5); - let mut rng = ::test::rng(); + let chi = ChiSquared::new(0.5); + let mut rng = ::test::rng(202); for _ in 0..1000 { chi.sample(&mut rng); - chi.ind_sample(&mut rng); } } #[test] fn test_chi_squared_large() { - let mut chi = ChiSquared::new(30.0); - let mut rng = ::test::rng(); + let chi = ChiSquared::new(30.0); + let mut rng = ::test::rng(203); for _ in 0..1000 { chi.sample(&mut rng); - chi.ind_sample(&mut rng); } } #[test] @@ -366,21 +380,34 @@ mod test { #[test] fn test_f() { - let mut f = FisherF::new(2.0, 32.0); - let mut rng = ::test::rng(); + let f = FisherF::new(2.0, 32.0); + let mut rng = ::test::rng(204); for _ in 0..1000 { f.sample(&mut rng); - f.ind_sample(&mut rng); } } #[test] fn test_t() { - let mut t = StudentT::new(11.0); - let mut rng = ::test::rng(); + let t = StudentT::new(11.0); + let mut rng = ::test::rng(205); for _ in 0..1000 { t.sample(&mut rng); - t.ind_sample(&mut rng); } } + + #[test] + fn test_beta() { + let beta = Beta::new(1.0, 2.0); + let mut rng = ::test::rng(201); + for _ in 0..1000 { + beta.sample(&mut rng); + } + } + + #[test] + #[should_panic] + fn test_beta_invalid_dof() { + Beta::new(0., 0.); + } } diff --git a/third_party/rust/rand/src/distributions/integer.rs b/third_party/rust/rand/src/distributions/integer.rs new file mode 100644 index 000000000000..7e408dbf1b25 --- /dev/null +++ b/third_party/rust/rand/src/distributions/integer.rs @@ -0,0 +1,161 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The implementations of the `Standard` distribution for integer types. + +use {Rng}; +use distributions::{Distribution, Standard}; +#[cfg(feature="simd_support")] +use packed_simd::*; +#[cfg(all(target_arch = "x86", feature="nightly"))] +use core::arch::x86::*; +#[cfg(all(target_arch = "x86_64", feature="nightly"))] +use core::arch::x86_64::*; + +impl Distribution for Standard { + #[inline] + fn sample(&self, rng: &mut R) -> u8 { + rng.next_u32() as u8 + } +} + +impl Distribution for Standard { + #[inline] + fn sample(&self, rng: &mut R) -> u16 { + rng.next_u32() as u16 + } +} + +impl Distribution for Standard { + #[inline] + fn sample(&self, rng: &mut R) -> u32 { + rng.next_u32() + } +} + +impl Distribution for Standard { + #[inline] + fn sample(&self, rng: &mut R) -> u64 { + rng.next_u64() + } +} + +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] +impl Distribution for Standard { + #[inline] + fn sample(&self, rng: &mut R) -> u128 { + // Use LE; we explicitly generate one value before the next. + let x = rng.next_u64() as u128; + let y = rng.next_u64() as u128; + (y << 64) | x + } +} + +impl Distribution for Standard { + #[inline] + #[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))] + fn sample(&self, rng: &mut R) -> usize { + rng.next_u32() as usize + } + + #[inline] + #[cfg(target_pointer_width = "64")] + fn sample(&self, rng: &mut R) -> usize { + rng.next_u64() as usize + } +} + +macro_rules! impl_int_from_uint { + ($ty:ty, $uty:ty) => { + impl Distribution<$ty> for Standard { + #[inline] + fn sample(&self, rng: &mut R) -> $ty { + rng.gen::<$uty>() as $ty + } + } + } +} + +impl_int_from_uint! { i8, u8 } +impl_int_from_uint! { i16, u16 } +impl_int_from_uint! { i32, u32 } +impl_int_from_uint! { i64, u64 } +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] impl_int_from_uint! { i128, u128 } +impl_int_from_uint! { isize, usize } + +#[cfg(feature="simd_support")] +macro_rules! simd_impl { + ($(($intrinsic:ident, $vec:ty),)+) => {$( + impl Distribution<$intrinsic> for Standard { + #[inline] + fn sample(&self, rng: &mut R) -> $intrinsic { + $intrinsic::from_bits(rng.gen::<$vec>()) + } + } + )+}; + + ($bits:expr,) => {}; + ($bits:expr, $ty:ty, $($ty_more:ty,)*) => { + simd_impl!($bits, $($ty_more,)*); + + impl Distribution<$ty> for Standard { + #[inline] + fn sample(&self, rng: &mut R) -> $ty { + let mut vec: $ty = Default::default(); + unsafe { + let ptr = &mut vec; + let b_ptr = &mut *(ptr as *mut $ty as *mut [u8; $bits/8]); + rng.fill_bytes(b_ptr); + } + vec.to_le() + } + } + }; +} + +#[cfg(feature="simd_support")] +simd_impl!(16, u8x2, i8x2,); +#[cfg(feature="simd_support")] +simd_impl!(32, u8x4, i8x4, u16x2, i16x2,); +#[cfg(feature="simd_support")] +simd_impl!(64, u8x8, i8x8, u16x4, i16x4, u32x2, i32x2,); +#[cfg(feature="simd_support")] +simd_impl!(128, u8x16, i8x16, u16x8, i16x8, u32x4, i32x4, u64x2, i64x2,); +#[cfg(feature="simd_support")] +simd_impl!(256, u8x32, i8x32, u16x16, i16x16, u32x8, i32x8, u64x4, i64x4,); +#[cfg(feature="simd_support")] +simd_impl!(512, u8x64, i8x64, u16x32, i16x32, u32x16, i32x16, u64x8, i64x8,); +#[cfg(all(feature="simd_support", feature="nightly", any(target_arch="x86", target_arch="x86_64")))] +simd_impl!((__m64, u8x8), (__m128i, u8x16), (__m256i, u8x32),); + +#[cfg(test)] +mod tests { + use Rng; + use distributions::{Standard}; + + #[test] + fn test_integers() { + let mut rng = ::test::rng(806); + + rng.sample::(Standard); + rng.sample::(Standard); + rng.sample::(Standard); + rng.sample::(Standard); + rng.sample::(Standard); + #[cfg(all(rustc_1_26, not(target_os = "emscripten")))] + rng.sample::(Standard); + + rng.sample::(Standard); + rng.sample::(Standard); + rng.sample::(Standard); + rng.sample::(Standard); + rng.sample::(Standard); + #[cfg(all(rustc_1_26, not(target_os = "emscripten")))] + rng.sample::(Standard); + } +} diff --git a/third_party/rust/rand/src/distributions/mod.rs b/third_party/rust/rand/src/distributions/mod.rs index 5de8efb9c472..6e2d6c7bad28 100644 --- a/third_party/rust/rand/src/distributions/mod.rs +++ b/third_party/rust/rand/src/distributions/mod.rs @@ -1,94 +1,381 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. +// Copyright 2018 Developers of the Rand project. +// Copyright 2013-2017 The Rust Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license -// , at your +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Sampling from random distributions. +//! Generating random samples from probability distributions. //! -//! This is a generalization of `Rand` to allow parameters to control the -//! exact properties of the generated values, e.g. the mean and standard -//! deviation of a normal distribution. The `Sample` trait is the most -//! general, and allows for generating values that change some state -//! internally. The `IndependentSample` trait is for generating values -//! that do not need to record state. +//! This module is the home of the [`Distribution`] trait and several of its +//! implementations. It is the workhorse behind some of the convenient +//! functionality of the [`Rng`] trait, including [`gen`], [`gen_range`] and +//! of course [`sample`]. +//! +//! Abstractly, a [probability distribution] describes the probability of +//! occurance of each value in its sample space. +//! +//! More concretely, an implementation of `Distribution` for type `X` is an +//! algorithm for choosing values from the sample space (a subset of `T`) +//! according to the distribution `X` represents, using an external source of +//! randomness (an RNG supplied to the `sample` function). +//! +//! A type `X` may implement `Distribution` for multiple types `T`. +//! Any type implementing [`Distribution`] is stateless (i.e. immutable), +//! but it may have internal parameters set at construction time (for example, +//! [`Uniform`] allows specification of its sample space as a range within `T`). +//! +//! +//! # The `Standard` distribution +//! +//! The [`Standard`] distribution is important to mention. This is the +//! distribution used by [`Rng::gen()`] and represents the "default" way to +//! produce a random value for many different types, including most primitive +//! types, tuples, arrays, and a few derived types. See the documentation of +//! [`Standard`] for more details. +//! +//! Implementing `Distribution` for [`Standard`] for user types `T` makes it +//! possible to generate type `T` with [`Rng::gen()`], and by extension also +//! with the [`random()`] function. +//! +//! +//! # Distribution to sample from a `Uniform` range +//! +//! The [`Uniform`] distribution is more flexible than [`Standard`], but also +//! more specialised: it supports fewer target types, but allows the sample +//! space to be specified as an arbitrary range within its target type `T`. +//! Both [`Standard`] and [`Uniform`] are in some sense uniform distributions. +//! +//! Values may be sampled from this distribution using [`Rng::gen_range`] or +//! by creating a distribution object with [`Uniform::new`], +//! [`Uniform::new_inclusive`] or `From`. When the range limits are not +//! known at compile time it is typically faster to reuse an existing +//! distribution object than to call [`Rng::gen_range`]. +//! +//! User types `T` may also implement `Distribution` for [`Uniform`], +//! although this is less straightforward than for [`Standard`] (see the +//! documentation in the [`uniform`] module. Doing so enables generation of +//! values of type `T` with [`Rng::gen_range`]. +//! +//! +//! # Other distributions +//! +//! There are surprisingly many ways to uniformly generate random floats. A +//! range between 0 and 1 is standard, but the exact bounds (open vs closed) +//! and accuracy differ. In addition to the [`Standard`] distribution Rand offers +//! [`Open01`] and [`OpenClosed01`]. See "Floating point implementation" section of +//! [`Standard`] documentation for more details. +//! +//! [`Alphanumeric`] is a simple distribution to sample random letters and +//! numbers of the `char` type; in contrast [`Standard`] may sample any valid +//! `char`. +//! +//! [`WeightedIndex`] can be used to do weighted sampling from a set of items, +//! such as from an array. +//! +//! # Non-uniform probability distributions +//! +//! Rand currently provides the following probability distributions: +//! +//! - Related to real-valued quantities that grow linearly +//! (e.g. errors, offsets): +//! - [`Normal`] distribution, and [`StandardNormal`] as a primitive +//! - [`Cauchy`] distribution +//! - Related to Bernoulli trials (yes/no events, with a given probability): +//! - [`Binomial`] distribution +//! - [`Bernoulli`] distribution, similar to [`Rng::gen_bool`]. +//! - Related to positive real-valued quantities that grow exponentially +//! (e.g. prices, incomes, populations): +//! - [`LogNormal`] distribution +//! - Related to the occurrence of independent events at a given rate: +//! - [`Pareto`] distribution +//! - [`Poisson`] distribution +//! - [`Exp`]onential distribution, and [`Exp1`] as a primitive +//! - [`Weibull`] distribution +//! - Gamma and derived distributions: +//! - [`Gamma`] distribution +//! - [`ChiSquared`] distribution +//! - [`StudentT`] distribution +//! - [`FisherF`] distribution +//! - Triangular distribution: +//! - [`Beta`] distribution +//! - [`Triangular`] distribution +//! - Multivariate probability distributions +//! - [`Dirichlet`] distribution +//! - [`UnitSphereSurface`] distribution +//! - [`UnitCircle`] distribution +//! +//! # Examples +//! +//! Sampling from a distribution: +//! +//! ``` +//! use rand::{thread_rng, Rng}; +//! use rand::distributions::Exp; +//! +//! let exp = Exp::new(2.0); +//! let v = thread_rng().sample(exp); +//! println!("{} is from an Exp(2) distribution", v); +//! ``` +//! +//! Implementing the [`Standard`] distribution for a user type: +//! +//! ``` +//! # #![allow(dead_code)] +//! use rand::Rng; +//! use rand::distributions::{Distribution, Standard}; +//! +//! struct MyF32 { +//! x: f32, +//! } +//! +//! impl Distribution for Standard { +//! fn sample(&self, rng: &mut R) -> MyF32 { +//! MyF32 { x: rng.gen() } +//! } +//! } +//! ``` +//! +//! +//! [probability distribution]: https://en.wikipedia.org/wiki/Probability_distribution +//! [`gen_range`]: Rng::gen_range +//! [`gen`]: Rng::gen +//! [`sample`]: Rng::sample +//! [`new_inclusive`]: Uniform::new_inclusive +//! [`Alphanumeric`]: distributions::Alphanumeric +//! [`Bernoulli`]: distributions::Bernoulli +//! [`Beta`]: distributions::Beta +//! [`Binomial`]: distributions::Binomial +//! [`Cauchy`]: distributions::Cauchy +//! [`ChiSquared`]: distributions::ChiSquared +//! [`Dirichlet`]: distributions::Dirichlet +//! [`Exp`]: distributions::Exp +//! [`Exp1`]: distributions::Exp1 +//! [`FisherF`]: distributions::FisherF +//! [`Gamma`]: distributions::Gamma +//! [`LogNormal`]: distributions::LogNormal +//! [`Normal`]: distributions::Normal +//! [`Open01`]: distributions::Open01 +//! [`OpenClosed01`]: distributions::OpenClosed01 +//! [`Pareto`]: distributions::Pareto +//! [`Poisson`]: distributions::Poisson +//! [`Standard`]: distributions::Standard +//! [`StandardNormal`]: distributions::StandardNormal +//! [`StudentT`]: distributions::StudentT +//! [`Triangular`]: distributions::Triangular +//! [`Uniform`]: distributions::Uniform +//! [`Uniform::new`]: distributions::Uniform::new +//! [`Uniform::new_inclusive`]: distributions::Uniform::new_inclusive +//! [`UnitSphereSurface`]: distributions::UnitSphereSurface +//! [`UnitCircle`]: distributions::UnitCircle +//! [`Weibull`]: distributions::Weibull +//! [`WeightedIndex`]: distributions::WeightedIndex -use core::marker; +#[cfg(any(rustc_1_26, features="nightly"))] +use core::iter; +use Rng; -use {Rng, Rand}; +pub use self::other::Alphanumeric; +#[doc(inline)] pub use self::uniform::Uniform; +pub use self::float::{OpenClosed01, Open01}; +pub use self::bernoulli::Bernoulli; +#[cfg(feature="alloc")] pub use self::weighted::{WeightedIndex, WeightedError}; +#[cfg(feature="std")] pub use self::unit_sphere::UnitSphereSurface; +#[cfg(feature="std")] pub use self::unit_circle::UnitCircle; +#[cfg(feature="std")] pub use self::gamma::{Gamma, ChiSquared, FisherF, + StudentT, Beta}; +#[cfg(feature="std")] pub use self::normal::{Normal, LogNormal, StandardNormal}; +#[cfg(feature="std")] pub use self::exponential::{Exp, Exp1}; +#[cfg(feature="std")] pub use self::pareto::Pareto; +#[cfg(feature="std")] pub use self::poisson::Poisson; +#[cfg(feature="std")] pub use self::binomial::Binomial; +#[cfg(feature="std")] pub use self::cauchy::Cauchy; +#[cfg(feature="std")] pub use self::dirichlet::Dirichlet; +#[cfg(feature="std")] pub use self::triangular::Triangular; +#[cfg(feature="std")] pub use self::weibull::Weibull; -pub use self::range::Range; -#[cfg(feature="std")] -pub use self::gamma::{Gamma, ChiSquared, FisherF, StudentT}; -#[cfg(feature="std")] -pub use self::normal::{Normal, LogNormal}; -#[cfg(feature="std")] -pub use self::exponential::Exp; +pub mod uniform; +mod bernoulli; +#[cfg(feature="alloc")] mod weighted; +#[cfg(feature="std")] mod unit_sphere; +#[cfg(feature="std")] mod unit_circle; +#[cfg(feature="std")] mod gamma; +#[cfg(feature="std")] mod normal; +#[cfg(feature="std")] mod exponential; +#[cfg(feature="std")] mod pareto; +#[cfg(feature="std")] mod poisson; +#[cfg(feature="std")] mod binomial; +#[cfg(feature="std")] mod cauchy; +#[cfg(feature="std")] mod dirichlet; +#[cfg(feature="std")] mod triangular; +#[cfg(feature="std")] mod weibull; -pub mod range; -#[cfg(feature="std")] -pub mod gamma; -#[cfg(feature="std")] -pub mod normal; -#[cfg(feature="std")] -pub mod exponential; +mod float; +mod integer; +mod other; +mod utils; +#[cfg(feature="std")] mod ziggurat_tables; -#[cfg(feature="std")] -mod ziggurat_tables; - -/// Types that can be used to create a random instance of `Support`. -pub trait Sample { - /// Generate a random value of `Support`, using `rng` as the - /// source of randomness. - fn sample(&mut self, rng: &mut R) -> Support; -} - -/// `Sample`s that do not require keeping track of state. +/// Types (distributions) that can be used to create a random instance of `T`. /// -/// Since no state is recorded, each sample is (statistically) -/// independent of all others, assuming the `Rng` used has this -/// property. -// FIXME maybe having this separate is overkill (the only reason is to -// take &self rather than &mut self)? or maybe this should be the -// trait called `Sample` and the other should be `DependentSample`. -pub trait IndependentSample: Sample { - /// Generate a random value. - fn ind_sample(&self, &mut R) -> Support; +/// It is possible to sample from a distribution through both the +/// `Distribution` and [`Rng`] traits, via `distr.sample(&mut rng)` and +/// `rng.sample(distr)`. They also both offer the [`sample_iter`] method, which +/// produces an iterator that samples from the distribution. +/// +/// All implementations are expected to be immutable; this has the significant +/// advantage of not needing to consider thread safety, and for most +/// distributions efficient state-less sampling algorithms are available. +/// +/// [`sample_iter`]: Distribution::method.sample_iter +pub trait Distribution { + /// Generate a random value of `T`, using `rng` as the source of randomness. + fn sample(&self, rng: &mut R) -> T; + + /// Create an iterator that generates random values of `T`, using `rng` as + /// the source of randomness. + /// + /// # Example + /// + /// ``` + /// use rand::thread_rng; + /// use rand::distributions::{Distribution, Alphanumeric, Uniform, Standard}; + /// + /// let mut rng = thread_rng(); + /// + /// // Vec of 16 x f32: + /// let v: Vec = Standard.sample_iter(&mut rng).take(16).collect(); + /// + /// // String: + /// let s: String = Alphanumeric.sample_iter(&mut rng).take(7).collect(); + /// + /// // Dice-rolling: + /// let die_range = Uniform::new_inclusive(1, 6); + /// let mut roll_die = die_range.sample_iter(&mut rng); + /// while roll_die.next().unwrap() != 6 { + /// println!("Not a 6; rolling again!"); + /// } + /// ``` + fn sample_iter<'a, R>(&'a self, rng: &'a mut R) -> DistIter<'a, Self, R, T> + where Self: Sized, R: Rng + { + DistIter { + distr: self, + rng: rng, + phantom: ::core::marker::PhantomData, + } + } } -/// A wrapper for generating types that implement `Rand` via the -/// `Sample` & `IndependentSample` traits. +impl<'a, T, D: Distribution> Distribution for &'a D { + fn sample(&self, rng: &mut R) -> T { + (*self).sample(rng) + } +} + + +/// An iterator that generates random values of `T` with distribution `D`, +/// using `R` as the source of randomness. +/// +/// This `struct` is created by the [`sample_iter`] method on [`Distribution`]. +/// See its documentation for more. +/// +/// [`sample_iter`]: Distribution::sample_iter #[derive(Debug)] -pub struct RandSample { - _marker: marker::PhantomData Sup>, +pub struct DistIter<'a, D: 'a, R: 'a, T> { + distr: &'a D, + rng: &'a mut R, + phantom: ::core::marker::PhantomData, } -impl Copy for RandSample {} -impl Clone for RandSample { - fn clone(&self) -> Self { *self } -} +impl<'a, D, R, T> Iterator for DistIter<'a, D, R, T> + where D: Distribution, R: Rng + 'a +{ + type Item = T; -impl Sample for RandSample { - fn sample(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) } -} + #[inline(always)] + fn next(&mut self) -> Option { + Some(self.distr.sample(self.rng)) + } -impl IndependentSample for RandSample { - fn ind_sample(&self, rng: &mut R) -> Sup { - rng.gen() + fn size_hint(&self) -> (usize, Option) { + (usize::max_value(), None) } } -impl RandSample { - pub fn new() -> RandSample { - RandSample { _marker: marker::PhantomData } - } -} +#[cfg(rustc_1_26)] +impl<'a, D, R, T> iter::FusedIterator for DistIter<'a, D, R, T> + where D: Distribution, R: Rng + 'a {} + +#[cfg(features = "nightly")] +impl<'a, D, R, T> iter::TrustedLen for DistIter<'a, D, R, T> + where D: Distribution, R: Rng + 'a {} + + +/// A generic random value distribution, implemented for many primitive types. +/// Usually generates values with a numerically uniform distribution, and with a +/// range appropriate to the type. +/// +/// ## Built-in Implementations +/// +/// Assuming the provided `Rng` is well-behaved, these implementations +/// generate values with the following ranges and distributions: +/// +/// * Integers (`i32`, `u32`, `isize`, `usize`, etc.): Uniformly distributed +/// over all values of the type. +/// * `char`: Uniformly distributed over all Unicode scalar values, i.e. all +/// code points in the range `0...0x10_FFFF`, except for the range +/// `0xD800...0xDFFF` (the surrogate code points). This includes +/// unassigned/reserved code points. +/// * `bool`: Generates `false` or `true`, each with probability 0.5. +/// * Floating point types (`f32` and `f64`): Uniformly distributed in the +/// half-open range `[0, 1)`. See notes below. +/// * Wrapping integers (`Wrapping`), besides the type identical to their +/// normal integer variants. +/// +/// The following aggregate types also implement the distribution `Standard` as +/// long as their component types implement it: +/// +/// * Tuples and arrays: Each element of the tuple or array is generated +/// independently, using the `Standard` distribution recursively. +/// * `Option` where `Standard` is implemented for `T`: Returns `None` with +/// probability 0.5; otherwise generates a random `x: T` and returns `Some(x)`. +/// +/// # Example +/// ``` +/// use rand::prelude::*; +/// use rand::distributions::Standard; +/// +/// let val: f32 = SmallRng::from_entropy().sample(Standard); +/// println!("f32 from [0, 1): {}", val); +/// ``` +/// +/// # Floating point implementation +/// The floating point implementations for `Standard` generate a random value in +/// the half-open interval `[0, 1)`, i.e. including 0 but not 1. +/// +/// All values that can be generated are of the form `n * ε/2`. For `f32` +/// the 23 most significant random bits of a `u32` are used and for `f64` the +/// 53 most significant bits of a `u64` are used. The conversion uses the +/// multiplicative method: `(rng.gen::<$uty>() >> N) as $ty * (ε/2)`. +/// +/// See also: [`Open01`] which samples from `(0, 1)`, [`OpenClosed01`] which +/// samples from `(0, 1]` and `Rng::gen_range(0, 1)` which also samples from +/// `[0, 1)`. Note that `Open01` and `gen_range` (which uses [`Uniform`]) use +/// transmute-based methods which yield 1 bit less precision but may perform +/// faster on some architectures (on modern Intel CPUs all methods have +/// approximately equal performance). +/// +/// [`Uniform`]: uniform::Uniform +#[derive(Clone, Copy, Debug)] +pub struct Standard; + /// A value with a particular weight for use with `WeightedChoice`. +#[deprecated(since="0.6.0", note="use WeightedIndex instead")] +#[allow(deprecated)] #[derive(Copy, Clone, Debug)] pub struct Weighted { /// The numerical weight of this item @@ -99,35 +386,19 @@ pub struct Weighted { /// A distribution that selects from a finite collection of weighted items. /// -/// Each item has an associated weight that influences how likely it -/// is to be chosen: higher weight is more likely. +/// Deprecated: use [`WeightedIndex`] instead. /// -/// The `Clone` restriction is a limitation of the `Sample` and -/// `IndependentSample` traits. Note that `&T` is (cheaply) `Clone` for -/// all `T`, as is `u32`, so one can store references or indices into -/// another vector. -/// -/// # Example -/// -/// ```rust -/// use rand::distributions::{Weighted, WeightedChoice, IndependentSample}; -/// -/// let mut items = vec!(Weighted { weight: 2, item: 'a' }, -/// Weighted { weight: 4, item: 'b' }, -/// Weighted { weight: 1, item: 'c' }); -/// let wc = WeightedChoice::new(&mut items); -/// let mut rng = rand::thread_rng(); -/// for _ in 0..16 { -/// // on average prints 'a' 4 times, 'b' 8 and 'c' twice. -/// println!("{}", wc.ind_sample(&mut rng)); -/// } -/// ``` +/// [`WeightedIndex`]: WeightedIndex +#[deprecated(since="0.6.0", note="use WeightedIndex instead")] +#[allow(deprecated)] #[derive(Debug)] pub struct WeightedChoice<'a, T:'a> { items: &'a mut [Weighted], - weight_range: Range + weight_range: Uniform, } +#[deprecated(since="0.6.0", note="use WeightedIndex instead")] +#[allow(deprecated)] impl<'a, T: Clone> WeightedChoice<'a, T> { /// Create a new `WeightedChoice`. /// @@ -157,26 +428,24 @@ impl<'a, T: Clone> WeightedChoice<'a, T> { assert!(running_total != 0, "WeightedChoice::new called with a total weight of 0"); WeightedChoice { - items: items, + items, // we're likely to be generating numbers in this range // relatively often, so might as well cache it - weight_range: Range::new(0, running_total) + weight_range: Uniform::new(0, running_total) } } } -impl<'a, T: Clone> Sample for WeightedChoice<'a, T> { - fn sample(&mut self, rng: &mut R) -> T { self.ind_sample(rng) } -} - -impl<'a, T: Clone> IndependentSample for WeightedChoice<'a, T> { - fn ind_sample(&self, rng: &mut R) -> T { +#[deprecated(since="0.6.0", note="use WeightedIndex instead")] +#[allow(deprecated)] +impl<'a, T: Clone> Distribution for WeightedChoice<'a, T> { + fn sample(&self, rng: &mut R) -> T { // we want to find the first element that has cumulative // weight > sample_weight, which we do by binary since the // cumulative weights of self.items are sorted. // choose a weight in [0, total_weight) - let sample_weight = self.weight_range.ind_sample(rng); + let sample_weight = self.weight_range.sample(rng); // short circuit when it's the first item if sample_weight < self.items[0].weight { @@ -208,163 +477,78 @@ impl<'a, T: Clone> IndependentSample for WeightedChoice<'a, T> { } modifier /= 2; } - return self.items[idx + 1].item.clone(); - } -} - -/// Sample a random number using the Ziggurat method (specifically the -/// ZIGNOR variant from Doornik 2005). Most of the arguments are -/// directly from the paper: -/// -/// * `rng`: source of randomness -/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0. -/// * `X`: the $x_i$ abscissae. -/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$) -/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$ -/// * `pdf`: the probability density function -/// * `zero_case`: manual sampling from the tail when we chose the -/// bottom box (i.e. i == 0) - -// the perf improvement (25-50%) is definitely worth the extra code -// size from force-inlining. -#[cfg(feature="std")] -#[inline(always)] -fn ziggurat( - rng: &mut R, - symmetric: bool, - x_tab: ziggurat_tables::ZigTable, - f_tab: ziggurat_tables::ZigTable, - mut pdf: P, - mut zero_case: Z) - -> f64 where P: FnMut(f64) -> f64, Z: FnMut(&mut R, f64) -> f64 { - const SCALE: f64 = (1u64 << 53) as f64; - loop { - // reimplement the f64 generation as an optimisation suggested - // by the Doornik paper: we have a lot of precision-space - // (i.e. there are 11 bits of the 64 of a u64 to use after - // creating a f64), so we might as well reuse some to save - // generating a whole extra random number. (Seems to be 15% - // faster.) - // - // This unfortunately misses out on the benefits of direct - // floating point generation if an RNG like dSMFT is - // used. (That is, such RNGs create floats directly, highly - // efficiently and overload next_f32/f64, so by not calling it - // this may be slower than it would be otherwise.) - // FIXME: investigate/optimise for the above. - let bits: u64 = rng.gen(); - let i = (bits & 0xff) as usize; - let f = (bits >> 11) as f64 / SCALE; - - // u is either U(-1, 1) or U(0, 1) depending on if this is a - // symmetric distribution or not. - let u = if symmetric {2.0 * f - 1.0} else {f}; - let x = u * x_tab[i]; - - let test_x = if symmetric { x.abs() } else {x}; - - // algebraically equivalent to |u| < x_tab[i+1]/x_tab[i] (or u < x_tab[i+1]/x_tab[i]) - if test_x < x_tab[i + 1] { - return x; - } - if i == 0 { - return zero_case(rng, u); - } - // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1 - if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.gen::() < pdf(x) { - return x; - } + self.items[idx + 1].item.clone() } } #[cfg(test)] mod tests { - - use {Rng, Rand}; - use super::{RandSample, WeightedChoice, Weighted, Sample, IndependentSample}; - - #[derive(PartialEq, Debug)] - struct ConstRand(usize); - impl Rand for ConstRand { - fn rand(_: &mut R) -> ConstRand { - ConstRand(0) - } - } - - // 0, 1, 2, 3, ... - struct CountingRng { i: u32 } - impl Rng for CountingRng { - fn next_u32(&mut self) -> u32 { - self.i += 1; - self.i - 1 - } - fn next_u64(&mut self) -> u64 { - self.next_u32() as u64 - } - } + use rngs::mock::StepRng; + #[allow(deprecated)] + use super::{WeightedChoice, Weighted, Distribution}; #[test] - fn test_rand_sample() { - let mut rand_sample = RandSample::::new(); - - assert_eq!(rand_sample.sample(&mut ::test::rng()), ConstRand(0)); - assert_eq!(rand_sample.ind_sample(&mut ::test::rng()), ConstRand(0)); - } - #[test] + #[allow(deprecated)] fn test_weighted_choice() { // this makes assumptions about the internal implementation of - // WeightedChoice, specifically: it doesn't reorder the items, - // it doesn't do weird things to the RNG (so 0 maps to 0, 1 to - // 1, internally; modulo a modulo operation). + // WeightedChoice. It may fail when the implementation in + // `distributions::uniform::UniformInt` changes. macro_rules! t { ($items:expr, $expected:expr) => {{ let mut items = $items; + let mut total_weight = 0; + for item in &items { total_weight += item.weight; } + let wc = WeightedChoice::new(&mut items); let expected = $expected; - let mut rng = CountingRng { i: 0 }; + // Use extremely large steps between the random numbers, because + // we test with small ranges and `UniformInt` is designed to prefer + // the most significant bits. + let mut rng = StepRng::new(0, !0 / (total_weight as u64)); for &val in expected.iter() { - assert_eq!(wc.ind_sample(&mut rng), val) + assert_eq!(wc.sample(&mut rng), val) } }} } - t!(vec!(Weighted { weight: 1, item: 10}), [10]); + t!([Weighted { weight: 1, item: 10}], [10]); // skip some - t!(vec!(Weighted { weight: 0, item: 20}, - Weighted { weight: 2, item: 21}, - Weighted { weight: 0, item: 22}, - Weighted { weight: 1, item: 23}), - [21,21, 23]); + t!([Weighted { weight: 0, item: 20}, + Weighted { weight: 2, item: 21}, + Weighted { weight: 0, item: 22}, + Weighted { weight: 1, item: 23}], + [21, 21, 23]); // different weights - t!(vec!(Weighted { weight: 4, item: 30}, - Weighted { weight: 3, item: 31}), - [30,30,30,30, 31,31,31]); + t!([Weighted { weight: 4, item: 30}, + Weighted { weight: 3, item: 31}], + [30, 31, 30, 31, 30, 31, 30]); // check that we're binary searching // correctly with some vectors of odd // length. - t!(vec!(Weighted { weight: 1, item: 40}, - Weighted { weight: 1, item: 41}, - Weighted { weight: 1, item: 42}, - Weighted { weight: 1, item: 43}, - Weighted { weight: 1, item: 44}), + t!([Weighted { weight: 1, item: 40}, + Weighted { weight: 1, item: 41}, + Weighted { weight: 1, item: 42}, + Weighted { weight: 1, item: 43}, + Weighted { weight: 1, item: 44}], [40, 41, 42, 43, 44]); - t!(vec!(Weighted { weight: 1, item: 50}, - Weighted { weight: 1, item: 51}, - Weighted { weight: 1, item: 52}, - Weighted { weight: 1, item: 53}, - Weighted { weight: 1, item: 54}, - Weighted { weight: 1, item: 55}, - Weighted { weight: 1, item: 56}), - [50, 51, 52, 53, 54, 55, 56]); + t!([Weighted { weight: 1, item: 50}, + Weighted { weight: 1, item: 51}, + Weighted { weight: 1, item: 52}, + Weighted { weight: 1, item: 53}, + Weighted { weight: 1, item: 54}, + Weighted { weight: 1, item: 55}, + Weighted { weight: 1, item: 56}], + [50, 54, 51, 55, 52, 56, 53]); } #[test] + #[allow(deprecated)] fn test_weighted_clone_initialization() { let initial : Weighted = Weighted {weight: 1, item: 1}; let clone = initial.clone(); @@ -373,6 +557,7 @@ mod tests { } #[test] #[should_panic] + #[allow(deprecated)] fn test_weighted_clone_change_weight() { let initial : Weighted = Weighted {weight: 1, item: 1}; let mut clone = initial.clone(); @@ -381,6 +566,7 @@ mod tests { } #[test] #[should_panic] + #[allow(deprecated)] fn test_weighted_clone_change_item() { let initial : Weighted = Weighted {weight: 1, item: 1}; let mut clone = initial.clone(); @@ -390,20 +576,33 @@ mod tests { } #[test] #[should_panic] + #[allow(deprecated)] fn test_weighted_choice_no_items() { WeightedChoice::::new(&mut []); } #[test] #[should_panic] + #[allow(deprecated)] fn test_weighted_choice_zero_weight() { WeightedChoice::new(&mut [Weighted { weight: 0, item: 0}, Weighted { weight: 0, item: 1}]); } #[test] #[should_panic] + #[allow(deprecated)] fn test_weighted_choice_weight_overflows() { - let x = ::std::u32::MAX / 2; // x + x + 2 is the overflow + let x = ::core::u32::MAX / 2; // x + x + 2 is the overflow WeightedChoice::new(&mut [Weighted { weight: x, item: 0 }, Weighted { weight: 1, item: 1 }, Weighted { weight: x, item: 2 }, Weighted { weight: 1, item: 3 }]); } + + #[cfg(feature="std")] + #[test] + fn test_distributions_iter() { + use distributions::Normal; + let mut rng = ::test::rng(210); + let distr = Normal::new(10.0, 10.0); + let results: Vec<_> = distr.sample_iter(&mut rng).take(100).collect(); + println!("{:?}", results); + } } diff --git a/third_party/rust/rand/src/distributions/normal.rs b/third_party/rust/rand/src/distributions/normal.rs index 280613d8595d..089865e0ad1d 100644 --- a/third_party/rust/rand/src/distributions/normal.rs +++ b/third_party/rust/rand/src/distributions/normal.rs @@ -1,49 +1,50 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. +// Copyright 2018 Developers of the Rand project. +// Copyright 2013 The Rust Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license -// , at your +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! The normal and derived distributions. -use {Rng, Rand, Open01}; -use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample}; +use Rng; +use distributions::{ziggurat_tables, Distribution, Open01}; +use distributions::utils::ziggurat; -/// A wrapper around an `f64` to generate N(0, 1) random numbers -/// (a.k.a. a standard normal, or Gaussian). +/// Samples floating-point numbers according to the normal distribution +/// `N(0, 1)` (a.k.a. a standard normal, or Gaussian). This is equivalent to +/// `Normal::new(0.0, 1.0)` but faster. /// /// See `Normal` for the general normal distribution. /// -/// Implemented via the ZIGNOR variant[1] of the Ziggurat method. +/// Implemented via the ZIGNOR variant[^1] of the Ziggurat method. /// -/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to -/// Generate Normal Random -/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield -/// College, Oxford +/// [^1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to +/// Generate Normal Random Samples*]( +/// https://www.doornik.com/research/ziggurat.pdf). +/// Nuffield College, Oxford /// /// # Example +/// ``` +/// use rand::prelude::*; +/// use rand::distributions::StandardNormal; /// -/// ```rust -/// use rand::distributions::normal::StandardNormal; -/// -/// let StandardNormal(x) = rand::random(); -/// println!("{}", x); +/// let val: f64 = SmallRng::from_entropy().sample(StandardNormal); +/// println!("{}", val); /// ``` #[derive(Clone, Copy, Debug)] -pub struct StandardNormal(pub f64); +pub struct StandardNormal; -impl Rand for StandardNormal { - fn rand(rng: &mut R) -> StandardNormal { +impl Distribution for StandardNormal { + fn sample(&self, rng: &mut R) -> f64 { #[inline] fn pdf(x: f64) -> f64 { (-x*x/2.0).exp() } #[inline] - fn zero_case(rng: &mut R, u: f64) -> f64 { + fn zero_case(rng: &mut R, u: f64) -> f64 { // compute a random number in the tail by hand // strange initial conditions, because the loop is not @@ -54,8 +55,8 @@ impl Rand for StandardNormal { let mut y = 0.0f64; while -2.0 * y < x * x { - let Open01(x_) = rng.gen::>(); - let Open01(y_) = rng.gen::>(); + let x_: f64 = rng.sample(Open01); + let y_: f64 = rng.sample(Open01); x = x_.ln() / ziggurat_tables::ZIG_NORM_R; y = y_.ln(); @@ -64,30 +65,33 @@ impl Rand for StandardNormal { if u < 0.0 { x - ziggurat_tables::ZIG_NORM_R } else { ziggurat_tables::ZIG_NORM_R - x } } - StandardNormal(ziggurat( - rng, - true, // this is symmetric - &ziggurat_tables::ZIG_NORM_X, - &ziggurat_tables::ZIG_NORM_F, - pdf, zero_case)) + ziggurat(rng, true, // this is symmetric + &ziggurat_tables::ZIG_NORM_X, + &ziggurat_tables::ZIG_NORM_F, + pdf, zero_case) } } /// The normal distribution `N(mean, std_dev**2)`. /// -/// This uses the ZIGNOR variant of the Ziggurat method, see -/// `StandardNormal` for more details. +/// This uses the ZIGNOR variant of the Ziggurat method, see [`StandardNormal`] +/// for more details. +/// +/// Note that [`StandardNormal`] is an optimised implementation for mean 0, and +/// standard deviation 1. /// /// # Example /// -/// ```rust -/// use rand::distributions::{Normal, IndependentSample}; +/// ``` +/// use rand::distributions::{Normal, Distribution}; /// /// // mean 2, standard deviation 3 /// let normal = Normal::new(2.0, 3.0); -/// let v = normal.ind_sample(&mut rand::thread_rng()); +/// let v = normal.sample(&mut rand::thread_rng()); /// println!("{} is from a N(2, 9) distribution", v) /// ``` +/// +/// [`StandardNormal`]: crate::distributions::StandardNormal #[derive(Clone, Copy, Debug)] pub struct Normal { mean: f64, @@ -105,17 +109,14 @@ impl Normal { pub fn new(mean: f64, std_dev: f64) -> Normal { assert!(std_dev >= 0.0, "Normal::new called with `std_dev` < 0"); Normal { - mean: mean, - std_dev: std_dev + mean, + std_dev } } } -impl Sample for Normal { - fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } -} -impl IndependentSample for Normal { - fn ind_sample(&self, rng: &mut R) -> f64 { - let StandardNormal(n) = rng.gen::(); +impl Distribution for Normal { + fn sample(&self, rng: &mut R) -> f64 { + let n = rng.sample(StandardNormal); self.mean + self.std_dev * n } } @@ -123,17 +124,17 @@ impl IndependentSample for Normal { /// The log-normal distribution `ln N(mean, std_dev**2)`. /// -/// If `X` is log-normal distributed, then `ln(X)` is `N(mean, -/// std_dev**2)` distributed. +/// If `X` is log-normal distributed, then `ln(X)` is `N(mean, std_dev**2)` +/// distributed. /// /// # Example /// -/// ```rust -/// use rand::distributions::{LogNormal, IndependentSample}; +/// ``` +/// use rand::distributions::{LogNormal, Distribution}; /// /// // mean 2, standard deviation 3 /// let log_normal = LogNormal::new(2.0, 3.0); -/// let v = log_normal.ind_sample(&mut rand::thread_rng()); +/// let v = log_normal.sample(&mut rand::thread_rng()); /// println!("{} is from an ln N(2, 9) distribution", v) /// ``` #[derive(Clone, Copy, Debug)] @@ -154,27 +155,23 @@ impl LogNormal { LogNormal { norm: Normal::new(mean, std_dev) } } } -impl Sample for LogNormal { - fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } -} -impl IndependentSample for LogNormal { - fn ind_sample(&self, rng: &mut R) -> f64 { - self.norm.ind_sample(rng).exp() +impl Distribution for LogNormal { + fn sample(&self, rng: &mut R) -> f64 { + self.norm.sample(rng).exp() } } #[cfg(test)] mod tests { - use distributions::{Sample, IndependentSample}; + use distributions::Distribution; use super::{Normal, LogNormal}; #[test] fn test_normal() { - let mut norm = Normal::new(10.0, 10.0); - let mut rng = ::test::rng(); + let norm = Normal::new(10.0, 10.0); + let mut rng = ::test::rng(210); for _ in 0..1000 { norm.sample(&mut rng); - norm.ind_sample(&mut rng); } } #[test] @@ -186,11 +183,10 @@ mod tests { #[test] fn test_log_normal() { - let mut lnorm = LogNormal::new(10.0, 10.0); - let mut rng = ::test::rng(); + let lnorm = LogNormal::new(10.0, 10.0); + let mut rng = ::test::rng(211); for _ in 0..1000 { lnorm.sample(&mut rng); - lnorm.ind_sample(&mut rng); } } #[test] diff --git a/third_party/rust/rand/src/distributions/other.rs b/third_party/rust/rand/src/distributions/other.rs new file mode 100644 index 000000000000..2295f790de1a --- /dev/null +++ b/third_party/rust/rand/src/distributions/other.rs @@ -0,0 +1,219 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The implementations of the `Standard` distribution for other built-in types. + +use core::char; +use core::num::Wrapping; + +use {Rng}; +use distributions::{Distribution, Standard, Uniform}; + +// ----- Sampling distributions ----- + +/// Sample a `char`, uniformly distributed over ASCII letters and numbers: +/// a-z, A-Z and 0-9. +/// +/// # Example +/// +/// ``` +/// use std::iter; +/// use rand::{Rng, thread_rng}; +/// use rand::distributions::Alphanumeric; +/// +/// let mut rng = thread_rng(); +/// let chars: String = iter::repeat(()) +/// .map(|()| rng.sample(Alphanumeric)) +/// .take(7) +/// .collect(); +/// println!("Random chars: {}", chars); +/// ``` +#[derive(Debug)] +pub struct Alphanumeric; + + +// ----- Implementations of distributions ----- + +impl Distribution for Standard { + #[inline] + fn sample(&self, rng: &mut R) -> char { + // A valid `char` is either in the interval `[0, 0xD800)` or + // `(0xDFFF, 0x11_0000)`. All `char`s must therefore be in + // `[0, 0x11_0000)` but not in the "gap" `[0xD800, 0xDFFF]` which is + // reserved for surrogates. This is the size of that gap. + const GAP_SIZE: u32 = 0xDFFF - 0xD800 + 1; + + // Uniform::new(0, 0x11_0000 - GAP_SIZE) can also be used but it + // seemed slower. + let range = Uniform::new(GAP_SIZE, 0x11_0000); + + let mut n = range.sample(rng); + if n <= 0xDFFF { + n -= GAP_SIZE; + } + unsafe { char::from_u32_unchecked(n) } + } +} + +impl Distribution for Alphanumeric { + fn sample(&self, rng: &mut R) -> char { + const RANGE: u32 = 26 + 26 + 10; + const GEN_ASCII_STR_CHARSET: &[u8] = + b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ + abcdefghijklmnopqrstuvwxyz\ + 0123456789"; + // We can pick from 62 characters. This is so close to a power of 2, 64, + // that we can do better than `Uniform`. Use a simple bitshift and + // rejection sampling. We do not use a bitmask, because for small RNGs + // the most significant bits are usually of higher quality. + loop { + let var = rng.next_u32() >> (32 - 6); + if var < RANGE { + return GEN_ASCII_STR_CHARSET[var as usize] as char + } + } + } +} + +impl Distribution for Standard { + #[inline] + fn sample(&self, rng: &mut R) -> bool { + // We can compare against an arbitrary bit of an u32 to get a bool. + // Because the least significant bits of a lower quality RNG can have + // simple patterns, we compare against the most significant bit. This is + // easiest done using a sign test. + (rng.next_u32() as i32) < 0 + } +} + +macro_rules! tuple_impl { + // use variables to indicate the arity of the tuple + ($($tyvar:ident),* ) => { + // the trailing commas are for the 1 tuple + impl< $( $tyvar ),* > + Distribution<( $( $tyvar ),* , )> + for Standard + where $( Standard: Distribution<$tyvar> ),* + { + #[inline] + fn sample(&self, _rng: &mut R) -> ( $( $tyvar ),* , ) { + ( + // use the $tyvar's to get the appropriate number of + // repeats (they're not actually needed) + $( + _rng.gen::<$tyvar>() + ),* + , + ) + } + } + } +} + +impl Distribution<()> for Standard { + #[inline] + fn sample(&self, _: &mut R) -> () { () } +} +tuple_impl!{A} +tuple_impl!{A, B} +tuple_impl!{A, B, C} +tuple_impl!{A, B, C, D} +tuple_impl!{A, B, C, D, E} +tuple_impl!{A, B, C, D, E, F} +tuple_impl!{A, B, C, D, E, F, G} +tuple_impl!{A, B, C, D, E, F, G, H} +tuple_impl!{A, B, C, D, E, F, G, H, I} +tuple_impl!{A, B, C, D, E, F, G, H, I, J} +tuple_impl!{A, B, C, D, E, F, G, H, I, J, K} +tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L} + +macro_rules! array_impl { + // recursive, given at least one type parameter: + {$n:expr, $t:ident, $($ts:ident,)*} => { + array_impl!{($n - 1), $($ts,)*} + + impl Distribution<[T; $n]> for Standard where Standard: Distribution { + #[inline] + fn sample(&self, _rng: &mut R) -> [T; $n] { + [_rng.gen::<$t>(), $(_rng.gen::<$ts>()),*] + } + } + }; + // empty case: + {$n:expr,} => { + impl Distribution<[T; $n]> for Standard { + fn sample(&self, _rng: &mut R) -> [T; $n] { [] } + } + }; +} + +array_impl!{32, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,} + +impl Distribution> for Standard where Standard: Distribution { + #[inline] + fn sample(&self, rng: &mut R) -> Option { + // UFCS is needed here: https://github.com/rust-lang/rust/issues/24066 + if rng.gen::() { + Some(rng.gen()) + } else { + None + } + } +} + +impl Distribution> for Standard where Standard: Distribution { + #[inline] + fn sample(&self, rng: &mut R) -> Wrapping { + Wrapping(rng.gen()) + } +} + + +#[cfg(test)] +mod tests { + use {Rng, RngCore, Standard}; + use distributions::Alphanumeric; + #[cfg(all(not(feature="std"), feature="alloc"))] use alloc::string::String; + + #[test] + fn test_misc() { + let rng: &mut RngCore = &mut ::test::rng(820); + + rng.sample::(Standard); + rng.sample::(Standard); + } + + #[cfg(feature="alloc")] + #[test] + fn test_chars() { + use core::iter; + let mut rng = ::test::rng(805); + + // Test by generating a relatively large number of chars, so we also + // take the rejection sampling path. + let word: String = iter::repeat(()) + .map(|()| rng.gen::()).take(1000).collect(); + assert!(word.len() != 0); + } + + #[test] + fn test_alphanumeric() { + let mut rng = ::test::rng(806); + + // Test by generating a relatively large number of chars, so we also + // take the rejection sampling path. + let mut incorrect = false; + for _ in 0..100 { + let c = rng.sample(Alphanumeric); + incorrect |= !((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') ); + } + assert!(incorrect == false); + } +} diff --git a/third_party/rust/rand/src/distributions/pareto.rs b/third_party/rust/rand/src/distributions/pareto.rs new file mode 100644 index 000000000000..744a157fdaef --- /dev/null +++ b/third_party/rust/rand/src/distributions/pareto.rs @@ -0,0 +1,74 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The Pareto distribution. + +use Rng; +use distributions::{Distribution, OpenClosed01}; + +/// Samples floating-point numbers according to the Pareto distribution +/// +/// # Example +/// ``` +/// use rand::prelude::*; +/// use rand::distributions::Pareto; +/// +/// let val: f64 = SmallRng::from_entropy().sample(Pareto::new(1., 2.)); +/// println!("{}", val); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Pareto { + scale: f64, + inv_neg_shape: f64, +} + +impl Pareto { + /// Construct a new Pareto distribution with given `scale` and `shape`. + /// + /// In the literature, `scale` is commonly written as xm or k and + /// `shape` is often written as α. + /// + /// # Panics + /// + /// `scale` and `shape` have to be non-zero and positive. + pub fn new(scale: f64, shape: f64) -> Pareto { + assert!((scale > 0.) & (shape > 0.)); + Pareto { scale, inv_neg_shape: -1.0 / shape } + } +} + +impl Distribution for Pareto { + fn sample(&self, rng: &mut R) -> f64 { + let u: f64 = rng.sample(OpenClosed01); + self.scale * u.powf(self.inv_neg_shape) + } +} + +#[cfg(test)] +mod tests { + use distributions::Distribution; + use super::Pareto; + + #[test] + #[should_panic] + fn invalid() { + Pareto::new(0., 0.); + } + + #[test] + fn sample() { + let scale = 1.0; + let shape = 2.0; + let d = Pareto::new(scale, shape); + let mut rng = ::test::rng(1); + for _ in 0..1000 { + let r = d.sample(&mut rng); + assert!(r >= scale); + } + } +} diff --git a/third_party/rust/rand/src/distributions/poisson.rs b/third_party/rust/rand/src/distributions/poisson.rs new file mode 100644 index 000000000000..1244caadab06 --- /dev/null +++ b/third_party/rust/rand/src/distributions/poisson.rs @@ -0,0 +1,157 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2016-2017 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The Poisson distribution. + +use Rng; +use distributions::{Distribution, Cauchy}; +use distributions::utils::log_gamma; + +/// The Poisson distribution `Poisson(lambda)`. +/// +/// This distribution has a density function: +/// `f(k) = lambda^k * exp(-lambda) / k!` for `k >= 0`. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Poisson, Distribution}; +/// +/// let poi = Poisson::new(2.0); +/// let v = poi.sample(&mut rand::thread_rng()); +/// println!("{} is from a Poisson(2) distribution", v); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Poisson { + lambda: f64, + // precalculated values + exp_lambda: f64, + log_lambda: f64, + sqrt_2lambda: f64, + magic_val: f64, +} + +impl Poisson { + /// Construct a new `Poisson` with the given shape parameter + /// `lambda`. Panics if `lambda <= 0`. + pub fn new(lambda: f64) -> Poisson { + assert!(lambda > 0.0, "Poisson::new called with lambda <= 0"); + let log_lambda = lambda.ln(); + Poisson { + lambda, + exp_lambda: (-lambda).exp(), + log_lambda, + sqrt_2lambda: (2.0 * lambda).sqrt(), + magic_val: lambda * log_lambda - log_gamma(1.0 + lambda), + } + } +} + +impl Distribution for Poisson { + fn sample(&self, rng: &mut R) -> u64 { + // using the algorithm from Numerical Recipes in C + + // for low expected values use the Knuth method + if self.lambda < 12.0 { + let mut result = 0; + let mut p = 1.0; + while p > self.exp_lambda { + p *= rng.gen::(); + result += 1; + } + result - 1 + } + // high expected values - rejection method + else { + let mut int_result: u64; + + // we use the Cauchy distribution as the comparison distribution + // f(x) ~ 1/(1+x^2) + let cauchy = Cauchy::new(0.0, 1.0); + + loop { + let mut result; + let mut comp_dev; + + loop { + // draw from the Cauchy distribution + comp_dev = rng.sample(cauchy); + // shift the peak of the comparison ditribution + result = self.sqrt_2lambda * comp_dev + self.lambda; + // repeat the drawing until we are in the range of possible values + if result >= 0.0 { + break; + } + } + // now the result is a random variable greater than 0 with Cauchy distribution + // the result should be an integer value + result = result.floor(); + int_result = result as u64; + + // this is the ratio of the Poisson distribution to the comparison distribution + // the magic value scales the distribution function to a range of approximately 0-1 + // since it is not exact, we multiply the ratio by 0.9 to avoid ratios greater than 1 + // this doesn't change the resulting distribution, only increases the rate of failed drawings + let check = 0.9 * (1.0 + comp_dev * comp_dev) + * (result * self.log_lambda - log_gamma(1.0 + result) - self.magic_val).exp(); + + // check with uniform random value - if below the threshold, we are within the target distribution + if rng.gen::() <= check { + break; + } + } + int_result + } + } +} + +#[cfg(test)] +mod test { + use distributions::Distribution; + use super::Poisson; + + #[test] + fn test_poisson_10() { + let poisson = Poisson::new(10.0); + let mut rng = ::test::rng(123); + let mut sum = 0; + for _ in 0..1000 { + sum += poisson.sample(&mut rng); + } + let avg = (sum as f64) / 1000.0; + println!("Poisson average: {}", avg); + assert!((avg - 10.0).abs() < 0.5); // not 100% certain, but probable enough + } + + #[test] + fn test_poisson_15() { + // Take the 'high expected values' path + let poisson = Poisson::new(15.0); + let mut rng = ::test::rng(123); + let mut sum = 0; + for _ in 0..1000 { + sum += poisson.sample(&mut rng); + } + let avg = (sum as f64) / 1000.0; + println!("Poisson average: {}", avg); + assert!((avg - 15.0).abs() < 0.5); // not 100% certain, but probable enough + } + + #[test] + #[should_panic] + fn test_poisson_invalid_lambda_zero() { + Poisson::new(0.0); + } + + #[test] + #[should_panic] + fn test_poisson_invalid_lambda_neg() { + Poisson::new(-10.0); + } +} diff --git a/third_party/rust/rand/src/distributions/triangular.rs b/third_party/rust/rand/src/distributions/triangular.rs new file mode 100644 index 000000000000..a6eef5c263c2 --- /dev/null +++ b/third_party/rust/rand/src/distributions/triangular.rs @@ -0,0 +1,86 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +//! The triangular distribution. + +use Rng; +use distributions::{Distribution, Standard}; + +/// The triangular distribution. +/// +/// # Example +/// +/// ```rust +/// use rand::distributions::{Triangular, Distribution}; +/// +/// let d = Triangular::new(0., 5., 2.5); +/// let v = d.sample(&mut rand::thread_rng()); +/// println!("{} is from a triangular distribution", v); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Triangular { + min: f64, + max: f64, + mode: f64, +} + +impl Triangular { + /// Construct a new `Triangular` with minimum `min`, maximum `max` and mode + /// `mode`. + /// + /// # Panics + /// + /// If `max < mode`, `mode < max` or `max == min`. + /// + #[inline] + pub fn new(min: f64, max: f64, mode: f64) -> Triangular { + assert!(max >= mode); + assert!(mode >= min); + assert!(max != min); + Triangular { min, max, mode } + } +} + +impl Distribution for Triangular { + #[inline] + fn sample(&self, rng: &mut R) -> f64 { + let f: f64 = rng.sample(Standard); + let diff_mode_min = self.mode - self.min; + let diff_max_min = self.max - self.min; + if f * diff_max_min < diff_mode_min { + self.min + (f * diff_max_min * diff_mode_min).sqrt() + } else { + self.max - ((1. - f) * diff_max_min * (self.max - self.mode)).sqrt() + } + } +} + +#[cfg(test)] +mod test { + use distributions::Distribution; + use super::Triangular; + + #[test] + fn test_new() { + for &(min, max, mode) in &[ + (-1., 1., 0.), (1., 2., 1.), (5., 25., 25.), (1e-5, 1e5, 1e-3), + (0., 1., 0.9), (-4., -0.5, -2.), (-13.039, 8.41, 1.17), + ] { + println!("{} {} {}", min, max, mode); + let _ = Triangular::new(min, max, mode); + } + } + + #[test] + fn test_sample() { + let norm = Triangular::new(0., 1., 0.5); + let mut rng = ::test::rng(1); + for _ in 0..1000 { + norm.sample(&mut rng); + } + } +} diff --git a/third_party/rust/rand/src/distributions/uniform.rs b/third_party/rust/rand/src/distributions/uniform.rs new file mode 100644 index 000000000000..19b49345b379 --- /dev/null +++ b/third_party/rust/rand/src/distributions/uniform.rs @@ -0,0 +1,1283 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2017 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A distribution uniformly sampling numbers within a given range. +//! +//! [`Uniform`] is the standard distribution to sample uniformly from a range; +//! e.g. `Uniform::new_inclusive(1, 6)` can sample integers from 1 to 6, like a +//! standard die. [`Rng::gen_range`] supports any type supported by +//! [`Uniform`]. +//! +//! This distribution is provided with support for several primitive types +//! (all integer and floating-point types) as well as [`std::time::Duration`], +//! and supports extension to user-defined types via a type-specific *back-end* +//! implementation. +//! +//! The types [`UniformInt`], [`UniformFloat`] and [`UniformDuration`] are the +//! back-ends supporting sampling from primitive integer and floating-point +//! ranges as well as from [`std::time::Duration`]; these types do not normally +//! need to be used directly (unless implementing a derived back-end). +//! +//! # Example usage +//! +//! ``` +//! use rand::{Rng, thread_rng}; +//! use rand::distributions::Uniform; +//! +//! let mut rng = thread_rng(); +//! let side = Uniform::new(-10.0, 10.0); +//! +//! // sample between 1 and 10 points +//! for _ in 0..rng.gen_range(1, 11) { +//! // sample a point from the square with sides -10 - 10 in two dimensions +//! let (x, y) = (rng.sample(side), rng.sample(side)); +//! println!("Point: {}, {}", x, y); +//! } +//! ``` +//! +//! # Extending `Uniform` to support a custom type +//! +//! To extend [`Uniform`] to support your own types, write a back-end which +//! implements the [`UniformSampler`] trait, then implement the [`SampleUniform`] +//! helper trait to "register" your back-end. See the `MyF32` example below. +//! +//! At a minimum, the back-end needs to store any parameters needed for sampling +//! (e.g. the target range) and implement `new`, `new_inclusive` and `sample`. +//! Those methods should include an assert to check the range is valid (i.e. +//! `low < high`). The example below merely wraps another back-end. +//! +//! The `new`, `new_inclusive` and `sample_single` functions use arguments of +//! type SampleBorrow in order to support passing in values by reference or +//! by value. In the implementation of these functions, you can choose to +//! simply use the reference returned by [`SampleBorrow::borrow`], or you can choose +//! to copy or clone the value, whatever is appropriate for your type. +//! +//! ``` +//! use rand::prelude::*; +//! use rand::distributions::uniform::{Uniform, SampleUniform, +//! UniformSampler, UniformFloat, SampleBorrow}; +//! +//! struct MyF32(f32); +//! +//! #[derive(Clone, Copy, Debug)] +//! struct UniformMyF32 { +//! inner: UniformFloat, +//! } +//! +//! impl UniformSampler for UniformMyF32 { +//! type X = MyF32; +//! fn new(low: B1, high: B2) -> Self +//! where B1: SampleBorrow + Sized, +//! B2: SampleBorrow + Sized +//! { +//! UniformMyF32 { +//! inner: UniformFloat::::new(low.borrow().0, high.borrow().0), +//! } +//! } +//! fn new_inclusive(low: B1, high: B2) -> Self +//! where B1: SampleBorrow + Sized, +//! B2: SampleBorrow + Sized +//! { +//! UniformSampler::new(low, high) +//! } +//! fn sample(&self, rng: &mut R) -> Self::X { +//! MyF32(self.inner.sample(rng)) +//! } +//! } +//! +//! impl SampleUniform for MyF32 { +//! type Sampler = UniformMyF32; +//! } +//! +//! let (low, high) = (MyF32(17.0f32), MyF32(22.0f32)); +//! let uniform = Uniform::new(low, high); +//! let x = uniform.sample(&mut thread_rng()); +//! ``` +//! +//! [`SampleUniform`]: crate::distributions::uniform::SampleUniform +//! [`UniformSampler`]: crate::distributions::uniform::UniformSampler +//! [`UniformInt`]: crate::distributions::uniform::UniformInt +//! [`UniformFloat`]: crate::distributions::uniform::UniformFloat +//! [`UniformDuration`]: crate::distributions::uniform::UniformDuration +//! [`SampleBorrow::borrow`]: crate::distributions::uniform::SampleBorrow::borrow + +#[cfg(feature = "std")] +use std::time::Duration; +#[cfg(all(not(feature = "std"), rustc_1_25))] +use core::time::Duration; + +use Rng; +use distributions::Distribution; +use distributions::float::IntoFloat; +use distributions::utils::{WideningMultiply, FloatSIMDUtils, FloatAsSIMD, BoolAsSIMD}; + +#[cfg(not(feature = "std"))] +#[allow(unused_imports)] // rustc doesn't detect that this is actually used +use distributions::utils::Float; + + +#[cfg(feature="simd_support")] +use packed_simd::*; + +/// Sample values uniformly between two bounds. +/// +/// [`Uniform::new`] and [`Uniform::new_inclusive`] construct a uniform +/// distribution sampling from the given range; these functions may do extra +/// work up front to make sampling of multiple values faster. +/// +/// When sampling from a constant range, many calculations can happen at +/// compile-time and all methods should be fast; for floating-point ranges and +/// the full range of integer types this should have comparable performance to +/// the `Standard` distribution. +/// +/// Steps are taken to avoid bias which might be present in naive +/// implementations; for example `rng.gen::() % 170` samples from the range +/// `[0, 169]` but is twice as likely to select numbers less than 85 than other +/// values. Further, the implementations here give more weight to the high-bits +/// generated by the RNG than the low bits, since with some RNGs the low-bits +/// are of lower quality than the high bits. +/// +/// Implementations must sample in `[low, high)` range for +/// `Uniform::new(low, high)`, i.e., excluding `high`. In particular care must +/// be taken to ensure that rounding never results values `< low` or `>= high`. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Distribution, Uniform}; +/// +/// fn main() { +/// let between = Uniform::from(10..10000); +/// let mut rng = rand::thread_rng(); +/// let mut sum = 0; +/// for _ in 0..1000 { +/// sum += between.sample(&mut rng); +/// } +/// println!("{}", sum); +/// } +/// ``` +/// +/// [`new`]: Uniform::new +/// [`new_inclusive`]: Uniform::new_inclusive +#[derive(Clone, Copy, Debug)] +pub struct Uniform { + inner: X::Sampler, +} + +impl Uniform { + /// Create a new `Uniform` instance which samples uniformly from the half + /// open range `[low, high)` (excluding `high`). Panics if `low >= high`. + pub fn new(low: B1, high: B2) -> Uniform + where B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized + { + Uniform { inner: X::Sampler::new(low, high) } + } + + /// Create a new `Uniform` instance which samples uniformly from the closed + /// range `[low, high]` (inclusive). Panics if `low > high`. + pub fn new_inclusive(low: B1, high: B2) -> Uniform + where B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized + { + Uniform { inner: X::Sampler::new_inclusive(low, high) } + } +} + +impl Distribution for Uniform { + fn sample(&self, rng: &mut R) -> X { + self.inner.sample(rng) + } +} + +/// Helper trait for creating objects using the correct implementation of +/// [`UniformSampler`] for the sampling type. +/// +/// See the [module documentation] on how to implement [`Uniform`] range +/// sampling for a custom type. +/// +/// [module documentation]: crate::distributions::uniform +pub trait SampleUniform: Sized { + /// The `UniformSampler` implementation supporting type `X`. + type Sampler: UniformSampler; +} + +/// Helper trait handling actual uniform sampling. +/// +/// See the [module documentation] on how to implement [`Uniform`] range +/// sampling for a custom type. +/// +/// Implementation of [`sample_single`] is optional, and is only useful when +/// the implementation can be faster than `Self::new(low, high).sample(rng)`. +/// +/// [module documentation]: crate::distributions::uniform +/// [`sample_single`]: UniformSampler::sample_single +pub trait UniformSampler: Sized { + /// The type sampled by this implementation. + type X; + + /// Construct self, with inclusive lower bound and exclusive upper bound + /// `[low, high)`. + /// + /// Usually users should not call this directly but instead use + /// `Uniform::new`, which asserts that `low < high` before calling this. + fn new(low: B1, high: B2) -> Self + where B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized; + + /// Construct self, with inclusive bounds `[low, high]`. + /// + /// Usually users should not call this directly but instead use + /// `Uniform::new_inclusive`, which asserts that `low <= high` before + /// calling this. + fn new_inclusive(low: B1, high: B2) -> Self + where B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized; + + /// Sample a value. + fn sample(&self, rng: &mut R) -> Self::X; + + /// Sample a single value uniformly from a range with inclusive lower bound + /// and exclusive upper bound `[low, high)`. + /// + /// Usually users should not call this directly but instead use + /// `Uniform::sample_single`, which asserts that `low < high` before calling + /// this. + /// + /// Via this method, implementations can provide a method optimized for + /// sampling only a single value from the specified range. The default + /// implementation simply calls `UniformSampler::new` then `sample` on the + /// result. + fn sample_single(low: B1, high: B2, rng: &mut R) + -> Self::X + where B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized + { + let uniform: Self = UniformSampler::new(low, high); + uniform.sample(rng) + } +} + +impl From<::core::ops::Range> for Uniform { + fn from(r: ::core::ops::Range) -> Uniform { + Uniform::new(r.start, r.end) + } +} + +#[cfg(rustc_1_27)] +impl From<::core::ops::RangeInclusive> for Uniform { + fn from(r: ::core::ops::RangeInclusive) -> Uniform { + Uniform::new_inclusive(r.start(), r.end()) + } +} + +/// Helper trait similar to [`Borrow`] but implemented +/// only for SampleUniform and references to SampleUniform in +/// order to resolve ambiguity issues. +/// +/// [`Borrow`]: std::borrow::Borrow +pub trait SampleBorrow { + /// Immutably borrows from an owned value. See [`Borrow::borrow`] + /// + /// [`Borrow::borrow`]: std::borrow::Borrow::borrow + fn borrow(&self) -> &Borrowed; +} +impl SampleBorrow for Borrowed where Borrowed: SampleUniform { + #[inline(always)] + fn borrow(&self) -> &Borrowed { self } +} +impl<'a, Borrowed> SampleBorrow for &'a Borrowed where Borrowed: SampleUniform { + #[inline(always)] + fn borrow(&self) -> &Borrowed { *self } +} + +//////////////////////////////////////////////////////////////////////////////// + +// What follows are all back-ends. + + +/// The back-end implementing [`UniformSampler`] for integer types. +/// +/// Unless you are implementing [`UniformSampler`] for your own type, this type +/// should not be used directly, use [`Uniform`] instead. +/// +/// # Implementation notes +/// +/// For a closed range, the number of possible numbers we should generate is +/// `range = (high - low + 1)`. It is not possible to end up with a uniform +/// distribution if we map *all* the random integers that can be generated to +/// this range. We have to map integers from a `zone` that is a multiple of the +/// range. The rest of the integers, that cause a bias, are rejected. +/// +/// The problem with `range` is that to cover the full range of the type, it has +/// to store `unsigned_max + 1`, which can't be represented. But if the range +/// covers the full range of the type, no modulus is needed. A range of size 0 +/// can't exist, so we use that to represent this special case. Wrapping +/// arithmetic even makes representing `unsigned_max + 1` as 0 simple. +/// +/// We don't calculate `zone` directly, but first calculate the number of +/// integers to reject. To handle `unsigned_max + 1` not fitting in the type, +/// we use: +/// `ints_to_reject = (unsigned_max + 1) % range;` +/// `ints_to_reject = (unsigned_max - range + 1) % range;` +/// +/// The smallest integer PRNGs generate is `u32`. That is why for small integer +/// sizes (`i8`/`u8` and `i16`/`u16`) there is an optimization: don't pick the +/// largest zone that can fit in the small type, but pick the largest zone that +/// can fit in an `u32`. `ints_to_reject` is always less than half the size of +/// the small integer. This means the first bit of `zone` is always 1, and so +/// are all the other preceding bits of a larger integer. The easiest way to +/// grow the `zone` for the larger type is to simply sign extend it. +/// +/// An alternative to using a modulus is widening multiply: After a widening +/// multiply by `range`, the result is in the high word. Then comparing the low +/// word against `zone` makes sure our distribution is uniform. +#[derive(Clone, Copy, Debug)] +pub struct UniformInt { + low: X, + range: X, + zone: X, +} + +macro_rules! uniform_int_impl { + ($ty:ty, $signed:ty, $unsigned:ident, + $i_large:ident, $u_large:ident) => { + impl SampleUniform for $ty { + type Sampler = UniformInt<$ty>; + } + + impl UniformSampler for UniformInt<$ty> { + // We play free and fast with unsigned vs signed here + // (when $ty is signed), but that's fine, since the + // contract of this macro is for $ty and $unsigned to be + // "bit-equal", so casting between them is a no-op. + + type X = $ty; + + #[inline] // if the range is constant, this helps LLVM to do the + // calculations at compile-time. + fn new(low_b: B1, high_b: B2) -> Self + where B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized + { + let low = *low_b.borrow(); + let high = *high_b.borrow(); + assert!(low < high, "Uniform::new called with `low >= high`"); + UniformSampler::new_inclusive(low, high - 1) + } + + #[inline] // if the range is constant, this helps LLVM to do the + // calculations at compile-time. + fn new_inclusive(low_b: B1, high_b: B2) -> Self + where B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized + { + let low = *low_b.borrow(); + let high = *high_b.borrow(); + assert!(low <= high, + "Uniform::new_inclusive called with `low > high`"); + let unsigned_max = ::core::$unsigned::MAX; + + let range = high.wrapping_sub(low).wrapping_add(1) as $unsigned; + let ints_to_reject = + if range > 0 { + (unsigned_max - range + 1) % range + } else { + 0 + }; + let zone = unsigned_max - ints_to_reject; + + UniformInt { + low: low, + // These are really $unsigned values, but store as $ty: + range: range as $ty, + zone: zone as $ty + } + } + + fn sample(&self, rng: &mut R) -> Self::X { + let range = self.range as $unsigned as $u_large; + if range > 0 { + // Grow `zone` to fit a type of at least 32 bits, by + // sign-extending it (the first bit is always 1, so are all + // the preceding bits of the larger type). + // For types that already have the right size, all the + // casting is a no-op. + let zone = self.zone as $signed as $i_large as $u_large; + loop { + let v: $u_large = rng.gen(); + let (hi, lo) = v.wmul(range); + if lo <= zone { + return self.low.wrapping_add(hi as $ty); + } + } + } else { + // Sample from the entire integer range. + rng.gen() + } + } + + fn sample_single(low_b: B1, high_b: B2, rng: &mut R) + -> Self::X + where B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized + { + let low = *low_b.borrow(); + let high = *high_b.borrow(); + assert!(low < high, + "Uniform::sample_single called with low >= high"); + let range = high.wrapping_sub(low) as $unsigned as $u_large; + let zone = + if ::core::$unsigned::MAX <= ::core::u16::MAX as $unsigned { + // Using a modulus is faster than the approximation for + // i8 and i16. I suppose we trade the cost of one + // modulus for near-perfect branch prediction. + let unsigned_max: $u_large = ::core::$u_large::MAX; + let ints_to_reject = (unsigned_max - range + 1) % range; + unsigned_max - ints_to_reject + } else { + // conservative but fast approximation. `- 1` is necessary to allow the + // same comparison without bias. + (range << range.leading_zeros()).wrapping_sub(1) + }; + + loop { + let v: $u_large = rng.gen(); + let (hi, lo) = v.wmul(range); + if lo <= zone { + return low.wrapping_add(hi as $ty); + } + } + } + } + } +} + +uniform_int_impl! { i8, i8, u8, i32, u32 } +uniform_int_impl! { i16, i16, u16, i32, u32 } +uniform_int_impl! { i32, i32, u32, i32, u32 } +uniform_int_impl! { i64, i64, u64, i64, u64 } +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] +uniform_int_impl! { i128, i128, u128, u128, u128 } +uniform_int_impl! { isize, isize, usize, isize, usize } +uniform_int_impl! { u8, i8, u8, i32, u32 } +uniform_int_impl! { u16, i16, u16, i32, u32 } +uniform_int_impl! { u32, i32, u32, i32, u32 } +uniform_int_impl! { u64, i64, u64, i64, u64 } +uniform_int_impl! { usize, isize, usize, isize, usize } +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] +uniform_int_impl! { u128, u128, u128, i128, u128 } + +#[cfg(all(feature = "simd_support", feature = "nightly"))] +macro_rules! uniform_simd_int_impl { + ($ty:ident, $unsigned:ident, $u_scalar:ident) => { + // The "pick the largest zone that can fit in an `u32`" optimization + // is less useful here. Multiple lanes complicate things, we don't + // know the PRNG's minimal output size, and casting to a larger vector + // is generally a bad idea for SIMD performance. The user can still + // implement it manually. + + // TODO: look into `Uniform::::new(0u32, 100)` functionality + // perhaps `impl SampleUniform for $u_scalar`? + impl SampleUniform for $ty { + type Sampler = UniformInt<$ty>; + } + + impl UniformSampler for UniformInt<$ty> { + type X = $ty; + + #[inline] // if the range is constant, this helps LLVM to do the + // calculations at compile-time. + fn new(low_b: B1, high_b: B2) -> Self + where B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized + { + let low = *low_b.borrow(); + let high = *high_b.borrow(); + assert!(low.lt(high).all(), "Uniform::new called with `low >= high`"); + UniformSampler::new_inclusive(low, high - 1) + } + + #[inline] // if the range is constant, this helps LLVM to do the + // calculations at compile-time. + fn new_inclusive(low_b: B1, high_b: B2) -> Self + where B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized + { + let low = *low_b.borrow(); + let high = *high_b.borrow(); + assert!(low.le(high).all(), + "Uniform::new_inclusive called with `low > high`"); + let unsigned_max = ::core::$u_scalar::MAX; + + // NOTE: these may need to be replaced with explicitly + // wrapping operations if `packed_simd` changes + let range: $unsigned = ((high - low) + 1).cast(); + // `% 0` will panic at runtime. + let not_full_range = range.gt($unsigned::splat(0)); + // replacing 0 with `unsigned_max` allows a faster `select` + // with bitwise OR + let modulo = not_full_range.select(range, $unsigned::splat(unsigned_max)); + // wrapping addition + let ints_to_reject = (unsigned_max - range + 1) % modulo; + // When `range` is 0, `lo` of `v.wmul(range)` will always be + // zero which means only one sample is needed. + let zone = unsigned_max - ints_to_reject; + + UniformInt { + low: low, + // These are really $unsigned values, but store as $ty: + range: range.cast(), + zone: zone.cast(), + } + } + + fn sample(&self, rng: &mut R) -> Self::X { + let range: $unsigned = self.range.cast(); + let zone: $unsigned = self.zone.cast(); + + // This might seem very slow, generating a whole new + // SIMD vector for every sample rejection. For most uses + // though, the chance of rejection is small and provides good + // general performance. With multiple lanes, that chance is + // multiplied. To mitigate this, we replace only the lanes of + // the vector which fail, iteratively reducing the chance of + // rejection. The replacement method does however add a little + // overhead. Benchmarking or calculating probabilities might + // reveal contexts where this replacement method is slower. + let mut v: $unsigned = rng.gen(); + loop { + let (hi, lo) = v.wmul(range); + let mask = lo.le(zone); + if mask.all() { + let hi: $ty = hi.cast(); + // wrapping addition + let result = self.low + hi; + // `select` here compiles to a blend operation + // When `range.eq(0).none()` the compare and blend + // operations are avoided. + let v: $ty = v.cast(); + return range.gt($unsigned::splat(0)).select(result, v); + } + // Replace only the failing lanes + v = mask.select(v, rng.gen()); + } + } + } + }; + + // bulk implementation + ($(($unsigned:ident, $signed:ident),)+ $u_scalar:ident) => { + $( + uniform_simd_int_impl!($unsigned, $unsigned, $u_scalar); + uniform_simd_int_impl!($signed, $unsigned, $u_scalar); + )+ + }; +} + +#[cfg(all(feature = "simd_support", feature = "nightly"))] +uniform_simd_int_impl! { + (u64x2, i64x2), + (u64x4, i64x4), + (u64x8, i64x8), + u64 +} + +#[cfg(all(feature = "simd_support", feature = "nightly"))] +uniform_simd_int_impl! { + (u32x2, i32x2), + (u32x4, i32x4), + (u32x8, i32x8), + (u32x16, i32x16), + u32 +} + +#[cfg(all(feature = "simd_support", feature = "nightly"))] +uniform_simd_int_impl! { + (u16x2, i16x2), + (u16x4, i16x4), + (u16x8, i16x8), + (u16x16, i16x16), + (u16x32, i16x32), + u16 +} + +#[cfg(all(feature = "simd_support", feature = "nightly"))] +uniform_simd_int_impl! { + (u8x2, i8x2), + (u8x4, i8x4), + (u8x8, i8x8), + (u8x16, i8x16), + (u8x32, i8x32), + (u8x64, i8x64), + u8 +} + + +/// The back-end implementing [`UniformSampler`] for floating-point types. +/// +/// Unless you are implementing [`UniformSampler`] for your own type, this type +/// should not be used directly, use [`Uniform`] instead. +/// +/// # Implementation notes +/// +/// Instead of generating a float in the `[0, 1)` range using [`Standard`], the +/// `UniformFloat` implementation converts the output of an PRNG itself. This +/// way one or two steps can be optimized out. +/// +/// The floats are first converted to a value in the `[1, 2)` interval using a +/// transmute-based method, and then mapped to the expected range with a +/// multiply and addition. Values produced this way have what equals 22 bits of +/// random digits for an `f32`, and 52 for an `f64`. +/// +/// [`new`]: UniformSampler::new +/// [`new_inclusive`]: UniformSampler::new_inclusive +/// [`Standard`]: crate::distributions::Standard +#[derive(Clone, Copy, Debug)] +pub struct UniformFloat { + low: X, + scale: X, +} + +macro_rules! uniform_float_impl { + ($ty:ty, $uty:ident, $f_scalar:ident, $u_scalar:ident, $bits_to_discard:expr) => { + impl SampleUniform for $ty { + type Sampler = UniformFloat<$ty>; + } + + impl UniformSampler for UniformFloat<$ty> { + type X = $ty; + + fn new(low_b: B1, high_b: B2) -> Self + where B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized + { + let low = *low_b.borrow(); + let high = *high_b.borrow(); + assert!(low.all_lt(high), + "Uniform::new called with `low >= high`"); + assert!(low.all_finite() && high.all_finite(), + "Uniform::new called with non-finite boundaries"); + let max_rand = <$ty>::splat((::core::$u_scalar::MAX >> $bits_to_discard) + .into_float_with_exponent(0) - 1.0); + + let mut scale = high - low; + + loop { + let mask = (scale * max_rand + low).ge_mask(high); + if mask.none() { + break; + } + scale = scale.decrease_masked(mask); + } + + debug_assert!(<$ty>::splat(0.0).all_le(scale)); + + UniformFloat { low, scale } + } + + fn new_inclusive(low_b: B1, high_b: B2) -> Self + where B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized + { + let low = *low_b.borrow(); + let high = *high_b.borrow(); + assert!(low.all_le(high), + "Uniform::new_inclusive called with `low > high`"); + assert!(low.all_finite() && high.all_finite(), + "Uniform::new_inclusive called with non-finite boundaries"); + let max_rand = <$ty>::splat((::core::$u_scalar::MAX >> $bits_to_discard) + .into_float_with_exponent(0) - 1.0); + + let mut scale = (high - low) / max_rand; + + loop { + let mask = (scale * max_rand + low).gt_mask(high); + if mask.none() { + break; + } + scale = scale.decrease_masked(mask); + } + + debug_assert!(<$ty>::splat(0.0).all_le(scale)); + + UniformFloat { low, scale } + } + + fn sample(&self, rng: &mut R) -> Self::X { + // Generate a value in the range [1, 2) + let value1_2 = (rng.gen::<$uty>() >> $bits_to_discard) + .into_float_with_exponent(0); + + // Get a value in the range [0, 1) in order to avoid + // overflowing into infinity when multiplying with scale + let value0_1 = value1_2 - 1.0; + + // We don't use `f64::mul_add`, because it is not available with + // `no_std`. Furthermore, it is slower for some targets (but + // faster for others). However, the order of multiplication and + // addition is important, because on some platforms (e.g. ARM) + // it will be optimized to a single (non-FMA) instruction. + value0_1 * self.scale + self.low + } + + #[inline] + fn sample_single(low_b: B1, high_b: B2, rng: &mut R) + -> Self::X + where B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized + { + let low = *low_b.borrow(); + let high = *high_b.borrow(); + assert!(low.all_lt(high), + "Uniform::sample_single called with low >= high"); + let mut scale = high - low; + + loop { + // Generate a value in the range [1, 2) + let value1_2 = (rng.gen::<$uty>() >> $bits_to_discard) + .into_float_with_exponent(0); + + // Get a value in the range [0, 1) in order to avoid + // overflowing into infinity when multiplying with scale + let value0_1 = value1_2 - 1.0; + + // Doing multiply before addition allows some architectures + // to use a single instruction. + let res = value0_1 * scale + low; + + debug_assert!(low.all_le(res) || !scale.all_finite()); + if res.all_lt(high) { + return res; + } + + // This handles a number of edge cases. + // * `low` or `high` is NaN. In this case `scale` and + // `res` are going to end up as NaN. + // * `low` is negative infinity and `high` is finite. + // `scale` is going to be infinite and `res` will be + // NaN. + // * `high` is positive infinity and `low` is finite. + // `scale` is going to be infinite and `res` will + // be infinite or NaN (if value0_1 is 0). + // * `low` is negative infinity and `high` is positive + // infinity. `scale` will be infinite and `res` will + // be NaN. + // * `low` and `high` are finite, but `high - low` + // overflows to infinite. `scale` will be infinite + // and `res` will be infinite or NaN (if value0_1 is 0). + // So if `high` or `low` are non-finite, we are guaranteed + // to fail the `res < high` check above and end up here. + // + // While we technically should check for non-finite `low` + // and `high` before entering the loop, by doing the checks + // here instead, we allow the common case to avoid these + // checks. But we are still guaranteed that if `low` or + // `high` are non-finite we'll end up here and can do the + // appropriate checks. + // + // Likewise `high - low` overflowing to infinity is also + // rare, so handle it here after the common case. + let mask = !scale.finite_mask(); + if mask.any() { + assert!(low.all_finite() && high.all_finite(), + "Uniform::sample_single called with non-finite boundaries"); + scale = scale.decrease_masked(mask); + } + } + } + } + } +} + +uniform_float_impl! { f32, u32, f32, u32, 32 - 23 } +uniform_float_impl! { f64, u64, f64, u64, 64 - 52 } + +#[cfg(feature="simd_support")] +uniform_float_impl! { f32x2, u32x2, f32, u32, 32 - 23 } +#[cfg(feature="simd_support")] +uniform_float_impl! { f32x4, u32x4, f32, u32, 32 - 23 } +#[cfg(feature="simd_support")] +uniform_float_impl! { f32x8, u32x8, f32, u32, 32 - 23 } +#[cfg(feature="simd_support")] +uniform_float_impl! { f32x16, u32x16, f32, u32, 32 - 23 } + +#[cfg(feature="simd_support")] +uniform_float_impl! { f64x2, u64x2, f64, u64, 64 - 52 } +#[cfg(feature="simd_support")] +uniform_float_impl! { f64x4, u64x4, f64, u64, 64 - 52 } +#[cfg(feature="simd_support")] +uniform_float_impl! { f64x8, u64x8, f64, u64, 64 - 52 } + + + +/// The back-end implementing [`UniformSampler`] for `Duration`. +/// +/// Unless you are implementing [`UniformSampler`] for your own types, this type +/// should not be used directly, use [`Uniform`] instead. +#[cfg(any(feature = "std", rustc_1_25))] +#[derive(Clone, Copy, Debug)] +pub struct UniformDuration { + mode: UniformDurationMode, + offset: u32, +} + +#[cfg(any(feature = "std", rustc_1_25))] +#[derive(Debug, Copy, Clone)] +enum UniformDurationMode { + Small { + secs: u64, + nanos: Uniform, + }, + Medium { + nanos: Uniform, + }, + Large { + max_secs: u64, + max_nanos: u32, + secs: Uniform, + } +} + +#[cfg(any(feature = "std", rustc_1_25))] +impl SampleUniform for Duration { + type Sampler = UniformDuration; +} + +#[cfg(any(feature = "std", rustc_1_25))] +impl UniformSampler for UniformDuration { + type X = Duration; + + #[inline] + fn new(low_b: B1, high_b: B2) -> Self + where B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized + { + let low = *low_b.borrow(); + let high = *high_b.borrow(); + assert!(low < high, "Uniform::new called with `low >= high`"); + UniformDuration::new_inclusive(low, high - Duration::new(0, 1)) + } + + #[inline] + fn new_inclusive(low_b: B1, high_b: B2) -> Self + where B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized + { + let low = *low_b.borrow(); + let high = *high_b.borrow(); + assert!(low <= high, "Uniform::new_inclusive called with `low > high`"); + + let low_s = low.as_secs(); + let low_n = low.subsec_nanos(); + let mut high_s = high.as_secs(); + let mut high_n = high.subsec_nanos(); + + if high_n < low_n { + high_s = high_s - 1; + high_n = high_n + 1_000_000_000; + } + + let mode = if low_s == high_s { + UniformDurationMode::Small { + secs: low_s, + nanos: Uniform::new_inclusive(low_n, high_n), + } + } else { + let max = high_s + .checked_mul(1_000_000_000) + .and_then(|n| n.checked_add(high_n as u64)); + + if let Some(higher_bound) = max { + let lower_bound = low_s * 1_000_000_000 + low_n as u64; + UniformDurationMode::Medium { + nanos: Uniform::new_inclusive(lower_bound, higher_bound), + } + } else { + // An offset is applied to simplify generation of nanoseconds + let max_nanos = high_n - low_n; + UniformDurationMode::Large { + max_secs: high_s, + max_nanos, + secs: Uniform::new_inclusive(low_s, high_s), + } + } + }; + UniformDuration { + mode, + offset: low_n, + } + } + + #[inline] + fn sample(&self, rng: &mut R) -> Duration { + match self.mode { + UniformDurationMode::Small { secs, nanos } => { + let n = nanos.sample(rng); + Duration::new(secs, n) + } + UniformDurationMode::Medium { nanos } => { + let nanos = nanos.sample(rng); + Duration::new(nanos / 1_000_000_000, (nanos % 1_000_000_000) as u32) + } + UniformDurationMode::Large { max_secs, max_nanos, secs } => { + // constant folding means this is at least as fast as `gen_range` + let nano_range = Uniform::new(0, 1_000_000_000); + loop { + let s = secs.sample(rng); + let n = nano_range.sample(rng); + if !(s == max_secs && n > max_nanos) { + let sum = n + self.offset; + break Duration::new(s, sum); + } + } + } + } + } +} + +#[cfg(test)] +mod tests { + use Rng; + use rngs::mock::StepRng; + use distributions::uniform::Uniform; + use distributions::utils::FloatAsSIMD; + #[cfg(feature="simd_support")] use packed_simd::*; + + #[should_panic] + #[test] + fn test_uniform_bad_limits_equal_int() { + Uniform::new(10, 10); + } + + #[test] + fn test_uniform_good_limits_equal_int() { + let mut rng = ::test::rng(804); + let dist = Uniform::new_inclusive(10, 10); + for _ in 0..20 { + assert_eq!(rng.sample(dist), 10); + } + } + + #[should_panic] + #[test] + fn test_uniform_bad_limits_flipped_int() { + Uniform::new(10, 5); + } + + #[test] + fn test_integers() { + use core::{i8, i16, i32, i64, isize}; + use core::{u8, u16, u32, u64, usize}; + #[cfg(all(rustc_1_26, not(target_os = "emscripten")))] + use core::{i128, u128}; + + let mut rng = ::test::rng(251); + macro_rules! t { + ($ty:ident, $v:expr, $le:expr, $lt:expr) => {{ + for &(low, high) in $v.iter() { + let my_uniform = Uniform::new(low, high); + for _ in 0..1000 { + let v: $ty = rng.sample(my_uniform); + assert!($le(low, v) && $lt(v, high)); + } + + let my_uniform = Uniform::new_inclusive(low, high); + for _ in 0..1000 { + let v: $ty = rng.sample(my_uniform); + assert!($le(low, v) && $le(v, high)); + } + + let my_uniform = Uniform::new(&low, high); + for _ in 0..1000 { + let v: $ty = rng.sample(my_uniform); + assert!($le(low, v) && $lt(v, high)); + } + + let my_uniform = Uniform::new_inclusive(&low, &high); + for _ in 0..1000 { + let v: $ty = rng.sample(my_uniform); + assert!($le(low, v) && $le(v, high)); + } + + for _ in 0..1000 { + let v: $ty = rng.gen_range(low, high); + assert!($le(low, v) && $lt(v, high)); + } + } + }}; + + // scalar bulk + ($($ty:ident),*) => {{ + $(t!( + $ty, + [(0, 10), (10, 127), ($ty::MIN, $ty::MAX)], + |x, y| x <= y, + |x, y| x < y + );)* + }}; + + // simd bulk + ($($ty:ident),* => $scalar:ident) => {{ + $(t!( + $ty, + [ + ($ty::splat(0), $ty::splat(10)), + ($ty::splat(10), $ty::splat(127)), + ($ty::splat($scalar::MIN), $ty::splat($scalar::MAX)), + ], + |x: $ty, y| x.le(y).all(), + |x: $ty, y| x.lt(y).all() + );)* + }}; + } + t!(i8, i16, i32, i64, isize, + u8, u16, u32, u64, usize); + #[cfg(all(rustc_1_26, not(target_os = "emscripten")))] + t!(i128, u128); + + #[cfg(all(feature = "simd_support", feature = "nightly"))] + { + t!(u8x2, u8x4, u8x8, u8x16, u8x32, u8x64 => u8); + t!(i8x2, i8x4, i8x8, i8x16, i8x32, i8x64 => i8); + t!(u16x2, u16x4, u16x8, u16x16, u16x32 => u16); + t!(i16x2, i16x4, i16x8, i16x16, i16x32 => i16); + t!(u32x2, u32x4, u32x8, u32x16 => u32); + t!(i32x2, i32x4, i32x8, i32x16 => i32); + t!(u64x2, u64x4, u64x8 => u64); + t!(i64x2, i64x4, i64x8 => i64); + } + } + + #[test] + fn test_floats() { + let mut rng = ::test::rng(252); + let mut zero_rng = StepRng::new(0, 0); + let mut max_rng = StepRng::new(0xffff_ffff_ffff_ffff, 0); + macro_rules! t { + ($ty:ty, $f_scalar:ident, $bits_shifted:expr) => {{ + let v: &[($f_scalar, $f_scalar)]= + &[(0.0, 100.0), + (-1e35, -1e25), + (1e-35, 1e-25), + (-1e35, 1e35), + (<$f_scalar>::from_bits(0), <$f_scalar>::from_bits(3)), + (-<$f_scalar>::from_bits(10), -<$f_scalar>::from_bits(1)), + (-<$f_scalar>::from_bits(5), 0.0), + (-<$f_scalar>::from_bits(7), -0.0), + (10.0, ::core::$f_scalar::MAX), + (-100.0, ::core::$f_scalar::MAX), + (-::core::$f_scalar::MAX / 5.0, ::core::$f_scalar::MAX), + (-::core::$f_scalar::MAX, ::core::$f_scalar::MAX / 5.0), + (-::core::$f_scalar::MAX * 0.8, ::core::$f_scalar::MAX * 0.7), + (-::core::$f_scalar::MAX, ::core::$f_scalar::MAX), + ]; + for &(low_scalar, high_scalar) in v.iter() { + for lane in 0..<$ty>::lanes() { + let low = <$ty>::splat(0.0 as $f_scalar).replace(lane, low_scalar); + let high = <$ty>::splat(1.0 as $f_scalar).replace(lane, high_scalar); + let my_uniform = Uniform::new(low, high); + let my_incl_uniform = Uniform::new_inclusive(low, high); + for _ in 0..100 { + let v = rng.sample(my_uniform).extract(lane); + assert!(low_scalar <= v && v < high_scalar); + let v = rng.sample(my_incl_uniform).extract(lane); + assert!(low_scalar <= v && v <= high_scalar); + let v = rng.gen_range(low, high).extract(lane); + assert!(low_scalar <= v && v < high_scalar); + } + + assert_eq!(rng.sample(Uniform::new_inclusive(low, low)).extract(lane), low_scalar); + + assert_eq!(zero_rng.sample(my_uniform).extract(lane), low_scalar); + assert_eq!(zero_rng.sample(my_incl_uniform).extract(lane), low_scalar); + assert_eq!(zero_rng.gen_range(low, high).extract(lane), low_scalar); + assert!(max_rng.sample(my_uniform).extract(lane) < high_scalar); + assert!(max_rng.sample(my_incl_uniform).extract(lane) <= high_scalar); + + // Don't run this test for really tiny differences between high and low + // since for those rounding might result in selecting high for a very + // long time. + if (high_scalar - low_scalar) > 0.0001 { + let mut lowering_max_rng = + StepRng::new(0xffff_ffff_ffff_ffff, + (-1i64 << $bits_shifted) as u64); + assert!(lowering_max_rng.gen_range(low, high).extract(lane) < high_scalar); + } + } + } + + assert_eq!(rng.sample(Uniform::new_inclusive(::core::$f_scalar::MAX, + ::core::$f_scalar::MAX)), + ::core::$f_scalar::MAX); + assert_eq!(rng.sample(Uniform::new_inclusive(-::core::$f_scalar::MAX, + -::core::$f_scalar::MAX)), + -::core::$f_scalar::MAX); + }} + } + + t!(f32, f32, 32 - 23); + t!(f64, f64, 64 - 52); + #[cfg(feature="simd_support")] + { + t!(f32x2, f32, 32 - 23); + t!(f32x4, f32, 32 - 23); + t!(f32x8, f32, 32 - 23); + t!(f32x16, f32, 32 - 23); + t!(f64x2, f64, 64 - 52); + t!(f64x4, f64, 64 - 52); + t!(f64x8, f64, 64 - 52); + } + } + + #[test] + #[cfg(all(feature="std", + not(target_arch = "wasm32"), + not(target_arch = "asmjs")))] + fn test_float_assertions() { + use std::panic::catch_unwind; + use super::SampleUniform; + fn range(low: T, high: T) { + let mut rng = ::test::rng(253); + rng.gen_range(low, high); + } + + macro_rules! t { + ($ty:ident, $f_scalar:ident) => {{ + let v: &[($f_scalar, $f_scalar)] = + &[(::std::$f_scalar::NAN, 0.0), + (1.0, ::std::$f_scalar::NAN), + (::std::$f_scalar::NAN, ::std::$f_scalar::NAN), + (1.0, 0.5), + (::std::$f_scalar::MAX, -::std::$f_scalar::MAX), + (::std::$f_scalar::INFINITY, ::std::$f_scalar::INFINITY), + (::std::$f_scalar::NEG_INFINITY, ::std::$f_scalar::NEG_INFINITY), + (::std::$f_scalar::NEG_INFINITY, 5.0), + (5.0, ::std::$f_scalar::INFINITY), + (::std::$f_scalar::NAN, ::std::$f_scalar::INFINITY), + (::std::$f_scalar::NEG_INFINITY, ::std::$f_scalar::NAN), + (::std::$f_scalar::NEG_INFINITY, ::std::$f_scalar::INFINITY), + ]; + for &(low_scalar, high_scalar) in v.iter() { + for lane in 0..<$ty>::lanes() { + let low = <$ty>::splat(0.0 as $f_scalar).replace(lane, low_scalar); + let high = <$ty>::splat(1.0 as $f_scalar).replace(lane, high_scalar); + assert!(catch_unwind(|| range(low, high)).is_err()); + assert!(catch_unwind(|| Uniform::new(low, high)).is_err()); + assert!(catch_unwind(|| Uniform::new_inclusive(low, high)).is_err()); + assert!(catch_unwind(|| range(low, low)).is_err()); + assert!(catch_unwind(|| Uniform::new(low, low)).is_err()); + } + } + }} + } + + t!(f32, f32); + t!(f64, f64); + #[cfg(feature="simd_support")] + { + t!(f32x2, f32); + t!(f32x4, f32); + t!(f32x8, f32); + t!(f32x16, f32); + t!(f64x2, f64); + t!(f64x4, f64); + t!(f64x8, f64); + } + } + + + #[test] + #[cfg(any(feature = "std", rustc_1_25))] + fn test_durations() { + #[cfg(feature = "std")] + use std::time::Duration; + #[cfg(all(not(feature = "std"), rustc_1_25))] + use core::time::Duration; + + let mut rng = ::test::rng(253); + + let v = &[(Duration::new(10, 50000), Duration::new(100, 1234)), + (Duration::new(0, 100), Duration::new(1, 50)), + (Duration::new(0, 0), Duration::new(u64::max_value(), 999_999_999))]; + for &(low, high) in v.iter() { + let my_uniform = Uniform::new(low, high); + for _ in 0..1000 { + let v = rng.sample(my_uniform); + assert!(low <= v && v < high); + } + } + } + + #[test] + fn test_custom_uniform() { + use distributions::uniform::{UniformSampler, UniformFloat, SampleUniform, SampleBorrow}; + #[derive(Clone, Copy, PartialEq, PartialOrd)] + struct MyF32 { + x: f32, + } + #[derive(Clone, Copy, Debug)] + struct UniformMyF32 { + inner: UniformFloat, + } + impl UniformSampler for UniformMyF32 { + type X = MyF32; + fn new(low: B1, high: B2) -> Self + where B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized + { + UniformMyF32 { + inner: UniformFloat::::new(low.borrow().x, high.borrow().x), + } + } + fn new_inclusive(low: B1, high: B2) -> Self + where B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized + { + UniformSampler::new(low, high) + } + fn sample(&self, rng: &mut R) -> Self::X { + MyF32 { x: self.inner.sample(rng) } + } + } + impl SampleUniform for MyF32 { + type Sampler = UniformMyF32; + } + + let (low, high) = (MyF32{ x: 17.0f32 }, MyF32{ x: 22.0f32 }); + let uniform = Uniform::new(low, high); + let mut rng = ::test::rng(804); + for _ in 0..100 { + let x: MyF32 = rng.sample(uniform); + assert!(low <= x && x < high); + } + } + + #[test] + fn test_uniform_from_std_range() { + let r = Uniform::from(2u32..7); + assert_eq!(r.inner.low, 2); + assert_eq!(r.inner.range, 5); + let r = Uniform::from(2.0f64..7.0); + assert_eq!(r.inner.low, 2.0); + assert_eq!(r.inner.scale, 5.0); + } + + #[cfg(rustc_1_27)] + #[test] + fn test_uniform_from_std_range_inclusive() { + let r = Uniform::from(2u32..=6); + assert_eq!(r.inner.low, 2); + assert_eq!(r.inner.range, 5); + let r = Uniform::from(2.0f64..=7.0); + assert_eq!(r.inner.low, 2.0); + assert!(r.inner.scale > 5.0); + assert!(r.inner.scale < 5.0 + 1e-14); + } +} diff --git a/third_party/rust/rand/src/distributions/unit_circle.rs b/third_party/rust/rand/src/distributions/unit_circle.rs new file mode 100644 index 000000000000..01ab76a38516 --- /dev/null +++ b/third_party/rust/rand/src/distributions/unit_circle.rs @@ -0,0 +1,101 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use Rng; +use distributions::{Distribution, Uniform}; + +/// Samples uniformly from the edge of the unit circle in two dimensions. +/// +/// Implemented via a method by von Neumann[^1]. +/// +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{UnitCircle, Distribution}; +/// +/// let circle = UnitCircle::new(); +/// let v = circle.sample(&mut rand::thread_rng()); +/// println!("{:?} is from the unit circle.", v) +/// ``` +/// +/// [^1]: von Neumann, J. (1951) [*Various Techniques Used in Connection with +/// Random Digits.*](https://mcnp.lanl.gov/pdf_files/nbs_vonneumann.pdf) +/// NBS Appl. Math. Ser., No. 12. Washington, DC: U.S. Government Printing +/// Office, pp. 36-38. +#[derive(Clone, Copy, Debug)] +pub struct UnitCircle; + +impl UnitCircle { + /// Construct a new `UnitCircle` distribution. + #[inline] + pub fn new() -> UnitCircle { + UnitCircle + } +} + +impl Distribution<[f64; 2]> for UnitCircle { + #[inline] + fn sample(&self, rng: &mut R) -> [f64; 2] { + let uniform = Uniform::new(-1., 1.); + let mut x1; + let mut x2; + let mut sum; + loop { + x1 = uniform.sample(rng); + x2 = uniform.sample(rng); + sum = x1*x1 + x2*x2; + if sum < 1. { + break; + } + } + let diff = x1*x1 - x2*x2; + [diff / sum, 2.*x1*x2 / sum] + } +} + +#[cfg(test)] +mod tests { + use distributions::Distribution; + use super::UnitCircle; + + /// Assert that two numbers are almost equal to each other. + /// + /// On panic, this macro will print the values of the expressions with their + /// debug representations. + macro_rules! assert_almost_eq { + ($a:expr, $b:expr, $prec:expr) => ( + let diff = ($a - $b).abs(); + if diff > $prec { + panic!(format!( + "assertion failed: `abs(left - right) = {:.1e} < {:e}`, \ + (left: `{}`, right: `{}`)", + diff, $prec, $a, $b)); + } + ); + } + + #[test] + fn norm() { + let mut rng = ::test::rng(1); + let dist = UnitCircle::new(); + for _ in 0..1000 { + let x = dist.sample(&mut rng); + assert_almost_eq!(x[0]*x[0] + x[1]*x[1], 1., 1e-15); + } + } + + #[test] + fn value_stability() { + let mut rng = ::test::rng(2); + let dist = UnitCircle::new(); + assert_eq!(dist.sample(&mut rng), [-0.8032118336637037, 0.5956935036263119]); + assert_eq!(dist.sample(&mut rng), [-0.4742919588505423, -0.880367615130018]); + assert_eq!(dist.sample(&mut rng), [0.9297328981467168, 0.368234623716601]); + } +} diff --git a/third_party/rust/rand/src/distributions/unit_sphere.rs b/third_party/rust/rand/src/distributions/unit_sphere.rs new file mode 100644 index 000000000000..37de88b6a1fe --- /dev/null +++ b/third_party/rust/rand/src/distributions/unit_sphere.rs @@ -0,0 +1,99 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use Rng; +use distributions::{Distribution, Uniform}; + +/// Samples uniformly from the surface of the unit sphere in three dimensions. +/// +/// Implemented via a method by Marsaglia[^1]. +/// +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{UnitSphereSurface, Distribution}; +/// +/// let sphere = UnitSphereSurface::new(); +/// let v = sphere.sample(&mut rand::thread_rng()); +/// println!("{:?} is from the unit sphere surface.", v) +/// ``` +/// +/// [^1]: Marsaglia, George (1972). [*Choosing a Point from the Surface of a +/// Sphere.*](https://doi.org/10.1214/aoms/1177692644) +/// Ann. Math. Statist. 43, no. 2, 645--646. +#[derive(Clone, Copy, Debug)] +pub struct UnitSphereSurface; + +impl UnitSphereSurface { + /// Construct a new `UnitSphereSurface` distribution. + #[inline] + pub fn new() -> UnitSphereSurface { + UnitSphereSurface + } +} + +impl Distribution<[f64; 3]> for UnitSphereSurface { + #[inline] + fn sample(&self, rng: &mut R) -> [f64; 3] { + let uniform = Uniform::new(-1., 1.); + loop { + let (x1, x2) = (uniform.sample(rng), uniform.sample(rng)); + let sum = x1*x1 + x2*x2; + if sum >= 1. { + continue; + } + let factor = 2. * (1.0_f64 - sum).sqrt(); + return [x1 * factor, x2 * factor, 1. - 2.*sum]; + } + } +} + +#[cfg(test)] +mod tests { + use distributions::Distribution; + use super::UnitSphereSurface; + + /// Assert that two numbers are almost equal to each other. + /// + /// On panic, this macro will print the values of the expressions with their + /// debug representations. + macro_rules! assert_almost_eq { + ($a:expr, $b:expr, $prec:expr) => ( + let diff = ($a - $b).abs(); + if diff > $prec { + panic!(format!( + "assertion failed: `abs(left - right) = {:.1e} < {:e}`, \ + (left: `{}`, right: `{}`)", + diff, $prec, $a, $b)); + } + ); + } + + #[test] + fn norm() { + let mut rng = ::test::rng(1); + let dist = UnitSphereSurface::new(); + for _ in 0..1000 { + let x = dist.sample(&mut rng); + assert_almost_eq!(x[0]*x[0] + x[1]*x[1] + x[2]*x[2], 1., 1e-15); + } + } + + #[test] + fn value_stability() { + let mut rng = ::test::rng(2); + let dist = UnitSphereSurface::new(); + assert_eq!(dist.sample(&mut rng), + [-0.24950027180862533, -0.7552572587896719, 0.6060825747478084]); + assert_eq!(dist.sample(&mut rng), + [0.47604534507233487, -0.797200864987207, -0.3712837328763685]); + assert_eq!(dist.sample(&mut rng), + [0.9795722330927367, 0.18692349236651176, 0.07414747571708524]); + } +} diff --git a/third_party/rust/rand/src/distributions/utils.rs b/third_party/rust/rand/src/distributions/utils.rs new file mode 100644 index 000000000000..d4d36426392f --- /dev/null +++ b/third_party/rust/rand/src/distributions/utils.rs @@ -0,0 +1,504 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Math helper functions + +#[cfg(feature="simd_support")] +use packed_simd::*; +#[cfg(feature="std")] +use distributions::ziggurat_tables; +#[cfg(feature="std")] +use Rng; + + +pub trait WideningMultiply { + type Output; + + fn wmul(self, x: RHS) -> Self::Output; +} + +macro_rules! wmul_impl { + ($ty:ty, $wide:ty, $shift:expr) => { + impl WideningMultiply for $ty { + type Output = ($ty, $ty); + + #[inline(always)] + fn wmul(self, x: $ty) -> Self::Output { + let tmp = (self as $wide) * (x as $wide); + ((tmp >> $shift) as $ty, tmp as $ty) + } + } + }; + + // simd bulk implementation + ($(($ty:ident, $wide:ident),)+, $shift:expr) => { + $( + impl WideningMultiply for $ty { + type Output = ($ty, $ty); + + #[inline(always)] + fn wmul(self, x: $ty) -> Self::Output { + // For supported vectors, this should compile to a couple + // supported multiply & swizzle instructions (no actual + // casting). + // TODO: optimize + let y: $wide = self.cast(); + let x: $wide = x.cast(); + let tmp = y * x; + let hi: $ty = (tmp >> $shift).cast(); + let lo: $ty = tmp.cast(); + (hi, lo) + } + } + )+ + }; +} +wmul_impl! { u8, u16, 8 } +wmul_impl! { u16, u32, 16 } +wmul_impl! { u32, u64, 32 } +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] +wmul_impl! { u64, u128, 64 } + +// This code is a translation of the __mulddi3 function in LLVM's +// compiler-rt. It is an optimised variant of the common method +// `(a + b) * (c + d) = ac + ad + bc + bd`. +// +// For some reason LLVM can optimise the C version very well, but +// keeps shuffling registers in this Rust translation. +macro_rules! wmul_impl_large { + ($ty:ty, $half:expr) => { + impl WideningMultiply for $ty { + type Output = ($ty, $ty); + + #[inline(always)] + fn wmul(self, b: $ty) -> Self::Output { + const LOWER_MASK: $ty = !0 >> $half; + let mut low = (self & LOWER_MASK).wrapping_mul(b & LOWER_MASK); + let mut t = low >> $half; + low &= LOWER_MASK; + t += (self >> $half).wrapping_mul(b & LOWER_MASK); + low += (t & LOWER_MASK) << $half; + let mut high = t >> $half; + t = low >> $half; + low &= LOWER_MASK; + t += (b >> $half).wrapping_mul(self & LOWER_MASK); + low += (t & LOWER_MASK) << $half; + high += t >> $half; + high += (self >> $half).wrapping_mul(b >> $half); + + (high, low) + } + } + }; + + // simd bulk implementation + (($($ty:ty,)+) $scalar:ty, $half:expr) => { + $( + impl WideningMultiply for $ty { + type Output = ($ty, $ty); + + #[inline(always)] + fn wmul(self, b: $ty) -> Self::Output { + // needs wrapping multiplication + const LOWER_MASK: $scalar = !0 >> $half; + let mut low = (self & LOWER_MASK) * (b & LOWER_MASK); + let mut t = low >> $half; + low &= LOWER_MASK; + t += (self >> $half) * (b & LOWER_MASK); + low += (t & LOWER_MASK) << $half; + let mut high = t >> $half; + t = low >> $half; + low &= LOWER_MASK; + t += (b >> $half) * (self & LOWER_MASK); + low += (t & LOWER_MASK) << $half; + high += t >> $half; + high += (self >> $half) * (b >> $half); + + (high, low) + } + } + )+ + }; +} +#[cfg(not(all(rustc_1_26, not(target_os = "emscripten"))))] +wmul_impl_large! { u64, 32 } +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] +wmul_impl_large! { u128, 64 } + +macro_rules! wmul_impl_usize { + ($ty:ty) => { + impl WideningMultiply for usize { + type Output = (usize, usize); + + #[inline(always)] + fn wmul(self, x: usize) -> Self::Output { + let (high, low) = (self as $ty).wmul(x as $ty); + (high as usize, low as usize) + } + } + } +} +#[cfg(target_pointer_width = "32")] +wmul_impl_usize! { u32 } +#[cfg(target_pointer_width = "64")] +wmul_impl_usize! { u64 } + +#[cfg(all(feature = "simd_support", feature = "nightly"))] +mod simd_wmul { + #[cfg(target_arch = "x86")] + use core::arch::x86::*; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::*; + use super::*; + + wmul_impl! { + (u8x2, u16x2), + (u8x4, u16x4), + (u8x8, u16x8), + (u8x16, u16x16), + (u8x32, u16x32),, + 8 + } + + wmul_impl! { (u16x2, u32x2),, 16 } + #[cfg(not(target_feature = "sse2"))] + wmul_impl! { (u16x4, u32x4),, 16 } + #[cfg(not(target_feature = "sse4.2"))] + wmul_impl! { (u16x8, u32x8),, 16 } + #[cfg(not(target_feature = "avx2"))] + wmul_impl! { (u16x16, u32x16),, 16 } + + // 16-bit lane widths allow use of the x86 `mulhi` instructions, which + // means `wmul` can be implemented with only two instructions. + #[allow(unused_macros)] + macro_rules! wmul_impl_16 { + ($ty:ident, $intrinsic:ident, $mulhi:ident, $mullo:ident) => { + impl WideningMultiply for $ty { + type Output = ($ty, $ty); + + #[inline(always)] + fn wmul(self, x: $ty) -> Self::Output { + let b = $intrinsic::from_bits(x); + let a = $intrinsic::from_bits(self); + let hi = $ty::from_bits(unsafe { $mulhi(a, b) }); + let lo = $ty::from_bits(unsafe { $mullo(a, b) }); + (hi, lo) + } + } + }; + } + + #[cfg(target_feature = "sse2")] + wmul_impl_16! { u16x4, __m64, _mm_mulhi_pu16, _mm_mullo_pi16 } + #[cfg(target_feature = "sse4.2")] + wmul_impl_16! { u16x8, __m128i, _mm_mulhi_epu16, _mm_mullo_epi16 } + #[cfg(target_feature = "avx2")] + wmul_impl_16! { u16x16, __m256i, _mm256_mulhi_epu16, _mm256_mullo_epi16 } + // FIXME: there are no `__m512i` types in stdsimd yet, so `wmul::` + // cannot use the same implementation. + + wmul_impl! { + (u32x2, u64x2), + (u32x4, u64x4), + (u32x8, u64x8),, + 32 + } + + // TODO: optimize, this seems to seriously slow things down + wmul_impl_large! { (u8x64,) u8, 4 } + wmul_impl_large! { (u16x32,) u16, 8 } + wmul_impl_large! { (u32x16,) u32, 16 } + wmul_impl_large! { (u64x2, u64x4, u64x8,) u64, 32 } +} +#[cfg(all(feature = "simd_support", feature = "nightly"))] +pub use self::simd_wmul::*; + + +/// Helper trait when dealing with scalar and SIMD floating point types. +pub(crate) trait FloatSIMDUtils { + // `PartialOrd` for vectors compares lexicographically. We want to compare all + // the individual SIMD lanes instead, and get the combined result over all + // lanes. This is possible using something like `a.lt(b).all()`, but we + // implement it as a trait so we can write the same code for `f32` and `f64`. + // Only the comparison functions we need are implemented. + fn all_lt(self, other: Self) -> bool; + fn all_le(self, other: Self) -> bool; + fn all_finite(self) -> bool; + + type Mask; + fn finite_mask(self) -> Self::Mask; + fn gt_mask(self, other: Self) -> Self::Mask; + fn ge_mask(self, other: Self) -> Self::Mask; + + // Decrease all lanes where the mask is `true` to the next lower value + // representable by the floating-point type. At least one of the lanes + // must be set. + fn decrease_masked(self, mask: Self::Mask) -> Self; + + // Convert from int value. Conversion is done while retaining the numerical + // value, not by retaining the binary representation. + type UInt; + fn cast_from_int(i: Self::UInt) -> Self; +} + +/// Implement functions available in std builds but missing from core primitives +#[cfg(not(std))] +pub(crate) trait Float : Sized { + type Bits; + + fn is_nan(self) -> bool; + fn is_infinite(self) -> bool; + fn is_finite(self) -> bool; + fn to_bits(self) -> Self::Bits; + fn from_bits(v: Self::Bits) -> Self; +} + +/// Implement functions on f32/f64 to give them APIs similar to SIMD types +pub(crate) trait FloatAsSIMD : Sized { + #[inline(always)] + fn lanes() -> usize { 1 } + #[inline(always)] + fn splat(scalar: Self) -> Self { scalar } + #[inline(always)] + fn extract(self, index: usize) -> Self { debug_assert_eq!(index, 0); self } + #[inline(always)] + fn replace(self, index: usize, new_value: Self) -> Self { debug_assert_eq!(index, 0); new_value } +} + +pub(crate) trait BoolAsSIMD : Sized { + fn any(self) -> bool; + fn all(self) -> bool; + fn none(self) -> bool; +} + +impl BoolAsSIMD for bool { + #[inline(always)] + fn any(self) -> bool { self } + #[inline(always)] + fn all(self) -> bool { self } + #[inline(always)] + fn none(self) -> bool { !self } +} + +macro_rules! scalar_float_impl { + ($ty:ident, $uty:ident) => { + #[cfg(not(std))] + impl Float for $ty { + type Bits = $uty; + + #[inline] + fn is_nan(self) -> bool { + self != self + } + + #[inline] + fn is_infinite(self) -> bool { + self == ::core::$ty::INFINITY || self == ::core::$ty::NEG_INFINITY + } + + #[inline] + fn is_finite(self) -> bool { + !(self.is_nan() || self.is_infinite()) + } + + #[inline] + fn to_bits(self) -> Self::Bits { + unsafe { ::core::mem::transmute(self) } + } + + #[inline] + fn from_bits(v: Self::Bits) -> Self { + // It turns out the safety issues with sNaN were overblown! Hooray! + unsafe { ::core::mem::transmute(v) } + } + } + + impl FloatSIMDUtils for $ty { + type Mask = bool; + #[inline(always)] + fn all_lt(self, other: Self) -> bool { self < other } + #[inline(always)] + fn all_le(self, other: Self) -> bool { self <= other } + #[inline(always)] + fn all_finite(self) -> bool { self.is_finite() } + #[inline(always)] + fn finite_mask(self) -> Self::Mask { self.is_finite() } + #[inline(always)] + fn gt_mask(self, other: Self) -> Self::Mask { self > other } + #[inline(always)] + fn ge_mask(self, other: Self) -> Self::Mask { self >= other } + #[inline(always)] + fn decrease_masked(self, mask: Self::Mask) -> Self { + debug_assert!(mask, "At least one lane must be set"); + <$ty>::from_bits(self.to_bits() - 1) + } + type UInt = $uty; + fn cast_from_int(i: Self::UInt) -> Self { i as $ty } + } + + impl FloatAsSIMD for $ty {} + } +} + +scalar_float_impl!(f32, u32); +scalar_float_impl!(f64, u64); + + +#[cfg(feature="simd_support")] +macro_rules! simd_impl { + ($ty:ident, $f_scalar:ident, $mty:ident, $uty:ident) => { + impl FloatSIMDUtils for $ty { + type Mask = $mty; + #[inline(always)] + fn all_lt(self, other: Self) -> bool { self.lt(other).all() } + #[inline(always)] + fn all_le(self, other: Self) -> bool { self.le(other).all() } + #[inline(always)] + fn all_finite(self) -> bool { self.finite_mask().all() } + #[inline(always)] + fn finite_mask(self) -> Self::Mask { + // This can possibly be done faster by checking bit patterns + let neg_inf = $ty::splat(::core::$f_scalar::NEG_INFINITY); + let pos_inf = $ty::splat(::core::$f_scalar::INFINITY); + self.gt(neg_inf) & self.lt(pos_inf) + } + #[inline(always)] + fn gt_mask(self, other: Self) -> Self::Mask { self.gt(other) } + #[inline(always)] + fn ge_mask(self, other: Self) -> Self::Mask { self.ge(other) } + #[inline(always)] + fn decrease_masked(self, mask: Self::Mask) -> Self { + // Casting a mask into ints will produce all bits set for + // true, and 0 for false. Adding that to the binary + // representation of a float means subtracting one from + // the binary representation, resulting in the next lower + // value representable by $ty. This works even when the + // current value is infinity. + debug_assert!(mask.any(), "At least one lane must be set"); + <$ty>::from_bits(<$uty>::from_bits(self) + <$uty>::from_bits(mask)) + } + type UInt = $uty; + fn cast_from_int(i: Self::UInt) -> Self { i.cast() } + } + } +} + +#[cfg(feature="simd_support")] simd_impl! { f32x2, f32, m32x2, u32x2 } +#[cfg(feature="simd_support")] simd_impl! { f32x4, f32, m32x4, u32x4 } +#[cfg(feature="simd_support")] simd_impl! { f32x8, f32, m32x8, u32x8 } +#[cfg(feature="simd_support")] simd_impl! { f32x16, f32, m32x16, u32x16 } +#[cfg(feature="simd_support")] simd_impl! { f64x2, f64, m64x2, u64x2 } +#[cfg(feature="simd_support")] simd_impl! { f64x4, f64, m64x4, u64x4 } +#[cfg(feature="simd_support")] simd_impl! { f64x8, f64, m64x8, u64x8 } + +/// Calculates ln(gamma(x)) (natural logarithm of the gamma +/// function) using the Lanczos approximation. +/// +/// The approximation expresses the gamma function as: +/// `gamma(z+1) = sqrt(2*pi)*(z+g+0.5)^(z+0.5)*exp(-z-g-0.5)*Ag(z)` +/// `g` is an arbitrary constant; we use the approximation with `g=5`. +/// +/// Noting that `gamma(z+1) = z*gamma(z)` and applying `ln` to both sides: +/// `ln(gamma(z)) = (z+0.5)*ln(z+g+0.5)-(z+g+0.5) + ln(sqrt(2*pi)*Ag(z)/z)` +/// +/// `Ag(z)` is an infinite series with coefficients that can be calculated +/// ahead of time - we use just the first 6 terms, which is good enough +/// for most purposes. +#[cfg(feature="std")] +pub fn log_gamma(x: f64) -> f64 { + // precalculated 6 coefficients for the first 6 terms of the series + let coefficients: [f64; 6] = [ + 76.18009172947146, + -86.50532032941677, + 24.01409824083091, + -1.231739572450155, + 0.1208650973866179e-2, + -0.5395239384953e-5, + ]; + + // (x+0.5)*ln(x+g+0.5)-(x+g+0.5) + let tmp = x + 5.5; + let log = (x + 0.5) * tmp.ln() - tmp; + + // the first few terms of the series for Ag(x) + let mut a = 1.000000000190015; + let mut denom = x; + for coeff in &coefficients { + denom += 1.0; + a += coeff / denom; + } + + // get everything together + // a is Ag(x) + // 2.5066... is sqrt(2pi) + log + (2.5066282746310005 * a / x).ln() +} + +/// Sample a random number using the Ziggurat method (specifically the +/// ZIGNOR variant from Doornik 2005). Most of the arguments are +/// directly from the paper: +/// +/// * `rng`: source of randomness +/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0. +/// * `X`: the $x_i$ abscissae. +/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$) +/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$ +/// * `pdf`: the probability density function +/// * `zero_case`: manual sampling from the tail when we chose the +/// bottom box (i.e. i == 0) + +// the perf improvement (25-50%) is definitely worth the extra code +// size from force-inlining. +#[cfg(feature="std")] +#[inline(always)] +pub fn ziggurat( + rng: &mut R, + symmetric: bool, + x_tab: ziggurat_tables::ZigTable, + f_tab: ziggurat_tables::ZigTable, + mut pdf: P, + mut zero_case: Z) + -> f64 where P: FnMut(f64) -> f64, Z: FnMut(&mut R, f64) -> f64 { + use distributions::float::IntoFloat; + loop { + // As an optimisation we re-implement the conversion to a f64. + // From the remaining 12 most significant bits we use 8 to construct `i`. + // This saves us generating a whole extra random number, while the added + // precision of using 64 bits for f64 does not buy us much. + let bits = rng.next_u64(); + let i = bits as usize & 0xff; + + let u = if symmetric { + // Convert to a value in the range [2,4) and substract to get [-1,1) + // We can't convert to an open range directly, that would require + // substracting `3.0 - EPSILON`, which is not representable. + // It is possible with an extra step, but an open range does not + // seem neccesary for the ziggurat algorithm anyway. + (bits >> 12).into_float_with_exponent(1) - 3.0 + } else { + // Convert to a value in the range [1,2) and substract to get (0,1) + (bits >> 12).into_float_with_exponent(0) + - (1.0 - ::core::f64::EPSILON / 2.0) + }; + let x = u * x_tab[i]; + + let test_x = if symmetric { x.abs() } else {x}; + + // algebraically equivalent to |u| < x_tab[i+1]/x_tab[i] (or u < x_tab[i+1]/x_tab[i]) + if test_x < x_tab[i + 1] { + return x; + } + if i == 0 { + return zero_case(rng, u); + } + // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1 + if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.gen::() < pdf(x) { + return x; + } + } +} diff --git a/third_party/rust/rand/src/distributions/weibull.rs b/third_party/rust/rand/src/distributions/weibull.rs new file mode 100644 index 000000000000..5fbe10ae9607 --- /dev/null +++ b/third_party/rust/rand/src/distributions/weibull.rs @@ -0,0 +1,71 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The Weibull distribution. + +use Rng; +use distributions::{Distribution, OpenClosed01}; + +/// Samples floating-point numbers according to the Weibull distribution +/// +/// # Example +/// ``` +/// use rand::prelude::*; +/// use rand::distributions::Weibull; +/// +/// let val: f64 = SmallRng::from_entropy().sample(Weibull::new(1., 10.)); +/// println!("{}", val); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Weibull { + inv_shape: f64, + scale: f64, +} + +impl Weibull { + /// Construct a new `Weibull` distribution with given `scale` and `shape`. + /// + /// # Panics + /// + /// `scale` and `shape` have to be non-zero and positive. + pub fn new(scale: f64, shape: f64) -> Weibull { + assert!((scale > 0.) & (shape > 0.)); + Weibull { inv_shape: 1./shape, scale } + } +} + +impl Distribution for Weibull { + fn sample(&self, rng: &mut R) -> f64 { + let x: f64 = rng.sample(OpenClosed01); + self.scale * (-x.ln()).powf(self.inv_shape) + } +} + +#[cfg(test)] +mod tests { + use distributions::Distribution; + use super::Weibull; + + #[test] + #[should_panic] + fn invalid() { + Weibull::new(0., 0.); + } + + #[test] + fn sample() { + let scale = 1.0; + let shape = 2.0; + let d = Weibull::new(scale, shape); + let mut rng = ::test::rng(1); + for _ in 0..1000 { + let r = d.sample(&mut rng); + assert!(r >= 0.); + } + } +} diff --git a/third_party/rust/rand/src/distributions/weighted.rs b/third_party/rust/rand/src/distributions/weighted.rs new file mode 100644 index 000000000000..d7499596e39f --- /dev/null +++ b/third_party/rust/rand/src/distributions/weighted.rs @@ -0,0 +1,230 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use Rng; +use distributions::Distribution; +use distributions::uniform::{UniformSampler, SampleUniform, SampleBorrow}; +use ::core::cmp::PartialOrd; +use core::fmt; + +// Note that this whole module is only imported if feature="alloc" is enabled. +#[cfg(not(feature="std"))] use alloc::vec::Vec; + +/// A distribution using weighted sampling to pick a discretely selected +/// item. +/// +/// Sampling a `WeightedIndex` distribution returns the index of a randomly +/// selected element from the iterator used when the `WeightedIndex` was +/// created. The chance of a given element being picked is proportional to the +/// value of the element. The weights can use any type `X` for which an +/// implementation of [`Uniform`] exists. +/// +/// # Performance +/// +/// A `WeightedIndex` contains a `Vec` and a [`Uniform`] and so its +/// size is the sum of the size of those objects, possibly plus some alignment. +/// +/// Creating a `WeightedIndex` will allocate enough space to hold `N - 1` +/// weights of type `X`, where `N` is the number of weights. However, since +/// `Vec` doesn't guarantee a particular growth strategy, additional memory +/// might be allocated but not used. Since the `WeightedIndex` object also +/// contains, this might cause additional allocations, though for primitive +/// types, ['Uniform`] doesn't allocate any memory. +/// +/// Time complexity of sampling from `WeightedIndex` is `O(log N)` where +/// `N` is the number of weights. +/// +/// Sampling from `WeightedIndex` will result in a single call to +/// `Uniform::sample` (method of the [`Distribution`] trait), which typically +/// will request a single value from the underlying [`RngCore`], though the +/// exact number depends on the implementaiton of `Uniform::sample`. +/// +/// # Example +/// +/// ``` +/// use rand::prelude::*; +/// use rand::distributions::WeightedIndex; +/// +/// let choices = ['a', 'b', 'c']; +/// let weights = [2, 1, 1]; +/// let dist = WeightedIndex::new(&weights).unwrap(); +/// let mut rng = thread_rng(); +/// for _ in 0..100 { +/// // 50% chance to print 'a', 25% chance to print 'b', 25% chance to print 'c' +/// println!("{}", choices[dist.sample(&mut rng)]); +/// } +/// +/// let items = [('a', 0), ('b', 3), ('c', 7)]; +/// let dist2 = WeightedIndex::new(items.iter().map(|item| item.1)).unwrap(); +/// for _ in 0..100 { +/// // 0% chance to print 'a', 30% chance to print 'b', 70% chance to print 'c' +/// println!("{}", items[dist2.sample(&mut rng)].0); +/// } +/// ``` +/// +/// [`Uniform`]: crate::distributions::uniform::Uniform +/// [`RngCore`]: rand_core::RngCore +#[derive(Debug, Clone)] +pub struct WeightedIndex { + cumulative_weights: Vec, + weight_distribution: X::Sampler, +} + +impl WeightedIndex { + /// Creates a new a `WeightedIndex` [`Distribution`] using the values + /// in `weights`. The weights can use any type `X` for which an + /// implementation of [`Uniform`] exists. + /// + /// Returns an error if the iterator is empty, if any weight is `< 0`, or + /// if its total value is 0. + /// + /// [`Uniform`]: crate::distributions::uniform::Uniform + pub fn new(weights: I) -> Result, WeightedError> + where I: IntoIterator, + I::Item: SampleBorrow, + X: for<'a> ::core::ops::AddAssign<&'a X> + + Clone + + Default { + let mut iter = weights.into_iter(); + let mut total_weight: X = iter.next() + .ok_or(WeightedError::NoItem)? + .borrow() + .clone(); + + let zero = ::default(); + if total_weight < zero { + return Err(WeightedError::NegativeWeight); + } + + let mut weights = Vec::::with_capacity(iter.size_hint().0); + for w in iter { + if *w.borrow() < zero { + return Err(WeightedError::NegativeWeight); + } + weights.push(total_weight.clone()); + total_weight += w.borrow(); + } + + if total_weight == zero { + return Err(WeightedError::AllWeightsZero); + } + let distr = X::Sampler::new(zero, total_weight); + + Ok(WeightedIndex { cumulative_weights: weights, weight_distribution: distr }) + } +} + +impl Distribution for WeightedIndex where + X: SampleUniform + PartialOrd { + fn sample(&self, rng: &mut R) -> usize { + use ::core::cmp::Ordering; + let chosen_weight = self.weight_distribution.sample(rng); + // Find the first item which has a weight *higher* than the chosen weight. + self.cumulative_weights.binary_search_by( + |w| if *w <= chosen_weight { Ordering::Less } else { Ordering::Greater }).unwrap_err() + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_weightedindex() { + let mut r = ::test::rng(700); + const N_REPS: u32 = 5000; + let weights = [1u32, 2, 3, 0, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7]; + let total_weight = weights.iter().sum::() as f32; + + let verify = |result: [i32; 14]| { + for (i, count) in result.iter().enumerate() { + let exp = (weights[i] * N_REPS) as f32 / total_weight; + let mut err = (*count as f32 - exp).abs(); + if err != 0.0 { + err /= exp; + } + assert!(err <= 0.25); + } + }; + + // WeightedIndex from vec + let mut chosen = [0i32; 14]; + let distr = WeightedIndex::new(weights.to_vec()).unwrap(); + for _ in 0..N_REPS { + chosen[distr.sample(&mut r)] += 1; + } + verify(chosen); + + // WeightedIndex from slice + chosen = [0i32; 14]; + let distr = WeightedIndex::new(&weights[..]).unwrap(); + for _ in 0..N_REPS { + chosen[distr.sample(&mut r)] += 1; + } + verify(chosen); + + // WeightedIndex from iterator + chosen = [0i32; 14]; + let distr = WeightedIndex::new(weights.iter()).unwrap(); + for _ in 0..N_REPS { + chosen[distr.sample(&mut r)] += 1; + } + verify(chosen); + + for _ in 0..5 { + assert_eq!(WeightedIndex::new(&[0, 1]).unwrap().sample(&mut r), 1); + assert_eq!(WeightedIndex::new(&[1, 0]).unwrap().sample(&mut r), 0); + assert_eq!(WeightedIndex::new(&[0, 0, 0, 0, 10, 0]).unwrap().sample(&mut r), 4); + } + + assert_eq!(WeightedIndex::new(&[10][0..0]).unwrap_err(), WeightedError::NoItem); + assert_eq!(WeightedIndex::new(&[0]).unwrap_err(), WeightedError::AllWeightsZero); + assert_eq!(WeightedIndex::new(&[10, 20, -1, 30]).unwrap_err(), WeightedError::NegativeWeight); + assert_eq!(WeightedIndex::new(&[-10, 20, 1, 30]).unwrap_err(), WeightedError::NegativeWeight); + assert_eq!(WeightedIndex::new(&[-10]).unwrap_err(), WeightedError::NegativeWeight); + } +} + +/// Error type returned from `WeightedIndex::new`. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum WeightedError { + /// The provided iterator contained no items. + NoItem, + + /// A weight lower than zero was used. + NegativeWeight, + + /// All items in the provided iterator had a weight of zero. + AllWeightsZero, +} + +impl WeightedError { + fn msg(&self) -> &str { + match *self { + WeightedError::NoItem => "No items found", + WeightedError::NegativeWeight => "Item has negative weight", + WeightedError::AllWeightsZero => "All items had weight zero", + } + } +} + +#[cfg(feature="std")] +impl ::std::error::Error for WeightedError { + fn description(&self) -> &str { + self.msg() + } + fn cause(&self) -> Option<&::std::error::Error> { + None + } +} + +impl fmt::Display for WeightedError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.msg()) + } +} diff --git a/third_party/rust/rand/src/distributions/ziggurat_tables.rs b/third_party/rust/rand/src/distributions/ziggurat_tables.rs index b6de4bf892cd..ca1ce30410f2 100644 --- a/third_party/rust/rand/src/distributions/ziggurat_tables.rs +++ b/third_party/rust/rand/src/distributions/ziggurat_tables.rs @@ -1,10 +1,9 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. +// Copyright 2018 Developers of the Rand project. +// Copyright 2013 The Rust Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license -// , at your +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// , at your // option. This file may not be copied, modified, or distributed // except according to those terms. diff --git a/third_party/rust/rand/src/lib.rs b/third_party/rust/rand/src/lib.rs index 7b22dd45de7e..9c0482f328ee 100644 --- a/third_party/rust/rand/src/lib.rs +++ b/third_party/rust/rand/src/lib.rs @@ -1,467 +1,208 @@ -// Copyright 2013-2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. +// Copyright 2018 Developers of the Rand project. +// Copyright 2013-2017 The Rust Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license -// , at your +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Utilities for random number generation //! -//! The key functions are `random()` and `Rng::gen()`. These are polymorphic and -//! so can be used to generate any type that implements `Rand`. Type inference -//! means that often a simple call to `rand::random()` or `rng.gen()` will -//! suffice, but sometimes an annotation is required, e.g. -//! `rand::random::()`. +//! Rand provides utilities to generate random numbers, to convert them to +//! useful types and distributions, and some randomness-related algorithms. //! -//! See the `distributions` submodule for sampling random numbers from -//! distributions like normal and exponential. +//! # Quick Start //! -//! # Usage +//! To get you started quickly, the easiest and highest-level way to get +//! a random value is to use [`random()`]; alternatively you can use +//! [`thread_rng()`]. The [`Rng`] trait provides a useful API on all RNGs, while +//! the [`distributions`] and [`seq`] modules provide further +//! functionality on top of RNGs. //! -//! This crate is [on crates.io](https://crates.io/crates/rand) and can be -//! used by adding `rand` to the dependencies in your project's `Cargo.toml`. -//! -//! ```toml -//! [dependencies] -//! rand = "0.4" //! ``` +//! use rand::prelude::*; //! -//! and this to your crate root: -//! -//! ```rust -//! extern crate rand; -//! ``` -//! -//! # Thread-local RNG -//! -//! There is built-in support for a RNG associated with each thread stored -//! in thread-local storage. This RNG can be accessed via `thread_rng`, or -//! used implicitly via `random`. This RNG is normally randomly seeded -//! from an operating-system source of randomness, e.g. `/dev/urandom` on -//! Unix systems, and will automatically reseed itself from this source -//! after generating 32 KiB of random data. -//! -//! # Cryptographic security -//! -//! An application that requires an entropy source for cryptographic purposes -//! must use `OsRng`, which reads randomness from the source that the operating -//! system provides (e.g. `/dev/urandom` on Unixes or `CryptGenRandom()` on -//! Windows). -//! The other random number generators provided by this module are not suitable -//! for such purposes. -//! -//! *Note*: many Unix systems provide `/dev/random` as well as `/dev/urandom`. -//! This module uses `/dev/urandom` for the following reasons: -//! -//! - On Linux, `/dev/random` may block if entropy pool is empty; -//! `/dev/urandom` will not block. This does not mean that `/dev/random` -//! provides better output than `/dev/urandom`; the kernel internally runs a -//! cryptographically secure pseudorandom number generator (CSPRNG) based on -//! entropy pool for random number generation, so the "quality" of -//! `/dev/random` is not better than `/dev/urandom` in most cases. However, -//! this means that `/dev/urandom` can yield somewhat predictable randomness -//! if the entropy pool is very small, such as immediately after first -//! booting. Linux 3.17 added the `getrandom(2)` system call which solves -//! the issue: it blocks if entropy pool is not initialized yet, but it does -//! not block once initialized. `OsRng` tries to use `getrandom(2)` if -//! available, and use `/dev/urandom` fallback if not. If an application -//! does not have `getrandom` and likely to be run soon after first booting, -//! or on a system with very few entropy sources, one should consider using -//! `/dev/random` via `ReadRng`. -//! - On some systems (e.g. FreeBSD, OpenBSD and Mac OS X) there is no -//! difference between the two sources. (Also note that, on some systems -//! e.g. FreeBSD, both `/dev/random` and `/dev/urandom` may block once if -//! the CSPRNG has not seeded yet.) -//! -//! # Examples -//! -//! ```rust -//! use rand::Rng; +//! if rand::random() { // generates a boolean +//! // Try printing a random unicode code point (probably a bad idea)! +//! println!("char: {}", rand::random::()); +//! } //! //! let mut rng = rand::thread_rng(); -//! if rng.gen() { // random bool -//! println!("i32: {}, u32: {}", rng.gen::(), rng.gen::()) -//! } +//! let y: f64 = rng.gen(); // generates a float between 0 and 1 +//! +//! let mut nums: Vec = (1..100).collect(); +//! nums.shuffle(&mut rng); //! ``` //! -//! ```rust -//! let tuple = rand::random::<(f64, char)>(); -//! println!("{:?}", tuple) -//! ``` +//! # The Book //! -//! ## Monte Carlo estimation of Ï€ -//! -//! For this example, imagine we have a square with sides of length 2 and a unit -//! circle, both centered at the origin. Since the area of a unit circle is Ï€, -//! we have: -//! -//! ```text -//! (area of unit circle) / (area of square) = Ï€ / 4 -//! ``` -//! -//! So if we sample many points randomly from the square, roughly Ï€ / 4 of them -//! should be inside the circle. -//! -//! We can use the above fact to estimate the value of Ï€: pick many points in -//! the square at random, calculate the fraction that fall within the circle, -//! and multiply this fraction by 4. -//! -//! ``` -//! use rand::distributions::{IndependentSample, Range}; -//! -//! fn main() { -//! let between = Range::new(-1f64, 1.); -//! let mut rng = rand::thread_rng(); -//! -//! let total = 1_000_000; -//! let mut in_circle = 0; -//! -//! for _ in 0..total { -//! let a = between.ind_sample(&mut rng); -//! let b = between.ind_sample(&mut rng); -//! if a*a + b*b <= 1. { -//! in_circle += 1; -//! } -//! } -//! -//! // prints something close to 3.14159... -//! println!("{}", 4. * (in_circle as f64) / (total as f64)); -//! } -//! ``` -//! -//! ## Monty Hall Problem -//! -//! This is a simulation of the [Monty Hall Problem][]: -//! -//! > Suppose you're on a game show, and you're given the choice of three doors: -//! > Behind one door is a car; behind the others, goats. You pick a door, say -//! > No. 1, and the host, who knows what's behind the doors, opens another -//! > door, say No. 3, which has a goat. He then says to you, "Do you want to -//! > pick door No. 2?" Is it to your advantage to switch your choice? -//! -//! The rather unintuitive answer is that you will have a 2/3 chance of winning -//! if you switch and a 1/3 chance of winning if you don't, so it's better to -//! switch. -//! -//! This program will simulate the game show and with large enough simulation -//! steps it will indeed confirm that it is better to switch. -//! -//! [Monty Hall Problem]: http://en.wikipedia.org/wiki/Monty_Hall_problem -//! -//! ``` -//! use rand::Rng; -//! use rand::distributions::{IndependentSample, Range}; -//! -//! struct SimulationResult { -//! win: bool, -//! switch: bool, -//! } -//! -//! // Run a single simulation of the Monty Hall problem. -//! fn simulate(random_door: &Range, rng: &mut R) -//! -> SimulationResult { -//! let car = random_door.ind_sample(rng); -//! -//! // This is our initial choice -//! let mut choice = random_door.ind_sample(rng); -//! -//! // The game host opens a door -//! let open = game_host_open(car, choice, rng); -//! -//! // Shall we switch? -//! let switch = rng.gen(); -//! if switch { -//! choice = switch_door(choice, open); -//! } -//! -//! SimulationResult { win: choice == car, switch: switch } -//! } -//! -//! // Returns the door the game host opens given our choice and knowledge of -//! // where the car is. The game host will never open the door with the car. -//! fn game_host_open(car: u32, choice: u32, rng: &mut R) -> u32 { -//! let choices = free_doors(&[car, choice]); -//! rand::seq::sample_slice(rng, &choices, 1)[0] -//! } -//! -//! // Returns the door we switch to, given our current choice and -//! // the open door. There will only be one valid door. -//! fn switch_door(choice: u32, open: u32) -> u32 { -//! free_doors(&[choice, open])[0] -//! } -//! -//! fn free_doors(blocked: &[u32]) -> Vec { -//! (0..3).filter(|x| !blocked.contains(x)).collect() -//! } -//! -//! fn main() { -//! // The estimation will be more accurate with more simulations -//! let num_simulations = 10000; -//! -//! let mut rng = rand::thread_rng(); -//! let random_door = Range::new(0, 3); -//! -//! let (mut switch_wins, mut switch_losses) = (0, 0); -//! let (mut keep_wins, mut keep_losses) = (0, 0); -//! -//! println!("Running {} simulations...", num_simulations); -//! for _ in 0..num_simulations { -//! let result = simulate(&random_door, &mut rng); -//! -//! match (result.win, result.switch) { -//! (true, true) => switch_wins += 1, -//! (true, false) => keep_wins += 1, -//! (false, true) => switch_losses += 1, -//! (false, false) => keep_losses += 1, -//! } -//! } -//! -//! let total_switches = switch_wins + switch_losses; -//! let total_keeps = keep_wins + keep_losses; -//! -//! println!("Switched door {} times with {} wins and {} losses", -//! total_switches, switch_wins, switch_losses); -//! -//! println!("Kept our choice {} times with {} wins and {} losses", -//! total_keeps, keep_wins, keep_losses); -//! -//! // With a large number of simulations, the values should converge to -//! // 0.667 and 0.333 respectively. -//! println!("Estimated chance to win if we switch: {}", -//! switch_wins as f32 / total_switches as f32); -//! println!("Estimated chance to win if we don't: {}", -//! keep_wins as f32 / total_keeps as f32); -//! } -//! ``` +//! For the user guide and futher documentation, please read +//! [The Rust Rand Book](https://rust-random.github.io/book). + #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", html_favicon_url = "https://www.rust-lang.org/favicon.ico", - html_root_url = "https://docs.rs/rand/0.4")] + html_root_url = "https://rust-random.github.io/rand/")] +#![deny(missing_docs)] #![deny(missing_debug_implementations)] +#![doc(test(attr(allow(unused_variables), deny(warnings))))] #![cfg_attr(not(feature="std"), no_std)] #![cfg_attr(all(feature="alloc", not(feature="std")), feature(alloc))] -#![cfg_attr(feature = "i128_support", feature(i128_type, i128))] +#![cfg_attr(all(feature="simd_support", feature="nightly"), feature(stdsimd))] -#[cfg(feature="std")] extern crate std as core; -#[cfg(all(feature = "alloc", not(feature="std")))] extern crate alloc; +#[cfg(feature = "std")] extern crate core; +#[cfg(all(feature = "alloc", not(feature="std")))] #[macro_use] extern crate alloc; -use core::marker; -use core::mem; -#[cfg(feature="std")] use std::cell::RefCell; -#[cfg(feature="std")] use std::io; -#[cfg(feature="std")] use std::rc::Rc; +#[cfg(feature="simd_support")] extern crate packed_simd; -// external rngs -pub use jitter::JitterRng; -#[cfg(feature="std")] pub use os::OsRng; +extern crate rand_jitter; +#[cfg(feature = "rand_os")] +extern crate rand_os; -// pseudo rngs -pub use isaac::{IsaacRng, Isaac64Rng}; -pub use chacha::ChaChaRng; -pub use prng::XorShiftRng; +extern crate rand_core; +extern crate rand_isaac; // only for deprecations +extern crate rand_chacha; // only for deprecations +extern crate rand_hc; +extern crate rand_pcg; +extern crate rand_xorshift; -// local use declarations -#[cfg(target_pointer_width = "32")] -use prng::IsaacRng as IsaacWordRng; -#[cfg(target_pointer_width = "64")] -use prng::Isaac64Rng as IsaacWordRng; +#[cfg(feature = "log")] #[macro_use] extern crate log; +#[allow(unused)] +#[cfg(not(feature = "log"))] macro_rules! trace { ($($x:tt)*) => () } +#[allow(unused)] +#[cfg(not(feature = "log"))] macro_rules! debug { ($($x:tt)*) => () } +#[allow(unused)] +#[cfg(not(feature = "log"))] macro_rules! info { ($($x:tt)*) => () } +#[allow(unused)] +#[cfg(not(feature = "log"))] macro_rules! warn { ($($x:tt)*) => () } +#[allow(unused)] +#[cfg(not(feature = "log"))] macro_rules! error { ($($x:tt)*) => () } -use distributions::{Range, IndependentSample}; -use distributions::range::SampleRange; -// public modules +// Re-exports from rand_core +pub use rand_core::{RngCore, CryptoRng, SeedableRng}; +pub use rand_core::{ErrorKind, Error}; + +// Public exports +#[cfg(feature="std")] pub use rngs::thread::thread_rng; + +// Public modules pub mod distributions; -pub mod jitter; -#[cfg(feature="std")] pub mod os; -#[cfg(feature="std")] pub mod read; -pub mod reseeding; -#[cfg(any(feature="std", feature = "alloc"))] pub mod seq; +pub mod prelude; +#[deprecated(since="0.6.0")] +pub mod prng; +pub mod rngs; +pub mod seq; -// These tiny modules are here to avoid API breakage, probably only temporarily +//////////////////////////////////////////////////////////////////////////////// +// Compatibility re-exports. Documentation is hidden; will be removed eventually. + +#[doc(hidden)] mod deprecated; + +#[allow(deprecated)] +#[doc(hidden)] pub use deprecated::ReseedingRng; + +#[allow(deprecated)] +#[cfg(feature="std")] #[doc(hidden)] pub use deprecated::EntropyRng; + +#[allow(deprecated)] +#[cfg(feature="rand_os")] +#[doc(hidden)] +pub use deprecated::OsRng; + +#[allow(deprecated)] +#[doc(hidden)] pub use deprecated::{ChaChaRng, IsaacRng, Isaac64Rng, XorShiftRng}; +#[allow(deprecated)] +#[doc(hidden)] pub use deprecated::StdRng; + + +#[allow(deprecated)] +#[doc(hidden)] +pub mod jitter { + pub use deprecated::JitterRng; + pub use rngs::TimerError; +} +#[allow(deprecated)] +#[cfg(feature="rand_os")] +#[doc(hidden)] +pub mod os { + pub use deprecated::OsRng; +} +#[allow(deprecated)] +#[doc(hidden)] pub mod chacha { - //! The ChaCha random number generator. - pub use prng::ChaChaRng; + pub use deprecated::ChaChaRng; } +#[allow(deprecated)] +#[doc(hidden)] pub mod isaac { - //! The ISAAC random number generator. - pub use prng::{IsaacRng, Isaac64Rng}; + pub use deprecated::{IsaacRng, Isaac64Rng}; +} +#[allow(deprecated)] +#[cfg(feature="std")] +#[doc(hidden)] +pub mod read { + pub use deprecated::ReadRng; } -// private modules -mod rand_impls; -mod prng; +#[allow(deprecated)] +#[cfg(feature="std")] #[doc(hidden)] pub use deprecated::ThreadRng; + +//////////////////////////////////////////////////////////////////////////////// -/// A type that can be randomly generated using an `Rng`. +use core::{mem, slice}; +use distributions::{Distribution, Standard}; +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. /// -/// ## Built-in Implementations +/// This is the primary trait to use when generating random values. /// -/// This crate implements `Rand` for various primitive types. Assuming the -/// provided `Rng` is well-behaved, these implementations generate values with -/// the following ranges and distributions: +/// # Generic usage /// -/// * Integers (`i32`, `u32`, `isize`, `usize`, etc.): Uniformly distributed -/// over all values of the type. -/// * `char`: Uniformly distributed over all Unicode scalar values, i.e. all -/// code points in the range `0...0x10_FFFF`, except for the range -/// `0xD800...0xDFFF` (the surrogate code points). This includes -/// unassigned/reserved code points. -/// * `bool`: Generates `false` or `true`, each with probability 0.5. -/// * Floating point types (`f32` and `f64`): Uniformly distributed in the -/// half-open range `[0, 1)`. (The [`Open01`], [`Closed01`], [`Exp1`], and -/// [`StandardNormal`] wrapper types produce floating point numbers with -/// alternative ranges or distributions.) +/// The basic pattern is `fn foo(rng: &mut R)`. Some +/// things are worth noting here: /// -/// [`Open01`]: struct.Open01.html -/// [`Closed01`]: struct.Closed01.html -/// [`Exp1`]: distributions/exponential/struct.Exp1.html -/// [`StandardNormal`]: distributions/normal/struct.StandardNormal.html +/// - 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)`. /// -/// The following aggregate types also implement `Rand` as long as their -/// component types implement it: +/// An alternative pattern is possible: `fn foo(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 +/// on references (including type-erased references). Unfortunately within the +/// function `foo` it is not known whether `rng` is a reference type or not, +/// 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. /// -/// * Tuples and arrays: Each element of the tuple or array is generated -/// independently, using its own `Rand` implementation. -/// * `Option`: Returns `None` with probability 0.5; otherwise generates a -/// random `T` and returns `Some(T)`. -pub trait Rand : Sized { - /// Generates a random instance of this type using the specified source of - /// randomness. - fn rand(rng: &mut R) -> Self; -} - -/// A random number generator. -pub trait Rng { - /// Return the next random u32. +/// Example: +/// +/// ``` +/// # use rand::thread_rng; +/// use rand::Rng; +/// +/// fn foo(rng: &mut R) -> f32 { +/// rng.gen() +/// } +/// +/// # let v = foo(&mut thread_rng()); +/// ``` +pub trait Rng: RngCore { + /// Return a random value supporting the [`Standard`] distribution. /// - /// This rarely needs to be called directly, prefer `r.gen()` to - /// `r.next_u32()`. - // FIXME #rust-lang/rfcs#628: Should be implemented in terms of next_u64 - fn next_u32(&mut self) -> u32; - - /// Return the next random u64. - /// - /// By default this is implemented in terms of `next_u32`. An - /// implementation of this trait must provide at least one of - /// these two methods. Similarly to `next_u32`, this rarely needs - /// to be called directly, prefer `r.gen()` to `r.next_u64()`. - fn next_u64(&mut self) -> u64 { - ((self.next_u32() as u64) << 32) | (self.next_u32() as u64) - } - - /// Return the next random f32 selected from the half-open - /// interval `[0, 1)`. - /// - /// This uses a technique described by Saito and Matsumoto at - /// MCQMC'08. Given that the IEEE floating point numbers are - /// uniformly distributed over [1,2), we generate a number in - /// this range and then offset it onto the range [0,1). Our - /// choice of bits (masking v. shifting) is arbitrary and - /// should be immaterial for high quality generators. For low - /// quality generators (ex. LCG), prefer bitshifting due to - /// correlation between sequential low order bits. - /// - /// See: - /// A PRNG specialized in double precision floating point numbers using - /// an affine transition - /// - /// * - /// * - /// - /// By default this is implemented in terms of `next_u32`, but a - /// random number generator which can generate numbers satisfying - /// the requirements directly can overload this for performance. - /// It is required that the return value lies in `[0, 1)`. - /// - /// See `Closed01` for the closed interval `[0,1]`, and - /// `Open01` for the open interval `(0,1)`. - fn next_f32(&mut self) -> f32 { - const UPPER_MASK: u32 = 0x3F800000; - const LOWER_MASK: u32 = 0x7FFFFF; - let tmp = UPPER_MASK | (self.next_u32() & LOWER_MASK); - let result: f32 = unsafe { mem::transmute(tmp) }; - result - 1.0 - } - - /// Return the next random f64 selected from the half-open - /// interval `[0, 1)`. - /// - /// By default this is implemented in terms of `next_u64`, but a - /// random number generator which can generate numbers satisfying - /// the requirements directly can overload this for performance. - /// It is required that the return value lies in `[0, 1)`. - /// - /// See `Closed01` for the closed interval `[0,1]`, and - /// `Open01` for the open interval `(0,1)`. - fn next_f64(&mut self) -> f64 { - const UPPER_MASK: u64 = 0x3FF0000000000000; - const LOWER_MASK: u64 = 0xFFFFFFFFFFFFF; - let tmp = UPPER_MASK | (self.next_u64() & LOWER_MASK); - let result: f64 = unsafe { mem::transmute(tmp) }; - result - 1.0 - } - - /// Fill `dest` with random data. - /// - /// This has a default implementation in terms of `next_u64` and - /// `next_u32`, but should be overridden by implementations that - /// offer a more efficient solution than just calling those - /// methods repeatedly. - /// - /// This method does *not* have a requirement to bear any fixed - /// relationship to the other methods, for example, it does *not* - /// have to result in the same output as progressively filling - /// `dest` with `self.gen::()`, and any such behaviour should - /// not be relied upon. - /// - /// This method should guarantee that `dest` is entirely filled - /// with new data, and may panic if this is impossible - /// (e.g. reading past the end of a file that is being used as the - /// source of randomness). + /// [`Standard`]: distributions::Standard /// /// # Example /// - /// ```rust - /// use rand::{thread_rng, Rng}; - /// - /// let mut v = [0u8; 13579]; - /// thread_rng().fill_bytes(&mut v); - /// println!("{:?}", &v[..]); /// ``` - fn fill_bytes(&mut self, dest: &mut [u8]) { - // this could, in theory, be done by transmuting dest to a - // [u64], but this is (1) likely to be undefined behaviour for - // LLVM, (2) has to be very careful about alignment concerns, - // (3) adds more `unsafe` that needs to be checked, (4) - // probably doesn't give much performance gain if - // optimisations are on. - let mut count = 0; - let mut num = 0; - for byte in dest.iter_mut() { - if count == 0 { - // we could micro-optimise here by generating a u32 if - // we only need a few more bytes to fill the vector - // (i.e. at most 4). - num = self.next_u64(); - count = 8; - } - - *byte = (num & 0xff) as u8; - num >>= 8; - count -= 1; - } - } - - /// Return a random value of a `Rand` type. - /// - /// # Example - /// - /// ```rust /// use rand::{thread_rng, Rng}; /// /// let mut rng = thread_rng(); @@ -469,36 +210,17 @@ pub trait Rng { /// println!("{}", x); /// println!("{:?}", rng.gen::<(f64, bool)>()); /// ``` - #[inline(always)] - fn gen(&mut self) -> T where Self: Sized { - Rand::rand(self) + #[inline] + fn gen(&mut self) -> T where Standard: Distribution { + Standard.sample(self) } - /// Return an iterator that will yield an infinite number of randomly - /// generated items. + /// Generate a random value in the range [`low`, `high`), i.e. inclusive of + /// `low` and exclusive of `high`. /// - /// # Example - /// - /// ``` - /// use rand::{thread_rng, Rng}; - /// - /// let mut rng = thread_rng(); - /// let x = rng.gen_iter::().take(10).collect::>(); - /// println!("{:?}", x); - /// println!("{:?}", rng.gen_iter::<(f64, bool)>().take(5) - /// .collect::>()); - /// ``` - fn gen_iter<'a, T: Rand>(&'a mut self) -> Generator<'a, T, Self> where Self: Sized { - Generator { rng: self, _marker: marker::PhantomData } - } - - /// Generate a random value in the range [`low`, `high`). - /// - /// This is a convenience wrapper around - /// `distributions::Range`. If this function will be called - /// repeatedly with the same arguments, one should use `Range`, as - /// that will amortize the computations that allow for perfect - /// uniformity, as they only happen on initialization. + /// This function is optimised for the case that only a single sample is + /// made from the given range. See also the [`Uniform`] distribution + /// type which may be faster if sampling from the same range repeatedly. /// /// # Panics /// @@ -506,7 +228,7 @@ pub trait Rng { /// /// # Example /// - /// ```rust + /// ``` /// use rand::{thread_rng, Rng}; /// /// let mut rng = thread_rng(); @@ -515,407 +237,379 @@ pub trait Rng { /// let m: f64 = rng.gen_range(-40.0f64, 1.3e5f64); /// println!("{}", m); /// ``` - fn gen_range(&mut self, low: T, high: T) -> T where Self: Sized { - assert!(low < high, "Rng.gen_range called with low >= high"); - Range::new(low, high).ind_sample(self) + /// + /// [`Uniform`]: distributions::uniform::Uniform + fn gen_range(&mut self, low: B1, high: B2) -> T + where B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized { + T::Sampler::sample_single(low, high, self) } - /// Return a bool with a 1 in n chance of true + /// Sample a new value, using the given distribution. + /// + /// ### Example + /// + /// ``` + /// use rand::{thread_rng, Rng}; + /// use rand::distributions::Uniform; + /// + /// let mut rng = thread_rng(); + /// let x = rng.sample(Uniform::new(10u32, 15)); + /// // Type annotation requires two types, the type and distribution; the + /// // distribution can be inferred. + /// let y = rng.sample::(Uniform::new(10, 15)); + /// ``` + fn sample>(&mut self, distr: D) -> T { + distr.sample(self) + } + + /// Create an iterator that generates values using the given distribution. /// /// # Example /// - /// ```rust + /// ``` + /// use rand::{thread_rng, Rng}; + /// use rand::distributions::{Alphanumeric, Uniform, Standard}; + /// + /// let mut rng = thread_rng(); + /// + /// // Vec of 16 x f32: + /// let v: Vec = thread_rng().sample_iter(&Standard).take(16).collect(); + /// + /// // String: + /// let s: String = rng.sample_iter(&Alphanumeric).take(7).collect(); + /// + /// // Combined values + /// println!("{:?}", thread_rng().sample_iter(&Standard).take(5) + /// .collect::>()); + /// + /// // Dice-rolling: + /// let die_range = Uniform::new_inclusive(1, 6); + /// let mut roll_die = rng.sample_iter(&die_range); + /// while roll_die.next().unwrap() != 6 { + /// println!("Not a 6; rolling again!"); + /// } + /// ``` + fn sample_iter<'a, T, D: Distribution>(&'a mut self, distr: &'a D) + -> distributions::DistIter<'a, D, Self, T> where Self: Sized + { + distr.sample_iter(self) + } + + /// Fill `dest` entirely with random bytes (uniform value distribution), + /// where `dest` is any type supporting [`AsByteSliceMut`], namely slices + /// and arrays over primitive integer types (`i8`, `i16`, `u32`, etc.). + /// + /// On big-endian platforms this performs byte-swapping to ensure + /// portability of results from reproducible generators. + /// + /// This uses [`fill_bytes`] internally which may handle some RNG errors + /// implicitly (e.g. waiting if the OS generator is not ready), but panics + /// on other errors. See also [`try_fill`] which returns errors. + /// + /// # Example + /// + /// ``` + /// use rand::{thread_rng, Rng}; + /// + /// let mut arr = [0i8; 20]; + /// thread_rng().fill(&mut arr[..]); + /// ``` + /// + /// [`fill_bytes`]: RngCore::fill_bytes + /// [`try_fill`]: Rng::try_fill + fn fill(&mut self, dest: &mut T) { + self.fill_bytes(dest.as_byte_slice_mut()); + dest.to_le(); + } + + /// Fill `dest` entirely with random bytes (uniform value distribution), + /// where `dest` is any type supporting [`AsByteSliceMut`], namely slices + /// and arrays over primitive integer types (`i8`, `i16`, `u32`, etc.). + /// + /// On big-endian platforms this performs byte-swapping to ensure + /// portability of results from reproducible generators. + /// + /// This uses [`try_fill_bytes`] internally and forwards all RNG errors. In + /// some cases errors may be resolvable; see [`ErrorKind`] and + /// documentation for the RNG in use. If you do not plan to handle these + /// errors you may prefer to use [`fill`]. + /// + /// # Example + /// + /// ``` + /// # use rand::Error; + /// use rand::{thread_rng, Rng}; + /// + /// # fn try_inner() -> Result<(), Error> { + /// let mut arr = [0u64; 4]; + /// thread_rng().try_fill(&mut arr[..])?; + /// # Ok(()) + /// # } + /// + /// # try_inner().unwrap() + /// ``` + /// + /// [`try_fill_bytes`]: RngCore::try_fill_bytes + /// [`fill`]: Rng::fill + fn try_fill(&mut self, dest: &mut T) -> Result<(), Error> { + self.try_fill_bytes(dest.as_byte_slice_mut())?; + dest.to_le(); + Ok(()) + } + + /// Return a bool with a probability `p` of being true. + /// + /// See also the [`Bernoulli`] distribution, which may be faster if + /// sampling from the same probability repeatedly. + /// + /// # Example + /// + /// ``` /// use rand::{thread_rng, Rng}; /// /// let mut rng = thread_rng(); - /// println!("{}", rng.gen_weighted_bool(3)); + /// println!("{}", rng.gen_bool(1.0 / 3.0)); /// ``` - fn gen_weighted_bool(&mut self, n: u32) -> bool where Self: Sized { - n <= 1 || self.gen_range(0, n) == 0 + /// + /// # Panics + /// + /// If `p < 0` or `p > 1`. + /// + /// [`Bernoulli`]: distributions::bernoulli::Bernoulli + #[inline] + fn gen_bool(&mut self, p: f64) -> bool { + let d = distributions::Bernoulli::new(p); + self.sample(d) } - /// Return an iterator of random characters from the set A-Z,a-z,0-9. + /// Return a bool with a probability of `numerator/denominator` of being + /// true. I.e. `gen_ratio(2, 3)` has chance of 2 in 3, or about 67%, of + /// returning true. If `numerator == denominator`, then the returned value + /// is guaranteed to be `true`. If `numerator == 0`, then the returned + /// value is guaranteed to be `false`. + /// + /// See also the [`Bernoulli`] distribution, which may be faster if + /// sampling from the same `numerator` and `denominator` repeatedly. + /// + /// # Panics + /// + /// If `denominator == 0` or `numerator > denominator`. /// /// # Example /// - /// ```rust + /// ``` /// use rand::{thread_rng, Rng}; /// - /// let s: String = thread_rng().gen_ascii_chars().take(10).collect(); - /// println!("{}", s); + /// let mut rng = thread_rng(); + /// println!("{}", rng.gen_ratio(2, 3)); /// ``` - fn gen_ascii_chars<'a>(&'a mut self) -> AsciiGenerator<'a, Self> where Self: Sized { - AsciiGenerator { rng: self } + /// + /// [`Bernoulli`]: distributions::bernoulli::Bernoulli + #[inline] + fn gen_ratio(&mut self, numerator: u32, denominator: u32) -> bool { + let d = distributions::Bernoulli::from_ratio(numerator, denominator); + self.sample(d) } /// Return a random element from `values`. /// - /// Return `None` if `values` is empty. - /// - /// # Example - /// - /// ``` - /// use rand::{thread_rng, Rng}; - /// - /// let choices = [1, 2, 4, 8, 16, 32]; - /// let mut rng = thread_rng(); - /// println!("{:?}", rng.choose(&choices)); - /// assert_eq!(rng.choose(&choices[..0]), None); - /// ``` - fn choose<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T> where Self: Sized { - if values.is_empty() { - None - } else { - Some(&values[self.gen_range(0, values.len())]) - } + /// Deprecated: use [`seq::SliceRandom::choose`] instead. + #[deprecated(since="0.6.0", note="use SliceRandom::choose instead")] + fn choose<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T> { + use seq::SliceRandom; + values.choose(self) } /// Return a mutable pointer to a random element from `values`. /// - /// Return `None` if `values` is empty. - fn choose_mut<'a, T>(&mut self, values: &'a mut [T]) -> Option<&'a mut T> where Self: Sized { - if values.is_empty() { - None - } else { - let len = values.len(); - Some(&mut values[self.gen_range(0, len)]) - } + /// Deprecated: use [`seq::SliceRandom::choose_mut`] instead. + #[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> { + use seq::SliceRandom; + values.choose_mut(self) } /// Shuffle a mutable slice in place. /// - /// This applies Durstenfeld's algorithm for the [Fisher–Yates shuffle](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm) - /// which produces an unbiased permutation. - /// - /// # Example - /// - /// ```rust - /// use rand::{thread_rng, Rng}; - /// - /// let mut rng = thread_rng(); - /// let mut y = [1, 2, 3]; - /// rng.shuffle(&mut y); - /// println!("{:?}", y); - /// rng.shuffle(&mut y); - /// println!("{:?}", y); - /// ``` - fn shuffle(&mut self, values: &mut [T]) where Self: Sized { - let mut i = values.len(); - while i >= 2 { - // invariant: elements with index >= i have been locked in place. - i -= 1; - // lock element i in place. - values.swap(i, self.gen_range(0, i + 1)); - } + /// Deprecated: use [`seq::SliceRandom::shuffle`] instead. + #[deprecated(since="0.6.0", note="use SliceRandom::shuffle instead")] + fn shuffle(&mut self, values: &mut [T]) { + use seq::SliceRandom; + values.shuffle(self) } } -impl<'a, R: ?Sized> Rng for &'a mut R where R: Rng { - fn next_u32(&mut self) -> u32 { - (**self).next_u32() - } +impl Rng for R {} - fn next_u64(&mut self) -> u64 { - (**self).next_u64() - } +/// Trait for casting types to byte slices +/// +/// This is used by the [`Rng::fill`] and [`Rng::try_fill`] methods. +pub trait AsByteSliceMut { + /// Return a mutable reference to self as a byte slice + fn as_byte_slice_mut(&mut self) -> &mut [u8]; - fn next_f32(&mut self) -> f32 { - (**self).next_f32() - } - - fn next_f64(&mut self) -> f64 { - (**self).next_f64() - } - - fn fill_bytes(&mut self, dest: &mut [u8]) { - (**self).fill_bytes(dest) - } + /// Call `to_le` on each element (i.e. byte-swap on Big Endian platforms). + fn to_le(&mut self); } -#[cfg(feature="std")] -impl Rng for Box where R: Rng { - fn next_u32(&mut self) -> u32 { - (**self).next_u32() +impl AsByteSliceMut for [u8] { + fn as_byte_slice_mut(&mut self) -> &mut [u8] { + self } - fn next_u64(&mut self) -> u64 { - (**self).next_u64() - } - - fn next_f32(&mut self) -> f32 { - (**self).next_f32() - } - - fn next_f64(&mut self) -> f64 { - (**self).next_f64() - } - - fn fill_bytes(&mut self, dest: &mut [u8]) { - (**self).fill_bytes(dest) - } + fn to_le(&mut self) {} } -/// Iterator which will generate a stream of random items. -/// -/// This iterator is created via the [`gen_iter`] method on [`Rng`]. -/// -/// [`gen_iter`]: trait.Rng.html#method.gen_iter -/// [`Rng`]: trait.Rng.html -#[derive(Debug)] -pub struct Generator<'a, T, R:'a> { - rng: &'a mut R, - _marker: marker::PhantomData T>, -} - -impl<'a, T: Rand, R: Rng> Iterator for Generator<'a, T, R> { - type Item = T; - - fn next(&mut self) -> Option { - Some(self.rng.gen()) - } -} - -/// Iterator which will continuously generate random ascii characters. -/// -/// This iterator is created via the [`gen_ascii_chars`] method on [`Rng`]. -/// -/// [`gen_ascii_chars`]: trait.Rng.html#method.gen_ascii_chars -/// [`Rng`]: trait.Rng.html -#[derive(Debug)] -pub struct AsciiGenerator<'a, R:'a> { - rng: &'a mut R, -} - -impl<'a, R: Rng> Iterator for AsciiGenerator<'a, R> { - type Item = char; - - fn next(&mut self) -> Option { - const GEN_ASCII_STR_CHARSET: &'static [u8] = - b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ - abcdefghijklmnopqrstuvwxyz\ - 0123456789"; - Some(*self.rng.choose(GEN_ASCII_STR_CHARSET).unwrap() as char) - } -} - -/// A random number generator that can be explicitly seeded to produce -/// the same stream of randomness multiple times. -pub trait SeedableRng: Rng { - /// Reseed an RNG with the given seed. - /// - /// # Example - /// - /// ```rust - /// use rand::{Rng, SeedableRng, StdRng}; - /// - /// let seed: &[_] = &[1, 2, 3, 4]; - /// let mut rng: StdRng = SeedableRng::from_seed(seed); - /// println!("{}", rng.gen::()); - /// rng.reseed(&[5, 6, 7, 8]); - /// println!("{}", rng.gen::()); - /// ``` - fn reseed(&mut self, Seed); - - /// Create a new RNG with the given seed. - /// - /// # Example - /// - /// ```rust - /// use rand::{Rng, SeedableRng, StdRng}; - /// - /// let seed: &[_] = &[1, 2, 3, 4]; - /// let mut rng: StdRng = SeedableRng::from_seed(seed); - /// println!("{}", rng.gen::()); - /// ``` - fn from_seed(seed: Seed) -> Self; -} - -/// A wrapper for generating floating point numbers uniformly in the -/// open interval `(0,1)` (not including either endpoint). -/// -/// Use `Closed01` for the closed interval `[0,1]`, and the default -/// `Rand` implementation for `f32` and `f64` for the half-open -/// `[0,1)`. -/// -/// # Example -/// ```rust -/// use rand::{random, Open01}; -/// -/// let Open01(val) = random::>(); -/// println!("f32 from (0,1): {}", val); -/// ``` -#[derive(Debug)] -pub struct Open01(pub F); - -/// A wrapper for generating floating point numbers uniformly in the -/// closed interval `[0,1]` (including both endpoints). -/// -/// Use `Open01` for the closed interval `(0,1)`, and the default -/// `Rand` implementation of `f32` and `f64` for the half-open -/// `[0,1)`. -/// -/// # Example -/// -/// ```rust -/// use rand::{random, Closed01}; -/// -/// let Closed01(val) = random::>(); -/// println!("f32 from [0,1]: {}", val); -/// ``` -#[derive(Debug)] -pub struct Closed01(pub F); - -/// The standard RNG. This is designed to be efficient on the current -/// platform. -#[derive(Copy, Clone, Debug)] -pub struct StdRng { - rng: IsaacWordRng, -} - -impl StdRng { - /// Create a randomly seeded instance of `StdRng`. - /// - /// This is a very expensive operation as it has to read - /// randomness from the operating system and use this in an - /// expensive seeding operation. If one is only generating a small - /// number of random numbers, or doesn't need the utmost speed for - /// generating each number, `thread_rng` and/or `random` may be more - /// appropriate. - /// - /// Reading the randomness from the OS may fail, and any error is - /// propagated via the `io::Result` return value. - #[cfg(feature="std")] - pub fn new() -> io::Result { - match OsRng::new() { - Ok(mut r) => Ok(StdRng { rng: r.gen() }), - Err(e1) => { - match JitterRng::new() { - Ok(mut r) => Ok(StdRng { rng: r.gen() }), - Err(_) => { - Err(e1) +macro_rules! impl_as_byte_slice { + ($t:ty) => { + impl AsByteSliceMut for [$t] { + fn as_byte_slice_mut(&mut self) -> &mut [u8] { + if self.len() == 0 { + unsafe { + // must not use null pointer + slice::from_raw_parts_mut(0x1 as *mut u8, 0) } + } else { + unsafe { + slice::from_raw_parts_mut(&mut self[0] + as *mut $t + as *mut u8, + self.len() * mem::size_of::<$t>() + ) + } + } + } + + fn to_le(&mut self) { + for x in self { + *x = x.to_le(); } } } } } -impl Rng for StdRng { - #[inline] - fn next_u32(&mut self) -> u32 { - self.rng.next_u32() - } +impl_as_byte_slice!(u16); +impl_as_byte_slice!(u32); +impl_as_byte_slice!(u64); +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] impl_as_byte_slice!(u128); +impl_as_byte_slice!(usize); +impl_as_byte_slice!(i8); +impl_as_byte_slice!(i16); +impl_as_byte_slice!(i32); +impl_as_byte_slice!(i64); +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] impl_as_byte_slice!(i128); +impl_as_byte_slice!(isize); - #[inline] - fn next_u64(&mut self) -> u64 { - self.rng.next_u64() - } -} +macro_rules! impl_as_byte_slice_arrays { + ($n:expr,) => {}; + ($n:expr, $N:ident, $($NN:ident,)*) => { + impl_as_byte_slice_arrays!($n - 1, $($NN,)*); -impl<'a> SeedableRng<&'a [usize]> for StdRng { - fn reseed(&mut self, seed: &'a [usize]) { - // the internal RNG can just be seeded from the above - // randomness. - self.rng.reseed(unsafe {mem::transmute(seed)}) - } + impl AsByteSliceMut for [T; $n] where [T]: AsByteSliceMut { + fn as_byte_slice_mut(&mut self) -> &mut [u8] { + self[..].as_byte_slice_mut() + } - fn from_seed(seed: &'a [usize]) -> StdRng { - StdRng { rng: SeedableRng::from_seed(unsafe {mem::transmute(seed)}) } - } -} - -/// Create a weak random number generator with a default algorithm and seed. -/// -/// It returns the fastest `Rng` algorithm currently available in Rust without -/// consideration for cryptography or security. If you require a specifically -/// seeded `Rng` for consistency over time you should pick one algorithm and -/// create the `Rng` yourself. -/// -/// This will seed the generator with randomness from thread_rng. -#[cfg(feature="std")] -pub fn weak_rng() -> XorShiftRng { - thread_rng().gen() -} - -/// Controls how the thread-local RNG is reseeded. -#[cfg(feature="std")] -#[derive(Debug)] -struct ThreadRngReseeder; - -#[cfg(feature="std")] -impl reseeding::Reseeder for ThreadRngReseeder { - fn reseed(&mut self, rng: &mut StdRng) { - match StdRng::new() { - Ok(r) => *rng = r, - Err(e) => panic!("No entropy available: {}", e), + fn to_le(&mut self) { + self[..].to_le() + } } - } -} -#[cfg(feature="std")] -const THREAD_RNG_RESEED_THRESHOLD: u64 = 32_768; -#[cfg(feature="std")] -type ThreadRngInner = reseeding::ReseedingRng; + }; + (!div $n:expr,) => {}; + (!div $n:expr, $N:ident, $($NN:ident,)*) => { + impl_as_byte_slice_arrays!(!div $n / 2, $($NN,)*); -/// The thread-local RNG. -#[cfg(feature="std")] -#[derive(Clone, Debug)] -pub struct ThreadRng { - rng: Rc>, -} + impl AsByteSliceMut for [T; $n] where [T]: AsByteSliceMut { + fn as_byte_slice_mut(&mut self) -> &mut [u8] { + self[..].as_byte_slice_mut() + } -/// Retrieve the lazily-initialized thread-local random number -/// generator, seeded by the system. Intended to be used in method -/// chaining style, e.g. `thread_rng().gen::()`. + fn to_le(&mut self) { + self[..].to_le() + } + } + }; +} +impl_as_byte_slice_arrays!(32, N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,); +impl_as_byte_slice_arrays!(!div 4096, N,N,N,N,N,N,N,); + + +/// A convenience extension to [`SeedableRng`] allowing construction from fresh +/// entropy. This trait is automatically implemented for any PRNG implementing +/// [`SeedableRng`] and is not intended to be implemented by users. /// -/// After generating a certain amount of randomness, the RNG will reseed itself -/// from the operating system or, if the operating system RNG returns an error, -/// a seed based on the current system time. +/// This is equivalent to using `SeedableRng::from_rng(EntropyRng::new())` then +/// unwrapping the result. /// -/// The internal RNG used is platform and architecture dependent, even -/// if the operating system random number generator is rigged to give -/// the same sequence always. If absolute consistency is required, -/// explicitly select an RNG, e.g. `IsaacRng` or `Isaac64Rng`. +/// Since this is convenient and secure, it is the recommended way to create +/// PRNGs, though two alternatives may be considered: +/// +/// * Deterministic creation using [`SeedableRng::from_seed`] with a fixed seed +/// * Seeding from `thread_rng`: `SeedableRng::from_rng(thread_rng())?`; +/// this will usually be faster and should also be secure, but requires +/// trusting one extra component. +/// +/// ## Example +/// +/// ``` +/// use rand::{Rng, FromEntropy}; +/// use rand::rngs::StdRng; +/// +/// let mut rng = StdRng::from_entropy(); +/// println!("Random die roll: {}", rng.gen_range(1, 7)); +/// ``` +/// +/// [`EntropyRng`]: rngs::EntropyRng #[cfg(feature="std")] -pub fn thread_rng() -> ThreadRng { - // used to make space in TLS for a random number generator - thread_local!(static THREAD_RNG_KEY: Rc> = { - let r = match StdRng::new() { - Ok(r) => r, - Err(e) => panic!("No entropy available: {}", e), - }; - let rng = reseeding::ReseedingRng::new(r, - THREAD_RNG_RESEED_THRESHOLD, - ThreadRngReseeder); - Rc::new(RefCell::new(rng)) - }); - - ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) } +pub trait FromEntropy: SeedableRng { + /// Creates a new instance, automatically seeded with fresh entropy. + /// + /// Normally this will use `OsRng`, but if that fails `JitterRng` will be + /// used instead. Both should be suitable for cryptography. It is possible + /// that both entropy sources will fail though unlikely; failures would + /// almost certainly be platform limitations or build issues, i.e. most + /// applications targetting PC/mobile platforms should not need to worry + /// about this failing. + /// + /// # Panics + /// + /// If all entropy sources fail this will panic. If you need to handle + /// errors, use the following code, equivalent aside from error handling: + /// + /// ``` + /// # use rand::Error; + /// use rand::prelude::*; + /// use rand::rngs::EntropyRng; + /// + /// # fn try_inner() -> Result<(), Error> { + /// // This uses StdRng, but is valid for any R: SeedableRng + /// let mut rng = StdRng::from_rng(EntropyRng::new())?; + /// + /// println!("random number: {}", rng.gen_range(1, 10)); + /// # Ok(()) + /// # } + /// + /// # try_inner().unwrap() + /// ``` + fn from_entropy() -> Self; } #[cfg(feature="std")] -impl Rng for ThreadRng { - fn next_u32(&mut self) -> u32 { - self.rng.borrow_mut().next_u32() - } - - fn next_u64(&mut self) -> u64 { - self.rng.borrow_mut().next_u64() - } - - #[inline] - fn fill_bytes(&mut self, bytes: &mut [u8]) { - self.rng.borrow_mut().fill_bytes(bytes) +impl FromEntropy for R { + fn from_entropy() -> R { + R::from_rng(rngs::EntropyRng::new()).unwrap_or_else(|err| + panic!("FromEntropy::from_entropy() failed: {}", err)) } } + /// Generates a random value using the thread-local random number generator. /// -/// `random()` can generate various types of random things, and so may require -/// type hinting to generate the specific type you want. -/// -/// This function uses the thread local random number generator. This means -/// that if you're calling `random()` in a loop, caching the generator can -/// increase performance. An example is shown below. +/// This is simply a shortcut for `thread_rng().gen()`. See [`thread_rng`] for +/// documentation of the entropy source and [`Standard`] for documentation of +/// distributions and type-specific generation. /// /// # Examples /// @@ -931,7 +625,8 @@ impl Rng for ThreadRng { /// } /// ``` /// -/// Caching the thread local random number generator: +/// If you're calling `random()` in a loop, caching the generator as in the +/// following example can increase performance. /// /// ``` /// use rand::Rng; @@ -950,93 +645,53 @@ impl Rng for ThreadRng { /// *x = rng.gen(); /// } /// ``` +/// +/// [`Standard`]: distributions::Standard #[cfg(feature="std")] #[inline] -pub fn random() -> T { +pub fn random() -> T where Standard: Distribution { thread_rng().gen() } -/// DEPRECATED: use `seq::sample_iter` instead. -/// -/// Randomly sample up to `amount` elements from a finite iterator. -/// The order of elements in the sample is not random. -/// -/// # Example -/// -/// ```rust -/// use rand::{thread_rng, sample}; -/// -/// let mut rng = thread_rng(); -/// let sample = sample(&mut rng, 1..100, 5); -/// println!("{:?}", sample); -/// ``` -#[cfg(feature="std")] -#[inline(always)] -#[deprecated(since="0.4.0", note="renamed to seq::sample_iter")] -pub fn sample(rng: &mut R, iterable: I, amount: usize) -> Vec - where I: IntoIterator, - R: Rng, -{ - // the legacy sample didn't care whether amount was met - seq::sample_iter(rng, iterable, amount) - .unwrap_or_else(|e| e) -} - #[cfg(test)] mod test { - use super::{Rng, thread_rng, random, SeedableRng, StdRng, weak_rng}; - use std::iter::repeat; + use rngs::mock::StepRng; + use rngs::StdRng; + use super::*; + #[cfg(all(not(feature="std"), feature="alloc"))] use alloc::boxed::Box; - pub struct MyRng { inner: R } + pub struct TestRng { inner: R } - impl Rng for MyRng { + impl RngCore for TestRng { fn next_u32(&mut self) -> u32 { - fn next(t: &mut T) -> u32 { - t.next_u32() - } - next(&mut self.inner) + self.inner.next_u32() + } + fn next_u64(&mut self) -> u64 { + self.inner.next_u64() + } + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.inner.fill_bytes(dest) + } + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.inner.try_fill_bytes(dest) } } - pub fn rng() -> MyRng<::ThreadRng> { - MyRng { inner: ::thread_rng() } - } - - struct ConstRng { i: u64 } - impl Rng for ConstRng { - fn next_u32(&mut self) -> u32 { self.i as u32 } - fn next_u64(&mut self) -> u64 { self.i } - - // no fill_bytes on purpose - } - - pub fn iter_eq(i: I, j: J) -> bool - where I: IntoIterator, - J: IntoIterator, - I::Item: Eq - { - // make sure the iterators have equal length - let mut i = i.into_iter(); - let mut j = j.into_iter(); - loop { - match (i.next(), j.next()) { - (Some(ref ei), Some(ref ej)) if ei == ej => { } - (None, None) => return true, - _ => return false, - } - } + pub fn rng(seed: u64) -> TestRng { + TestRng { inner: StdRng::seed_from_u64(seed) } } #[test] fn test_fill_bytes_default() { - let mut r = ConstRng { i: 0x11_22_33_44_55_66_77_88 }; + let mut r = StepRng::new(0x11_22_33_44_55_66_77_88, 0); // check every remainder mod 8, both in small and big vectors. let lengths = [0, 1, 2, 3, 4, 5, 6, 7, 80, 81, 82, 83, 84, 85, 86, 87]; for &n in lengths.iter() { - let mut v = repeat(0u8).take(n).collect::>(); - r.fill_bytes(&mut v); + let mut buffer = [0u8; 87]; + let v = &mut buffer[0..n]; + r.fill_bytes(v); // use this to get nicer error messages. for (i, &byte) in v.iter().enumerate() { @@ -1048,127 +703,100 @@ mod test { } #[test] - fn test_gen_range() { - let mut r = thread_rng(); - for _ in 0..1000 { - let a = r.gen_range(-3, 42); - assert!(a >= -3 && a < 42); - assert_eq!(r.gen_range(0, 1), 0); - assert_eq!(r.gen_range(-12, -11), -12); - } + 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]; + let mut rng = StepRng::new(0, 1); + rng.fill(&mut array); + rng.fill(&mut array[..]); + } + + #[test] + fn test_gen_range() { + let mut r = rng(101); for _ in 0..1000 { - let a = r.gen_range(10, 42); - assert!(a >= 10 && a < 42); - assert_eq!(r.gen_range(0, 1), 0); + let a = r.gen_range(-4711, 17); + assert!(a >= -4711 && a < 17); + let a = r.gen_range(-3i8, 42); + assert!(a >= -3i8 && a < 42i8); + let a = r.gen_range(&10u16, 99); + assert!(a >= 10u16 && a < 99u16); + let a = r.gen_range(-100i32, &2000); + assert!(a >= -100i32 && a < 2000i32); + let a = r.gen_range(&12u32, &24u32); + assert!(a >= 12u32 && a < 24u32); + + assert_eq!(r.gen_range(0u32, 1), 0u32); + assert_eq!(r.gen_range(-12i64, -11), -12i64); assert_eq!(r.gen_range(3_000_000, 3_000_001), 3_000_000); } - } #[test] #[should_panic] fn test_gen_range_panic_int() { - let mut r = thread_rng(); + let mut r = rng(102); r.gen_range(5, -2); } #[test] #[should_panic] fn test_gen_range_panic_usize() { - let mut r = thread_rng(); + let mut r = rng(103); r.gen_range(5, 2); } #[test] - fn test_gen_weighted_bool() { - let mut r = thread_rng(); - assert_eq!(r.gen_weighted_bool(0), true); - assert_eq!(r.gen_weighted_bool(1), true); - } - - #[test] - fn test_gen_ascii_str() { - let mut r = thread_rng(); - assert_eq!(r.gen_ascii_chars().take(0).count(), 0); - assert_eq!(r.gen_ascii_chars().take(10).count(), 10); - assert_eq!(r.gen_ascii_chars().take(16).count(), 16); - } - - #[test] - fn test_gen_vec() { - let mut r = thread_rng(); - assert_eq!(r.gen_iter::().take(0).count(), 0); - assert_eq!(r.gen_iter::().take(10).count(), 10); - assert_eq!(r.gen_iter::().take(16).count(), 16); - } - - #[test] - fn test_choose() { - let mut r = thread_rng(); - assert_eq!(r.choose(&[1, 1, 1]).map(|&x|x), Some(1)); - - let v: &[isize] = &[]; - assert_eq!(r.choose(v), None); - } - - #[test] - fn test_shuffle() { - let mut r = thread_rng(); - let empty: &mut [isize] = &mut []; - r.shuffle(empty); - let mut one = [1]; - r.shuffle(&mut one); - let b: &[_] = &[1]; - assert_eq!(one, b); - - let mut two = [1, 2]; - r.shuffle(&mut two); - assert!(two == [1, 2] || two == [2, 1]); - - let mut x = [1, 1, 1]; - r.shuffle(&mut x); - let b: &[_] = &[1, 1, 1]; - assert_eq!(x, b); - } - - #[test] - fn test_thread_rng() { - let mut r = thread_rng(); - r.gen::(); - let mut v = [1, 1, 1]; - r.shuffle(&mut v); - let b: &[_] = &[1, 1, 1]; - assert_eq!(v, b); - assert_eq!(r.gen_range(0, 1), 0); + fn test_gen_bool() { + let mut r = rng(105); + for _ in 0..5 { + assert_eq!(r.gen_bool(0.0), false); + assert_eq!(r.gen_bool(1.0), true); + } } #[test] fn test_rng_trait_object() { - let mut rng = thread_rng(); - { - let mut r = &mut rng as &mut Rng; - r.next_u32(); - (&mut r).gen::(); - let mut v = [1, 1, 1]; - (&mut r).shuffle(&mut v); - let b: &[_] = &[1, 1, 1]; - assert_eq!(v, b); - assert_eq!((&mut r).gen_range(0, 1), 0); - } - { - let mut r = Box::new(rng) as Box; - r.next_u32(); - r.gen::(); - let mut v = [1, 1, 1]; - r.shuffle(&mut v); - let b: &[_] = &[1, 1, 1]; - assert_eq!(v, b); - assert_eq!(r.gen_range(0, 1), 0); - } + use distributions::{Distribution, Standard}; + let mut rng = rng(109); + let mut r = &mut rng as &mut RngCore; + r.next_u32(); + r.gen::(); + assert_eq!(r.gen_range(0, 1), 0); + let _c: u8 = Standard.sample(&mut r); } #[test] + #[cfg(feature="alloc")] + fn test_rng_boxed_trait() { + use distributions::{Distribution, Standard}; + let rng = rng(110); + let mut r = Box::new(rng) as Box; + r.next_u32(); + r.gen::(); + assert_eq!(r.gen_range(0, 1), 0); + let _c: u8 = Standard.sample(&mut r); + } + + #[test] + #[cfg(feature="std")] fn test_random() { // not sure how to test this aside from just getting some values let _n : usize = random(); @@ -1183,32 +811,20 @@ mod test { } #[test] - fn test_std_rng_seeded() { - let s = thread_rng().gen_iter::().take(256).collect::>(); - let mut ra: StdRng = SeedableRng::from_seed(&s[..]); - let mut rb: StdRng = SeedableRng::from_seed(&s[..]); - assert!(iter_eq(ra.gen_ascii_chars().take(100), - rb.gen_ascii_chars().take(100))); - } + fn test_gen_ratio_average() { + const NUM: u32 = 3; + const DENOM: u32 = 10; + const N: u32 = 100_000; - #[test] - fn test_std_rng_reseed() { - let s = thread_rng().gen_iter::().take(256).collect::>(); - let mut r: StdRng = SeedableRng::from_seed(&s[..]); - let string1 = r.gen_ascii_chars().take(100).collect::(); - - r.reseed(&s); - - let string2 = r.gen_ascii_chars().take(100).collect::(); - assert_eq!(string1, string2); - } - - #[test] - fn test_weak_rng() { - let s = weak_rng().gen_iter::().take(256).collect::>(); - let mut ra: StdRng = SeedableRng::from_seed(&s[..]); - let mut rb: StdRng = SeedableRng::from_seed(&s[..]); - assert!(iter_eq(ra.gen_ascii_chars().take(100), - rb.gen_ascii_chars().take(100))); + let mut sum: u32 = 0; + let mut rng = rng(111); + for _ in 0..N { + if rng.gen_ratio(NUM, DENOM) { + sum += 1; + } + } + // Have Binomial(N, NUM/DENOM) distribution + let expected = (NUM * N) / DENOM; // exact integer + assert!(((sum - expected) as i32).abs() < 500); } } diff --git a/third_party/rust/rand/src/prelude.rs b/third_party/rust/rand/src/prelude.rs new file mode 100644 index 000000000000..5d8a0e9b2aa0 --- /dev/null +++ b/third_party/rust/rand/src/prelude.rs @@ -0,0 +1,27 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Convenience re-export of common members +//! +//! Like the standard library's prelude, this module simplifies importing of +//! common items. Unlike the standard prelude, the contents of this module must +//! be imported manually: +//! +//! ``` +//! use rand::prelude::*; +//! # let _ = StdRng::from_entropy(); +//! # let mut r = SmallRng::from_rng(thread_rng()).unwrap(); +//! # let _: f32 = r.gen(); +//! ``` + +#[doc(no_inline)] pub use distributions::Distribution; +#[doc(no_inline)] pub use rngs::{SmallRng, StdRng}; +#[doc(no_inline)] #[cfg(feature="std")] pub use rngs::ThreadRng; +#[doc(no_inline)] pub use {Rng, RngCore, CryptoRng, SeedableRng}; +#[doc(no_inline)] #[cfg(feature="std")] pub use {FromEntropy, random, thread_rng}; +#[doc(no_inline)] pub use seq::{SliceRandom, IteratorRandom}; diff --git a/third_party/rust/rand/src/prng/mod.rs b/third_party/rust/rand/src/prng/mod.rs index ed3e01886495..3c0d27b2e8c1 100644 --- a/third_party/rust/rand/src/prng/mod.rs +++ b/third_party/rust/rand/src/prng/mod.rs @@ -1,51 +1,37 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. +// Copyright 2018 Developers of the Rand project. // // Licensed under the Apache License, Version 2.0 or the MIT license -// , at your +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Pseudo random number generators are algorithms to produce *apparently -//! random* numbers deterministically, and usually fairly quickly. +//! Pseudo-random number generators. +//! +//! This module is deprecated: //! -//! So long as the algorithm is computationally secure, is initialised with -//! sufficient entropy (i.e. unknown by an attacker), and its internal state is -//! also protected (unknown to an attacker), the output will also be -//! *computationally secure*. Computationally Secure Pseudo Random Number -//! Generators (CSPRNGs) are thus suitable sources of random numbers for -//! cryptography. There are a couple of gotchas here, however. First, the seed -//! used for initialisation must be unknown. Usually this should be provided by -//! the operating system and should usually be secure, however this may not -//! always be the case (especially soon after startup). Second, user-space -//! memory may be vulnerable, for example when written to swap space, and after -//! forking a child process should reinitialise any user-space PRNGs. For this -//! reason it may be preferable to source random numbers directly from the OS -//! for cryptographic applications. -//! -//! PRNGs are also widely used for non-cryptographic uses: randomised -//! algorithms, simulations, games. In these applications it is usually not -//! important for numbers to be cryptographically *unguessable*, but even -//! distribution and independence from other samples (from the point of view -//! of someone unaware of the algorithm used, at least) may still be important. -//! Good PRNGs should satisfy these properties, but do not take them for -//! granted; Wikipedia's article on -//! [Pseudorandom number generators](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) -//! provides some background on this topic. -//! -//! Care should be taken when seeding (initialising) PRNGs. Some PRNGs have -//! short periods for some seeds. If one PRNG is seeded from another using the -//! same algorithm, it is possible that both will yield the same sequence of -//! values (with some lag). +//! - documentation has moved to +//! [The Book](https://rust-random.github.io/book/guide-rngs.html), +//! - PRNGs have moved to other `rand_*` crates. -mod chacha; -mod isaac; -mod isaac64; -mod xorshift; - -pub use self::chacha::ChaChaRng; -pub use self::isaac::IsaacRng; -pub use self::isaac64::Isaac64Rng; -pub use self::xorshift::XorShiftRng; +// Deprecations (to be removed in 0.7) +#[doc(hidden)] #[allow(deprecated)] +pub use deprecated::XorShiftRng; +#[doc(hidden)] pub mod isaac { + // Note: we miss `IsaacCore` here but probably unimportant. + #[allow(deprecated)] pub use deprecated::IsaacRng; +} +#[doc(hidden)] pub mod isaac64 { + #[allow(deprecated)] pub use deprecated::Isaac64Rng; +} +#[doc(hidden)] #[allow(deprecated)] pub use deprecated::{IsaacRng, Isaac64Rng}; +#[doc(hidden)] pub mod chacha { + // Note: we miss `ChaChaCore` here but probably unimportant. + #[allow(deprecated)] pub use deprecated::ChaChaRng; +} +#[doc(hidden)] #[allow(deprecated)] pub use deprecated::ChaChaRng; +#[doc(hidden)] pub mod hc128 { + // Note: we miss `Hc128Core` here but probably unimportant. + #[allow(deprecated)] pub use deprecated::Hc128Rng; +} +#[doc(hidden)] #[allow(deprecated)] pub use deprecated::Hc128Rng; diff --git a/third_party/rust/rand/src/rngs/adapter/mod.rs b/third_party/rust/rand/src/rngs/adapter/mod.rs new file mode 100644 index 000000000000..60b832e9a4d2 --- /dev/null +++ b/third_party/rust/rand/src/rngs/adapter/mod.rs @@ -0,0 +1,15 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Wrappers / adapters forming RNGs + +#[cfg(feature="std")] #[doc(hidden)] pub mod read; +mod reseeding; + +#[cfg(feature="std")] pub use self::read::ReadRng; +pub use self::reseeding::ReseedingRng; diff --git a/third_party/rust/rand/src/rngs/adapter/read.rs b/third_party/rust/rand/src/rngs/adapter/read.rs new file mode 100644 index 000000000000..9b9c18b3ebc6 --- /dev/null +++ b/third_party/rust/rand/src/rngs/adapter/read.rs @@ -0,0 +1,136 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A wrapper around any Read to treat it as an RNG. + +use std::io::Read; + +use rand_core::{RngCore, Error, ErrorKind, impls}; + + +/// An RNG that reads random bytes straight from any type supporting +/// [`std::io::Read`], for example files. +/// +/// This will work best with an infinite reader, but that is not required. +/// +/// This can be used with `/dev/urandom` on Unix but it is recommended to use +/// [`OsRng`] instead. +/// +/// # Panics +/// +/// `ReadRng` uses [`std::io::Read::read_exact`], which retries on interrupts. +/// All other errors from the underlying reader, including when it does not +/// have enough data, will only be reported through [`try_fill_bytes`]. +/// The other [`RngCore`] methods will panic in case of an error. +/// +/// # Example +/// +/// ``` +/// use rand::Rng; +/// use rand::rngs::adapter::ReadRng; +/// +/// let data = vec![1, 2, 3, 4, 5, 6, 7, 8]; +/// let mut rng = ReadRng::new(&data[..]); +/// println!("{:x}", rng.gen::()); +/// ``` +/// +/// [`OsRng`]: rand_os::OsRng +/// [`try_fill_bytes`]: RngCore::try_fill_bytes +#[derive(Debug)] +pub struct ReadRng { + reader: R +} + +impl ReadRng { + /// Create a new `ReadRng` from a `Read`. + pub fn new(r: R) -> ReadRng { + ReadRng { + reader: r + } + } +} + +impl RngCore for ReadRng { + fn next_u32(&mut self) -> u32 { + impls::next_u32_via_fill(self) + } + + fn next_u64(&mut self) -> u64 { + impls::next_u64_via_fill(self) + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.try_fill_bytes(dest).unwrap_or_else(|err| + panic!("reading random bytes from Read implementation failed; error: {}", err)); + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + if dest.len() == 0 { return Ok(()); } + // Use `std::io::read_exact`, which retries on `ErrorKind::Interrupted`. + self.reader.read_exact(dest).map_err(|err| { + match err.kind() { + ::std::io::ErrorKind::UnexpectedEof => Error::with_cause( + ErrorKind::Unavailable, + "not enough bytes available, reached end of source", err), + _ => Error::with_cause(ErrorKind::Unavailable, + "error reading from Read source", err) + } + }) + } +} + +#[cfg(test)] +mod test { + use super::ReadRng; + use {RngCore, ErrorKind}; + + #[test] + fn test_reader_rng_u64() { + // transmute from the target to avoid endianness concerns. + let v = vec![0u8, 0, 0, 0, 0, 0, 0, 1, + 0 , 0, 0, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 3]; + let mut rng = ReadRng::new(&v[..]); + + assert_eq!(rng.next_u64(), 1_u64.to_be()); + assert_eq!(rng.next_u64(), 2_u64.to_be()); + assert_eq!(rng.next_u64(), 3_u64.to_be()); + } + + #[test] + fn test_reader_rng_u32() { + let v = vec![0u8, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3]; + let mut rng = ReadRng::new(&v[..]); + + assert_eq!(rng.next_u32(), 1_u32.to_be()); + assert_eq!(rng.next_u32(), 2_u32.to_be()); + assert_eq!(rng.next_u32(), 3_u32.to_be()); + } + + #[test] + fn test_reader_rng_fill_bytes() { + let v = [1u8, 2, 3, 4, 5, 6, 7, 8]; + let mut w = [0u8; 8]; + + let mut rng = ReadRng::new(&v[..]); + rng.fill_bytes(&mut w); + + assert!(v == w); + } + + #[test] + fn test_reader_rng_insufficient_bytes() { + let v = [1u8, 2, 3, 4, 5, 6, 7, 8]; + let mut w = [0u8; 9]; + + let mut rng = ReadRng::new(&v[..]); + + assert!(rng.try_fill_bytes(&mut w).err().unwrap().kind == ErrorKind::Unavailable); + } +} diff --git a/third_party/rust/rand/src/rngs/adapter/reseeding.rs b/third_party/rust/rand/src/rngs/adapter/reseeding.rs new file mode 100644 index 000000000000..ed2aab4cffaa --- /dev/null +++ b/third_party/rust/rand/src/rngs/adapter/reseeding.rs @@ -0,0 +1,370 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A wrapper around another PRNG that reseeds it after it +//! generates a certain number of random bytes. + +use core::mem::size_of; + +use rand_core::{RngCore, CryptoRng, SeedableRng, Error, ErrorKind}; +use rand_core::block::{BlockRngCore, BlockRng}; + +/// A wrapper around any PRNG that implements [`BlockRngCore`], that adds the +/// ability to reseed it. +/// +/// `ReseedingRng` reseeds the underlying PRNG in the following cases: +/// +/// - On a manual call to [`reseed()`]. +/// - After `clone()`, the clone will be reseeded on first use. +/// - After a process is forked, the RNG in the child process is reseeded within +/// the next few generated values, depending on the block size of the +/// underlying PRNG. For [`ChaChaCore`] and [`Hc128Core`] this is a maximum of +/// 15 `u32` values before reseeding. +/// - After the PRNG has generated a configurable number of random bytes. +/// +/// # When should reseeding after a fixed number of generated bytes be used? +/// +/// Reseeding after a fixed number of generated bytes is never strictly +/// *necessary*. Cryptographic PRNGs don't have a limited number of bytes they +/// can output, or at least not a limit reachable in any practical way. There is +/// no such thing as 'running out of entropy'. +/// +/// Occasionally reseeding can be seen as some form of 'security in depth'. Even +/// if in the future a cryptographic weakness is found in the CSPRNG being used, +/// or a flaw in the implementation, occasionally reseeding should make +/// exploiting it much more difficult or even impossible. +/// +/// Use [`ReseedingRng::new`] with a `threshold` of `0` to disable reseeding +/// after a fixed number of generated bytes. +/// +/// # Error handling +/// +/// Although unlikely, reseeding the wrapped PRNG can fail. `ReseedingRng` will +/// never panic but try to handle the error intelligently through some +/// combination of retrying and delaying reseeding until later. +/// If handling the source error fails `ReseedingRng` will continue generating +/// data from the wrapped PRNG without reseeding. +/// +/// Manually calling [`reseed()`] will not have this retry or delay logic, but +/// reports the error. +/// +/// # Example +/// +/// ``` +/// # extern crate rand; +/// # extern crate rand_chacha; +/// # fn main() { +/// use rand::prelude::*; +/// use rand_chacha::ChaChaCore; // Internal part of ChaChaRng that +/// // implements BlockRngCore +/// use rand::rngs::OsRng; +/// use rand::rngs::adapter::ReseedingRng; +/// +/// let prng = ChaChaCore::from_entropy(); +// FIXME: it is better to use EntropyRng as reseeder, but that doesn't implement +// clone yet. +/// let reseeder = OsRng::new().unwrap(); +/// let mut reseeding_rng = ReseedingRng::new(prng, 0, reseeder); +/// +/// println!("{}", reseeding_rng.gen::()); +/// +/// let mut cloned_rng = reseeding_rng.clone(); +/// assert!(reseeding_rng.gen::() != cloned_rng.gen::()); +/// # } +/// ``` +/// +/// [`ChaChaCore`]: rand_chacha::ChaChaCore +/// [`Hc128Core`]: rand_hc::Hc128Core +/// [`BlockRngCore`]: rand_core::block::BlockRngCore +/// [`ReseedingRng::new`]: ReseedingRng::new +/// [`reseed()`]: ReseedingRng::reseed +#[derive(Debug)] +pub struct ReseedingRng(BlockRng>) +where R: BlockRngCore + SeedableRng, + Rsdr: RngCore; + +impl ReseedingRng +where R: BlockRngCore + SeedableRng, + Rsdr: RngCore +{ + /// Create a new `ReseedingRng` from an existing PRNG, combined with a RNG + /// to use as reseeder. + /// + /// `threshold` sets the number of generated bytes after which to reseed the + /// PRNG. Set it to zero to never reseed based on the number of generated + /// values. + pub fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self { + ReseedingRng(BlockRng::new(ReseedingCore::new(rng, threshold, reseeder))) + } + + /// Reseed the internal PRNG. + pub fn reseed(&mut self) -> Result<(), Error> { + self.0.core.reseed() + } +} + +// TODO: this should be implemented for any type where the inner type +// implements RngCore, but we can't specify that because ReseedingCore is private +impl RngCore for ReseedingRng +where R: BlockRngCore + SeedableRng, + ::Results: AsRef<[u32]> + AsMut<[u32]> +{ + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl Clone for ReseedingRng +where R: BlockRngCore + SeedableRng + Clone, + Rsdr: RngCore + Clone +{ + fn clone(&self) -> ReseedingRng { + // Recreating `BlockRng` seems easier than cloning it and resetting + // the index. + ReseedingRng(BlockRng::new(self.0.core.clone())) + } +} + +impl CryptoRng for ReseedingRng +where R: BlockRngCore + SeedableRng + CryptoRng, + Rsdr: RngCore + CryptoRng {} + +#[derive(Debug)] +struct ReseedingCore { + inner: R, + reseeder: Rsdr, + threshold: i64, + bytes_until_reseed: i64, + fork_counter: usize, +} + +impl BlockRngCore for ReseedingCore +where R: BlockRngCore + SeedableRng, + Rsdr: RngCore +{ + type Item = ::Item; + type Results = ::Results; + + fn generate(&mut self, results: &mut Self::Results) { + let global_fork_counter = fork::get_fork_counter(); + if self.bytes_until_reseed <= 0 || + self.is_forked(global_fork_counter) { + // We get better performance by not calling only `reseed` here + // and continuing with the rest of the function, but by directly + // returning from a non-inlined function. + return self.reseed_and_generate(results, global_fork_counter); + } + let num_bytes = results.as_ref().len() * size_of::(); + self.bytes_until_reseed -= num_bytes as i64; + self.inner.generate(results); + } +} + +impl ReseedingCore +where R: BlockRngCore + SeedableRng, + Rsdr: RngCore +{ + /// Create a new `ReseedingCore`. + fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self { + use ::core::i64::MAX; + fork::register_fork_handler(); + + // Because generating more values than `i64::MAX` takes centuries on + // current hardware, we just clamp to that value. + // Also we set a threshold of 0, which indicates no limit, to that + // value. + let threshold = + if threshold == 0 { MAX } + else if threshold <= MAX as u64 { threshold as i64 } + else { MAX }; + + ReseedingCore { + inner: rng, + reseeder, + threshold: threshold as i64, + bytes_until_reseed: threshold as i64, + fork_counter: 0, + } + } + + /// Reseed the internal PRNG. + fn reseed(&mut self) -> Result<(), Error> { + R::from_rng(&mut self.reseeder).map(|result| { + self.bytes_until_reseed = self.threshold; + self.inner = result + }) + } + + fn is_forked(&self, global_fork_counter: usize) -> bool { + // In theory, on 32-bit platforms, it is possible for + // `global_fork_counter` to wrap around after ~4e9 forks. + // + // This check will detect a fork in the normal case where + // `fork_counter < global_fork_counter`, and also when the difference + // between both is greater than `isize::MAX` (wrapped around). + // + // It will still fail to detect a fork if there have been more than + // `isize::MAX` forks, without any reseed in between. Seems unlikely + // enough. + (self.fork_counter.wrapping_sub(global_fork_counter) as isize) < 0 + } + + #[inline(never)] + fn reseed_and_generate(&mut self, + results: &mut ::Results, + global_fork_counter: usize) + { + if self.is_forked(global_fork_counter) { + info!("Fork detected, reseeding RNG"); + } else { + trace!("Reseeding RNG (periodic reseed)"); + } + + let num_bytes = + results.as_ref().len() * size_of::<::Item>(); + + let threshold = if let Err(e) = self.reseed() { + let delay = match e.kind { + ErrorKind::Transient => num_bytes as i64, + kind @ _ if kind.should_retry() => self.threshold >> 8, + _ => self.threshold, + }; + warn!("Reseeding RNG delayed reseeding by {} bytes due to \ + error from source: {}", delay, e); + delay + } else { + self.fork_counter = global_fork_counter; + self.threshold + }; + + self.bytes_until_reseed = threshold - num_bytes as i64; + self.inner.generate(results); + } +} + +impl Clone for ReseedingCore +where R: BlockRngCore + SeedableRng + Clone, + Rsdr: RngCore + Clone +{ + fn clone(&self) -> ReseedingCore { + ReseedingCore { + inner: self.inner.clone(), + reseeder: self.reseeder.clone(), + threshold: self.threshold, + bytes_until_reseed: 0, // reseed clone on first use + fork_counter: self.fork_counter, + } + } +} + +impl CryptoRng for ReseedingCore +where R: BlockRngCore + SeedableRng + CryptoRng, + Rsdr: RngCore + CryptoRng {} + + +#[cfg(all(feature="std", unix, not(target_os="emscripten")))] +mod fork { + extern crate libc; + + use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; + use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT}; + + // Fork protection + // + // We implement fork protection on Unix using `pthread_atfork`. + // When the process is forked, we increment `RESEEDING_RNG_FORK_COUNTER`. + // Every `ReseedingRng` stores the last known value of the static in + // `fork_counter`. If the cached `fork_counter` is less than + // `RESEEDING_RNG_FORK_COUNTER`, it is time to reseed this RNG. + // + // If reseeding fails, we don't deal with this by setting a delay, but just + // don't update `fork_counter`, so a reseed is attempted as soon as + // possible. + + static RESEEDING_RNG_FORK_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; + + pub fn get_fork_counter() -> usize { + RESEEDING_RNG_FORK_COUNTER.load(Ordering::Relaxed) + } + + static FORK_HANDLER_REGISTERED: AtomicBool = ATOMIC_BOOL_INIT; + + extern fn fork_handler() { + // Note: fetch_add is defined to wrap on overflow + // (which is what we want). + RESEEDING_RNG_FORK_COUNTER.fetch_add(1, Ordering::Relaxed); + } + + pub fn register_fork_handler() { + if FORK_HANDLER_REGISTERED.load(Ordering::Relaxed) == false { + unsafe { libc::pthread_atfork(None, None, Some(fork_handler)) }; + FORK_HANDLER_REGISTERED.store(true, Ordering::Relaxed); + } + } +} + +#[cfg(not(all(feature="std", unix, not(target_os="emscripten"))))] +mod fork { + pub fn get_fork_counter() -> usize { 0 } + pub fn register_fork_handler() {} +} + + +#[cfg(test)] +mod test { + use {Rng, SeedableRng}; + use rand_chacha::ChaChaCore; + use rngs::mock::StepRng; + use super::ReseedingRng; + + #[test] + fn test_reseeding() { + let mut zero = StepRng::new(0, 0); + let rng = ChaChaCore::from_rng(&mut zero).unwrap(); + let mut reseeding = ReseedingRng::new(rng, 32*4, zero); + + // Currently we only support for arrays up to length 32. + // TODO: cannot generate seq via Rng::gen because it uses different alg + let mut buf = [0u32; 32]; // Needs to be a multiple of the RNGs result + // size to test exactly. + reseeding.fill(&mut buf); + let seq = buf; + for _ in 0..10 { + reseeding.fill(&mut buf); + assert_eq!(buf, seq); + } + } + + #[test] + fn test_clone_reseeding() { + let mut zero = StepRng::new(0, 0); + let rng = ChaChaCore::from_rng(&mut zero).unwrap(); + let mut rng1 = ReseedingRng::new(rng, 32*4, zero); + + let first: u32 = rng1.gen(); + for _ in 0..10 { let _ = rng1.gen::(); } + + let mut rng2 = rng1.clone(); + assert_eq!(first, rng2.gen::()); + } +} diff --git a/third_party/rust/rand/src/rngs/entropy.rs b/third_party/rust/rand/src/rngs/entropy.rs new file mode 100644 index 000000000000..9a2affdffc18 --- /dev/null +++ b/third_party/rust/rand/src/rngs/entropy.rs @@ -0,0 +1,248 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Entropy generator, or wrapper around external generators + +use rand_core::{RngCore, CryptoRng, Error, ErrorKind, impls}; +#[allow(unused)] +use rngs; + +/// An interface returning random data from external source(s), provided +/// specifically for securely seeding algorithmic generators (PRNGs). +/// +/// Where possible, `EntropyRng` retrieves random data from the operating +/// system's interface for random numbers ([`OsRng`]); if that fails it will +/// fall back to the [`JitterRng`] entropy collector. In the latter case it will +/// still try to use [`OsRng`] on the next usage. +/// +/// If no secure source of entropy is available `EntropyRng` will panic on use; +/// i.e. it should never output predictable data. +/// +/// This is either a little slow ([`OsRng`] requires a system call) or extremely +/// slow ([`JitterRng`] must use significant CPU time to generate sufficient +/// jitter); for better performance it is common to seed a local PRNG from +/// external entropy then primarily use the local PRNG ([`thread_rng`] is +/// provided as a convenient, local, automatically-seeded CSPRNG). +/// +/// # Panics +/// +/// On most systems, like Windows, Linux, macOS and *BSD on common hardware, it +/// is highly unlikely for both [`OsRng`] and [`JitterRng`] to fail. But on +/// combinations like webassembly without Emscripten or stdweb both sources are +/// unavailable. If both sources fail, only [`try_fill_bytes`] is able to +/// report the error, and only the one from `OsRng`. The other [`RngCore`] +/// methods will panic in case of an error. +/// +/// [`OsRng`]: rand_os::OsRng +/// [`thread_rng`]: crate::thread_rng +/// [`JitterRng`]: crate::rngs::JitterRng +/// [`try_fill_bytes`]: RngCore::try_fill_bytes +#[derive(Debug)] +pub struct EntropyRng { + source: Source, +} + +#[derive(Debug)] +enum Source { + Os(Os), + Custom(Custom), + Jitter(Jitter), + None, +} + +impl EntropyRng { + /// Create a new `EntropyRng`. + /// + /// This method will do no system calls or other initialization routines, + /// those are done on first use. This is done to make `new` infallible, + /// and `try_fill_bytes` the only place to report errors. + pub fn new() -> Self { + EntropyRng { source: Source::None } + } +} + +impl Default for EntropyRng { + fn default() -> Self { + EntropyRng::new() + } +} + +impl RngCore for EntropyRng { + fn next_u32(&mut self) -> u32 { + impls::next_u32_via_fill(self) + } + + fn next_u64(&mut self) -> u64 { + impls::next_u64_via_fill(self) + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.try_fill_bytes(dest).unwrap_or_else(|err| + panic!("all entropy sources failed; first error: {}", err)) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + let mut reported_error = None; + + if let Source::Os(ref mut os_rng) = self.source { + match os_rng.fill(dest) { + Ok(()) => return Ok(()), + Err(err) => { + warn!("EntropyRng: OsRng failed \ + [trying other entropy sources]: {}", err); + reported_error = Some(err); + }, + } + } else if Os::is_supported() { + match Os::new_and_fill(dest) { + Ok(os_rng) => { + debug!("EntropyRng: using OsRng"); + self.source = Source::Os(os_rng); + return Ok(()); + }, + Err(err) => { reported_error = reported_error.or(Some(err)) }, + } + } + + if let Source::Custom(ref mut rng) = self.source { + match rng.fill(dest) { + Ok(()) => return Ok(()), + Err(err) => { + warn!("EntropyRng: custom entropy source failed \ + [trying other entropy sources]: {}", err); + reported_error = Some(err); + }, + } + } else if Custom::is_supported() { + match Custom::new_and_fill(dest) { + Ok(custom) => { + debug!("EntropyRng: using custom entropy source"); + self.source = Source::Custom(custom); + return Ok(()); + }, + Err(err) => { reported_error = reported_error.or(Some(err)) }, + } + } + + if let Source::Jitter(ref mut jitter_rng) = self.source { + match jitter_rng.fill(dest) { + Ok(()) => return Ok(()), + Err(err) => { + warn!("EntropyRng: JitterRng failed: {}", err); + reported_error = Some(err); + }, + } + } else if Jitter::is_supported() { + match Jitter::new_and_fill(dest) { + Ok(jitter_rng) => { + debug!("EntropyRng: using JitterRng"); + self.source = Source::Jitter(jitter_rng); + return Ok(()); + }, + Err(err) => { reported_error = reported_error.or(Some(err)) }, + } + } + + if let Some(err) = reported_error { + Err(Error::with_cause(ErrorKind::Unavailable, + "All entropy sources failed", + err)) + } else { + Err(Error::new(ErrorKind::Unavailable, + "No entropy sources available")) + } + } +} + +impl CryptoRng for EntropyRng {} + + + +trait EntropySource { + fn new_and_fill(dest: &mut [u8]) -> Result + where Self: Sized; + + fn fill(&mut self, dest: &mut [u8]) -> Result<(), Error>; + + fn is_supported() -> bool { true } +} + +#[allow(unused)] +#[derive(Clone, Debug)] +struct NoSource; + +#[allow(unused)] +impl EntropySource for NoSource { + fn new_and_fill(dest: &mut [u8]) -> Result { + Err(Error::new(ErrorKind::Unavailable, "Source not supported")) + } + + fn fill(&mut self, dest: &mut [u8]) -> Result<(), Error> { + unreachable!() + } + + fn is_supported() -> bool { false } +} + + +#[cfg(feature="rand_os")] +#[derive(Clone, Debug)] +pub struct Os(rngs::OsRng); + +#[cfg(feature="rand_os")] +impl EntropySource for Os { + fn new_and_fill(dest: &mut [u8]) -> Result { + let mut rng = rngs::OsRng::new()?; + rng.try_fill_bytes(dest)?; + Ok(Os(rng)) + } + + fn fill(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +#[cfg(not(feature="std"))] +type Os = NoSource; + + +type Custom = NoSource; + + +#[cfg(not(target_arch = "wasm32"))] +#[derive(Clone, Debug)] +pub struct Jitter(rngs::JitterRng); + +#[cfg(not(target_arch = "wasm32"))] +impl EntropySource for Jitter { + fn new_and_fill(dest: &mut [u8]) -> Result { + let mut rng = rngs::JitterRng::new()?; + rng.try_fill_bytes(dest)?; + Ok(Jitter(rng)) + } + + fn fill(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +#[cfg(target_arch = "wasm32")] +type Jitter = NoSource; + + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_entropy() { + let mut rng = EntropyRng::new(); + let n = (rng.next_u32() ^ rng.next_u32()).count_ones(); + assert!(n >= 2); // p(failure) approx 1e-7 + } +} diff --git a/third_party/rust/rand/src/rngs/mock.rs b/third_party/rust/rand/src/rngs/mock.rs new file mode 100644 index 000000000000..3c9a994ebe8b --- /dev/null +++ b/third_party/rust/rand/src/rngs/mock.rs @@ -0,0 +1,59 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Mock random number generator + +use rand_core::{RngCore, Error, impls}; + +/// A simple implementation of `RngCore` for testing purposes. +/// +/// This generates an arithmetic sequence (i.e. adds a constant each step) +/// over a `u64` number, using wrapping arithmetic. If the increment is 0 +/// the generator yields a constant. +/// +/// ``` +/// use rand::Rng; +/// use rand::rngs::mock::StepRng; +/// +/// let mut my_rng = StepRng::new(2, 1); +/// let sample: [u64; 3] = my_rng.gen(); +/// assert_eq!(sample, [2, 3, 4]); +/// ``` +#[derive(Debug, Clone)] +pub struct StepRng { + v: u64, + a: u64, +} + +impl StepRng { + /// Create a `StepRng`, yielding an arithmetic sequence starting with + /// `initial` and incremented by `increment` each time. + pub fn new(initial: u64, increment: u64) -> Self { + StepRng { v: initial, a: increment } + } +} + +impl RngCore for StepRng { + fn next_u32(&mut self) -> u32 { + self.next_u64() as u32 + } + + fn next_u64(&mut self) -> u64 { + let result = self.v; + self.v = self.v.wrapping_add(self.a); + result + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + impls::fill_bytes_via_next(self, dest); + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} diff --git a/third_party/rust/rand/src/rngs/mod.rs b/third_party/rust/rand/src/rngs/mod.rs new file mode 100644 index 000000000000..b3f05a072edd --- /dev/null +++ b/third_party/rust/rand/src/rngs/mod.rs @@ -0,0 +1,167 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Random number generators and adapters for common usage: +//! +//! - [`ThreadRng`], a fast, secure, auto-seeded thread-local generator +//! - [`StdRng`] and [`SmallRng`], algorithms to cover typical usage +//! - [`EntropyRng`], [`OsRng`] and [`JitterRng`] as entropy sources +//! - [`mock::StepRng`] as a simple counter for tests +//! - [`adapter::ReadRng`] to read from a file/stream +//! - [`adapter::ReseedingRng`] to reseed a PRNG on clone / process fork etc. +//! +//! # Background — Random number generators (RNGs) +//! +//! Computers are inherently deterministic, so to get *random* numbers one +//! either has to use a hardware generator or collect bits of *entropy* from +//! various sources (e.g. event timestamps, or jitter). This is a relatively +//! slow and complicated operation. +//! +//! Generally the operating system will collect some entropy, remove bias, and +//! use that to seed its own PRNG; [`OsRng`] provides an interface to this. +//! [`JitterRng`] is an entropy collector included with Rand that measures +//! jitter in the CPU execution time, and jitter in memory access time. +//! [`EntropyRng`] is a wrapper that uses the best entropy source that is +//! available. +//! +//! ## Pseudo-random number generators +//! +//! What is commonly used instead of "true" random number renerators, are +//! *pseudo-random number generators* (PRNGs), deterministic algorithms that +//! produce an infinite stream of pseudo-random numbers from a small random +//! seed. PRNGs are faster, and have better provable properties. The numbers +//! produced can be statistically of very high quality and can be impossible to +//! predict. (They can also have obvious correlations and be trivial to predict; +//! quality varies.) +//! +//! There are two different types of PRNGs: those developed for simulations +//! and statistics, and those developed for use in cryptography; the latter are +//! called Cryptographically Secure PRNGs (CSPRNG or CPRNG). Both types can +//! have good statistical quality but the latter also have to be impossible to +//! predict, even after seeing many previous output values. Rand provides a good +//! default algorithm from each class: +//! +//! - [`SmallRng`] is a PRNG chosen for low memory usage, high performance and +//! good statistical quality. +//! - [`StdRng`] is a CSPRNG chosen for good performance and trust of security +//! (based on reviews, maturity and usage). The current algorithm is HC-128, +//! which is one of the recommendations by ECRYPT's eSTREAM project. +//! +//! The above PRNGs do not cover all use-cases; more algorithms can be found in +//! the [`prng`][crate::prng] module, as well as in several other crates. For example, you +//! may wish a CSPRNG with significantly lower memory usage than [`StdRng`] +//! while being less concerned about performance, in which case [`ChaChaRng`] +//! is a good choice. +//! +//! One complexity is that the internal state of a PRNG must change with every +//! generated number. For APIs this generally means a mutable reference to the +//! state of the PRNG has to be passed around. +//! +//! A solution is [`ThreadRng`]. This is a thread-local implementation of +//! [`StdRng`] with automatic seeding on first use. It is the best choice if you +//! "just" want a convenient, secure, fast random number source. Use via the +//! [`thread_rng`] function, which gets a reference to the current thread's +//! local instance. +//! +//! ## Seeding +//! +//! As mentioned above, PRNGs require a random seed in order to produce random +//! output. This is especially important for CSPRNGs, which are still +//! deterministic algorithms, thus can only be secure if their seed value is +//! also secure. To seed a PRNG, use one of: +//! +//! - [`FromEntropy::from_entropy`]; this is the most convenient way to seed +//! with fresh, secure random data. +//! - [`SeedableRng::from_rng`]; this allows seeding from another PRNG or +//! from an entropy source such as [`EntropyRng`]. +//! - [`SeedableRng::from_seed`]; this is mostly useful if you wish to be able +//! to reproduce the output sequence by using a fixed seed. (Don't use +//! [`StdRng`] or [`SmallRng`] in this case since different algorithms may be +//! used by future versions of Rand; use an algorithm from the +//! [`prng`] module.) +//! +//! ## Conclusion +//! +//! - [`thread_rng`] is what you often want to use. +//! - If you want more control, flexibility, or better performance, use +//! [`StdRng`], [`SmallRng`] or an algorithm from the [`prng`] module. +//! - Use [`FromEntropy::from_entropy`] to seed new PRNGs. +//! - If you need reproducibility, use [`SeedableRng::from_seed`] combined with +//! a named PRNG. +//! +//! More information and notes on cryptographic security can be found +//! in the [`prng`] module. +//! +//! ## Examples +//! +//! Examples of seeding PRNGs: +//! +//! ``` +//! use rand::prelude::*; +//! # use rand::Error; +//! +//! // StdRng seeded securely by the OS or local entropy collector: +//! let mut rng = StdRng::from_entropy(); +//! # let v: u32 = rng.gen(); +//! +//! // SmallRng seeded from thread_rng: +//! # fn try_inner() -> Result<(), Error> { +//! let mut rng = SmallRng::from_rng(thread_rng())?; +//! # let v: u32 = rng.gen(); +//! # Ok(()) +//! # } +//! # try_inner().unwrap(); +//! +//! // SmallRng seeded by a constant, for deterministic results: +//! let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16]; // byte array +//! let mut rng = SmallRng::from_seed(seed); +//! # let v: u32 = rng.gen(); +//! ``` +//! +//! +//! # Implementing custom RNGs +//! +//! If you want to implement custom RNG, see the [`rand_core`] crate. The RNG +//! will have to implement the [`RngCore`] trait, where the [`Rng`] trait is +//! build on top of. +//! +//! If the RNG needs seeding, also implement the [`SeedableRng`] trait. +//! +//! [`CryptoRng`] is a marker trait cryptographically secure PRNGs can +//! implement. +//! +//! [`OsRng`]: rand_os::OsRng +//! [`SmallRng`]: rngs::SmallRng +//! [`StdRng`]: rngs::StdRng +//! [`ThreadRng`]: rngs::ThreadRng +//! [`EntropyRng`]: rngs::EntropyRng +//! [`JitterRng`]: rngs::JitterRng +//! [`mock::StepRng`]: rngs::mock::StepRng +//! [`adapter::ReadRng`]: rngs::adapter::ReadRng +//! [`adapter::ReseedingRng`]: rngs::adapter::ReseedingRng +//! [`ChaChaRng`]: rand_chacha::ChaChaRng + +pub mod adapter; + +#[cfg(feature="std")] mod entropy; +pub mod mock; // Public so we don't export `StepRng` directly, making it a bit + // more clear it is intended for testing. +mod small; +mod std; +#[cfg(feature="std")] pub(crate) mod thread; + + +pub use rand_jitter::{JitterRng, TimerError}; +#[cfg(feature="std")] pub use self::entropy::EntropyRng; + +pub use self::small::SmallRng; +pub use self::std::StdRng; +#[cfg(feature="std")] pub use self::thread::ThreadRng; + +#[cfg(feature="rand_os")] +pub use rand_os::OsRng; diff --git a/third_party/rust/rand/src/rngs/small.rs b/third_party/rust/rand/src/rngs/small.rs new file mode 100644 index 000000000000..9874d2469b82 --- /dev/null +++ b/third_party/rust/rand/src/rngs/small.rs @@ -0,0 +1,106 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A small fast RNG + +use {RngCore, SeedableRng, Error}; + +#[cfg(all(all(rustc_1_26, not(target_os = "emscripten")), target_pointer_width = "64"))] +type Rng = ::rand_pcg::Pcg64Mcg; +#[cfg(not(all(all(rustc_1_26, not(target_os = "emscripten")), target_pointer_width = "64")))] +type Rng = ::rand_pcg::Pcg32; + +/// An RNG recommended when small state, cheap initialization and good +/// performance are required. The PRNG algorithm in `SmallRng` is chosen to be +/// efficient on the current platform, **without consideration for cryptography +/// or security**. The size of its state is much smaller than for [`StdRng`]. +/// +/// Reproducibility of output from this generator is however not required, thus +/// future library versions may use a different internal generator with +/// different output. Further, this generator may not be portable and can +/// produce different output depending on the architecture. If you require +/// reproducible output, use a named RNG. +/// Refer to [The Book](https://rust-random.github.io/book/guide-rngs.html). +/// +/// +/// The current algorithm is [`Pcg64Mcg`][rand_pcg::Pcg64Mcg] on 64-bit platforms with Rust version +/// 1.26 and later, or [`Pcg32`][rand_pcg::Pcg32] otherwise. Both are found in +/// the [rand_pcg] crate. +/// +/// # Examples +/// +/// Initializing `SmallRng` with a random seed can be done using [`FromEntropy`]: +/// +/// ``` +/// # use rand::Rng; +/// use rand::FromEntropy; +/// use rand::rngs::SmallRng; +/// +/// // Create small, cheap to initialize and fast RNG with a random seed. +/// // The randomness is supplied by the operating system. +/// let mut small_rng = SmallRng::from_entropy(); +/// # let v: u32 = small_rng.gen(); +/// ``` +/// +/// When initializing a lot of `SmallRng`'s, using [`thread_rng`] can be more +/// efficient: +/// +/// ``` +/// use std::iter; +/// use rand::{SeedableRng, thread_rng}; +/// use rand::rngs::SmallRng; +/// +/// // Create a big, expensive to initialize and slower, but unpredictable RNG. +/// // This is cached and done only once per thread. +/// let mut thread_rng = thread_rng(); +/// // Create small, cheap to initialize and fast RNGs with random seeds. +/// // One can generally assume this won't fail. +/// let rngs: Vec = iter::repeat(()) +/// .map(|()| SmallRng::from_rng(&mut thread_rng).unwrap()) +/// .take(10) +/// .collect(); +/// ``` +/// +/// [`FromEntropy`]: crate::FromEntropy +/// [`StdRng`]: crate::rngs::StdRng +/// [`thread_rng`]: crate::thread_rng +/// [rand_pcg]: https://crates.io/crates/rand_pcg +#[derive(Clone, Debug)] +pub struct SmallRng(Rng); + +impl RngCore for SmallRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for SmallRng { + type Seed = ::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + SmallRng(Rng::from_seed(seed)) + } + + fn from_rng(rng: R) -> Result { + Rng::from_rng(rng).map(SmallRng) + } +} diff --git a/third_party/rust/rand/src/rngs/std.rs b/third_party/rust/rand/src/rngs/std.rs new file mode 100644 index 000000000000..e67a76da8b9c --- /dev/null +++ b/third_party/rust/rand/src/rngs/std.rs @@ -0,0 +1,85 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The standard RNG + +use {RngCore, CryptoRng, Error, SeedableRng}; +use rand_hc::Hc128Rng; + +/// The standard RNG. The PRNG algorithm in `StdRng` is chosen to be efficient +/// on the current platform, to be statistically strong and unpredictable +/// (meaning a cryptographically secure PRNG). +/// +/// The current algorithm used on all platforms is [HC-128], found in the +/// [rand_hc] crate. +/// +/// Reproducibility of output from this generator is however not required, thus +/// future library versions may use a different internal generator with +/// different output. Further, this generator may not be portable and can +/// produce different output depending on the architecture. If you require +/// reproducible output, use a named RNG, for example [`ChaChaRng`] from the +/// [rand_chacha] crate. +/// +/// [HC-128]: rand_hc::Hc128Rng +/// [`ChaChaRng`]: rand_chacha::ChaChaRng +/// [rand_hc]: https://crates.io/crates/rand_hc +/// [rand_chacha]: https://crates.io/crates/rand_chacha +#[derive(Clone, Debug)] +pub struct StdRng(Hc128Rng); + +impl RngCore for StdRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for StdRng { + type Seed = ::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + StdRng(Hc128Rng::from_seed(seed)) + } + + fn from_rng(rng: R) -> Result { + Hc128Rng::from_rng(rng).map(StdRng) + } +} + +impl CryptoRng for StdRng {} + + +#[cfg(test)] +mod test { + use {RngCore, SeedableRng}; + use rngs::StdRng; + + #[test] + fn test_stdrng_construction() { + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng1 = StdRng::from_seed(seed); + assert_eq!(rng1.next_u64(), 15759097995037006553); + + let mut rng2 = StdRng::from_rng(rng1).unwrap(); + assert_eq!(rng2.next_u64(), 6766915756997287454); + } +} diff --git a/third_party/rust/rand/src/rngs/thread.rs b/third_party/rust/rand/src/rngs/thread.rs new file mode 100644 index 000000000000..f1aa787dc4fa --- /dev/null +++ b/third_party/rust/rand/src/rngs/thread.rs @@ -0,0 +1,137 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Thread-local random number generator + +use std::cell::UnsafeCell; + +use {RngCore, CryptoRng, SeedableRng, Error}; +use rngs::adapter::ReseedingRng; +use rngs::EntropyRng; +use rand_hc::Hc128Core; + +// Rationale for using `UnsafeCell` in `ThreadRng`: +// +// Previously we used a `RefCell`, with an overhead of ~15%. There will only +// ever be one mutable reference to the interior of the `UnsafeCell`, because +// we only have such a reference inside `next_u32`, `next_u64`, etc. Within a +// single thread (which is the definition of `ThreadRng`), there will only ever +// be one of these methods active at a time. +// +// A possible scenario where there could be multiple mutable references is if +// `ThreadRng` is used inside `next_u32` and co. But the implementation is +// completely under our control. We just have to ensure none of them use +// `ThreadRng` internally, which is nonsensical anyway. We should also never run +// `ThreadRng` in destructors of its implementation, which is also nonsensical. +// +// The additional `Rc` is not strictly neccesary, and could be removed. For now +// it ensures `ThreadRng` stays `!Send` and `!Sync`, and implements `Clone`. + + +// Number of generated bytes after which to reseed `TreadRng`. +// +// The time it takes to reseed HC-128 is roughly equivalent to generating 7 KiB. +// We pick a treshold here that is large enough to not reduce the average +// performance too much, but also small enough to not make reseeding something +// that basically never happens. +const THREAD_RNG_RESEED_THRESHOLD: u64 = 32*1024*1024; // 32 MiB + +/// The type returned by [`thread_rng`], essentially just a reference to the +/// PRNG in thread-local memory. +/// +/// `ThreadRng` uses [`ReseedingRng`] wrapping the same PRNG as [`StdRng`], +/// which is reseeded after generating 32 MiB of random data. A single instance +/// is cached per thread and the returned `ThreadRng` is a reference to this +/// instance — hence `ThreadRng` is neither `Send` nor `Sync` but is safe to use +/// within a single thread. This RNG is seeded and reseeded via [`EntropyRng`] +/// as required. +/// +/// Note that the reseeding is done as an extra precaution against entropy +/// leaks and is in theory unnecessary — to predict `ThreadRng`'s output, an +/// attacker would have to either determine most of the RNG's seed or internal +/// state, or crack the algorithm used. +/// +/// Like [`StdRng`], `ThreadRng` is a cryptographically secure PRNG. The current +/// algorithm used is [HC-128], which is an array-based PRNG that trades memory +/// usage for better performance. This makes it similar to ISAAC, the algorithm +/// used in `ThreadRng` before rand 0.5. +/// +/// Cloning this handle just produces a new reference to the same thread-local +/// generator. +/// +/// [`ReseedingRng`]: crate::rngs::adapter::ReseedingRng +/// [`StdRng`]: crate::rngs::StdRng +/// [HC-128]: rand_hc::Hc128Rng +#[derive(Clone, Debug)] +pub struct ThreadRng { + // use of raw pointer implies type is neither Send nor Sync + rng: *mut ReseedingRng, +} + +thread_local!( + static THREAD_RNG_KEY: UnsafeCell> = { + let mut entropy_source = EntropyRng::new(); + let r = Hc128Core::from_rng(&mut entropy_source).unwrap_or_else(|err| + panic!("could not initialize thread_rng: {}", err)); + let rng = ReseedingRng::new(r, + THREAD_RNG_RESEED_THRESHOLD, + entropy_source); + UnsafeCell::new(rng) + } +); + +/// Retrieve the lazily-initialized thread-local random number generator, +/// seeded by the system. Intended to be used in method chaining style, +/// e.g. `thread_rng().gen::()`, or cached locally, e.g. +/// `let mut rng = thread_rng();`. Invoked by the `Default` trait, making +/// `ThreadRng::default()` equivelent. +/// +/// For more information see [`ThreadRng`]. +pub fn thread_rng() -> ThreadRng { + ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.get()) } +} + +impl Default for ThreadRng { + fn default() -> ThreadRng { + ::prelude::thread_rng() + } +} + +impl RngCore for ThreadRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + unsafe { (*self.rng).next_u32() } + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + unsafe { (*self.rng).next_u64() } + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + unsafe { (*self.rng).fill_bytes(dest) } + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + unsafe { (*self.rng).try_fill_bytes(dest) } + } +} + +impl CryptoRng for ThreadRng {} + + +#[cfg(test)] +mod test { + #[test] + fn test_thread_rng() { + use Rng; + let mut r = ::thread_rng(); + r.gen::(); + assert_eq!(r.gen_range(0, 1), 0); + } +} diff --git a/third_party/rust/rand/src/seq/index.rs b/third_party/rust/rand/src/seq/index.rs new file mode 100644 index 000000000000..a70c7367f858 --- /dev/null +++ b/third_party/rust/rand/src/seq/index.rs @@ -0,0 +1,378 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Index sampling + +#[cfg(feature="alloc")] use core::slice; + +#[cfg(feature="std")] use std::vec; +#[cfg(all(feature="alloc", not(feature="std")))] use alloc::vec::{self, Vec}; +// BTreeMap is not as fast in tests, but better than nothing. +#[cfg(feature="std")] use std::collections::{HashSet}; +#[cfg(all(feature="alloc", not(feature="std")))] use alloc::collections::BTreeSet; + +#[cfg(feature="alloc")] use distributions::{Distribution, Uniform}; +use Rng; + +/// A vector of indices. +/// +/// Multiple internal representations are possible. +#[derive(Clone, Debug)] +pub enum IndexVec { + #[doc(hidden)] U32(Vec), + #[doc(hidden)] USize(Vec), +} + +impl IndexVec { + /// Returns the number of indices + pub fn len(&self) -> usize { + match self { + &IndexVec::U32(ref v) => v.len(), + &IndexVec::USize(ref v) => v.len(), + } + } + + /// Return the value at the given `index`. + /// + /// (Note: we cannot implement [`std::ops::Index`] because of lifetime + /// restrictions.) + pub fn index(&self, index: usize) -> usize { + match self { + &IndexVec::U32(ref v) => v[index] as usize, + &IndexVec::USize(ref v) => v[index], + } + } + + /// Return result as a `Vec`. Conversion may or may not be trivial. + pub fn into_vec(self) -> Vec { + match self { + IndexVec::U32(v) => v.into_iter().map(|i| i as usize).collect(), + IndexVec::USize(v) => v, + } + } + + /// Iterate over the indices as a sequence of `usize` values + pub fn iter<'a>(&'a self) -> IndexVecIter<'a> { + match self { + &IndexVec::U32(ref v) => IndexVecIter::U32(v.iter()), + &IndexVec::USize(ref v) => IndexVecIter::USize(v.iter()), + } + } + + /// Convert into an iterator over the indices as a sequence of `usize` values + pub fn into_iter(self) -> IndexVecIntoIter { + match self { + IndexVec::U32(v) => IndexVecIntoIter::U32(v.into_iter()), + IndexVec::USize(v) => IndexVecIntoIter::USize(v.into_iter()), + } + } +} + +impl PartialEq for IndexVec { + fn eq(&self, other: &IndexVec) -> bool { + use self::IndexVec::*; + match (self, other) { + (&U32(ref v1), &U32(ref v2)) => v1 == v2, + (&USize(ref v1), &USize(ref v2)) => v1 == v2, + (&U32(ref v1), &USize(ref v2)) => (v1.len() == v2.len()) + && (v1.iter().zip(v2.iter()).all(|(x, y)| *x as usize == *y)), + (&USize(ref v1), &U32(ref v2)) => (v1.len() == v2.len()) + && (v1.iter().zip(v2.iter()).all(|(x, y)| *x == *y as usize)), + } + } +} + +impl From> for IndexVec { + fn from(v: Vec) -> Self { + IndexVec::U32(v) + } +} + +impl From> for IndexVec { + fn from(v: Vec) -> Self { + IndexVec::USize(v) + } +} + +/// Return type of `IndexVec::iter`. +#[derive(Debug)] +pub enum IndexVecIter<'a> { + #[doc(hidden)] U32(slice::Iter<'a, u32>), + #[doc(hidden)] USize(slice::Iter<'a, usize>), +} + +impl<'a> Iterator for IndexVecIter<'a> { + type Item = usize; + fn next(&mut self) -> Option { + use self::IndexVecIter::*; + match self { + &mut U32(ref mut iter) => iter.next().map(|i| *i as usize), + &mut USize(ref mut iter) => iter.next().cloned(), + } + } + + fn size_hint(&self) -> (usize, Option) { + match self { + &IndexVecIter::U32(ref v) => v.size_hint(), + &IndexVecIter::USize(ref v) => v.size_hint(), + } + } +} + +impl<'a> ExactSizeIterator for IndexVecIter<'a> {} + +/// Return type of `IndexVec::into_iter`. +#[derive(Clone, Debug)] +pub enum IndexVecIntoIter { + #[doc(hidden)] U32(vec::IntoIter), + #[doc(hidden)] USize(vec::IntoIter), +} + +impl Iterator for IndexVecIntoIter { + type Item = usize; + + fn next(&mut self) -> Option { + use self::IndexVecIntoIter::*; + match self { + &mut U32(ref mut v) => v.next().map(|i| i as usize), + &mut USize(ref mut v) => v.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + use self::IndexVecIntoIter::*; + match self { + &U32(ref v) => v.size_hint(), + &USize(ref v) => v.size_hint(), + } + } +} + +impl ExactSizeIterator for IndexVecIntoIter {} + + +/// Randomly sample exactly `amount` distinct indices from `0..length`, and +/// return them in random order (fully shuffled). +/// +/// This method is used internally by the slice sampling methods, but it can +/// sometimes be useful to have the indices themselves so this is provided as +/// an alternative. +/// +/// The implementation used is not specified; we automatically select the +/// fastest available algorithm for the `length` and `amount` parameters +/// (based on detailed profiling on an Intel Haswell CPU). Roughly speaking, +/// complexity is `O(amount)`, except that when `amount` is small, performance +/// is closer to `O(amount^2)`, and when `length` is close to `amount` then +/// `O(length)`. +/// +/// Note that performance is significantly better over `u32` indices than over +/// `u64` indices. Because of this we hide the underlying type behind an +/// abstraction, `IndexVec`. +/// +/// If an allocation-free `no_std` function is required, it is suggested +/// to adapt the internal `sample_floyd` implementation. +/// +/// Panics if `amount > length`. +pub fn sample(rng: &mut R, length: usize, amount: usize) -> IndexVec + where R: Rng + ?Sized, +{ + if amount > length { + panic!("`amount` of samples must be less than or equal to `length`"); + } + if length > (::core::u32::MAX as usize) { + // We never want to use inplace here, but could use floyd's alg + // Lazy version: always use the cache alg. + return sample_rejection(rng, length, amount); + } + let amount = amount as u32; + let length = length as u32; + + // Choice of algorithm here depends on both length and amount. See: + // https://github.com/rust-random/rand/pull/479 + // We do some calculations with f32. Accuracy is not very important. + + if amount < 163 { + const C: [[f32; 2]; 2] = [[1.6, 8.0/45.0], [10.0, 70.0/9.0]]; + let j = if length < 500_000 { 0 } else { 1 }; + let amount_fp = amount as f32; + let m4 = C[0][j] * amount_fp; + // Short-cut: when amount < 12, floyd's is always faster + if amount > 11 && (length as f32) < (C[1][j] + m4) * amount_fp { + sample_inplace(rng, length, amount) + } else { + sample_floyd(rng, length, amount) + } + } else { + const C: [f32; 2] = [270.0, 330.0/9.0]; + let j = if length < 500_000 { 0 } else { 1 }; + if (length as f32) < C[j] * (amount as f32) { + sample_inplace(rng, length, amount) + } else { + // note: could have a specific u32 impl, but I'm lazy and + // generics don't have usable conversions + sample_rejection(rng, length as usize, amount as usize) + } + } +} + +/// Randomly sample exactly `amount` indices from `0..length`, using Floyd's +/// combination algorithm. +/// +/// The output values are fully shuffled. (Overhead is under 50%.) +/// +/// This implementation uses `O(amount)` memory and `O(amount^2)` time. +fn sample_floyd(rng: &mut R, length: u32, amount: u32) -> IndexVec + where R: Rng + ?Sized, +{ + // For small amount we use Floyd's fully-shuffled variant. For larger + // amounts this is slow due to Vec::insert performance, so we shuffle + // afterwards. Benchmarks show little overhead from extra logic. + let floyd_shuffle = amount < 50; + + debug_assert!(amount <= length); + let mut indices = Vec::with_capacity(amount as usize); + for j in length - amount .. length { + let t = rng.gen_range(0, j + 1); + if floyd_shuffle { + if let Some(pos) = indices.iter().position(|&x| x == t) { + indices.insert(pos, j); + continue; + } + } else { + if indices.contains(&t) { + indices.push(j); + continue; + } + } + indices.push(t); + } + if !floyd_shuffle { + // Reimplement SliceRandom::shuffle with smaller indices + for i in (1..amount).rev() { + // invariant: elements with index > i have been locked in place. + indices.swap(i as usize, rng.gen_range(0, i + 1) as usize); + } + } + IndexVec::from(indices) +} + +/// Randomly sample exactly `amount` indices from `0..length`, using an inplace +/// partial Fisher-Yates method. +/// Sample an amount of indices using an inplace partial fisher yates method. +/// +/// This allocates the entire `length` of indices and randomizes only the first `amount`. +/// It then truncates to `amount` and returns. +/// +/// This method is not appropriate for large `length` and potentially uses a lot +/// of memory; because of this we only implement for `u32` index (which improves +/// performance in all cases). +/// +/// Set-up is `O(length)` time and memory and shuffling is `O(amount)` time. +fn sample_inplace(rng: &mut R, length: u32, amount: u32) -> IndexVec + where R: Rng + ?Sized, +{ + debug_assert!(amount <= length); + let mut indices: Vec = Vec::with_capacity(length as usize); + indices.extend(0..length); + for i in 0..amount { + let j: u32 = rng.gen_range(i, length); + indices.swap(i as usize, j as usize); + } + indices.truncate(amount as usize); + debug_assert_eq!(indices.len(), amount as usize); + IndexVec::from(indices) +} + +/// Randomly sample exactly `amount` indices from `0..length`, using rejection +/// sampling. +/// +/// Since `amount <<< length` there is a low chance of a random sample in +/// `0..length` being a duplicate. We test for duplicates and resample where +/// necessary. The algorithm is `O(amount)` time and memory. +fn sample_rejection(rng: &mut R, length: usize, amount: usize) -> IndexVec + where R: Rng + ?Sized, +{ + debug_assert!(amount < length); + #[cfg(feature="std")] let mut cache = HashSet::with_capacity(amount); + #[cfg(not(feature="std"))] let mut cache = BTreeSet::new(); + let distr = Uniform::new(0, length); + let mut indices = Vec::with_capacity(amount); + for _ in 0..amount { + let mut pos = distr.sample(rng); + while !cache.insert(pos) { + pos = distr.sample(rng); + } + indices.push(pos); + } + + debug_assert_eq!(indices.len(), amount); + IndexVec::from(indices) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_sample_boundaries() { + let mut r = ::test::rng(404); + + assert_eq!(sample_inplace(&mut r, 0, 0).len(), 0); + assert_eq!(sample_inplace(&mut r, 1, 0).len(), 0); + assert_eq!(sample_inplace(&mut r, 1, 1).into_vec(), vec![0]); + + assert_eq!(sample_rejection(&mut r, 1, 0).len(), 0); + + assert_eq!(sample_floyd(&mut r, 0, 0).len(), 0); + assert_eq!(sample_floyd(&mut r, 1, 0).len(), 0); + assert_eq!(sample_floyd(&mut r, 1, 1).into_vec(), vec![0]); + + // These algorithms should be fast with big numbers. Test average. + let sum: usize = sample_rejection(&mut r, 1 << 25, 10) + .into_iter().sum(); + assert!(1 << 25 < sum && sum < (1 << 25) * 25); + + let sum: usize = sample_floyd(&mut r, 1 << 25, 10) + .into_iter().sum(); + assert!(1 << 25 < sum && sum < (1 << 25) * 25); + } + + #[test] + fn test_sample_alg() { + let seed_rng = ::test::rng; + + // We can't test which algorithm is used directly, but Floyd's alg + // should produce different results from the others. (Also, `inplace` + // and `cached` currently use different sizes thus produce different results.) + + // A small length and relatively large amount should use inplace + let (length, amount): (usize, usize) = (100, 50); + let v1 = sample(&mut seed_rng(420), length, amount); + let v2 = sample_inplace(&mut seed_rng(420), length as u32, amount as u32); + assert!(v1.iter().all(|e| e < length)); + assert_eq!(v1, v2); + + // Test Floyd's alg does produce different results + let v3 = sample_floyd(&mut seed_rng(420), length as u32, amount as u32); + assert!(v1 != v3); + + // A large length and small amount should use Floyd + let (length, amount): (usize, usize) = (1<<20, 50); + let v1 = sample(&mut seed_rng(421), length, amount); + let v2 = sample_floyd(&mut seed_rng(421), length as u32, amount as u32); + assert!(v1.iter().all(|e| e < length)); + assert_eq!(v1, v2); + + // A large length and larger amount should use cache + let (length, amount): (usize, usize) = (1<<20, 600); + let v1 = sample(&mut seed_rng(422), length, amount); + let v2 = sample_rejection(&mut seed_rng(422), length, amount); + assert!(v1.iter().all(|e| e < length)); + assert_eq!(v1, v2); + } +} diff --git a/third_party/rust/rand/src/seq/mod.rs b/third_party/rust/rand/src/seq/mod.rs new file mode 100644 index 000000000000..d0f83084a66e --- /dev/null +++ b/third_party/rust/rand/src/seq/mod.rs @@ -0,0 +1,829 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Functions for randomly accessing and sampling sequences. +//! +//! TODO: module doc + + +#[cfg(feature="alloc")] pub mod index; + +#[cfg(feature="alloc")] use core::ops::Index; + +#[cfg(all(feature="alloc", not(feature="std")))] use alloc::vec::Vec; + +use Rng; +#[cfg(feature="alloc")] use distributions::WeightedError; +#[cfg(feature="alloc")] use distributions::uniform::{SampleUniform, SampleBorrow}; + +/// Extension trait on slices, providing random mutation and sampling methods. +/// +/// An implementation is provided for slices. This may also be implementable for +/// other types. +pub trait SliceRandom { + /// The element type. + type Item; + + /// Returns a reference to one random element of the slice, or `None` if the + /// slice is empty. + /// + /// Depending on the implementation, complexity is expected to be `O(1)`. + /// + /// # Example + /// + /// ``` + /// use rand::thread_rng; + /// use rand::seq::SliceRandom; + /// + /// let choices = [1, 2, 4, 8, 16, 32]; + /// let mut rng = thread_rng(); + /// println!("{:?}", choices.choose(&mut rng)); + /// assert_eq!(choices[..0].choose(&mut rng), None); + /// ``` + fn choose(&self, rng: &mut R) -> Option<&Self::Item> + where R: Rng + ?Sized; + + /// Returns a mutable reference to one random element of the slice, or + /// `None` if the slice is empty. + /// + /// Depending on the implementation, complexity is expected to be `O(1)`. + fn choose_mut(&mut self, rng: &mut R) -> Option<&mut Self::Item> + where R: Rng + ?Sized; + + /// Produces an iterator that chooses `amount` elements from the slice at + /// random without repeating any, and returns them in random order. + /// + /// In case this API is not sufficiently flexible, use `index::sample` then + /// apply the indices to the slice. + /// + /// Complexity is expected to be the same as `index::sample`. + /// + /// # Example + /// ``` + /// use rand::seq::SliceRandom; + /// + /// let mut rng = &mut rand::thread_rng(); + /// let sample = "Hello, audience!".as_bytes(); + /// + /// // collect the results into a vector: + /// let v: Vec = sample.choose_multiple(&mut rng, 3).cloned().collect(); + /// + /// // store in a buffer: + /// let mut buf = [0u8; 5]; + /// for (b, slot) in sample.choose_multiple(&mut rng, buf.len()).zip(buf.iter_mut()) { + /// *slot = *b; + /// } + /// ``` + #[cfg(feature = "alloc")] + fn choose_multiple(&self, rng: &mut R, amount: usize) -> SliceChooseIter + where R: Rng + ?Sized; + + /// Similar to [`choose`], where the likelihood of each outcome may be + /// specified. The specified function `weight` maps items `x` to a relative + /// likelihood `weight(x)`. The probability of each item being selected is + /// therefore `weight(x) / s`, where `s` is the sum of all `weight(x)`. + /// + /// # Example + /// + /// ``` + /// use rand::prelude::*; + /// + /// let choices = [('a', 2), ('b', 1), ('c', 1)]; + /// let mut rng = thread_rng(); + /// // 50% chance to print 'a', 25% chance to print 'b', 25% chance to print 'c' + /// println!("{:?}", choices.choose_weighted(&mut rng, |item| item.1).unwrap().0); + /// ``` + /// [`choose`]: SliceRandom::choose + #[cfg(feature = "alloc")] + fn choose_weighted(&self, rng: &mut R, weight: F) -> Result<&Self::Item, WeightedError> + where R: Rng + ?Sized, + F: Fn(&Self::Item) -> B, + B: SampleBorrow, + X: SampleUniform + + for<'a> ::core::ops::AddAssign<&'a X> + + ::core::cmp::PartialOrd + + Clone + + Default; + + /// Similar to [`choose_mut`], where the likelihood of each outcome may be + /// specified. The specified function `weight` maps items `x` to a relative + /// likelihood `weight(x)`. The probability of each item being selected is + /// therefore `weight(x) / s`, where `s` is the sum of all `weight(x)`. + /// + /// See also [`choose_weighted`]. + /// + /// [`choose_mut`]: SliceRandom::choose_mut + /// [`choose_weighted`]: SliceRandom::choose_weighted + #[cfg(feature = "alloc")] + fn choose_weighted_mut(&mut self, rng: &mut R, weight: F) -> Result<&mut Self::Item, WeightedError> + where R: Rng + ?Sized, + F: Fn(&Self::Item) -> B, + B: SampleBorrow, + X: SampleUniform + + for<'a> ::core::ops::AddAssign<&'a X> + + ::core::cmp::PartialOrd + + Clone + + Default; + + /// Shuffle a mutable slice in place. + /// + /// Depending on the implementation, complexity is expected to be `O(1)`. + /// + /// # Example + /// + /// ``` + /// use rand::thread_rng; + /// use rand::seq::SliceRandom; + /// + /// let mut rng = thread_rng(); + /// let mut y = [1, 2, 3, 4, 5]; + /// println!("Unshuffled: {:?}", y); + /// y.shuffle(&mut rng); + /// println!("Shuffled: {:?}", y); + /// ``` + fn shuffle(&mut self, rng: &mut R) where R: Rng + ?Sized; + + /// Shuffle a slice in place, but exit early. + /// + /// Returns two mutable slices from the source slice. The first contains + /// `amount` elements randomly permuted. The second has the remaining + /// elements that are not fully shuffled. + /// + /// This is an efficient method to select `amount` elements at random from + /// the slice, provided the slice may be mutated. + /// + /// If you only need to choose elements randomly and `amount > self.len()/2` + /// then you may improve performance by taking + /// `amount = values.len() - amount` and using only the second slice. + /// + /// If `amount` is greater than the number of elements in the slice, this + /// will perform a full shuffle. + /// + /// Complexity is expected to be `O(m)` where `m = amount`. + fn partial_shuffle(&mut self, rng: &mut R, amount: usize) + -> (&mut [Self::Item], &mut [Self::Item]) where R: Rng + ?Sized; +} + +/// Extension trait on iterators, providing random sampling methods. +pub trait IteratorRandom: Iterator + Sized { + /// Choose one element at random from the iterator. If you have a slice, + /// it's significantly faster to call the [`choose`] or [`choose_mut`] + /// functions using the slice instead. + /// + /// Returns `None` if and only if the iterator is empty. + /// + /// Complexity is `O(n)`, where `n` is the length of the iterator. + /// This likely consumes multiple random numbers, but the exact number + /// is unspecified. + /// + /// [`choose`]: SliceRandom::method.choose + /// [`choose_mut`]: SliceRandom::choose_mut + fn choose(mut self, rng: &mut R) -> Option + where R: Rng + ?Sized + { + let (mut lower, mut upper) = self.size_hint(); + let mut consumed = 0; + let mut result = None; + + if upper == Some(lower) { + return if lower == 0 { None } else { self.nth(rng.gen_range(0, lower)) }; + } + + // Continue until the iterator is exhausted + loop { + if lower > 1 { + let ix = rng.gen_range(0, lower + consumed); + let skip; + if ix < lower { + result = self.nth(ix); + skip = lower - (ix + 1); + } else { + skip = lower; + } + if upper == Some(lower) { + return result; + } + consumed += lower; + if skip > 0 { + self.nth(skip - 1); + } + } else { + let elem = self.next(); + if elem.is_none() { + return result; + } + consumed += 1; + let denom = consumed as f64; // accurate to 2^53 elements + if rng.gen_bool(1.0 / denom) { + result = elem; + } + } + + let hint = self.size_hint(); + lower = hint.0; + upper = hint.1; + } + } + + /// Collects `amount` values at random from the iterator into a supplied + /// buffer. + /// + /// Although the elements are selected randomly, the order of elements in + /// the buffer is neither stable nor fully random. If random ordering is + /// desired, shuffle the result. + /// + /// Returns the number of elements added to the buffer. This equals `amount` + /// unless the iterator contains insufficient elements, in which case this + /// equals the number of elements available. + /// + /// Complexity is `O(n)` where `n` is the length of the iterator. + fn choose_multiple_fill(mut self, rng: &mut R, buf: &mut [Self::Item]) + -> usize where R: Rng + ?Sized + { + let amount = buf.len(); + let mut len = 0; + while len < amount { + if let Some(elem) = self.next() { + buf[len] = elem; + len += 1; + } else { + // Iterator exhausted; stop early + return len; + } + } + + // Continue, since the iterator was not exhausted + for (i, elem) in self.enumerate() { + let k = rng.gen_range(0, i + 1 + amount); + if let Some(slot) = buf.get_mut(k) { + *slot = elem; + } + } + len + } + + /// Collects `amount` values at random from the iterator into a vector. + /// + /// This is equivalent to `choose_multiple_fill` except for the result type. + /// + /// Although the elements are selected randomly, the order of elements in + /// the buffer is neither stable nor fully random. If random ordering is + /// desired, shuffle the result. + /// + /// The length of the returned vector equals `amount` unless the iterator + /// contains insufficient elements, in which case it equals the number of + /// elements available. + /// + /// Complexity is `O(n)` where `n` is the length of the iterator. + #[cfg(feature = "alloc")] + fn choose_multiple(mut self, rng: &mut R, amount: usize) -> Vec + where R: Rng + ?Sized + { + let mut reservoir = Vec::with_capacity(amount); + reservoir.extend(self.by_ref().take(amount)); + + // Continue unless the iterator was exhausted + // + // note: this prevents iterators that "restart" from causing problems. + // If the iterator stops once, then so do we. + if reservoir.len() == amount { + for (i, elem) in self.enumerate() { + let k = rng.gen_range(0, i + 1 + amount); + if let Some(slot) = reservoir.get_mut(k) { + *slot = elem; + } + } + } else { + // Don't hang onto extra memory. There is a corner case where + // `amount` was much less than `self.len()`. + reservoir.shrink_to_fit(); + } + reservoir + } +} + + +impl SliceRandom for [T] { + type Item = T; + + fn choose(&self, rng: &mut R) -> Option<&Self::Item> + where R: Rng + ?Sized + { + if self.is_empty() { + None + } else { + Some(&self[rng.gen_range(0, self.len())]) + } + } + + fn choose_mut(&mut self, rng: &mut R) -> Option<&mut Self::Item> + where R: Rng + ?Sized + { + if self.is_empty() { + None + } else { + let len = self.len(); + Some(&mut self[rng.gen_range(0, len)]) + } + } + + #[cfg(feature = "alloc")] + fn choose_multiple(&self, rng: &mut R, amount: usize) + -> SliceChooseIter + where R: Rng + ?Sized + { + let amount = ::core::cmp::min(amount, self.len()); + SliceChooseIter { + slice: self, + _phantom: Default::default(), + indices: index::sample(rng, self.len(), amount).into_iter(), + } + } + + #[cfg(feature = "alloc")] + fn choose_weighted(&self, rng: &mut R, weight: F) -> Result<&Self::Item, WeightedError> + where R: Rng + ?Sized, + F: Fn(&Self::Item) -> B, + B: SampleBorrow, + X: SampleUniform + + for<'a> ::core::ops::AddAssign<&'a X> + + ::core::cmp::PartialOrd + + Clone + + Default { + use distributions::{Distribution, WeightedIndex}; + let distr = WeightedIndex::new(self.iter().map(weight))?; + Ok(&self[distr.sample(rng)]) + } + + #[cfg(feature = "alloc")] + fn choose_weighted_mut(&mut self, rng: &mut R, weight: F) -> Result<&mut Self::Item, WeightedError> + where R: Rng + ?Sized, + F: Fn(&Self::Item) -> B, + B: SampleBorrow, + X: SampleUniform + + for<'a> ::core::ops::AddAssign<&'a X> + + ::core::cmp::PartialOrd + + Clone + + Default { + use distributions::{Distribution, WeightedIndex}; + let distr = WeightedIndex::new(self.iter().map(weight))?; + Ok(&mut self[distr.sample(rng)]) + } + + fn shuffle(&mut self, rng: &mut R) where R: Rng + ?Sized + { + for i in (1..self.len()).rev() { + // invariant: elements with index > i have been locked in place. + self.swap(i, rng.gen_range(0, i + 1)); + } + } + + fn partial_shuffle(&mut self, rng: &mut R, amount: usize) + -> (&mut [Self::Item], &mut [Self::Item]) where R: Rng + ?Sized + { + // This applies Durstenfeld's algorithm for the + // [Fisher–Yates shuffle](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm) + // for an unbiased permutation, but exits early after choosing `amount` + // elements. + + let len = self.len(); + let end = if amount >= len { 0 } else { len - amount }; + + for i in (end..len).rev() { + // invariant: elements with index > i have been locked in place. + self.swap(i, rng.gen_range(0, i + 1)); + } + let r = self.split_at_mut(end); + (r.1, r.0) + } +} + +impl IteratorRandom for I where I: Iterator + Sized {} + + +/// Iterator over multiple choices, as returned by [`SliceRandom::choose_multiple] +#[cfg(feature = "alloc")] +#[derive(Debug)] +pub struct SliceChooseIter<'a, S: ?Sized + 'a, T: 'a> { + slice: &'a S, + _phantom: ::core::marker::PhantomData, + indices: index::IndexVecIntoIter, +} + +#[cfg(feature = "alloc")] +impl<'a, S: Index + ?Sized + 'a, T: 'a> Iterator for SliceChooseIter<'a, S, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + // TODO: investigate using SliceIndex::get_unchecked when stable + self.indices.next().map(|i| &self.slice[i as usize]) + } + + fn size_hint(&self) -> (usize, Option) { + (self.indices.len(), Some(self.indices.len())) + } +} + +#[cfg(feature = "alloc")] +impl<'a, S: Index + ?Sized + 'a, T: 'a> ExactSizeIterator + for SliceChooseIter<'a, S, T> +{ + fn len(&self) -> usize { + self.indices.len() + } +} + + +/// Randomly sample `amount` elements from a finite iterator. +/// +/// Deprecated: use [`IteratorRandom::choose_multiple`] instead. +#[cfg(feature = "alloc")] +#[deprecated(since="0.6.0", note="use IteratorRandom::choose_multiple instead")] +pub fn sample_iter(rng: &mut R, iterable: I, amount: usize) -> Result, Vec> + where I: IntoIterator, + R: Rng + ?Sized, +{ + use seq::IteratorRandom; + let iter = iterable.into_iter(); + let result = iter.choose_multiple(rng, amount); + if result.len() == amount { + Ok(result) + } else { + Err(result) + } +} + +/// Randomly sample exactly `amount` values from `slice`. +/// +/// The values are non-repeating and in random order. +/// +/// This implementation uses `O(amount)` time and memory. +/// +/// Panics if `amount > slice.len()` +/// +/// Deprecated: use [`SliceRandom::choose_multiple`] instead. +#[cfg(feature = "alloc")] +#[deprecated(since="0.6.0", note="use SliceRandom::choose_multiple instead")] +pub fn sample_slice(rng: &mut R, slice: &[T], amount: usize) -> Vec + where R: Rng + ?Sized, + T: Clone +{ + let indices = index::sample(rng, slice.len(), amount).into_iter(); + + let mut out = Vec::with_capacity(amount); + out.extend(indices.map(|i| slice[i].clone())); + out +} + +/// Randomly sample exactly `amount` references from `slice`. +/// +/// The references are non-repeating and in random order. +/// +/// This implementation uses `O(amount)` time and memory. +/// +/// Panics if `amount > slice.len()` +/// +/// Deprecated: use [`SliceRandom::choose_multiple`] instead. +#[cfg(feature = "alloc")] +#[deprecated(since="0.6.0", note="use SliceRandom::choose_multiple instead")] +pub fn sample_slice_ref<'a, R, T>(rng: &mut R, slice: &'a [T], amount: usize) -> Vec<&'a T> + where R: Rng + ?Sized +{ + let indices = index::sample(rng, slice.len(), amount).into_iter(); + + let mut out = Vec::with_capacity(amount); + out.extend(indices.map(|i| &slice[i])); + out +} + +#[cfg(test)] +mod test { + use super::*; + #[cfg(feature = "alloc")] use {Rng, SeedableRng}; + #[cfg(feature = "alloc")] use rngs::SmallRng; + #[cfg(all(feature="alloc", not(feature="std")))] + use alloc::vec::Vec; + + #[test] + fn test_slice_choose() { + let mut r = ::test::rng(107); + let chars = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n']; + let mut chosen = [0i32; 14]; + for _ in 0..1000 { + let picked = *chars.choose(&mut r).unwrap(); + chosen[(picked as usize) - ('a' as usize)] += 1; + } + for count in chosen.iter() { + let err = *count - (1000 / (chars.len() as i32)); + assert!(-20 <= err && err <= 20); + } + + chosen.iter_mut().for_each(|x| *x = 0); + for _ in 0..1000 { + *chosen.choose_mut(&mut r).unwrap() += 1; + } + for count in chosen.iter() { + let err = *count - (1000 / (chosen.len() as i32)); + assert!(-20 <= err && err <= 20); + } + + let mut v: [isize; 0] = []; + assert_eq!(v.choose(&mut r), None); + assert_eq!(v.choose_mut(&mut r), None); + } + + #[derive(Clone)] + struct UnhintedIterator { + iter: I, + } + impl Iterator for UnhintedIterator { + type Item = I::Item; + fn next(&mut self) -> Option { + self.iter.next() + } + } + + #[derive(Clone)] + struct ChunkHintedIterator { + iter: I, + chunk_remaining: usize, + chunk_size: usize, + hint_total_size: bool, + } + impl Iterator for ChunkHintedIterator { + type Item = I::Item; + fn next(&mut self) -> Option { + if self.chunk_remaining == 0 { + self.chunk_remaining = ::core::cmp::min(self.chunk_size, + self.iter.len()); + } + self.chunk_remaining = self.chunk_remaining.saturating_sub(1); + + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + (self.chunk_remaining, + if self.hint_total_size { Some(self.iter.len()) } else { None }) + } + } + + #[derive(Clone)] + struct WindowHintedIterator { + iter: I, + window_size: usize, + hint_total_size: bool, + } + impl Iterator for WindowHintedIterator { + type Item = I::Item; + fn next(&mut self) -> Option { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + (::core::cmp::min(self.iter.len(), self.window_size), + if self.hint_total_size { Some(self.iter.len()) } else { None }) + } + } + + #[test] + fn test_iterator_choose() { + let r = &mut ::test::rng(109); + fn test_iter + Clone>(r: &mut R, iter: Iter) { + let mut chosen = [0i32; 9]; + for _ in 0..1000 { + let picked = iter.clone().choose(r).unwrap(); + chosen[picked] += 1; + } + for count in chosen.iter() { + // Samples should follow Binomial(1000, 1/9) + // Octave: binopdf(x, 1000, 1/9) gives the prob of *count == x + // Note: have seen 153, which is unlikely but not impossible. + assert!(72 < *count && *count < 154, "count not close to 1000/9: {}", count); + } + } + + test_iter(r, 0..9); + test_iter(r, [0, 1, 2, 3, 4, 5, 6, 7, 8].iter().cloned()); + #[cfg(feature = "alloc")] + test_iter(r, (0..9).collect::>().into_iter()); + test_iter(r, UnhintedIterator { iter: 0..9 }); + test_iter(r, ChunkHintedIterator { iter: 0..9, chunk_size: 4, chunk_remaining: 4, hint_total_size: false }); + test_iter(r, ChunkHintedIterator { iter: 0..9, chunk_size: 4, chunk_remaining: 4, hint_total_size: true }); + test_iter(r, WindowHintedIterator { iter: 0..9, window_size: 2, hint_total_size: false }); + test_iter(r, WindowHintedIterator { iter: 0..9, window_size: 2, hint_total_size: true }); + + assert_eq!((0..0).choose(r), None); + assert_eq!(UnhintedIterator{ iter: 0..0 }.choose(r), None); + } + + #[test] + fn test_shuffle() { + let mut r = ::test::rng(108); + let empty: &mut [isize] = &mut []; + empty.shuffle(&mut r); + let mut one = [1]; + one.shuffle(&mut r); + let b: &[_] = &[1]; + assert_eq!(one, b); + + let mut two = [1, 2]; + two.shuffle(&mut r); + assert!(two == [1, 2] || two == [2, 1]); + + fn move_last(slice: &mut [usize], pos: usize) { + // use slice[pos..].rotate_left(1); once we can use that + let last_val = slice[pos]; + for i in pos..slice.len() - 1 { + slice[i] = slice[i + 1]; + } + *slice.last_mut().unwrap() = last_val; + } + let mut counts = [0i32; 24]; + for _ in 0..10000 { + let mut arr: [usize; 4] = [0, 1, 2, 3]; + arr.shuffle(&mut r); + let mut permutation = 0usize; + let mut pos_value = counts.len(); + for i in 0..4 { + pos_value /= 4 - i; + let pos = arr.iter().position(|&x| x == i).unwrap(); + assert!(pos < (4 - i)); + permutation += pos * pos_value; + move_last(&mut arr, pos); + assert_eq!(arr[3], i); + } + for i in 0..4 { + assert_eq!(arr[i], i); + } + counts[permutation] += 1; + } + for count in counts.iter() { + let err = *count - 10000i32 / 24; + assert!(-50 <= err && err <= 50); + } + } + + #[test] + fn test_partial_shuffle() { + let mut r = ::test::rng(118); + + let mut empty: [u32; 0] = []; + let res = empty.partial_shuffle(&mut r, 10); + assert_eq!((res.0.len(), res.1.len()), (0, 0)); + + let mut v = [1, 2, 3, 4, 5]; + let res = v.partial_shuffle(&mut r, 2); + assert_eq!((res.0.len(), res.1.len()), (2, 3)); + assert!(res.0[0] != res.0[1]); + // First elements are only modified if selected, so at least one isn't modified: + assert!(res.1[0] == 1 || res.1[1] == 2 || res.1[2] == 3); + } + + #[test] + #[cfg(feature = "alloc")] + fn test_sample_iter() { + let min_val = 1; + let max_val = 100; + + let mut r = ::test::rng(401); + let vals = (min_val..max_val).collect::>(); + let small_sample = vals.iter().choose_multiple(&mut r, 5); + let large_sample = vals.iter().choose_multiple(&mut r, vals.len() + 5); + + assert_eq!(small_sample.len(), 5); + assert_eq!(large_sample.len(), vals.len()); + // no randomization happens when amount >= len + assert_eq!(large_sample, vals.iter().collect::>()); + + assert!(small_sample.iter().all(|e| { + **e >= min_val && **e <= max_val + })); + } + + #[test] + #[cfg(feature = "alloc")] + #[allow(deprecated)] + fn test_sample_slice_boundaries() { + let empty: &[u8] = &[]; + + let mut r = ::test::rng(402); + + // sample 0 items + assert_eq!(&sample_slice(&mut r, empty, 0)[..], [0u8; 0]); + assert_eq!(&sample_slice(&mut r, &[42, 2, 42], 0)[..], [0u8; 0]); + + // sample 1 item + assert_eq!(&sample_slice(&mut r, &[42], 1)[..], [42]); + let v = sample_slice(&mut r, &[1, 42], 1)[0]; + assert!(v == 1 || v == 42); + + // sample "all" the items + let v = sample_slice(&mut r, &[42, 133], 2); + assert!(&v[..] == [42, 133] || v[..] == [133, 42]); + + // Make sure lucky 777's aren't lucky + let slice = &[42, 777]; + let mut num_42 = 0; + let total = 1000; + for _ in 0..total { + let v = sample_slice(&mut r, slice, 1); + assert_eq!(v.len(), 1); + let v = v[0]; + assert!(v == 42 || v == 777); + if v == 42 { + num_42 += 1; + } + } + let ratio_42 = num_42 as f64 / 1000 as f64; + assert!(0.4 <= ratio_42 || ratio_42 <= 0.6, "{}", ratio_42); + } + + #[test] + #[cfg(feature = "alloc")] + #[allow(deprecated)] + fn test_sample_slice() { + let seeded_rng = SmallRng::from_seed; + + let mut r = ::test::rng(403); + + for n in 1..20 { + let length = 5*n - 4; // 1, 6, ... + let amount = r.gen_range(0, length); + let mut seed = [0u8; 16]; + r.fill(&mut seed); + + // assert the basics work + let regular = index::sample(&mut seeded_rng(seed), length, amount); + assert_eq!(regular.len(), amount); + assert!(regular.iter().all(|e| e < length)); + + // also test that sampling the slice works + let vec: Vec = (0..(length as u32)).collect(); + let result = sample_slice(&mut seeded_rng(seed), &vec, amount); + assert_eq!(result, regular.iter().map(|i| i as u32).collect::>()); + + let result = sample_slice_ref(&mut seeded_rng(seed), &vec, amount); + assert!(result.iter().zip(regular.iter()).all(|(i,j)| **i == j as u32)); + } + } + + #[test] + #[cfg(feature = "alloc")] + fn test_weighted() { + let mut r = ::test::rng(406); + const N_REPS: u32 = 3000; + let weights = [1u32, 2, 3, 0, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7]; + let total_weight = weights.iter().sum::() as f32; + + let verify = |result: [i32; 14]| { + for (i, count) in result.iter().enumerate() { + let exp = (weights[i] * N_REPS) as f32 / total_weight; + let mut err = (*count as f32 - exp).abs(); + if err != 0.0 { + err /= exp; + } + assert!(err <= 0.25); + } + }; + + // choose_weighted + fn get_weight(item: &(u32, T)) -> u32 { + item.0 + } + let mut chosen = [0i32; 14]; + let mut items = [(0u32, 0usize); 14]; // (weight, index) + for (i, item) in items.iter_mut().enumerate() { + *item = (weights[i], i); + } + for _ in 0..N_REPS { + let item = items.choose_weighted(&mut r, get_weight).unwrap(); + chosen[item.1] += 1; + } + verify(chosen); + + // choose_weighted_mut + let mut items = [(0u32, 0i32); 14]; // (weight, count) + for (i, item) in items.iter_mut().enumerate() { + *item = (weights[i], 0); + } + for _ in 0..N_REPS { + items.choose_weighted_mut(&mut r, get_weight).unwrap().1 += 1; + } + for (ch, item) in chosen.iter_mut().zip(items.iter()) { + *ch = item.1; + } + verify(chosen); + + // Check error cases + let empty_slice = &mut [10][0..0]; + assert_eq!(empty_slice.choose_weighted(&mut r, |_| 1), Err(WeightedError::NoItem)); + assert_eq!(empty_slice.choose_weighted_mut(&mut r, |_| 1), Err(WeightedError::NoItem)); + assert_eq!(['x'].choose_weighted_mut(&mut r, |_| 0), Err(WeightedError::AllWeightsZero)); + assert_eq!([0, -1].choose_weighted_mut(&mut r, |x| *x), Err(WeightedError::NegativeWeight)); + assert_eq!([-1, 0].choose_weighted_mut(&mut r, |x| *x), Err(WeightedError::NegativeWeight)); + } +} diff --git a/third_party/rust/rand/tests/uniformity.rs b/third_party/rust/rand/tests/uniformity.rs new file mode 100644 index 000000000000..b8f74a62e5bd --- /dev/null +++ b/third_party/rust/rand/tests/uniformity.rs @@ -0,0 +1,67 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg(feature = "std")] + +#[macro_use] +extern crate average; +extern crate rand; + +use std as core; +use rand::FromEntropy; +use rand::distributions::Distribution; +use average::Histogram; + +const N_BINS: usize = 100; +const N_SAMPLES: u32 = 1_000_000; +const TOL: f64 = 1e-3; +define_histogram!(hist, 100); +use hist::Histogram as Histogram100; + +#[test] +fn unit_sphere() { + const N_DIM: usize = 3; + let h = Histogram100::with_const_width(-1., 1.); + let mut histograms = [h.clone(), h.clone(), h]; + let dist = rand::distributions::UnitSphereSurface::new(); + let mut rng = rand::rngs::SmallRng::from_entropy(); + for _ in 0..N_SAMPLES { + let v = dist.sample(&mut rng); + for i in 0..N_DIM { + histograms[i].add(v[i]).map_err( + |e| { println!("v: {}", v[i]); e } + ).unwrap(); + } + } + for h in &histograms { + let sum: u64 = h.bins().iter().sum(); + println!("{:?}", h); + for &b in h.bins() { + let p = (b as f64) / (sum as f64); + assert!((p - 1.0 / (N_BINS as f64)).abs() < TOL, "{}", p); + } + } +} + +#[test] +fn unit_circle() { + use ::std::f64::consts::PI; + let mut h = Histogram100::with_const_width(-PI, PI); + let dist = rand::distributions::UnitCircle::new(); + let mut rng = rand::rngs::SmallRng::from_entropy(); + for _ in 0..N_SAMPLES { + let v = dist.sample(&mut rng); + h.add(v[0].atan2(v[1])).unwrap(); + } + let sum: u64 = h.bins().iter().sum(); + println!("{:?}", h); + for &b in h.bins() { + let p = (b as f64) / (sum as f64); + assert!((p - 1.0 / (N_BINS as f64)).abs() < TOL, "{}", p); + } +} diff --git a/third_party/rust/rand_chacha/.cargo-checksum.json b/third_party/rust/rand_chacha/.cargo-checksum.json new file mode 100644 index 000000000000..42ac0826af27 --- /dev/null +++ b/third_party/rust/rand_chacha/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"66b938cf98ad5c5305ef4cc07886b0f64d9985189f6b32630bf32712a0395e5d","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.toml":"020a747006ee14a2faae021077d5f2d1b41c90a79f97a79bd33a6fc2b256206f","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"2c4782326824e620912d671f1903722c60ada94c440817ff5e6f83e784f472bf","build.rs":"003108281c4f4bd7a40a93529012acc9d2555c7a4f4b3bfc3ab81d0ed92b8864","src/chacha.rs":"ea9bc97d0fec99d627fcd5ee57f3e187571efdea752ef4b514d1ae0c00476801","src/lib.rs":"ff1162b8836ccc23763cf7f64fa92c2d91b09d1b9ac80960a1486dca6d8a23ca"},"package":"556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"} \ No newline at end of file diff --git a/third_party/rust/rand_chacha/CHANGELOG.md b/third_party/rust/rand_chacha/CHANGELOG.md new file mode 100644 index 000000000000..a1979f601cb2 --- /dev/null +++ b/third_party/rust/rand_chacha/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.1.1] - 2019-01-04 +- Disable `i128` and `u128` if the `target_os` is `emscripten` (#671: work-around Emscripten limitation) +- Update readme and doc links + +## [0.1.0] - 2018-10-17 +- Pulled out of the Rand crate diff --git a/third_party/rust/rand_chacha/COPYRIGHT b/third_party/rust/rand_chacha/COPYRIGHT new file mode 100644 index 000000000000..468d907caf99 --- /dev/null +++ b/third_party/rust/rand_chacha/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 or + or the MIT license + or , at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/third_party/rust/rand_chacha/Cargo.toml b/third_party/rust/rand_chacha/Cargo.toml new file mode 100644 index 000000000000..e6d5523021ca --- /dev/null +++ b/third_party/rust/rand_chacha/Cargo.toml @@ -0,0 +1,35 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand_chacha" +version = "0.1.1" +authors = ["The Rand Project Developers", "The Rust Project Developers"] +build = "build.rs" +description = "ChaCha random number generator\n" +homepage = "https://crates.io/crates/rand_chacha" +documentation = "https://rust-random.github.io/rand/rand_chacha" +readme = "README.md" +keywords = ["random", "rng", "chacha"] +categories = ["algorithms", "no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-random/rand" +[dependencies.rand_core] +version = ">=0.2, <0.4" +default-features = false +[build-dependencies.autocfg] +version = "0.1" +[badges.appveyor] +repository = "rust-random/rand" + +[badges.travis-ci] +repository = "rust-random/rand" diff --git a/third_party/rust/rand_chacha/LICENSE-APACHE b/third_party/rust/rand_chacha/LICENSE-APACHE new file mode 100644 index 000000000000..17d74680f8cf --- /dev/null +++ b/third_party/rust/rand_chacha/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/rand_chacha/LICENSE-MIT b/third_party/rust/rand_chacha/LICENSE-MIT new file mode 100644 index 000000000000..d93b5baf341d --- /dev/null +++ b/third_party/rust/rand_chacha/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright 2018 Developers of the Rand project +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/rand_chacha/README.md b/third_party/rust/rand_chacha/README.md new file mode 100644 index 000000000000..5a1dbac8ac71 --- /dev/null +++ b/third_party/rust/rand_chacha/README.md @@ -0,0 +1,45 @@ +# rand_chacha + +[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Latest version](https://img.shields.io/crates/v/rand_chacha.svg)](https://crates.io/crates/rand_chacha) +[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) +[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_chacha) +[![API](https://docs.rs/rand_chacha/badge.svg)](https://docs.rs/rand_chacha) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) + +A cryptographically secure random number generator that uses the ChaCha +algorithm. + +ChaCha is a stream cipher designed by Daniel J. Bernstein[^1], that we use +as an RNG. It is an improved variant of the Salsa20 cipher family, which was +selected as one of the "stream ciphers suitable for widespread adoption" by +eSTREAM[^2]. + +Links: + +- [API documentation (master)](https://rust-random.github.io/rand/rand_chacha) +- [API documentation (docs.rs)](https://docs.rs/rand_chacha) +- [Changelog](CHANGELOG.md) + +[rand]: https://crates.io/crates/rand +[^1]: D. J. Bernstein, [*ChaCha, a variant of Salsa20*]( + https://cr.yp.to/chacha.html) + +[^2]: [eSTREAM: the ECRYPT Stream Cipher Project]( + http://www.ecrypt.eu.org/stream/) + + +## Crate Features + +`rand_chacha` is `no_std` compatible. It does not require any functionality +outside of the `core` lib, thus there are no features to configure. + + +# License + +`rand_chacha` is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/third_party/rust/rand_chacha/build.rs b/third_party/rust/rand_chacha/build.rs new file mode 100644 index 000000000000..06e12a47b6e8 --- /dev/null +++ b/third_party/rust/rand_chacha/build.rs @@ -0,0 +1,7 @@ +extern crate autocfg; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + let ac = autocfg::new(); + ac.emit_rustc_version(1, 26); +} diff --git a/third_party/rust/rand_chacha/src/chacha.rs b/third_party/rust/rand_chacha/src/chacha.rs new file mode 100644 index 000000000000..86f191e49aba --- /dev/null +++ b/third_party/rust/rand_chacha/src/chacha.rs @@ -0,0 +1,449 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2014 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The ChaCha random number generator. + +use core::fmt; +use rand_core::{CryptoRng, RngCore, SeedableRng, Error, le}; +use rand_core::block::{BlockRngCore, BlockRng}; + +const SEED_WORDS: usize = 8; // 8 words for the 256-bit key +const STATE_WORDS: usize = 16; + +/// A cryptographically secure random number generator that uses the ChaCha +/// algorithm. +/// +/// ChaCha is a stream cipher designed by Daniel J. Bernstein[^1], that we use +/// as an RNG. It is an improved variant of the Salsa20 cipher family, which was +/// selected as one of the "stream ciphers suitable for widespread adoption" by +/// eSTREAM[^2]. +/// +/// ChaCha uses add-rotate-xor (ARX) operations as its basis. These are safe +/// against timing attacks, although that is mostly a concern for ciphers and +/// not for RNGs. Also it is very suitable for SIMD implementation. +/// Here we do not provide a SIMD implementation yet, except for what is +/// provided by auto-vectorisation. +/// +/// With the ChaCha algorithm it is possible to choose the number of rounds the +/// core algorithm should run. The number of rounds is a tradeoff between +/// performance and security, where 8 rounds is the minimum potentially +/// secure configuration, and 20 rounds is widely used as a conservative choice. +/// We use 20 rounds in this implementation, but hope to allow type-level +/// configuration in the future. +/// +/// We use a 64-bit counter and 64-bit stream identifier as in Bernstein's +/// implementation[^1] except that we use a stream identifier in place of a +/// nonce. A 64-bit counter over 64-byte (16 word) blocks allows 1 ZiB of output +/// before cycling, and the stream identifier allows 264 unique +/// streams of output per seed. Both counter and stream are initialized to zero +/// but may be set via [`set_word_pos`] and [`set_stream`]. +/// +/// The word layout is: +/// +/// ```text +/// constant constant constant constant +/// seed seed seed seed +/// seed seed seed seed +/// counter counter stream_id stream_id +/// ``` +/// +/// This implementation uses an output buffer of sixteen `u32` words, and uses +/// [`BlockRng`] to implement the [`RngCore`] methods. +/// +/// [^1]: D. J. Bernstein, [*ChaCha, a variant of Salsa20*]( +/// https://cr.yp.to/chacha.html) +/// +/// [^2]: [eSTREAM: the ECRYPT Stream Cipher Project]( +/// http://www.ecrypt.eu.org/stream/) +/// +/// [`set_word_pos`]: #method.set_word_pos +/// [`set_stream`]: #method.set_stream +/// [`BlockRng`]: ../rand_core/block/struct.BlockRng.html +/// [`RngCore`]: ../rand_core/trait.RngCore.html +#[derive(Clone, Debug)] +pub struct ChaChaRng(BlockRng); + +impl RngCore for ChaChaRng { + #[inline] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest) + } + + #[inline] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for ChaChaRng { + type Seed = ::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + ChaChaRng(BlockRng::::from_seed(seed)) + } + + fn from_rng(rng: R) -> Result { + BlockRng::::from_rng(rng).map(ChaChaRng) + } +} + +impl CryptoRng for ChaChaRng {} + +impl ChaChaRng { + /// Get the offset from the start of the stream, in 32-bit words. + /// + /// Since the generated blocks are 16 words (24) long and the + /// counter is 64-bits, the offset is a 68-bit number. Sub-word offsets are + /// not supported, hence the result can simply be multiplied by 4 to get a + /// byte-offset. + /// + /// Note: this function is currently only available with Rust 1.26 or later. + #[cfg(all(rustc_1_26, not(target_os = "emscripten")))] + pub fn get_word_pos(&self) -> u128 { + let mut c = (self.0.core.state[13] as u64) << 32 + | (self.0.core.state[12] as u64); + let mut index = self.0.index(); + // c is the end of the last block generated, unless index is at end + if index >= STATE_WORDS { + index = 0; + } else { + c = c.wrapping_sub(1); + } + ((c as u128) << 4) | (index as u128) + } + + /// Set the offset from the start of the stream, in 32-bit words. + /// + /// As with `get_word_pos`, we use a 68-bit number. Since the generator + /// simply cycles at the end of its period (1 ZiB), we ignore the upper + /// 60 bits. + /// + /// Note: this function is currently only available with Rust 1.26 or later. + #[cfg(all(rustc_1_26, not(target_os = "emscripten")))] + pub fn set_word_pos(&mut self, word_offset: u128) { + let index = (word_offset as usize) & 0xF; + let counter = (word_offset >> 4) as u64; + self.0.core.state[12] = counter as u32; + self.0.core.state[13] = (counter >> 32) as u32; + if index != 0 { + self.0.generate_and_set(index); // also increments counter + } else { + self.0.reset(); + } + } + + /// Set the stream number. + /// + /// This is initialized to zero; 264 unique streams of output + /// are available per seed/key. + /// + /// Note that in order to reproduce ChaCha output with a specific 64-bit + /// nonce, one can convert that nonce to a `u64` in little-endian fashion + /// and pass to this function. In theory a 96-bit nonce can be used by + /// passing the last 64-bits to this function and using the first 32-bits as + /// the most significant half of the 64-bit counter (which may be set + /// indirectly via `set_word_pos`), but this is not directly supported. + pub fn set_stream(&mut self, stream: u64) { + let index = self.0.index(); + self.0.core.state[14] = stream as u32; + self.0.core.state[15] = (stream >> 32) as u32; + if index < STATE_WORDS { + // we need to regenerate a partial result buffer + { + // reverse of counter adjustment in generate() + if self.0.core.state[12] == 0 { + self.0.core.state[13] = self.0.core.state[13].wrapping_sub(1); + } + self.0.core.state[12] = self.0.core.state[12].wrapping_sub(1); + } + self.0.generate_and_set(index); + } + } +} + +/// The core of `ChaChaRng`, used with `BlockRng`. +#[derive(Clone)] +pub struct ChaChaCore { + state: [u32; STATE_WORDS], +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for ChaChaCore { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "ChaChaCore {{}}") + } +} + +macro_rules! quarter_round{ + ($a: expr, $b: expr, $c: expr, $d: expr) => {{ + $a = $a.wrapping_add($b); $d ^= $a; $d = $d.rotate_left(16); + $c = $c.wrapping_add($d); $b ^= $c; $b = $b.rotate_left(12); + $a = $a.wrapping_add($b); $d ^= $a; $d = $d.rotate_left( 8); + $c = $c.wrapping_add($d); $b ^= $c; $b = $b.rotate_left( 7); + }} +} + +macro_rules! double_round{ + ($x: expr) => {{ + // Column round + quarter_round!($x[ 0], $x[ 4], $x[ 8], $x[12]); + quarter_round!($x[ 1], $x[ 5], $x[ 9], $x[13]); + quarter_round!($x[ 2], $x[ 6], $x[10], $x[14]); + quarter_round!($x[ 3], $x[ 7], $x[11], $x[15]); + // Diagonal round + quarter_round!($x[ 0], $x[ 5], $x[10], $x[15]); + quarter_round!($x[ 1], $x[ 6], $x[11], $x[12]); + quarter_round!($x[ 2], $x[ 7], $x[ 8], $x[13]); + quarter_round!($x[ 3], $x[ 4], $x[ 9], $x[14]); + }} +} + +impl BlockRngCore for ChaChaCore { + type Item = u32; + type Results = [u32; STATE_WORDS]; + + fn generate(&mut self, results: &mut Self::Results) { + // For some reason extracting this part into a separate function + // improves performance by 50%. + fn core(results: &mut [u32; STATE_WORDS], + state: &[u32; STATE_WORDS]) + { + let mut tmp = *state; + let rounds = 20; + for _ in 0..rounds / 2 { + double_round!(tmp); + } + for i in 0..STATE_WORDS { + results[i] = tmp[i].wrapping_add(state[i]); + } + } + + core(results, &self.state); + + // update 64-bit counter + self.state[12] = self.state[12].wrapping_add(1); + if self.state[12] != 0 { return; }; + self.state[13] = self.state[13].wrapping_add(1); + } +} + +impl SeedableRng for ChaChaCore { + type Seed = [u8; SEED_WORDS*4]; + + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_le = [0u32; SEED_WORDS]; + le::read_u32_into(&seed, &mut seed_le); + Self { + state: [0x61707865, 0x3320646E, 0x79622D32, 0x6B206574, // constants + seed_le[0], seed_le[1], seed_le[2], seed_le[3], // seed + seed_le[4], seed_le[5], seed_le[6], seed_le[7], // seed + 0, 0, 0, 0], // counter + } + } +} + +impl CryptoRng for ChaChaCore {} + +impl From for ChaChaRng { + fn from(core: ChaChaCore) -> Self { + ChaChaRng(BlockRng::new(core)) + } +} + +#[cfg(test)] +mod test { + use ::rand_core::{RngCore, SeedableRng}; + use super::ChaChaRng; + + #[test] + fn test_chacha_construction() { + let seed = [0,0,0,0,0,0,0,0, + 1,0,0,0,0,0,0,0, + 2,0,0,0,0,0,0,0, + 3,0,0,0,0,0,0,0]; + let mut rng1 = ChaChaRng::from_seed(seed); + assert_eq!(rng1.next_u32(), 137206642); + + let mut rng2 = ChaChaRng::from_rng(rng1).unwrap(); + assert_eq!(rng2.next_u32(), 1325750369); + } + + #[test] + fn test_chacha_true_values_a() { + // Test vectors 1 and 2 from + // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 + let seed = [0u8; 32]; + let mut rng = ChaChaRng::from_seed(seed); + + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0xade0b876, 0x903df1a0, 0xe56a5d40, 0x28bd8653, + 0xb819d2bd, 0x1aed8da0, 0xccef36a8, 0xc70d778b, + 0x7c5941da, 0x8d485751, 0x3fe02477, 0x374ad8b8, + 0xf4b8436a, 0x1ca11815, 0x69b687c3, 0x8665eeb2]; + assert_eq!(results, expected); + + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0xbee7079f, 0x7a385155, 0x7c97ba98, 0x0d082d73, + 0xa0290fcb, 0x6965e348, 0x3e53c612, 0xed7aee32, + 0x7621b729, 0x434ee69c, 0xb03371d5, 0xd539d874, + 0x281fed31, 0x45fb0a51, 0x1f0ae1ac, 0x6f4d794b]; + assert_eq!(results, expected); + } + + #[test] + fn test_chacha_true_values_b() { + // Test vector 3 from + // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 + let seed = [0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1]; + let mut rng = ChaChaRng::from_seed(seed); + + // Skip block 0 + for _ in 0..16 { rng.next_u32(); } + + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0x2452eb3a, 0x9249f8ec, 0x8d829d9b, 0xddd4ceb1, + 0xe8252083, 0x60818b01, 0xf38422b8, 0x5aaa49c9, + 0xbb00ca8e, 0xda3ba7b4, 0xc4b592d1, 0xfdf2732f, + 0x4436274e, 0x2561b3c8, 0xebdd4aa6, 0xa0136c00]; + assert_eq!(results, expected); + } + + #[test] + #[cfg(all(rustc_1_26, not(target_os = "emscripten")))] + fn test_chacha_true_values_c() { + // Test vector 4 from + // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 + let seed = [0, 0xff, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0]; + let expected = [0xfb4dd572, 0x4bc42ef1, 0xdf922636, 0x327f1394, + 0xa78dea8f, 0x5e269039, 0xa1bebbc1, 0xcaf09aae, + 0xa25ab213, 0x48a6b46c, 0x1b9d9bcb, 0x092c5be6, + 0x546ca624, 0x1bec45d5, 0x87f47473, 0x96f0992e]; + let expected_end = 3 * 16; + let mut results = [0u32; 16]; + + // Test block 2 by skipping block 0 and 1 + let mut rng1 = ChaChaRng::from_seed(seed); + for _ in 0..32 { rng1.next_u32(); } + for i in results.iter_mut() { *i = rng1.next_u32(); } + assert_eq!(results, expected); + assert_eq!(rng1.get_word_pos(), expected_end); + + // Test block 2 by using `set_word_pos` + let mut rng2 = ChaChaRng::from_seed(seed); + rng2.set_word_pos(2 * 16); + for i in results.iter_mut() { *i = rng2.next_u32(); } + assert_eq!(results, expected); + assert_eq!(rng2.get_word_pos(), expected_end); + + // Test skipping behaviour with other types + let mut buf = [0u8; 32]; + rng2.fill_bytes(&mut buf[..]); + assert_eq!(rng2.get_word_pos(), expected_end + 8); + rng2.fill_bytes(&mut buf[0..25]); + assert_eq!(rng2.get_word_pos(), expected_end + 15); + rng2.next_u64(); + assert_eq!(rng2.get_word_pos(), expected_end + 17); + rng2.next_u32(); + rng2.next_u64(); + assert_eq!(rng2.get_word_pos(), expected_end + 20); + rng2.fill_bytes(&mut buf[0..1]); + assert_eq!(rng2.get_word_pos(), expected_end + 21); + } + + #[test] + fn test_chacha_multiple_blocks() { + let seed = [0,0,0,0, 1,0,0,0, 2,0,0,0, 3,0,0,0, 4,0,0,0, 5,0,0,0, 6,0,0,0, 7,0,0,0]; + let mut rng = ChaChaRng::from_seed(seed); + + // Store the 17*i-th 32-bit word, + // i.e., the i-th word of the i-th 16-word block + let mut results = [0u32; 16]; + for i in results.iter_mut() { + *i = rng.next_u32(); + for _ in 0..16 { + rng.next_u32(); + } + } + let expected = [0xf225c81a, 0x6ab1be57, 0x04d42951, 0x70858036, + 0x49884684, 0x64efec72, 0x4be2d186, 0x3615b384, + 0x11cfa18e, 0xd3c50049, 0x75c775f6, 0x434c6530, + 0x2c5bad8f, 0x898881dc, 0x5f1c86d9, 0xc1f8e7f4]; + assert_eq!(results, expected); + } + + #[test] + fn test_chacha_true_bytes() { + let seed = [0u8; 32]; + let mut rng = ChaChaRng::from_seed(seed); + let mut results = [0u8; 32]; + rng.fill_bytes(&mut results); + let expected = [118, 184, 224, 173, 160, 241, 61, 144, + 64, 93, 106, 229, 83, 134, 189, 40, + 189, 210, 25, 184, 160, 141, 237, 26, + 168, 54, 239, 204, 139, 119, 13, 199]; + assert_eq!(results, expected); + } + + #[test] + fn test_chacha_nonce() { + // Test vector 5 from + // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 + // Although we do not support setting a nonce, we try it here anyway so + // we can use this test vector. + let seed = [0u8; 32]; + let mut rng = ChaChaRng::from_seed(seed); + // 96-bit nonce in LE order is: 0,0,0,0, 0,0,0,0, 0,0,0,2 + rng.set_stream(2u64 << (24 + 32)); + + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0x374dc6c2, 0x3736d58c, 0xb904e24a, 0xcd3f93ef, + 0x88228b1a, 0x96a4dfb3, 0x5b76ab72, 0xc727ee54, + 0x0e0e978a, 0xf3145c95, 0x1b748ea8, 0xf786c297, + 0x99c28f5f, 0x628314e8, 0x398a19fa, 0x6ded1b53]; + assert_eq!(results, expected); + } + + #[test] + fn test_chacha_clone_streams() { + let seed = [0,0,0,0, 1,0,0,0, 2,0,0,0, 3,0,0,0, 4,0,0,0, 5,0,0,0, 6,0,0,0, 7,0,0,0]; + let mut rng = ChaChaRng::from_seed(seed); + let mut clone = rng.clone(); + for _ in 0..16 { + assert_eq!(rng.next_u64(), clone.next_u64()); + } + + rng.set_stream(51); + for _ in 0..7 { + assert!(rng.next_u32() != clone.next_u32()); + } + clone.set_stream(51); // switch part way through block + for _ in 7..16 { + assert_eq!(rng.next_u32(), clone.next_u32()); + } + } +} diff --git a/third_party/rust/rand_chacha/src/lib.rs b/third_party/rust/rand_chacha/src/lib.rs new file mode 100644 index 000000000000..8cff03ac0b25 --- /dev/null +++ b/third_party/rust/rand_chacha/src/lib.rs @@ -0,0 +1,25 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The ChaCha random number generator. + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://rust-random.github.io/rand/")] + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +#![no_std] + +extern crate rand_core; + +mod chacha; + +pub use chacha::{ChaChaRng, ChaChaCore}; diff --git a/third_party/rust/rand_core-0.3.1/.cargo-checksum.json b/third_party/rust/rand_core-0.3.1/.cargo-checksum.json new file mode 100644 index 000000000000..1fd20d4763c4 --- /dev/null +++ b/third_party/rust/rand_core-0.3.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"35b32c8dc19610e66f7c6967e93f5a0f49e5a021c633da72e7219571cfb7b457","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.toml":"38f22c1be27541f74b322a721c95aaacd622cddfa02cfa22f7976d613453dc78","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"2781af9ae12e434bb3f43c5a3b16b330eea7a8c80065e28e967333a82be7a507","src/block.rs":"43778ab70f0b650c3203a6da70b40bc33afa845a5e14ef88dd26c18a07b70f88","src/error.rs":"8403a968d7c9bd95cc9f23d9dc5cc4771ede8e81dda5a8fdd59d347590345d14","src/impls.rs":"c248ddd04a65c974768baaec028fa0d2a6117525fa27bce8a98f2ba2f352700a","src/le.rs":"cb187f58f7514877918f7f47633397e08e20392dcf072bc245d62c9e5238198c","src/lib.rs":"4452ea591ce26f69e6a3dd1341795faeec5c14af35eb4a17aaf2b5d342753cf0"},"package":"7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"} \ No newline at end of file diff --git a/third_party/rust/rand_core-0.3.1/CHANGELOG.md b/third_party/rust/rand_core-0.3.1/CHANGELOG.md new file mode 100644 index 000000000000..e3755364d9cb --- /dev/null +++ b/third_party/rust/rand_core-0.3.1/CHANGELOG.md @@ -0,0 +1,36 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.3.1] - 2019-01-25 +- Compatibility shim around version 0.4 + +## [0.3.0] - 2018-09-24 +- Add `SeedableRng::seed_from_u64` for convenient seeding. (#537) + +## [0.2.1] - 2018-06-08 +- References to a `CryptoRng` now also implement `CryptoRng`. (#470) + +## [0.2.0] - 2018-05-21 +- Enable the `std` feature by default. (#409) +- Remove `BlockRng{64}::inner` and `BlockRng::inner_mut`; instead making `core` public +- Add `BlockRng{64}::index` and `BlockRng{64}::generate_and_set`. (#374, #419) +- Change `BlockRngCore::Results` bound to also require `AsMut<[Self::Item]>`. (#419) +- Implement `std::io::Read` for RngCore. (#434) + +## [0.1.0] - 2018-04-17 +(Split out of the Rand crate, changes here are relative to rand 0.4.2) +- `RngCore` and `SeedableRng` are now part of `rand_core`. (#288) +- Add modules to help implementing RNGs `impl` and `le`. (#209, #228) +- Add `Error` and `ErrorKind`. (#225) +- Add `CryptoRng` marker trait. (#273) +- Add `BlockRngCore` trait. (#281) +- Add `BlockRng` and `BlockRng64` wrappers to help implementations. (#281, #325) +- Revise the `SeedableRng` trait. (#233) +- Remove default implementations for `RngCore::next_u64` and `RngCore::fill_bytes`. (#288) +- Add `RngCore::try_fill_bytes`. (#225) + +## [0.0.1] - 2017-09-14 (yanked) +Experimental version as part of the rand crate refactor. diff --git a/third_party/rust/rand_core-0.3.1/COPYRIGHT b/third_party/rust/rand_core-0.3.1/COPYRIGHT new file mode 100644 index 000000000000..468d907caf99 --- /dev/null +++ b/third_party/rust/rand_core-0.3.1/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 or + or the MIT license + or , at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/third_party/rust/rand_core-0.3.1/Cargo.toml b/third_party/rust/rand_core-0.3.1/Cargo.toml new file mode 100644 index 000000000000..439b7d174391 --- /dev/null +++ b/third_party/rust/rand_core-0.3.1/Cargo.toml @@ -0,0 +1,37 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand_core" +version = "0.3.1" +authors = ["The Rand Project Developers", "The Rust Project Developers"] +description = "Core random number generator traits and tools for implementation.\n" +homepage = "https://crates.io/crates/rand_core" +documentation = "https://rust-random.github.io/rand/rand_core" +readme = "README.md" +keywords = ["random", "rng"] +categories = ["algorithms", "no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-random/rand" +[dependencies.rand_core] +version = "0.4" + +[features] +alloc = ["rand_core/alloc"] +default = ["std"] +serde1 = ["rand_core/serde1"] +std = ["rand_core/std"] +[badges.appveyor] +repository = "rust-random/rand" + +[badges.travis-ci] +repository = "rust-random/rand" diff --git a/third_party/rust/rand_core-0.3.1/LICENSE-APACHE b/third_party/rust/rand_core-0.3.1/LICENSE-APACHE new file mode 100644 index 000000000000..17d74680f8cf --- /dev/null +++ b/third_party/rust/rand_core-0.3.1/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/rand_core-0.3.1/LICENSE-MIT b/third_party/rust/rand_core-0.3.1/LICENSE-MIT new file mode 100644 index 000000000000..d93b5baf341d --- /dev/null +++ b/third_party/rust/rand_core-0.3.1/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright 2018 Developers of the Rand project +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/rand_core-0.3.1/README.md b/third_party/rust/rand_core-0.3.1/README.md new file mode 100644 index 000000000000..dee650482109 --- /dev/null +++ b/third_party/rust/rand_core-0.3.1/README.md @@ -0,0 +1,65 @@ +# rand_core + +[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Latest version](https://img.shields.io/crates/v/rand_core.svg)](https://crates.io/crates/rand_core) +[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) +[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_core) +[![API](https://docs.rs/rand_core/badge.svg)](https://docs.rs/rand_core) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) + +Core traits and error types of the [rand] library, plus tools for implementing +RNGs. + +This crate is intended for use when implementing the core trait, `RngCore`; it +defines the core traits to be implemented as well as several small functions to +aid in their implementation and types required for error handling. + +The main [rand] crate re-exports most items defined in this crate, along with +tools to convert the integer samples generated by `RngCore` to many different +applications (including sampling from restricted ranges, conversion to floating +point, list permutations and secure initialisation of RNGs). Most users should +prefer to use the main [rand] crate. + +Links: + +- [API documentation (master)](https://rust-random.github.io/rand/rand_core) +- [API documentation (docs.rs)](https://docs.rs/rand_core) +- [Changelog](CHANGELOG.md) + +[rand]: https://crates.io/crates/rand + + +## Functionality + +The `rand_core` crate provides: + +- base random number generator traits +- error-reporting types +- functionality to aid implementation of RNGs + +The traits and error types are also available via `rand`. + +## Crate Features + +`rand_core` supports `no_std` and `alloc`-only configurations, as well as full +`std` functionality. The differences between `no_std` and full `std` are small, +comprising `RngCore` support for `Box` types where `R: RngCore`, as well as +extensions to the `Error` type's functionality. + +Due to [rust-lang/cargo#1596](https://github.com/rust-lang/cargo/issues/1596), +`rand_core` is built without `std` support by default. Since features are +unioned across the whole dependency tree, any crate using `rand` with its +default features will also enable `std` support in `rand_core`. + +The `serde1` feature can be used to derive `Serialize` and `Deserialize` for RNG +implementations that use the `BlockRng` or `BlockRng64` wrappers. + + +# License + +`rand_core` is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/third_party/rust/rand_core-0.3.1/src/block.rs b/third_party/rust/rand_core-0.3.1/src/block.rs new file mode 100644 index 000000000000..3045b9482f47 --- /dev/null +++ b/third_party/rust/rand_core-0.3.1/src/block.rs @@ -0,0 +1,499 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The `BlockRngCore` trait and implementation helpers +//! +//! The [`BlockRngCore`] trait exists to assist in the implementation of RNGs +//! which generate a block of data in a cache instead of returning generated +//! values directly. +//! +//! Usage of this trait is optional, but provides two advantages: +//! implementations only need to concern themselves with generation of the +//! block, not the various [`RngCore`] methods (especially [`fill_bytes`], where +//! the optimal implementations are not trivial), and this allows +//! `ReseedingRng` (see [`rand`](https://docs.rs/rand) crate) perform periodic +//! reseeding with very low overhead. +//! +//! # Example +//! +//! ```norun +//! use rand_core::block::{BlockRngCore, BlockRng}; +//! +//! struct MyRngCore; +//! +//! impl BlockRngCore for MyRngCore { +//! type Results = [u32; 16]; +//! +//! fn generate(&mut self, results: &mut Self::Results) { +//! unimplemented!() +//! } +//! } +//! +//! impl SeedableRng for MyRngCore { +//! type Seed = unimplemented!(); +//! fn from_seed(seed: Self::Seed) -> Self { +//! unimplemented!() +//! } +//! } +//! +//! // optionally, also implement CryptoRng for MyRngCore +//! +//! // Final RNG. +//! type MyRng = BlockRng; +//! ``` +//! +//! [`BlockRngCore`]: crate::block::BlockRngCore +//! [`fill_bytes`]: RngCore::fill_bytes + +use core::convert::AsRef; +use core::fmt; +use {RngCore, CryptoRng, SeedableRng, Error}; +use impls::{fill_via_u32_chunks, fill_via_u64_chunks}; + +/// A trait for RNGs which do not generate random numbers individually, but in +/// blocks (typically `[u32; N]`). This technique is commonly used by +/// cryptographic RNGs to improve performance. +/// +/// See the [module][crate::block] documentation for details. +pub trait BlockRngCore { + /// Results element type, e.g. `u32`. + type Item; + + /// Results type. This is the 'block' an RNG implementing `BlockRngCore` + /// generates, which will usually be an array like `[u32; 16]`. + type Results: AsRef<[Self::Item]> + AsMut<[Self::Item]> + Default; + + /// Generate a new block of results. + fn generate(&mut self, results: &mut Self::Results); +} + + +/// A wrapper type implementing [`RngCore`] for some type implementing +/// [`BlockRngCore`] with `u32` array buffer; i.e. this can be used to implement +/// a full RNG from just a `generate` function. +/// +/// The `core` field may be accessed directly but the results buffer may not. +/// PRNG implementations can simply use a type alias +/// (`pub type MyRng = BlockRng;`) but might prefer to use a +/// wrapper type (`pub struct MyRng(BlockRng);`); the latter must +/// re-implement `RngCore` but hides the implementation details and allows +/// extra functionality to be defined on the RNG +/// (e.g. `impl MyRng { fn set_stream(...){...} }`). +/// +/// `BlockRng` has heavily optimized implementations of the [`RngCore`] methods +/// reading values from the results buffer, as well as +/// calling [`BlockRngCore::generate`] directly on the output array when +/// [`fill_bytes`] / [`try_fill_bytes`] is called on a large array. These methods +/// also handle the bookkeeping of when to generate a new batch of values. +/// +/// No whole generated `u32` values are thown away and all values are consumed +/// in-order. [`next_u32`] simply takes the next available `u32` value. +/// [`next_u64`] is implemented by combining two `u32` values, least +/// significant first. [`fill_bytes`] and [`try_fill_bytes`] consume a whole +/// number of `u32` values, converting each `u32` to a byte slice in +/// little-endian order. If the requested byte length is not a multiple of 4, +/// some bytes will be discarded. +/// +/// See also [`BlockRng64`] which uses `u64` array buffers. Currently there is +/// no direct support for other buffer types. +/// +/// For easy initialization `BlockRng` also implements [`SeedableRng`]. +/// +/// [`next_u32`]: RngCore::next_u32 +/// [`next_u64`]: RngCore::next_u64 +/// [`fill_bytes`]: RngCore::fill_bytes +/// [`try_fill_bytes`]: RngCore::try_fill_bytes +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct BlockRng { + results: R::Results, + index: usize, + /// The *core* part of the RNG, implementing the `generate` function. + pub core: R, +} + +// Custom Debug implementation that does not expose the contents of `results`. +impl fmt::Debug for BlockRng { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("BlockRng") + .field("core", &self.core) + .field("result_len", &self.results.as_ref().len()) + .field("index", &self.index) + .finish() + } +} + +impl BlockRng { + /// Create a new `BlockRng` from an existing RNG implementing + /// `BlockRngCore`. Results will be generated on first use. + pub fn new(core: R) -> BlockRng{ + let results_empty = R::Results::default(); + BlockRng { + core, + index: results_empty.as_ref().len(), + results: results_empty, + } + } + + /// Get the index into the result buffer. + /// + /// If this is equal to or larger than the size of the result buffer then + /// the buffer is "empty" and `generate()` must be called to produce new + /// results. + pub fn index(&self) -> usize { + self.index + } + + /// Reset the number of available results. + /// This will force a new set of results to be generated on next use. + pub fn reset(&mut self) { + self.index = self.results.as_ref().len(); + } + + /// Generate a new set of results immediately, setting the index to the + /// given value. + pub fn generate_and_set(&mut self, index: usize) { + assert!(index < self.results.as_ref().len()); + self.core.generate(&mut self.results); + self.index = index; + } +} + +impl> RngCore for BlockRng +where ::Results: AsRef<[u32]> + AsMut<[u32]> +{ + #[inline(always)] + fn next_u32(&mut self) -> u32 { + if self.index >= self.results.as_ref().len() { + self.generate_and_set(0); + } + + let value = self.results.as_ref()[self.index]; + self.index += 1; + value + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + let read_u64 = |results: &[u32], index| { + if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { + // requires little-endian CPU supporting unaligned reads: + unsafe { *(&results[index] as *const u32 as *const u64) } + } else { + let x = u64::from(results[index]); + let y = u64::from(results[index + 1]); + (y << 32) | x + } + }; + + let len = self.results.as_ref().len(); + + let index = self.index; + if index < len-1 { + self.index += 2; + // Read an u64 from the current index + read_u64(self.results.as_ref(), index) + } else if index >= len { + self.generate_and_set(2); + read_u64(self.results.as_ref(), 0) + } else { + let x = u64::from(self.results.as_ref()[len-1]); + self.generate_and_set(1); + let y = u64::from(self.results.as_ref()[0]); + (y << 32) | x + } + } + + // As an optimization we try to write directly into the output buffer. + // This is only enabled for little-endian platforms where unaligned writes + // are known to be safe and fast. + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut filled = 0; + + // Continue filling from the current set of results + if self.index < self.results.as_ref().len() { + let (consumed_u32, filled_u8) = + fill_via_u32_chunks(&self.results.as_ref()[self.index..], + dest); + + self.index += consumed_u32; + filled += filled_u8; + } + + let len_remainder = + (dest.len() - filled) % (self.results.as_ref().len() * 4); + let end_direct = dest.len() - len_remainder; + + while filled < end_direct { + let dest_u32: &mut R::Results = unsafe { + &mut *(dest[filled..].as_mut_ptr() as + *mut ::Results) + }; + self.core.generate(dest_u32); + filled += self.results.as_ref().len() * 4; + self.index = self.results.as_ref().len(); + } + + if len_remainder > 0 { + self.core.generate(&mut self.results); + let (consumed_u32, _) = + fill_via_u32_chunks(self.results.as_ref(), + &mut dest[filled..]); + + self.index = consumed_u32; + } + } + + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut read_len = 0; + while read_len < dest.len() { + if self.index >= self.results.as_ref().len() { + self.generate_and_set(0); + } + let (consumed_u32, filled_u8) = + fill_via_u32_chunks(&self.results.as_ref()[self.index..], + &mut dest[read_len..]); + + self.index += consumed_u32; + read_len += filled_u8; + } + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.fill_bytes(dest); + Ok(()) + } +} + +impl SeedableRng for BlockRng { + type Seed = R::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + Self::new(R::from_seed(seed)) + } + + fn seed_from_u64(seed: u64) -> Self { + Self::new(R::seed_from_u64(seed)) + } + + fn from_rng(rng: S) -> Result { + Ok(Self::new(R::from_rng(rng)?)) + } +} + + + +/// A wrapper type implementing [`RngCore`] for some type implementing +/// [`BlockRngCore`] with `u64` array buffer; i.e. this can be used to implement +/// a full RNG from just a `generate` function. +/// +/// This is similar to [`BlockRng`], but specialized for algorithms that operate +/// on `u64` values. +/// +/// No whole generated `u64` values are thrown away and all values are consumed +/// in-order. [`next_u64`] simply takes the next available `u64` value. +/// [`next_u32`] is however a bit special: half of a `u64` is consumed, leaving +/// the other half in the buffer. If the next function called is [`next_u32`] +/// then the other half is then consumed, however both [`next_u64`] and +/// [`fill_bytes`] discard the rest of any half-consumed `u64`s when called. +/// +/// [`fill_bytes`] and [`try_fill_bytes`] consume a whole number of `u64` +/// values. If the requested length is not a multiple of 8, some bytes will be +/// discarded. +/// +/// [`next_u32`]: RngCore::next_u32 +/// [`next_u64`]: RngCore::next_u64 +/// [`fill_bytes`]: RngCore::fill_bytes +/// [`try_fill_bytes`]: RngCore::try_fill_bytes +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct BlockRng64 { + results: R::Results, + index: usize, + half_used: bool, // true if only half of the previous result is used + /// The *core* part of the RNG, implementing the `generate` function. + pub core: R, +} + +// Custom Debug implementation that does not expose the contents of `results`. +impl fmt::Debug for BlockRng64 { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("BlockRng64") + .field("core", &self.core) + .field("result_len", &self.results.as_ref().len()) + .field("index", &self.index) + .field("half_used", &self.half_used) + .finish() + } +} + +impl BlockRng64 { + /// Create a new `BlockRng` from an existing RNG implementing + /// `BlockRngCore`. Results will be generated on first use. + pub fn new(core: R) -> BlockRng64{ + let results_empty = R::Results::default(); + BlockRng64 { + core, + index: results_empty.as_ref().len(), + half_used: false, + results: results_empty, + } + } + + /// Get the index into the result buffer. + /// + /// If this is equal to or larger than the size of the result buffer then + /// the buffer is "empty" and `generate()` must be called to produce new + /// results. + pub fn index(&self) -> usize { + self.index + } + + /// Reset the number of available results. + /// This will force a new set of results to be generated on next use. + pub fn reset(&mut self) { + self.index = self.results.as_ref().len(); + self.half_used = false; + } + + /// Generate a new set of results immediately, setting the index to the + /// given value. + pub fn generate_and_set(&mut self, index: usize) { + assert!(index < self.results.as_ref().len()); + self.core.generate(&mut self.results); + self.index = index; + self.half_used = false; + } +} + +impl> RngCore for BlockRng64 +where ::Results: AsRef<[u64]> + AsMut<[u64]> +{ + #[inline(always)] + fn next_u32(&mut self) -> u32 { + let mut index = self.index * 2 - self.half_used as usize; + if index >= self.results.as_ref().len() * 2 { + self.core.generate(&mut self.results); + self.index = 0; + // `self.half_used` is by definition `false` + self.half_used = false; + index = 0; + } + + self.half_used = !self.half_used; + self.index += self.half_used as usize; + + // Index as if this is a u32 slice. + unsafe { + let results = + &*(self.results.as_ref() as *const [u64] as *const [u32]); + if cfg!(target_endian = "little") { + *results.get_unchecked(index) + } else { + *results.get_unchecked(index ^ 1) + } + } + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + if self.index >= self.results.as_ref().len() { + self.core.generate(&mut self.results); + self.index = 0; + } + + let value = self.results.as_ref()[self.index]; + self.index += 1; + self.half_used = false; + value + } + + // As an optimization we try to write directly into the output buffer. + // This is only enabled for little-endian platforms where unaligned writes + // are known to be safe and fast. + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut filled = 0; + self.half_used = false; + + // Continue filling from the current set of results + if self.index < self.results.as_ref().len() { + let (consumed_u64, filled_u8) = + fill_via_u64_chunks(&self.results.as_ref()[self.index..], + dest); + + self.index += consumed_u64; + filled += filled_u8; + } + + let len_remainder = + (dest.len() - filled) % (self.results.as_ref().len() * 8); + let end_direct = dest.len() - len_remainder; + + while filled < end_direct { + let dest_u64: &mut R::Results = unsafe { + ::core::mem::transmute(dest[filled..].as_mut_ptr()) + }; + self.core.generate(dest_u64); + filled += self.results.as_ref().len() * 8; + self.index = self.results.as_ref().len(); + } + + if len_remainder > 0 { + self.core.generate(&mut self.results); + let (consumed_u64, _) = + fill_via_u64_chunks(&mut self.results.as_ref(), + &mut dest[filled..]); + + self.index = consumed_u64; + } + } + + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut read_len = 0; + self.half_used = false; + while read_len < dest.len() { + if self.index as usize >= self.results.as_ref().len() { + self.core.generate(&mut self.results); + self.index = 0; + } + + let (consumed_u64, filled_u8) = + fill_via_u64_chunks(&self.results.as_ref()[self.index as usize..], + &mut dest[read_len..]); + + self.index += consumed_u64; + read_len += filled_u8; + } + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} + +impl SeedableRng for BlockRng64 { + type Seed = R::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + Self::new(R::from_seed(seed)) + } + + fn seed_from_u64(seed: u64) -> Self { + Self::new(R::seed_from_u64(seed)) + } + + fn from_rng(rng: S) -> Result { + Ok(Self::new(R::from_rng(rng)?)) + } +} + +impl CryptoRng for BlockRng {} diff --git a/third_party/rust/rand_core-0.3.1/src/error.rs b/third_party/rust/rand_core-0.3.1/src/error.rs new file mode 100644 index 000000000000..5a8459ea8bef --- /dev/null +++ b/third_party/rust/rand_core-0.3.1/src/error.rs @@ -0,0 +1,177 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Error types + +use core::fmt; + +#[cfg(feature="std")] +use std::error::Error as stdError; +#[cfg(feature="std")] +use std::io; + +/// Error kind which can be matched over. +#[derive(PartialEq, Eq, Debug, Copy, Clone)] +pub enum ErrorKind { + /// Feature is not available; not recoverable. + /// + /// This is the most permanent failure type and implies the error cannot be + /// resolved simply by retrying (e.g. the feature may not exist in this + /// build of the application or on the current platform). + Unavailable, + /// General failure; there may be a chance of recovery on retry. + /// + /// This is the catch-all kind for errors from known and unknown sources + /// which do not have a more specific kind / handling method. + /// + /// It is suggested to retry a couple of times or retry later when + /// handling; some error sources may be able to resolve themselves, + /// although this is not likely. + Unexpected, + /// A transient failure which likely can be resolved or worked around. + /// + /// This error kind exists for a few specific cases where it is known that + /// the error likely can be resolved internally, but is reported anyway. + Transient, + /// Not ready yet: recommended to try again a little later. + /// + /// This error kind implies the generator needs more time or needs some + /// other part of the application to do something else first before it is + /// ready for use; for example this may be used by external generators + /// which require time for initialization. + NotReady, + #[doc(hidden)] + __Nonexhaustive, +} + +impl ErrorKind { + /// True if this kind of error may resolve itself on retry. + /// + /// See also `should_wait()`. + pub fn should_retry(self) -> bool { + self != ErrorKind::Unavailable + } + + /// True if we should retry but wait before retrying + /// + /// This implies `should_retry()` is true. + pub fn should_wait(self) -> bool { + self == ErrorKind::NotReady + } + + /// A description of this error kind + pub fn description(self) -> &'static str { + match self { + ErrorKind::Unavailable => "permanently unavailable", + ErrorKind::Unexpected => "unexpected failure", + ErrorKind::Transient => "transient failure", + ErrorKind::NotReady => "not ready yet", + ErrorKind::__Nonexhaustive => unreachable!(), + } + } +} + + +/// Error type of random number generators +/// +/// This is a relatively simple error type, designed for compatibility with and +/// without the Rust `std` library. It embeds a "kind" code, a message (static +/// string only), and an optional chained cause (`std` only). The `kind` and +/// `msg` fields can be accessed directly; cause can be accessed via +/// `std::error::Error::cause` or `Error::take_cause`. Construction can only be +/// done via `Error::new` or `Error::with_cause`. +#[derive(Debug)] +pub struct Error { + /// The error kind + pub kind: ErrorKind, + /// The error message + pub msg: &'static str, + #[cfg(feature="std")] + cause: Option>, +} + +impl Error { + /// Create a new instance, with specified kind and a message. + pub fn new(kind: ErrorKind, msg: &'static str) -> Self { + #[cfg(feature="std")] { + Error { kind, msg, cause: None } + } + #[cfg(not(feature="std"))] { + Error { kind, msg } + } + } + + /// Create a new instance, with specified kind, message, and a + /// chained cause. + /// + /// Note: `stdError` is an alias for `std::error::Error`. + /// + /// If not targetting `std` (i.e. `no_std`), this function is replaced by + /// another with the same prototype, except that there are no bounds on the + /// type `E` (because both `Box` and `stdError` are unavailable), and the + /// `cause` is ignored. + #[cfg(feature="std")] + pub fn with_cause(kind: ErrorKind, msg: &'static str, cause: E) -> Self + where E: Into> + { + Error { kind, msg, cause: Some(cause.into()) } + } + + /// Create a new instance, with specified kind, message, and a + /// chained cause. + /// + /// In `no_std` mode the *cause* is ignored. + #[cfg(not(feature="std"))] + pub fn with_cause(kind: ErrorKind, msg: &'static str, _cause: E) -> Self { + Error { kind, msg } + } + + /// Take the cause, if any. This allows the embedded cause to be extracted. + /// This uses `Option::take`, leaving `self` with no cause. + #[cfg(feature="std")] + pub fn take_cause(&mut self) -> Option> { + self.cause.take() + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + #[cfg(feature="std")] { + if let Some(ref cause) = self.cause { + return write!(f, "{} ({}); cause: {}", + self.msg, self.kind.description(), cause); + } + } + write!(f, "{} ({})", self.msg, self.kind.description()) + } +} + +#[cfg(feature="std")] +impl stdError for Error { + fn description(&self) -> &str { + self.msg + } + + fn cause(&self) -> Option<&stdError> { + self.cause.as_ref().map(|e| e.as_ref() as &stdError) + } +} + +#[cfg(feature="std")] +impl From for io::Error { + fn from(error: Error) -> Self { + use std::io::ErrorKind::*; + match error.kind { + ErrorKind::Unavailable => io::Error::new(NotFound, error), + ErrorKind::Unexpected | + ErrorKind::Transient => io::Error::new(Other, error), + ErrorKind::NotReady => io::Error::new(WouldBlock, error), + ErrorKind::__Nonexhaustive => unreachable!(), + } + } +} diff --git a/third_party/rust/rand_core-0.3.1/src/impls.rs b/third_party/rust/rand_core-0.3.1/src/impls.rs new file mode 100644 index 000000000000..57bdd070d08a --- /dev/null +++ b/third_party/rust/rand_core-0.3.1/src/impls.rs @@ -0,0 +1,165 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Helper functions for implementing `RngCore` functions. +//! +//! For cross-platform reproducibility, these functions all use Little Endian: +//! least-significant part first. For example, `next_u64_via_u32` takes `u32` +//! values `x, y`, then outputs `(y << 32) | x`. To implement `next_u32` +//! from `next_u64` in little-endian order, one should use `next_u64() as u32`. +//! +//! Byte-swapping (like the std `to_le` functions) is only needed to convert +//! to/from byte sequences, and since its purpose is reproducibility, +//! non-reproducible sources (e.g. `OsRng`) need not bother with it. + +use core::intrinsics::transmute; +use core::ptr::copy_nonoverlapping; +use core::slice; +use core::cmp::min; +use core::mem::size_of; +use RngCore; + + +/// Implement `next_u64` via `next_u32`, little-endian order. +pub fn next_u64_via_u32(rng: &mut R) -> u64 { + // Use LE; we explicitly generate one value before the next. + let x = u64::from(rng.next_u32()); + let y = u64::from(rng.next_u32()); + (y << 32) | x +} + +/// Implement `fill_bytes` via `next_u64` and `next_u32`, little-endian order. +/// +/// The fastest way to fill a slice is usually to work as long as possible with +/// integers. That is why this method mostly uses `next_u64`, and only when +/// there are 4 or less bytes remaining at the end of the slice it uses +/// `next_u32` once. +pub fn fill_bytes_via_next(rng: &mut R, dest: &mut [u8]) { + let mut left = dest; + while left.len() >= 8 { + let (l, r) = {left}.split_at_mut(8); + left = r; + let chunk: [u8; 8] = unsafe { + transmute(rng.next_u64().to_le()) + }; + l.copy_from_slice(&chunk); + } + let n = left.len(); + if n > 4 { + let chunk: [u8; 8] = unsafe { + transmute(rng.next_u64().to_le()) + }; + left.copy_from_slice(&chunk[..n]); + } else if n > 0 { + let chunk: [u8; 4] = unsafe { + transmute(rng.next_u32().to_le()) + }; + left.copy_from_slice(&chunk[..n]); + } +} + +macro_rules! impl_uint_from_fill { + ($rng:expr, $ty:ty, $N:expr) => ({ + debug_assert!($N == size_of::<$ty>()); + + let mut int: $ty = 0; + unsafe { + let ptr = &mut int as *mut $ty as *mut u8; + let slice = slice::from_raw_parts_mut(ptr, $N); + $rng.fill_bytes(slice); + } + int + }); +} + +macro_rules! fill_via_chunks { + ($src:expr, $dst:expr, $ty:ty, $size:expr) => ({ + let chunk_size_u8 = min($src.len() * $size, $dst.len()); + let chunk_size = (chunk_size_u8 + $size - 1) / $size; + if cfg!(target_endian="little") { + unsafe { + copy_nonoverlapping( + $src.as_ptr() as *const u8, + $dst.as_mut_ptr(), + chunk_size_u8); + } + } else { + for (&n, chunk) in $src.iter().zip($dst.chunks_mut($size)) { + let tmp = n.to_le(); + let src_ptr = &tmp as *const $ty as *const u8; + unsafe { + copy_nonoverlapping(src_ptr, + chunk.as_mut_ptr(), + chunk.len()); + } + } + } + + (chunk_size, chunk_size_u8) + }); +} + +/// Implement `fill_bytes` by reading chunks from the output buffer of a block +/// based RNG. +/// +/// The return values are `(consumed_u32, filled_u8)`. +/// +/// `filled_u8` is the number of filled bytes in `dest`, which may be less than +/// the length of `dest`. +/// `consumed_u32` is the number of words consumed from `src`, which is the same +/// as `filled_u8 / 4` rounded up. +/// +/// # Example +/// (from `IsaacRng`) +/// +/// ```ignore +/// fn fill_bytes(&mut self, dest: &mut [u8]) { +/// let mut read_len = 0; +/// while read_len < dest.len() { +/// if self.index >= self.rsl.len() { +/// self.isaac(); +/// } +/// +/// let (consumed_u32, filled_u8) = +/// impls::fill_via_u32_chunks(&mut self.rsl[self.index..], +/// &mut dest[read_len..]); +/// +/// self.index += consumed_u32; +/// read_len += filled_u8; +/// } +/// } +/// ``` +pub fn fill_via_u32_chunks(src: &[u32], dest: &mut [u8]) -> (usize, usize) { + fill_via_chunks!(src, dest, u32, 4) +} + +/// Implement `fill_bytes` by reading chunks from the output buffer of a block +/// based RNG. +/// +/// The return values are `(consumed_u64, filled_u8)`. +/// `filled_u8` is the number of filled bytes in `dest`, which may be less than +/// the length of `dest`. +/// `consumed_u64` is the number of words consumed from `src`, which is the same +/// as `filled_u8 / 8` rounded up. +/// +/// See `fill_via_u32_chunks` for an example. +pub fn fill_via_u64_chunks(src: &[u64], dest: &mut [u8]) -> (usize, usize) { + fill_via_chunks!(src, dest, u64, 8) +} + +/// Implement `next_u32` via `fill_bytes`, little-endian order. +pub fn next_u32_via_fill(rng: &mut R) -> u32 { + impl_uint_from_fill!(rng, u32, 4) +} + +/// Implement `next_u64` via `fill_bytes`, little-endian order. +pub fn next_u64_via_fill(rng: &mut R) -> u64 { + impl_uint_from_fill!(rng, u64, 8) +} + +// TODO: implement tests for the above diff --git a/third_party/rust/rand_core-0.3.1/src/le.rs b/third_party/rust/rand_core-0.3.1/src/le.rs new file mode 100644 index 000000000000..266651f10dc7 --- /dev/null +++ b/third_party/rust/rand_core-0.3.1/src/le.rs @@ -0,0 +1,68 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Little-Endian utilities +//! +//! Little-Endian order has been chosen for internal usage; this makes some +//! useful functions available. + +use core::ptr; + +macro_rules! read_slice { + ($src:expr, $dst:expr, $size:expr, $which:ident) => {{ + assert_eq!($src.len(), $size * $dst.len()); + + unsafe { + ptr::copy_nonoverlapping( + $src.as_ptr(), + $dst.as_mut_ptr() as *mut u8, + $src.len()); + } + for v in $dst.iter_mut() { + *v = v.$which(); + } + }}; +} + +/// Reads unsigned 32 bit integers from `src` into `dst`. +/// Borrowed from the `byteorder` crate. +#[inline] +pub fn read_u32_into(src: &[u8], dst: &mut [u32]) { + read_slice!(src, dst, 4, to_le); +} + +/// Reads unsigned 64 bit integers from `src` into `dst`. +/// Borrowed from the `byteorder` crate. +#[inline] +pub fn read_u64_into(src: &[u8], dst: &mut [u64]) { + read_slice!(src, dst, 8, to_le); +} + +#[test] +fn test_read() { + let bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + + let mut buf = [0u32; 4]; + read_u32_into(&bytes, &mut buf); + assert_eq!(buf[0], 0x04030201); + assert_eq!(buf[3], 0x100F0E0D); + + let mut buf = [0u32; 3]; + read_u32_into(&bytes[1..13], &mut buf); // unaligned + assert_eq!(buf[0], 0x05040302); + assert_eq!(buf[2], 0x0D0C0B0A); + + let mut buf = [0u64; 2]; + read_u64_into(&bytes, &mut buf); + assert_eq!(buf[0], 0x0807060504030201); + assert_eq!(buf[1], 0x100F0E0D0C0B0A09); + + let mut buf = [0u64; 1]; + read_u64_into(&bytes[7..15], &mut buf); // unaligned + assert_eq!(buf[0], 0x0F0E0D0C0B0A0908); +} diff --git a/third_party/rust/rand_core-0.3.1/src/lib.rs b/third_party/rust/rand_core-0.3.1/src/lib.rs new file mode 100644 index 000000000000..892314225728 --- /dev/null +++ b/third_party/rust/rand_core-0.3.1/src/lib.rs @@ -0,0 +1,46 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2017-2018 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Random number generation traits +//! +//! This version of `rand_core` is a compatibility shim around version 0.3. +//! +//! This crate is mainly of interest to crates publishing implementations of +//! [`RngCore`]. Other users are encouraged to use the [`rand`] crate instead +//! which re-exports the main traits and error types. +//! +//! [`RngCore`] is the core trait implemented by algorithmic pseudo-random number +//! generators and external random-number sources. +//! +//! [`SeedableRng`] is an extension trait for construction from fixed seeds and +//! other random number generators. +//! +//! [`Error`] is provided for error-handling. It is safe to use in `no_std` +//! environments. +//! +//! The [`impls`] and [`le`] sub-modules include a few small functions to assist +//! implementation of [`RngCore`]. +//! +//! [`rand`]: https://docs.rs/rand + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://rust-random.github.io/rand/")] + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +#![no_std] + +extern crate rand_core as core4; + +pub use core4::{ErrorKind, Error}; +pub use core4::{block, impls, le}; +pub use core4::{RngCore, CryptoRng, SeedableRng}; diff --git a/third_party/rust/rand_core/.cargo-checksum.json b/third_party/rust/rand_core/.cargo-checksum.json new file mode 100644 index 000000000000..2979fb265399 --- /dev/null +++ b/third_party/rust/rand_core/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"93b4744c0355f232107547993a0d771bd276962c9233d4ea1cd4771d7c2f7f92","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.toml":"faab1bf947b13c78f97d87f0bd1ab5611b5fd9e128106282c50f03077b22cd2c","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"26d2c4a2f9c2c3016b76f27eed164adfffcc359b395ed8ec6df255c42eb9a117","src/block.rs":"43778ab70f0b650c3203a6da70b40bc33afa845a5e14ef88dd26c18a07b70f88","src/error.rs":"8403a968d7c9bd95cc9f23d9dc5cc4771ede8e81dda5a8fdd59d347590345d14","src/impls.rs":"c248ddd04a65c974768baaec028fa0d2a6117525fa27bce8a98f2ba2f352700a","src/le.rs":"cb187f58f7514877918f7f47633397e08e20392dcf072bc245d62c9e5238198c","src/lib.rs":"5b3d95e405bed6dc1e4525cc010f0afb2c9f0fc9fe8533f6a02e70ea112c22be"},"package":"d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"} \ No newline at end of file diff --git a/third_party/rust/rand_core/CHANGELOG.md b/third_party/rust/rand_core/CHANGELOG.md new file mode 100644 index 000000000000..7f2d7978fdcd --- /dev/null +++ b/third_party/rust/rand_core/CHANGELOG.md @@ -0,0 +1,36 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.4.0] - 2019-01-24 +- Disable the `std` feature by default (#702) + +## [0.3.0] - 2018-09-24 +- Add `SeedableRng::seed_from_u64` for convenient seeding. (#537) + +## [0.2.1] - 2018-06-08 +- References to a `CryptoRng` now also implement `CryptoRng`. (#470) + +## [0.2.0] - 2018-05-21 +- Enable the `std` feature by default. (#409) +- Remove `BlockRng{64}::inner` and `BlockRng::inner_mut`; instead making `core` public +- Add `BlockRng{64}::index` and `BlockRng{64}::generate_and_set`. (#374, #419) +- Change `BlockRngCore::Results` bound to also require `AsMut<[Self::Item]>`. (#419) +- Implement `std::io::Read` for RngCore. (#434) + +## [0.1.0] - 2018-04-17 +(Split out of the Rand crate, changes here are relative to rand 0.4.2) +- `RngCore` and `SeedableRng` are now part of `rand_core`. (#288) +- Add modules to help implementing RNGs `impl` and `le`. (#209, #228) +- Add `Error` and `ErrorKind`. (#225) +- Add `CryptoRng` marker trait. (#273) +- Add `BlockRngCore` trait. (#281) +- Add `BlockRng` and `BlockRng64` wrappers to help implementations. (#281, #325) +- Revise the `SeedableRng` trait. (#233) +- Remove default implementations for `RngCore::next_u64` and `RngCore::fill_bytes`. (#288) +- Add `RngCore::try_fill_bytes`. (#225) + +## [0.0.1] - 2017-09-14 (yanked) +Experimental version as part of the rand crate refactor. diff --git a/third_party/rust/rand_core/COPYRIGHT b/third_party/rust/rand_core/COPYRIGHT new file mode 100644 index 000000000000..468d907caf99 --- /dev/null +++ b/third_party/rust/rand_core/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 or + or the MIT license + or , at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/third_party/rust/rand_core/Cargo.toml b/third_party/rust/rand_core/Cargo.toml new file mode 100644 index 000000000000..aee2ec0b62b1 --- /dev/null +++ b/third_party/rust/rand_core/Cargo.toml @@ -0,0 +1,41 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand_core" +version = "0.4.0" +authors = ["The Rand Project Developers", "The Rust Project Developers"] +description = "Core random number generator traits and tools for implementation.\n" +homepage = "https://crates.io/crates/rand_core" +documentation = "https://rust-random.github.io/rand/rand_core" +readme = "README.md" +keywords = ["random", "rng"] +categories = ["algorithms", "no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-random/rand" +[dependencies.serde] +version = "1" +optional = true + +[dependencies.serde_derive] +version = "^1.0.38" +optional = true + +[features] +alloc = [] +serde1 = ["serde", "serde_derive"] +std = ["alloc"] +[badges.appveyor] +repository = "rust-random/rand" + +[badges.travis-ci] +repository = "rust-random/rand" diff --git a/third_party/rust/rand_core/LICENSE-APACHE b/third_party/rust/rand_core/LICENSE-APACHE new file mode 100644 index 000000000000..17d74680f8cf --- /dev/null +++ b/third_party/rust/rand_core/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/rand_core/LICENSE-MIT b/third_party/rust/rand_core/LICENSE-MIT new file mode 100644 index 000000000000..d93b5baf341d --- /dev/null +++ b/third_party/rust/rand_core/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright 2018 Developers of the Rand project +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/rand_core/README.md b/third_party/rust/rand_core/README.md new file mode 100644 index 000000000000..ef076b99d821 --- /dev/null +++ b/third_party/rust/rand_core/README.md @@ -0,0 +1,66 @@ +# rand_core + +[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Latest version](https://img.shields.io/crates/v/rand_core.svg)](https://crates.io/crates/rand_core) +[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) +[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_core) +[![API](https://docs.rs/rand_core/badge.svg)](https://docs.rs/rand_core) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) + +Core traits and error types of the [rand] library, plus tools for implementing +RNGs. + +This crate is intended for use when implementing the core trait, `RngCore`; it +defines the core traits to be implemented as well as several small functions to +aid in their implementation and types required for error handling. + +The main [rand] crate re-exports most items defined in this crate, along with +tools to convert the integer samples generated by `RngCore` to many different +applications (including sampling from restricted ranges, conversion to floating +point, list permutations and secure initialisation of RNGs). Most users should +prefer to use the main [rand] crate. + +Links: + +- [API documentation (master)](https://rust-random.github.io/rand/rand_core) +- [API documentation (docs.rs)](https://docs.rs/rand_core) +- [Changelog](CHANGELOG.md) + +[rand]: https://crates.io/crates/rand + + +## Functionality + +The `rand_core` crate provides: + +- base random number generator traits +- error-reporting types +- functionality to aid implementation of RNGs + +The traits and error types are also available via `rand`. + +## Crate Features + +`rand_core` supports `no_std` and `alloc`-only configurations, as well as full +`std` functionality. The differences between `no_std` and full `std` are small, +comprising `RngCore` support for `Box` types where `R: RngCore`, +`std::io::Read` support for types supporting `RngCore`, and +extensions to the `Error` type's functionality. + +The `std` feature is *not enabled by default*. This is primarily to avoid build +problems where one crate implicitly requires `rand_core` with `std` support and +another crate requires `rand` *without* `std` support. However, the `rand` crate +continues to enable `std` support by default, both for itself and `rand_core`. + +The `serde1` feature can be used to derive `Serialize` and `Deserialize` for RNG +implementations that use the `BlockRng` or `BlockRng64` wrappers. + + +# License + +`rand_core` is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/third_party/rust/rand_core/src/block.rs b/third_party/rust/rand_core/src/block.rs new file mode 100644 index 000000000000..3045b9482f47 --- /dev/null +++ b/third_party/rust/rand_core/src/block.rs @@ -0,0 +1,499 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The `BlockRngCore` trait and implementation helpers +//! +//! The [`BlockRngCore`] trait exists to assist in the implementation of RNGs +//! which generate a block of data in a cache instead of returning generated +//! values directly. +//! +//! Usage of this trait is optional, but provides two advantages: +//! implementations only need to concern themselves with generation of the +//! block, not the various [`RngCore`] methods (especially [`fill_bytes`], where +//! the optimal implementations are not trivial), and this allows +//! `ReseedingRng` (see [`rand`](https://docs.rs/rand) crate) perform periodic +//! reseeding with very low overhead. +//! +//! # Example +//! +//! ```norun +//! use rand_core::block::{BlockRngCore, BlockRng}; +//! +//! struct MyRngCore; +//! +//! impl BlockRngCore for MyRngCore { +//! type Results = [u32; 16]; +//! +//! fn generate(&mut self, results: &mut Self::Results) { +//! unimplemented!() +//! } +//! } +//! +//! impl SeedableRng for MyRngCore { +//! type Seed = unimplemented!(); +//! fn from_seed(seed: Self::Seed) -> Self { +//! unimplemented!() +//! } +//! } +//! +//! // optionally, also implement CryptoRng for MyRngCore +//! +//! // Final RNG. +//! type MyRng = BlockRng; +//! ``` +//! +//! [`BlockRngCore`]: crate::block::BlockRngCore +//! [`fill_bytes`]: RngCore::fill_bytes + +use core::convert::AsRef; +use core::fmt; +use {RngCore, CryptoRng, SeedableRng, Error}; +use impls::{fill_via_u32_chunks, fill_via_u64_chunks}; + +/// A trait for RNGs which do not generate random numbers individually, but in +/// blocks (typically `[u32; N]`). This technique is commonly used by +/// cryptographic RNGs to improve performance. +/// +/// See the [module][crate::block] documentation for details. +pub trait BlockRngCore { + /// Results element type, e.g. `u32`. + type Item; + + /// Results type. This is the 'block' an RNG implementing `BlockRngCore` + /// generates, which will usually be an array like `[u32; 16]`. + type Results: AsRef<[Self::Item]> + AsMut<[Self::Item]> + Default; + + /// Generate a new block of results. + fn generate(&mut self, results: &mut Self::Results); +} + + +/// A wrapper type implementing [`RngCore`] for some type implementing +/// [`BlockRngCore`] with `u32` array buffer; i.e. this can be used to implement +/// a full RNG from just a `generate` function. +/// +/// The `core` field may be accessed directly but the results buffer may not. +/// PRNG implementations can simply use a type alias +/// (`pub type MyRng = BlockRng;`) but might prefer to use a +/// wrapper type (`pub struct MyRng(BlockRng);`); the latter must +/// re-implement `RngCore` but hides the implementation details and allows +/// extra functionality to be defined on the RNG +/// (e.g. `impl MyRng { fn set_stream(...){...} }`). +/// +/// `BlockRng` has heavily optimized implementations of the [`RngCore`] methods +/// reading values from the results buffer, as well as +/// calling [`BlockRngCore::generate`] directly on the output array when +/// [`fill_bytes`] / [`try_fill_bytes`] is called on a large array. These methods +/// also handle the bookkeeping of when to generate a new batch of values. +/// +/// No whole generated `u32` values are thown away and all values are consumed +/// in-order. [`next_u32`] simply takes the next available `u32` value. +/// [`next_u64`] is implemented by combining two `u32` values, least +/// significant first. [`fill_bytes`] and [`try_fill_bytes`] consume a whole +/// number of `u32` values, converting each `u32` to a byte slice in +/// little-endian order. If the requested byte length is not a multiple of 4, +/// some bytes will be discarded. +/// +/// See also [`BlockRng64`] which uses `u64` array buffers. Currently there is +/// no direct support for other buffer types. +/// +/// For easy initialization `BlockRng` also implements [`SeedableRng`]. +/// +/// [`next_u32`]: RngCore::next_u32 +/// [`next_u64`]: RngCore::next_u64 +/// [`fill_bytes`]: RngCore::fill_bytes +/// [`try_fill_bytes`]: RngCore::try_fill_bytes +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct BlockRng { + results: R::Results, + index: usize, + /// The *core* part of the RNG, implementing the `generate` function. + pub core: R, +} + +// Custom Debug implementation that does not expose the contents of `results`. +impl fmt::Debug for BlockRng { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("BlockRng") + .field("core", &self.core) + .field("result_len", &self.results.as_ref().len()) + .field("index", &self.index) + .finish() + } +} + +impl BlockRng { + /// Create a new `BlockRng` from an existing RNG implementing + /// `BlockRngCore`. Results will be generated on first use. + pub fn new(core: R) -> BlockRng{ + let results_empty = R::Results::default(); + BlockRng { + core, + index: results_empty.as_ref().len(), + results: results_empty, + } + } + + /// Get the index into the result buffer. + /// + /// If this is equal to or larger than the size of the result buffer then + /// the buffer is "empty" and `generate()` must be called to produce new + /// results. + pub fn index(&self) -> usize { + self.index + } + + /// Reset the number of available results. + /// This will force a new set of results to be generated on next use. + pub fn reset(&mut self) { + self.index = self.results.as_ref().len(); + } + + /// Generate a new set of results immediately, setting the index to the + /// given value. + pub fn generate_and_set(&mut self, index: usize) { + assert!(index < self.results.as_ref().len()); + self.core.generate(&mut self.results); + self.index = index; + } +} + +impl> RngCore for BlockRng +where ::Results: AsRef<[u32]> + AsMut<[u32]> +{ + #[inline(always)] + fn next_u32(&mut self) -> u32 { + if self.index >= self.results.as_ref().len() { + self.generate_and_set(0); + } + + let value = self.results.as_ref()[self.index]; + self.index += 1; + value + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + let read_u64 = |results: &[u32], index| { + if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { + // requires little-endian CPU supporting unaligned reads: + unsafe { *(&results[index] as *const u32 as *const u64) } + } else { + let x = u64::from(results[index]); + let y = u64::from(results[index + 1]); + (y << 32) | x + } + }; + + let len = self.results.as_ref().len(); + + let index = self.index; + if index < len-1 { + self.index += 2; + // Read an u64 from the current index + read_u64(self.results.as_ref(), index) + } else if index >= len { + self.generate_and_set(2); + read_u64(self.results.as_ref(), 0) + } else { + let x = u64::from(self.results.as_ref()[len-1]); + self.generate_and_set(1); + let y = u64::from(self.results.as_ref()[0]); + (y << 32) | x + } + } + + // As an optimization we try to write directly into the output buffer. + // This is only enabled for little-endian platforms where unaligned writes + // are known to be safe and fast. + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut filled = 0; + + // Continue filling from the current set of results + if self.index < self.results.as_ref().len() { + let (consumed_u32, filled_u8) = + fill_via_u32_chunks(&self.results.as_ref()[self.index..], + dest); + + self.index += consumed_u32; + filled += filled_u8; + } + + let len_remainder = + (dest.len() - filled) % (self.results.as_ref().len() * 4); + let end_direct = dest.len() - len_remainder; + + while filled < end_direct { + let dest_u32: &mut R::Results = unsafe { + &mut *(dest[filled..].as_mut_ptr() as + *mut ::Results) + }; + self.core.generate(dest_u32); + filled += self.results.as_ref().len() * 4; + self.index = self.results.as_ref().len(); + } + + if len_remainder > 0 { + self.core.generate(&mut self.results); + let (consumed_u32, _) = + fill_via_u32_chunks(self.results.as_ref(), + &mut dest[filled..]); + + self.index = consumed_u32; + } + } + + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut read_len = 0; + while read_len < dest.len() { + if self.index >= self.results.as_ref().len() { + self.generate_and_set(0); + } + let (consumed_u32, filled_u8) = + fill_via_u32_chunks(&self.results.as_ref()[self.index..], + &mut dest[read_len..]); + + self.index += consumed_u32; + read_len += filled_u8; + } + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.fill_bytes(dest); + Ok(()) + } +} + +impl SeedableRng for BlockRng { + type Seed = R::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + Self::new(R::from_seed(seed)) + } + + fn seed_from_u64(seed: u64) -> Self { + Self::new(R::seed_from_u64(seed)) + } + + fn from_rng(rng: S) -> Result { + Ok(Self::new(R::from_rng(rng)?)) + } +} + + + +/// A wrapper type implementing [`RngCore`] for some type implementing +/// [`BlockRngCore`] with `u64` array buffer; i.e. this can be used to implement +/// a full RNG from just a `generate` function. +/// +/// This is similar to [`BlockRng`], but specialized for algorithms that operate +/// on `u64` values. +/// +/// No whole generated `u64` values are thrown away and all values are consumed +/// in-order. [`next_u64`] simply takes the next available `u64` value. +/// [`next_u32`] is however a bit special: half of a `u64` is consumed, leaving +/// the other half in the buffer. If the next function called is [`next_u32`] +/// then the other half is then consumed, however both [`next_u64`] and +/// [`fill_bytes`] discard the rest of any half-consumed `u64`s when called. +/// +/// [`fill_bytes`] and [`try_fill_bytes`] consume a whole number of `u64` +/// values. If the requested length is not a multiple of 8, some bytes will be +/// discarded. +/// +/// [`next_u32`]: RngCore::next_u32 +/// [`next_u64`]: RngCore::next_u64 +/// [`fill_bytes`]: RngCore::fill_bytes +/// [`try_fill_bytes`]: RngCore::try_fill_bytes +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct BlockRng64 { + results: R::Results, + index: usize, + half_used: bool, // true if only half of the previous result is used + /// The *core* part of the RNG, implementing the `generate` function. + pub core: R, +} + +// Custom Debug implementation that does not expose the contents of `results`. +impl fmt::Debug for BlockRng64 { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("BlockRng64") + .field("core", &self.core) + .field("result_len", &self.results.as_ref().len()) + .field("index", &self.index) + .field("half_used", &self.half_used) + .finish() + } +} + +impl BlockRng64 { + /// Create a new `BlockRng` from an existing RNG implementing + /// `BlockRngCore`. Results will be generated on first use. + pub fn new(core: R) -> BlockRng64{ + let results_empty = R::Results::default(); + BlockRng64 { + core, + index: results_empty.as_ref().len(), + half_used: false, + results: results_empty, + } + } + + /// Get the index into the result buffer. + /// + /// If this is equal to or larger than the size of the result buffer then + /// the buffer is "empty" and `generate()` must be called to produce new + /// results. + pub fn index(&self) -> usize { + self.index + } + + /// Reset the number of available results. + /// This will force a new set of results to be generated on next use. + pub fn reset(&mut self) { + self.index = self.results.as_ref().len(); + self.half_used = false; + } + + /// Generate a new set of results immediately, setting the index to the + /// given value. + pub fn generate_and_set(&mut self, index: usize) { + assert!(index < self.results.as_ref().len()); + self.core.generate(&mut self.results); + self.index = index; + self.half_used = false; + } +} + +impl> RngCore for BlockRng64 +where ::Results: AsRef<[u64]> + AsMut<[u64]> +{ + #[inline(always)] + fn next_u32(&mut self) -> u32 { + let mut index = self.index * 2 - self.half_used as usize; + if index >= self.results.as_ref().len() * 2 { + self.core.generate(&mut self.results); + self.index = 0; + // `self.half_used` is by definition `false` + self.half_used = false; + index = 0; + } + + self.half_used = !self.half_used; + self.index += self.half_used as usize; + + // Index as if this is a u32 slice. + unsafe { + let results = + &*(self.results.as_ref() as *const [u64] as *const [u32]); + if cfg!(target_endian = "little") { + *results.get_unchecked(index) + } else { + *results.get_unchecked(index ^ 1) + } + } + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + if self.index >= self.results.as_ref().len() { + self.core.generate(&mut self.results); + self.index = 0; + } + + let value = self.results.as_ref()[self.index]; + self.index += 1; + self.half_used = false; + value + } + + // As an optimization we try to write directly into the output buffer. + // This is only enabled for little-endian platforms where unaligned writes + // are known to be safe and fast. + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut filled = 0; + self.half_used = false; + + // Continue filling from the current set of results + if self.index < self.results.as_ref().len() { + let (consumed_u64, filled_u8) = + fill_via_u64_chunks(&self.results.as_ref()[self.index..], + dest); + + self.index += consumed_u64; + filled += filled_u8; + } + + let len_remainder = + (dest.len() - filled) % (self.results.as_ref().len() * 8); + let end_direct = dest.len() - len_remainder; + + while filled < end_direct { + let dest_u64: &mut R::Results = unsafe { + ::core::mem::transmute(dest[filled..].as_mut_ptr()) + }; + self.core.generate(dest_u64); + filled += self.results.as_ref().len() * 8; + self.index = self.results.as_ref().len(); + } + + if len_remainder > 0 { + self.core.generate(&mut self.results); + let (consumed_u64, _) = + fill_via_u64_chunks(&mut self.results.as_ref(), + &mut dest[filled..]); + + self.index = consumed_u64; + } + } + + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut read_len = 0; + self.half_used = false; + while read_len < dest.len() { + if self.index as usize >= self.results.as_ref().len() { + self.core.generate(&mut self.results); + self.index = 0; + } + + let (consumed_u64, filled_u8) = + fill_via_u64_chunks(&self.results.as_ref()[self.index as usize..], + &mut dest[read_len..]); + + self.index += consumed_u64; + read_len += filled_u8; + } + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} + +impl SeedableRng for BlockRng64 { + type Seed = R::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + Self::new(R::from_seed(seed)) + } + + fn seed_from_u64(seed: u64) -> Self { + Self::new(R::seed_from_u64(seed)) + } + + fn from_rng(rng: S) -> Result { + Ok(Self::new(R::from_rng(rng)?)) + } +} + +impl CryptoRng for BlockRng {} diff --git a/third_party/rust/rand_core/src/error.rs b/third_party/rust/rand_core/src/error.rs new file mode 100644 index 000000000000..5a8459ea8bef --- /dev/null +++ b/third_party/rust/rand_core/src/error.rs @@ -0,0 +1,177 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Error types + +use core::fmt; + +#[cfg(feature="std")] +use std::error::Error as stdError; +#[cfg(feature="std")] +use std::io; + +/// Error kind which can be matched over. +#[derive(PartialEq, Eq, Debug, Copy, Clone)] +pub enum ErrorKind { + /// Feature is not available; not recoverable. + /// + /// This is the most permanent failure type and implies the error cannot be + /// resolved simply by retrying (e.g. the feature may not exist in this + /// build of the application or on the current platform). + Unavailable, + /// General failure; there may be a chance of recovery on retry. + /// + /// This is the catch-all kind for errors from known and unknown sources + /// which do not have a more specific kind / handling method. + /// + /// It is suggested to retry a couple of times or retry later when + /// handling; some error sources may be able to resolve themselves, + /// although this is not likely. + Unexpected, + /// A transient failure which likely can be resolved or worked around. + /// + /// This error kind exists for a few specific cases where it is known that + /// the error likely can be resolved internally, but is reported anyway. + Transient, + /// Not ready yet: recommended to try again a little later. + /// + /// This error kind implies the generator needs more time or needs some + /// other part of the application to do something else first before it is + /// ready for use; for example this may be used by external generators + /// which require time for initialization. + NotReady, + #[doc(hidden)] + __Nonexhaustive, +} + +impl ErrorKind { + /// True if this kind of error may resolve itself on retry. + /// + /// See also `should_wait()`. + pub fn should_retry(self) -> bool { + self != ErrorKind::Unavailable + } + + /// True if we should retry but wait before retrying + /// + /// This implies `should_retry()` is true. + pub fn should_wait(self) -> bool { + self == ErrorKind::NotReady + } + + /// A description of this error kind + pub fn description(self) -> &'static str { + match self { + ErrorKind::Unavailable => "permanently unavailable", + ErrorKind::Unexpected => "unexpected failure", + ErrorKind::Transient => "transient failure", + ErrorKind::NotReady => "not ready yet", + ErrorKind::__Nonexhaustive => unreachable!(), + } + } +} + + +/// Error type of random number generators +/// +/// This is a relatively simple error type, designed for compatibility with and +/// without the Rust `std` library. It embeds a "kind" code, a message (static +/// string only), and an optional chained cause (`std` only). The `kind` and +/// `msg` fields can be accessed directly; cause can be accessed via +/// `std::error::Error::cause` or `Error::take_cause`. Construction can only be +/// done via `Error::new` or `Error::with_cause`. +#[derive(Debug)] +pub struct Error { + /// The error kind + pub kind: ErrorKind, + /// The error message + pub msg: &'static str, + #[cfg(feature="std")] + cause: Option>, +} + +impl Error { + /// Create a new instance, with specified kind and a message. + pub fn new(kind: ErrorKind, msg: &'static str) -> Self { + #[cfg(feature="std")] { + Error { kind, msg, cause: None } + } + #[cfg(not(feature="std"))] { + Error { kind, msg } + } + } + + /// Create a new instance, with specified kind, message, and a + /// chained cause. + /// + /// Note: `stdError` is an alias for `std::error::Error`. + /// + /// If not targetting `std` (i.e. `no_std`), this function is replaced by + /// another with the same prototype, except that there are no bounds on the + /// type `E` (because both `Box` and `stdError` are unavailable), and the + /// `cause` is ignored. + #[cfg(feature="std")] + pub fn with_cause(kind: ErrorKind, msg: &'static str, cause: E) -> Self + where E: Into> + { + Error { kind, msg, cause: Some(cause.into()) } + } + + /// Create a new instance, with specified kind, message, and a + /// chained cause. + /// + /// In `no_std` mode the *cause* is ignored. + #[cfg(not(feature="std"))] + pub fn with_cause(kind: ErrorKind, msg: &'static str, _cause: E) -> Self { + Error { kind, msg } + } + + /// Take the cause, if any. This allows the embedded cause to be extracted. + /// This uses `Option::take`, leaving `self` with no cause. + #[cfg(feature="std")] + pub fn take_cause(&mut self) -> Option> { + self.cause.take() + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + #[cfg(feature="std")] { + if let Some(ref cause) = self.cause { + return write!(f, "{} ({}); cause: {}", + self.msg, self.kind.description(), cause); + } + } + write!(f, "{} ({})", self.msg, self.kind.description()) + } +} + +#[cfg(feature="std")] +impl stdError for Error { + fn description(&self) -> &str { + self.msg + } + + fn cause(&self) -> Option<&stdError> { + self.cause.as_ref().map(|e| e.as_ref() as &stdError) + } +} + +#[cfg(feature="std")] +impl From for io::Error { + fn from(error: Error) -> Self { + use std::io::ErrorKind::*; + match error.kind { + ErrorKind::Unavailable => io::Error::new(NotFound, error), + ErrorKind::Unexpected | + ErrorKind::Transient => io::Error::new(Other, error), + ErrorKind::NotReady => io::Error::new(WouldBlock, error), + ErrorKind::__Nonexhaustive => unreachable!(), + } + } +} diff --git a/third_party/rust/rand_core/src/impls.rs b/third_party/rust/rand_core/src/impls.rs new file mode 100644 index 000000000000..57bdd070d08a --- /dev/null +++ b/third_party/rust/rand_core/src/impls.rs @@ -0,0 +1,165 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Helper functions for implementing `RngCore` functions. +//! +//! For cross-platform reproducibility, these functions all use Little Endian: +//! least-significant part first. For example, `next_u64_via_u32` takes `u32` +//! values `x, y`, then outputs `(y << 32) | x`. To implement `next_u32` +//! from `next_u64` in little-endian order, one should use `next_u64() as u32`. +//! +//! Byte-swapping (like the std `to_le` functions) is only needed to convert +//! to/from byte sequences, and since its purpose is reproducibility, +//! non-reproducible sources (e.g. `OsRng`) need not bother with it. + +use core::intrinsics::transmute; +use core::ptr::copy_nonoverlapping; +use core::slice; +use core::cmp::min; +use core::mem::size_of; +use RngCore; + + +/// Implement `next_u64` via `next_u32`, little-endian order. +pub fn next_u64_via_u32(rng: &mut R) -> u64 { + // Use LE; we explicitly generate one value before the next. + let x = u64::from(rng.next_u32()); + let y = u64::from(rng.next_u32()); + (y << 32) | x +} + +/// Implement `fill_bytes` via `next_u64` and `next_u32`, little-endian order. +/// +/// The fastest way to fill a slice is usually to work as long as possible with +/// integers. That is why this method mostly uses `next_u64`, and only when +/// there are 4 or less bytes remaining at the end of the slice it uses +/// `next_u32` once. +pub fn fill_bytes_via_next(rng: &mut R, dest: &mut [u8]) { + let mut left = dest; + while left.len() >= 8 { + let (l, r) = {left}.split_at_mut(8); + left = r; + let chunk: [u8; 8] = unsafe { + transmute(rng.next_u64().to_le()) + }; + l.copy_from_slice(&chunk); + } + let n = left.len(); + if n > 4 { + let chunk: [u8; 8] = unsafe { + transmute(rng.next_u64().to_le()) + }; + left.copy_from_slice(&chunk[..n]); + } else if n > 0 { + let chunk: [u8; 4] = unsafe { + transmute(rng.next_u32().to_le()) + }; + left.copy_from_slice(&chunk[..n]); + } +} + +macro_rules! impl_uint_from_fill { + ($rng:expr, $ty:ty, $N:expr) => ({ + debug_assert!($N == size_of::<$ty>()); + + let mut int: $ty = 0; + unsafe { + let ptr = &mut int as *mut $ty as *mut u8; + let slice = slice::from_raw_parts_mut(ptr, $N); + $rng.fill_bytes(slice); + } + int + }); +} + +macro_rules! fill_via_chunks { + ($src:expr, $dst:expr, $ty:ty, $size:expr) => ({ + let chunk_size_u8 = min($src.len() * $size, $dst.len()); + let chunk_size = (chunk_size_u8 + $size - 1) / $size; + if cfg!(target_endian="little") { + unsafe { + copy_nonoverlapping( + $src.as_ptr() as *const u8, + $dst.as_mut_ptr(), + chunk_size_u8); + } + } else { + for (&n, chunk) in $src.iter().zip($dst.chunks_mut($size)) { + let tmp = n.to_le(); + let src_ptr = &tmp as *const $ty as *const u8; + unsafe { + copy_nonoverlapping(src_ptr, + chunk.as_mut_ptr(), + chunk.len()); + } + } + } + + (chunk_size, chunk_size_u8) + }); +} + +/// Implement `fill_bytes` by reading chunks from the output buffer of a block +/// based RNG. +/// +/// The return values are `(consumed_u32, filled_u8)`. +/// +/// `filled_u8` is the number of filled bytes in `dest`, which may be less than +/// the length of `dest`. +/// `consumed_u32` is the number of words consumed from `src`, which is the same +/// as `filled_u8 / 4` rounded up. +/// +/// # Example +/// (from `IsaacRng`) +/// +/// ```ignore +/// fn fill_bytes(&mut self, dest: &mut [u8]) { +/// let mut read_len = 0; +/// while read_len < dest.len() { +/// if self.index >= self.rsl.len() { +/// self.isaac(); +/// } +/// +/// let (consumed_u32, filled_u8) = +/// impls::fill_via_u32_chunks(&mut self.rsl[self.index..], +/// &mut dest[read_len..]); +/// +/// self.index += consumed_u32; +/// read_len += filled_u8; +/// } +/// } +/// ``` +pub fn fill_via_u32_chunks(src: &[u32], dest: &mut [u8]) -> (usize, usize) { + fill_via_chunks!(src, dest, u32, 4) +} + +/// Implement `fill_bytes` by reading chunks from the output buffer of a block +/// based RNG. +/// +/// The return values are `(consumed_u64, filled_u8)`. +/// `filled_u8` is the number of filled bytes in `dest`, which may be less than +/// the length of `dest`. +/// `consumed_u64` is the number of words consumed from `src`, which is the same +/// as `filled_u8 / 8` rounded up. +/// +/// See `fill_via_u32_chunks` for an example. +pub fn fill_via_u64_chunks(src: &[u64], dest: &mut [u8]) -> (usize, usize) { + fill_via_chunks!(src, dest, u64, 8) +} + +/// Implement `next_u32` via `fill_bytes`, little-endian order. +pub fn next_u32_via_fill(rng: &mut R) -> u32 { + impl_uint_from_fill!(rng, u32, 4) +} + +/// Implement `next_u64` via `fill_bytes`, little-endian order. +pub fn next_u64_via_fill(rng: &mut R) -> u64 { + impl_uint_from_fill!(rng, u64, 8) +} + +// TODO: implement tests for the above diff --git a/third_party/rust/rand_core/src/le.rs b/third_party/rust/rand_core/src/le.rs new file mode 100644 index 000000000000..266651f10dc7 --- /dev/null +++ b/third_party/rust/rand_core/src/le.rs @@ -0,0 +1,68 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Little-Endian utilities +//! +//! Little-Endian order has been chosen for internal usage; this makes some +//! useful functions available. + +use core::ptr; + +macro_rules! read_slice { + ($src:expr, $dst:expr, $size:expr, $which:ident) => {{ + assert_eq!($src.len(), $size * $dst.len()); + + unsafe { + ptr::copy_nonoverlapping( + $src.as_ptr(), + $dst.as_mut_ptr() as *mut u8, + $src.len()); + } + for v in $dst.iter_mut() { + *v = v.$which(); + } + }}; +} + +/// Reads unsigned 32 bit integers from `src` into `dst`. +/// Borrowed from the `byteorder` crate. +#[inline] +pub fn read_u32_into(src: &[u8], dst: &mut [u32]) { + read_slice!(src, dst, 4, to_le); +} + +/// Reads unsigned 64 bit integers from `src` into `dst`. +/// Borrowed from the `byteorder` crate. +#[inline] +pub fn read_u64_into(src: &[u8], dst: &mut [u64]) { + read_slice!(src, dst, 8, to_le); +} + +#[test] +fn test_read() { + let bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + + let mut buf = [0u32; 4]; + read_u32_into(&bytes, &mut buf); + assert_eq!(buf[0], 0x04030201); + assert_eq!(buf[3], 0x100F0E0D); + + let mut buf = [0u32; 3]; + read_u32_into(&bytes[1..13], &mut buf); // unaligned + assert_eq!(buf[0], 0x05040302); + assert_eq!(buf[2], 0x0D0C0B0A); + + let mut buf = [0u64; 2]; + read_u64_into(&bytes, &mut buf); + assert_eq!(buf[0], 0x0807060504030201); + assert_eq!(buf[1], 0x100F0E0D0C0B0A09); + + let mut buf = [0u64; 1]; + read_u64_into(&bytes[7..15], &mut buf); // unaligned + assert_eq!(buf[0], 0x0F0E0D0C0B0A0908); +} diff --git a/third_party/rust/rand_core/src/lib.rs b/third_party/rust/rand_core/src/lib.rs new file mode 100644 index 000000000000..4b0e6e48b018 --- /dev/null +++ b/third_party/rust/rand_core/src/lib.rs @@ -0,0 +1,477 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2017-2018 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Random number generation traits +//! +//! This crate is mainly of interest to crates publishing implementations of +//! [`RngCore`]. Other users are encouraged to use the [`rand`] crate instead +//! which re-exports the main traits and error types. +//! +//! [`RngCore`] is the core trait implemented by algorithmic pseudo-random number +//! generators and external random-number sources. +//! +//! [`SeedableRng`] is an extension trait for construction from fixed seeds and +//! other random number generators. +//! +//! [`Error`] is provided for error-handling. It is safe to use in `no_std` +//! environments. +//! +//! The [`impls`] and [`le`] sub-modules include a few small functions to assist +//! implementation of [`RngCore`]. +//! +//! [`rand`]: https://docs.rs/rand + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://rust-random.github.io/rand/")] + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +#![cfg_attr(not(feature="std"), no_std)] +#![cfg_attr(all(feature="alloc", not(feature="std")), feature(alloc))] + +#[cfg(feature="std")] extern crate core; +#[cfg(all(feature = "alloc", not(feature="std")))] extern crate alloc; +#[cfg(feature="serde1")] extern crate serde; +#[cfg(feature="serde1")] #[macro_use] extern crate serde_derive; + + +use core::default::Default; +use core::convert::AsMut; +use core::ptr::copy_nonoverlapping; + +#[cfg(all(feature="alloc", not(feature="std")))] use alloc::boxed::Box; + +pub use error::{ErrorKind, Error}; + + +mod error; +pub mod block; +pub mod impls; +pub mod le; + + +/// The core of a random number generator. +/// +/// This trait encapsulates the low-level functionality common to all +/// generators, and is the "back end", to be implemented by generators. +/// End users should normally use the `Rng` trait from the [`rand`] crate, +/// which is automatically implemented for every type implementing `RngCore`. +/// +/// Three different methods for generating random data are provided since the +/// optimal implementation of each is dependent on the type of generator. There +/// is no required relationship between the output of each; e.g. many +/// implementations of [`fill_bytes`] consume a whole number of `u32` or `u64` +/// values and drop any remaining unused bytes. +/// +/// The [`try_fill_bytes`] method is a variant of [`fill_bytes`] allowing error +/// handling; it is not deemed sufficiently useful to add equivalents for +/// [`next_u32`] or [`next_u64`] since the latter methods are almost always used +/// with algorithmic generators (PRNGs), which are normally infallible. +/// +/// Algorithmic generators implementing [`SeedableRng`] should normally have +/// *portable, reproducible* output, i.e. fix Endianness when converting values +/// to avoid platform differences, and avoid making any changes which affect +/// output (except by communicating that the release has breaking changes). +/// +/// Typically implementators will implement only one of the methods available +/// in this trait directly, then use the helper functions from the +/// [`impls`] module to implement the other methods. +/// +/// It is recommended that implementations also implement: +/// +/// - `Debug` with a custom implementation which *does not* print any internal +/// state (at least, [`CryptoRng`]s should not risk leaking state through +/// `Debug`). +/// - `Serialize` and `Deserialize` (from Serde), preferably making Serde +/// support optional at the crate level in PRNG libs. +/// - `Clone`, if possible. +/// - *never* implement `Copy` (accidental copies may cause repeated values). +/// - *do not* implement `Default` for pseudorandom generators, but instead +/// implement [`SeedableRng`], to guide users towards proper seeding. +/// External / hardware RNGs can choose to implement `Default`. +/// - `Eq` and `PartialEq` could be implemented, but are probably not useful. +/// +/// # Example +/// +/// A simple example, obviously not generating very *random* output: +/// +/// ``` +/// #![allow(dead_code)] +/// use rand_core::{RngCore, Error, impls}; +/// +/// struct CountingRng(u64); +/// +/// impl RngCore for CountingRng { +/// fn next_u32(&mut self) -> u32 { +/// self.next_u64() as u32 +/// } +/// +/// fn next_u64(&mut self) -> u64 { +/// self.0 += 1; +/// self.0 +/// } +/// +/// fn fill_bytes(&mut self, dest: &mut [u8]) { +/// impls::fill_bytes_via_next(self, dest) +/// } +/// +/// fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { +/// Ok(self.fill_bytes(dest)) +/// } +/// } +/// ``` +/// +/// [`rand`]: https://docs.rs/rand +/// [`try_fill_bytes`]: RngCore::try_fill_bytes +/// [`fill_bytes`]: RngCore::fill_bytes +/// [`next_u32`]: RngCore::next_u32 +/// [`next_u64`]: RngCore::next_u64 +pub trait RngCore { + /// Return the next random `u32`. + /// + /// RNGs must implement at least one method from this trait directly. In + /// the case this method is not implemented directly, it can be implemented + /// using `self.next_u64() as u32` or via + /// [`fill_bytes`][impls::next_u32_via_fill]. + fn next_u32(&mut self) -> u32; + + /// Return the next random `u64`. + /// + /// RNGs must implement at least one method from this trait directly. In + /// the case this method is not implemented directly, it can be implemented + /// via [`next_u32`][impls::next_u64_via_u32] or via + /// [`fill_bytes`][impls::next_u64_via_fill]. + fn next_u64(&mut self) -> u64; + + /// Fill `dest` with random data. + /// + /// RNGs must implement at least one method from this trait directly. In + /// the case this method is not implemented directly, it can be implemented + /// via [`next_u*`][impls::fill_bytes_via_next] or + /// via [`try_fill_bytes`][RngCore::try_fill_bytes]; if this generator can + /// fail the implementation must choose how best to handle errors here + /// (e.g. panic with a descriptive message or log a warning and retry a few + /// times). + /// + /// This method should guarantee that `dest` is entirely filled + /// with new data, and may panic if this is impossible + /// (e.g. reading past the end of a file that is being used as the + /// source of randomness). + fn fill_bytes(&mut self, dest: &mut [u8]); + + /// Fill `dest` entirely with random data. + /// + /// This is the only method which allows an RNG to report errors while + /// generating random data thus making this the primary method implemented + /// by external (true) RNGs (e.g. `OsRng`) which can fail. It may be used + /// directly to generate keys and to seed (infallible) PRNGs. + /// + /// Other than error handling, this method is identical to [`fill_bytes`]; + /// thus this may be implemented using `Ok(self.fill_bytes(dest))` or + /// `fill_bytes` may be implemented with + /// `self.try_fill_bytes(dest).unwrap()` or more specific error handling. + /// + /// [`fill_bytes`]: RngCore::fill_bytes + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error>; +} + +/// A marker trait used to indicate that an [`RngCore`] or [`BlockRngCore`] +/// implementation is supposed to be cryptographically secure. +/// +/// *Cryptographically secure generators*, also known as *CSPRNGs*, should +/// satisfy an additional properties over other generators: given the first +/// *k* bits of an algorithm's output +/// sequence, it should not be possible using polynomial-time algorithms to +/// predict the next bit with probability significantly greater than 50%. +/// +/// Some generators may satisfy an additional property, however this is not +/// required by this trait: if the CSPRNG's state is revealed, it should not be +/// computationally-feasible to reconstruct output prior to this. Some other +/// generators allow backwards-computation and are consided *reversible*. +/// +/// Note that this trait is provided for guidance only and cannot guarantee +/// suitability for cryptographic applications. In general it should only be +/// implemented for well-reviewed code implementing well-regarded algorithms. +/// +/// Note also that use of a `CryptoRng` does not protect against other +/// weaknesses such as seeding from a weak entropy source or leaking state. +/// +/// [`BlockRngCore`]: block::BlockRngCore +pub trait CryptoRng {} + +/// A random number generator that can be explicitly seeded. +/// +/// This trait encapsulates the low-level functionality common to all +/// pseudo-random number generators (PRNGs, or algorithmic generators). +/// +/// The `FromEntropy` trait from the [`rand`] crate is automatically +/// implemented for every type implementing `SeedableRng`, providing +/// a convenient `from_entropy()` constructor. +/// +/// [`rand`]: https://docs.rs/rand +pub trait SeedableRng: Sized { + /// Seed type, which is restricted to types mutably-dereferencable as `u8` + /// arrays (we recommend `[u8; N]` for some `N`). + /// + /// It is recommended to seed PRNGs with a seed of at least circa 100 bits, + /// which means an array of `[u8; 12]` or greater to avoid picking RNGs with + /// partially overlapping periods. + /// + /// For cryptographic RNG's a seed of 256 bits is recommended, `[u8; 32]`. + /// + /// + /// # Implementing `SeedableRng` for RNGs with large seeds + /// + /// Note that the required traits `core::default::Default` and + /// `core::convert::AsMut` are not implemented for large arrays + /// `[u8; N]` with `N` > 32. To be able to implement the traits required by + /// `SeedableRng` for RNGs with such large seeds, the newtype pattern can be + /// used: + /// + /// ``` + /// use rand_core::SeedableRng; + /// + /// const N: usize = 64; + /// pub struct MyRngSeed(pub [u8; N]); + /// pub struct MyRng(MyRngSeed); + /// + /// impl Default for MyRngSeed { + /// fn default() -> MyRngSeed { + /// MyRngSeed([0; N]) + /// } + /// } + /// + /// impl AsMut<[u8]> for MyRngSeed { + /// fn as_mut(&mut self) -> &mut [u8] { + /// &mut self.0 + /// } + /// } + /// + /// impl SeedableRng for MyRng { + /// type Seed = MyRngSeed; + /// + /// fn from_seed(seed: MyRngSeed) -> MyRng { + /// MyRng(seed) + /// } + /// } + /// ``` + type Seed: Sized + Default + AsMut<[u8]>; + + /// Create a new PRNG using the given seed. + /// + /// PRNG implementations are allowed to assume that bits in the seed are + /// well distributed. That means usually that the number of one and zero + /// bits are about equal, and values like 0, 1 and (size - 1) are unlikely. + /// + /// PRNG implementations are recommended to be reproducible. A PRNG seeded + /// using this function with a fixed seed should produce the same sequence + /// of output in the future and on different architectures (with for example + /// different endianness). + /// + /// It is however not required that this function yield the same state as a + /// reference implementation of the PRNG given equivalent seed; if necessary + /// another constructor replicating behaviour from a reference + /// implementation can be added. + /// + /// PRNG implementations should make sure `from_seed` never panics. In the + /// case that some special values (like an all zero seed) are not viable + /// seeds it is preferable to map these to alternative constant value(s), + /// for example `0xBAD5EEDu32` or `0x0DDB1A5E5BAD5EEDu64` ("odd biases? bad + /// seed"). This is assuming only a small number of values must be rejected. + fn from_seed(seed: Self::Seed) -> Self; + + /// Create a new PRNG using a `u64` seed. + /// + /// This is a convenience-wrapper around `from_seed` to allow construction + /// of any `SeedableRng` from a simple `u64` value. It is designed such that + /// low Hamming Weight numbers like 0 and 1 can be used and should still + /// result in good, independent seeds to the PRNG which is returned. + /// + /// This **is not suitable for cryptography**, as should be clear given that + /// the input size is only 64 bits. + /// + /// Implementations for PRNGs *may* provide their own implementations of + /// this function, but the default implementation should be good enough for + /// all purposes. *Changing* the implementation of this function should be + /// considered a value-breaking change. + fn seed_from_u64(mut state: u64) -> Self { + // We use PCG32 to generate a u32 sequence, and copy to the seed + const MUL: u64 = 6364136223846793005; + const INC: u64 = 11634580027462260723; + + let mut seed = Self::Seed::default(); + for chunk in seed.as_mut().chunks_mut(4) { + // We advance the state first (to get away from the input value, + // in case it has low Hamming Weight). + state = state.wrapping_mul(MUL).wrapping_add(INC); + + // Use PCG output function with to_le to generate x: + let xorshifted = (((state >> 18) ^ state) >> 27) as u32; + let rot = (state >> 59) as u32; + let x = xorshifted.rotate_right(rot).to_le(); + + unsafe { + let p = &x as *const u32 as *const u8; + copy_nonoverlapping(p, chunk.as_mut_ptr(), chunk.len()); + } + } + + Self::from_seed(seed) + } + + /// Create a new PRNG seeded from another `Rng`. + /// + /// This is the recommended way to initialize PRNGs with fresh entropy. The + /// `FromEntropy` trait from the [`rand`] crate provides a convenient + /// `from_entropy` method based on `from_rng`. + /// + /// Usage of this method is not recommended when reproducibility is required + /// since implementing PRNGs are not required to fix Endianness and are + /// allowed to modify implementations in new releases. + /// + /// It is important to use a good source of randomness to initialize the + /// PRNG. Cryptographic PRNG may be rendered insecure when seeded from a + /// non-cryptographic PRNG or with insufficient entropy. + /// Many non-cryptographic PRNGs will show statistical bias in their first + /// results if their seed numbers are small or if there is a simple pattern + /// between them. + /// + /// Prefer to seed from a strong external entropy source like `OsRng` from + /// the [`rand_os`] crate or from a cryptographic PRNG; if creating a new + /// generator for cryptographic uses you *must* seed from a strong source. + /// + /// Seeding a small PRNG from another small PRNG is possible, but + /// something to be careful with. An extreme example of how this can go + /// wrong is seeding an Xorshift RNG from another Xorshift RNG, which + /// will effectively clone the generator. In general seeding from a + /// generator which is hard to predict is probably okay. + /// + /// PRNG implementations are allowed to assume that a good RNG is provided + /// for seeding, and that it is cryptographically secure when appropriate. + /// + /// [`rand`]: https://docs.rs/rand + /// [`rand_os`]: https://docs.rs/rand_os + fn from_rng(mut rng: R) -> Result { + let mut seed = Self::Seed::default(); + rng.try_fill_bytes(seed.as_mut())?; + Ok(Self::from_seed(seed)) + } +} + +// Implement `RngCore` for references to an `RngCore`. +// Force inlining all functions, so that it is up to the `RngCore` +// implementation and the optimizer to decide on inlining. +impl<'a, R: RngCore + ?Sized> RngCore for &'a mut R { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + (**self).next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + (**self).next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + (**self).fill_bytes(dest) + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + (**self).try_fill_bytes(dest) + } +} + +// Implement `RngCore` for boxed references to an `RngCore`. +// Force inlining all functions, so that it is up to the `RngCore` +// implementation and the optimizer to decide on inlining. +#[cfg(feature="alloc")] +impl RngCore for Box { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + (**self).next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + (**self).next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + (**self).fill_bytes(dest) + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + (**self).try_fill_bytes(dest) + } +} + +#[cfg(feature="std")] +impl std::io::Read for RngCore { + fn read(&mut self, buf: &mut [u8]) -> Result { + self.try_fill_bytes(buf)?; + Ok(buf.len()) + } +} + +// Implement `CryptoRng` for references to an `CryptoRng`. +impl<'a, R: CryptoRng + ?Sized> CryptoRng for &'a mut R {} + +// Implement `CryptoRng` for boxed references to an `CryptoRng`. +#[cfg(feature="alloc")] +impl CryptoRng for Box {} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_seed_from_u64() { + struct SeedableNum(u64); + impl SeedableRng for SeedableNum { + type Seed = [u8; 8]; + fn from_seed(seed: Self::Seed) -> Self { + let mut x = [0u64; 1]; + le::read_u64_into(&seed, &mut x); + SeedableNum(x[0]) + } + } + + const N: usize = 8; + const SEEDS: [u64; N] = [0u64, 1, 2, 3, 4, 8, 16, -1i64 as u64]; + let mut results = [0u64; N]; + for (i, seed) in SEEDS.iter().enumerate() { + let SeedableNum(x) = SeedableNum::seed_from_u64(*seed); + results[i] = x; + } + + for (i1, r1) in results.iter().enumerate() { + let weight = r1.count_ones(); + // This is the binomial distribution B(64, 0.5), so chance of + // weight < 20 is binocdf(19, 64, 0.5) = 7.8e-4, and same for + // weight > 44. + assert!(weight >= 20 && weight <= 44); + + for (i2, r2) in results.iter().enumerate() { + if i1 == i2 { continue; } + let diff_weight = (r1 ^ r2).count_ones(); + assert!(diff_weight >= 20); + } + } + + // value-breakage test: + assert_eq!(results[0], 5029875928683246316); + } +} diff --git a/third_party/rust/rand_hc/.cargo-checksum.json b/third_party/rust/rand_hc/.cargo-checksum.json new file mode 100644 index 000000000000..562cce313aba --- /dev/null +++ b/third_party/rust/rand_hc/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"f6dd960de06e087466066cd3e05bfd51288d144f917a62c591238697d7db1f49","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.toml":"467a2ecd73f7b32471fe00fe8042ef4dff756c05e6e4e6dd3a2e48d25867ef07","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"a771e4354f6b3ad4c92da1a5c9a239b6c291527db869632ecea4f20e24ca1135","README.md":"98a46c583c11b36bf3cc30ba646c9598a7d051b22c10e6d408aa0b1aefc6062d","src/hc128.rs":"ec8a1122eff5d1b79efa721d97d8aabaadd3f9af504336ecd928c082a9a40b45","src/lib.rs":"959f8d7280fac5683e4d2bf1713b3742a0a3685bb0b7e19d06875d254751cffb"},"package":"7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"} \ No newline at end of file diff --git a/third_party/rust/rand_hc/CHANGELOG.md b/third_party/rust/rand_hc/CHANGELOG.md new file mode 100644 index 000000000000..d0c4a2fcbc55 --- /dev/null +++ b/third_party/rust/rand_hc/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.1.0] - 2018-10-17 +- Pulled out of the Rand crate diff --git a/third_party/rust/rand_hc/COPYRIGHT b/third_party/rust/rand_hc/COPYRIGHT new file mode 100644 index 000000000000..468d907caf99 --- /dev/null +++ b/third_party/rust/rand_hc/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 or + or the MIT license + or , at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/third_party/rust/rand_hc/Cargo.toml b/third_party/rust/rand_hc/Cargo.toml new file mode 100644 index 000000000000..e080274737b4 --- /dev/null +++ b/third_party/rust/rand_hc/Cargo.toml @@ -0,0 +1,32 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand_hc" +version = "0.1.0" +authors = ["The Rand Project Developers"] +description = "HC128 random number generator\n" +homepage = "https://crates.io/crates/rand_hc" +documentation = "https://docs.rs/rand_hc" +readme = "README.md" +keywords = ["random", "rng", "hc128"] +categories = ["algorithms", "no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-random/rand" +[dependencies.rand_core] +version = ">=0.2, <0.4" +default-features = false +[badges.appveyor] +repository = "rust-random/rand" + +[badges.travis-ci] +repository = "rust-random/rand" diff --git a/third_party/rust/rand_hc/LICENSE-APACHE b/third_party/rust/rand_hc/LICENSE-APACHE new file mode 100644 index 000000000000..17d74680f8cf --- /dev/null +++ b/third_party/rust/rand_hc/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/rand_hc/LICENSE-MIT b/third_party/rust/rand_hc/LICENSE-MIT new file mode 100644 index 000000000000..cf656074cbf6 --- /dev/null +++ b/third_party/rust/rand_hc/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright 2018 Developers of the Rand project + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/rand_hc/README.md b/third_party/rust/rand_hc/README.md new file mode 100644 index 000000000000..9c1f5e1229b7 --- /dev/null +++ b/third_party/rust/rand_hc/README.md @@ -0,0 +1,44 @@ +# rand_hc + +[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Latest version](https://img.shields.io/crates/v/rand_hc.svg)](https://crates.io/crates/rand_hc) +[![Documentation](https://docs.rs/rand_hc/badge.svg)](https://docs.rs/rand_hc) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-yellow.svg)](https://github.com/rust-random/rand#rust-version-requirements) +[![License](https://img.shields.io/crates/l/rand_hc.svg)](https://github.com/rust-random/rand/tree/master/rand_hc#license) + +A cryptographically secure random number generator that uses the HC-128 +algorithm. + +HC-128 is a stream cipher designed by Hongjun Wu[^1], that we use as an +RNG. It is selected as one of the "stream ciphers suitable for widespread +adoption" by eSTREAM[^2]. + +Documentation: +[master branch](https://rust-random.github.io/rand/rand_hc/index.html), +[by release](https://docs.rs/rand_hc) + +[Changelog](CHANGELOG.md) + +[rand]: https://crates.io/crates/rand +[^1]: Hongjun Wu (2008). ["The Stream Cipher HC-128"]( + http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf). + *The eSTREAM Finalists*, LNCS 4986, pp. 39–47, Springer-Verlag. + +[^2]: [eSTREAM: the ECRYPT Stream Cipher Project]( + http://www.ecrypt.eu.org/stream/) + + +## Crate Features + +`rand_hc` is `no_std` compatible. It does not require any functionality +outside of the `core` lib, thus there are no features to configure. + + +# License + +`rand_hc` is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/third_party/rust/rand_hc/src/hc128.rs b/third_party/rust/rand_hc/src/hc128.rs new file mode 100644 index 000000000000..d1dadcc90834 --- /dev/null +++ b/third_party/rust/rand_hc/src/hc128.rs @@ -0,0 +1,462 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The HC-128 random number generator. + +use core::fmt; +use rand_core::{CryptoRng, RngCore, SeedableRng, Error, le}; +use rand_core::block::{BlockRngCore, BlockRng}; + +const SEED_WORDS: usize = 8; // 128 bit key followed by 128 bit iv + +/// A cryptographically secure random number generator that uses the HC-128 +/// algorithm. +/// +/// HC-128 is a stream cipher designed by Hongjun Wu[^1], that we use as an +/// RNG. It is selected as one of the "stream ciphers suitable for widespread +/// adoption" by eSTREAM[^2]. +/// +/// HC-128 is an array based RNG. In this it is similar to RC-4 and ISAAC before +/// it, but those have never been proven cryptographically secure (or have even +/// been significantly compromised, as in the case of RC-4[^5]). +/// +/// Because HC-128 works with simple indexing into a large array and with a few +/// operations that parallelize well, it has very good performance. The size of +/// the array it needs, 4kb, can however be a disadvantage. +/// +/// This implementation is not based on the version of HC-128 submitted to the +/// eSTREAM contest, but on a later version by the author with a few small +/// improvements from December 15, 2009[^3]. +/// +/// HC-128 has no known weaknesses that are easier to exploit than doing a +/// brute-force search of 2128. A very comprehensive analysis of the +/// current state of known attacks / weaknesses of HC-128 is given in *Some +/// Results On Analysis And Implementation Of HC-128 Stream Cipher*[^4]. +/// +/// The average cycle length is expected to be +/// 21024*32+10-1 = 232777. +/// We support seeding with a 256-bit array, which matches the 128-bit key +/// concatenated with a 128-bit IV from the stream cipher. +/// +/// This implementation uses an output buffer of sixteen `u32` words, and uses +/// [`BlockRng`] to implement the [`RngCore`] methods. +/// +/// ## References +/// [^1]: Hongjun Wu (2008). ["The Stream Cipher HC-128"]( +/// http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf). +/// *The eSTREAM Finalists*, LNCS 4986, pp. 39–47, Springer-Verlag. +/// +/// [^2]: [eSTREAM: the ECRYPT Stream Cipher Project]( +/// http://www.ecrypt.eu.org/stream/) +/// +/// [^3]: Hongjun Wu, [Stream Ciphers HC-128 and HC-256]( +/// https://www.ntu.edu.sg/home/wuhj/research/hc/index.html) +/// +/// [^4]: Shashwat Raizada (January 2015),["Some Results On Analysis And +/// Implementation Of HC-128 Stream Cipher"]( +/// http://library.isical.ac.in:8080/jspui/bitstream/123456789/6636/1/TH431.pdf). +/// +/// [^5]: Internet Engineering Task Force (February 2015), +/// ["Prohibiting RC4 Cipher Suites"](https://tools.ietf.org/html/rfc7465). +/// +/// [`BlockRng`]: ../rand_core/block/struct.BlockRng.html +/// [`RngCore`]: ../rand_core/trait.RngCore.html +#[derive(Clone, Debug)] +pub struct Hc128Rng(BlockRng); + +impl RngCore for Hc128Rng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for Hc128Rng { + type Seed = ::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + Hc128Rng(BlockRng::::from_seed(seed)) + } + + fn from_rng(rng: R) -> Result { + BlockRng::::from_rng(rng).map(Hc128Rng) + } +} + +impl CryptoRng for Hc128Rng {} + +/// The core of `Hc128Rng`, used with `BlockRng`. +#[derive(Clone)] +pub struct Hc128Core { + t: [u32; 1024], + counter1024: usize, +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for Hc128Core { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Hc128Core {{}}") + } +} + +impl BlockRngCore for Hc128Core { + type Item = u32; + type Results = [u32; 16]; + + fn generate(&mut self, results: &mut Self::Results) { + assert!(self.counter1024 % 16 == 0); + + let cc = self.counter1024 % 512; + let dd = (cc + 16) % 512; + let ee = cc.wrapping_sub(16) % 512; + + if self.counter1024 & 512 == 0 { + // P block + results[0] = self.step_p(cc+0, cc+1, ee+13, ee+6, ee+4); + results[1] = self.step_p(cc+1, cc+2, ee+14, ee+7, ee+5); + results[2] = self.step_p(cc+2, cc+3, ee+15, ee+8, ee+6); + results[3] = self.step_p(cc+3, cc+4, cc+0, ee+9, ee+7); + results[4] = self.step_p(cc+4, cc+5, cc+1, ee+10, ee+8); + results[5] = self.step_p(cc+5, cc+6, cc+2, ee+11, ee+9); + results[6] = self.step_p(cc+6, cc+7, cc+3, ee+12, ee+10); + results[7] = self.step_p(cc+7, cc+8, cc+4, ee+13, ee+11); + results[8] = self.step_p(cc+8, cc+9, cc+5, ee+14, ee+12); + results[9] = self.step_p(cc+9, cc+10, cc+6, ee+15, ee+13); + results[10] = self.step_p(cc+10, cc+11, cc+7, cc+0, ee+14); + results[11] = self.step_p(cc+11, cc+12, cc+8, cc+1, ee+15); + results[12] = self.step_p(cc+12, cc+13, cc+9, cc+2, cc+0); + results[13] = self.step_p(cc+13, cc+14, cc+10, cc+3, cc+1); + results[14] = self.step_p(cc+14, cc+15, cc+11, cc+4, cc+2); + results[15] = self.step_p(cc+15, dd+0, cc+12, cc+5, cc+3); + } else { + // Q block + results[0] = self.step_q(cc+0, cc+1, ee+13, ee+6, ee+4); + results[1] = self.step_q(cc+1, cc+2, ee+14, ee+7, ee+5); + results[2] = self.step_q(cc+2, cc+3, ee+15, ee+8, ee+6); + results[3] = self.step_q(cc+3, cc+4, cc+0, ee+9, ee+7); + results[4] = self.step_q(cc+4, cc+5, cc+1, ee+10, ee+8); + results[5] = self.step_q(cc+5, cc+6, cc+2, ee+11, ee+9); + results[6] = self.step_q(cc+6, cc+7, cc+3, ee+12, ee+10); + results[7] = self.step_q(cc+7, cc+8, cc+4, ee+13, ee+11); + results[8] = self.step_q(cc+8, cc+9, cc+5, ee+14, ee+12); + results[9] = self.step_q(cc+9, cc+10, cc+6, ee+15, ee+13); + results[10] = self.step_q(cc+10, cc+11, cc+7, cc+0, ee+14); + results[11] = self.step_q(cc+11, cc+12, cc+8, cc+1, ee+15); + results[12] = self.step_q(cc+12, cc+13, cc+9, cc+2, cc+0); + results[13] = self.step_q(cc+13, cc+14, cc+10, cc+3, cc+1); + results[14] = self.step_q(cc+14, cc+15, cc+11, cc+4, cc+2); + results[15] = self.step_q(cc+15, dd+0, cc+12, cc+5, cc+3); + } + self.counter1024 = self.counter1024.wrapping_add(16); + } +} + +impl Hc128Core { + // One step of HC-128, update P and generate 32 bits keystream + #[inline(always)] + fn step_p(&mut self, i: usize, i511: usize, i3: usize, i10: usize, i12: usize) + -> u32 + { + let (p, q) = self.t.split_at_mut(512); + // FIXME: it would be great if we the bounds checks here could be + // optimized out, and we would not need unsafe. + // This improves performance by about 7%. + unsafe { + let temp0 = p.get_unchecked(i511).rotate_right(23); + let temp1 = p.get_unchecked(i3).rotate_right(10); + let temp2 = p.get_unchecked(i10).rotate_right(8); + *p.get_unchecked_mut(i) = p.get_unchecked(i) + .wrapping_add(temp2) + .wrapping_add(temp0 ^ temp1); + let temp3 = { + // The h1 function in HC-128 + let a = *p.get_unchecked(i12) as u8; + let c = (p.get_unchecked(i12) >> 16) as u8; + q[a as usize].wrapping_add(q[256 + c as usize]) + }; + temp3 ^ p.get_unchecked(i) + } + } + + // One step of HC-128, update Q and generate 32 bits keystream + // Similar to `step_p`, but `p` and `q` are swapped, and the rotates are to + // the left instead of to the right. + #[inline(always)] + fn step_q(&mut self, i: usize, i511: usize, i3: usize, i10: usize, i12: usize) + -> u32 + { + let (p, q) = self.t.split_at_mut(512); + unsafe { + let temp0 = q.get_unchecked(i511).rotate_left(23); + let temp1 = q.get_unchecked(i3).rotate_left(10); + let temp2 = q.get_unchecked(i10).rotate_left(8); + *q.get_unchecked_mut(i) = q.get_unchecked(i) + .wrapping_add(temp2) + .wrapping_add(temp0 ^ temp1); + let temp3 = { + // The h2 function in HC-128 + let a = *q.get_unchecked(i12) as u8; + let c = (q.get_unchecked(i12) >> 16) as u8; + p[a as usize].wrapping_add(p[256 + c as usize]) + }; + temp3 ^ q.get_unchecked(i) + } + } + + fn sixteen_steps(&mut self) { + assert!(self.counter1024 % 16 == 0); + + let cc = self.counter1024 % 512; + let dd = (cc + 16) % 512; + let ee = cc.wrapping_sub(16) % 512; + + if self.counter1024 < 512 { + // P block + self.t[cc+0] = self.step_p(cc+0, cc+1, ee+13, ee+6, ee+4); + self.t[cc+1] = self.step_p(cc+1, cc+2, ee+14, ee+7, ee+5); + self.t[cc+2] = self.step_p(cc+2, cc+3, ee+15, ee+8, ee+6); + self.t[cc+3] = self.step_p(cc+3, cc+4, cc+0, ee+9, ee+7); + self.t[cc+4] = self.step_p(cc+4, cc+5, cc+1, ee+10, ee+8); + self.t[cc+5] = self.step_p(cc+5, cc+6, cc+2, ee+11, ee+9); + self.t[cc+6] = self.step_p(cc+6, cc+7, cc+3, ee+12, ee+10); + self.t[cc+7] = self.step_p(cc+7, cc+8, cc+4, ee+13, ee+11); + self.t[cc+8] = self.step_p(cc+8, cc+9, cc+5, ee+14, ee+12); + self.t[cc+9] = self.step_p(cc+9, cc+10, cc+6, ee+15, ee+13); + self.t[cc+10] = self.step_p(cc+10, cc+11, cc+7, cc+0, ee+14); + self.t[cc+11] = self.step_p(cc+11, cc+12, cc+8, cc+1, ee+15); + self.t[cc+12] = self.step_p(cc+12, cc+13, cc+9, cc+2, cc+0); + self.t[cc+13] = self.step_p(cc+13, cc+14, cc+10, cc+3, cc+1); + self.t[cc+14] = self.step_p(cc+14, cc+15, cc+11, cc+4, cc+2); + self.t[cc+15] = self.step_p(cc+15, dd+0, cc+12, cc+5, cc+3); + } else { + // Q block + self.t[cc+512+0] = self.step_q(cc+0, cc+1, ee+13, ee+6, ee+4); + self.t[cc+512+1] = self.step_q(cc+1, cc+2, ee+14, ee+7, ee+5); + self.t[cc+512+2] = self.step_q(cc+2, cc+3, ee+15, ee+8, ee+6); + self.t[cc+512+3] = self.step_q(cc+3, cc+4, cc+0, ee+9, ee+7); + self.t[cc+512+4] = self.step_q(cc+4, cc+5, cc+1, ee+10, ee+8); + self.t[cc+512+5] = self.step_q(cc+5, cc+6, cc+2, ee+11, ee+9); + self.t[cc+512+6] = self.step_q(cc+6, cc+7, cc+3, ee+12, ee+10); + self.t[cc+512+7] = self.step_q(cc+7, cc+8, cc+4, ee+13, ee+11); + self.t[cc+512+8] = self.step_q(cc+8, cc+9, cc+5, ee+14, ee+12); + self.t[cc+512+9] = self.step_q(cc+9, cc+10, cc+6, ee+15, ee+13); + self.t[cc+512+10] = self.step_q(cc+10, cc+11, cc+7, cc+0, ee+14); + self.t[cc+512+11] = self.step_q(cc+11, cc+12, cc+8, cc+1, ee+15); + self.t[cc+512+12] = self.step_q(cc+12, cc+13, cc+9, cc+2, cc+0); + self.t[cc+512+13] = self.step_q(cc+13, cc+14, cc+10, cc+3, cc+1); + self.t[cc+512+14] = self.step_q(cc+14, cc+15, cc+11, cc+4, cc+2); + self.t[cc+512+15] = self.step_q(cc+15, dd+0, cc+12, cc+5, cc+3); + } + self.counter1024 += 16; + } + + // Initialize an HC-128 random number generator. The seed has to be + // 256 bits in length (`[u32; 8]`), matching the 128 bit `key` followed by + // 128 bit `iv` when HC-128 where to be used as a stream cipher. + fn init(seed: [u32; SEED_WORDS]) -> Self { + #[inline] + fn f1(x: u32) -> u32 { + x.rotate_right(7) ^ x.rotate_right(18) ^ (x >> 3) + } + + #[inline] + fn f2(x: u32) -> u32 { + x.rotate_right(17) ^ x.rotate_right(19) ^ (x >> 10) + } + + let mut t = [0u32; 1024]; + + // Expand the key and iv into P and Q + let (key, iv) = seed.split_at(4); + t[..4].copy_from_slice(key); + t[4..8].copy_from_slice(key); + t[8..12].copy_from_slice(iv); + t[12..16].copy_from_slice(iv); + + // Generate the 256 intermediate values W[16] ... W[256+16-1], and + // copy the last 16 generated values to the start op P. + for i in 16..256+16 { + t[i] = f2(t[i-2]).wrapping_add(t[i-7]).wrapping_add(f1(t[i-15])) + .wrapping_add(t[i-16]).wrapping_add(i as u32); + } + { + let (p1, p2) = t.split_at_mut(256); + p1[0..16].copy_from_slice(&p2[0..16]); + } + + // Generate both the P and Q tables + for i in 16..1024 { + t[i] = f2(t[i-2]).wrapping_add(t[i-7]).wrapping_add(f1(t[i-15])) + .wrapping_add(t[i-16]).wrapping_add(256 + i as u32); + } + + let mut core = Self { t, counter1024: 0 }; + + // run the cipher 1024 steps + for _ in 0..64 { core.sixteen_steps() }; + core.counter1024 = 0; + core + } +} + +impl SeedableRng for Hc128Core { + type Seed = [u8; SEED_WORDS*4]; + + /// Create an HC-128 random number generator with a seed. The seed has to be + /// 256 bits in length, matching the 128 bit `key` followed by 128 bit `iv` + /// when HC-128 where to be used as a stream cipher. + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_u32 = [0u32; SEED_WORDS]; + le::read_u32_into(&seed, &mut seed_u32); + Self::init(seed_u32) + } +} + +impl CryptoRng for Hc128Core {} + +#[cfg(test)] +mod test { + use ::rand_core::{RngCore, SeedableRng}; + use super::Hc128Rng; + + #[test] + // Test vector 1 from the paper "The Stream Cipher HC-128" + fn test_hc128_true_values_a() { + let seed = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv + let mut rng = Hc128Rng::from_seed(seed); + + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0x73150082, 0x3bfd03a0, 0xfb2fd77f, 0xaa63af0e, + 0xde122fc6, 0xa7dc29b6, 0x62a68527, 0x8b75ec68, + 0x9036db1e, 0x81896005, 0x00ade078, 0x491fbf9a, + 0x1cdc3013, 0x6c3d6e24, 0x90f664b2, 0x9cd57102]; + assert_eq!(results, expected); + } + + #[test] + // Test vector 2 from the paper "The Stream Cipher HC-128" + fn test_hc128_true_values_b() { + let seed = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key + 1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv + let mut rng = Hc128Rng::from_seed(seed); + + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0xc01893d5, 0xb7dbe958, 0x8f65ec98, 0x64176604, + 0x36fc6724, 0xc82c6eec, 0x1b1c38a7, 0xc9b42a95, + 0x323ef123, 0x0a6a908b, 0xce757b68, 0x9f14f7bb, + 0xe4cde011, 0xaeb5173f, 0x89608c94, 0xb5cf46ca]; + assert_eq!(results, expected); + } + + #[test] + // Test vector 3 from the paper "The Stream Cipher HC-128" + fn test_hc128_true_values_c() { + let seed = [0x55,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv + let mut rng = Hc128Rng::from_seed(seed); + + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0x518251a4, 0x04b4930a, 0xb02af931, 0x0639f032, + 0xbcb4a47a, 0x5722480b, 0x2bf99f72, 0xcdc0e566, + 0x310f0c56, 0xd3cc83e8, 0x663db8ef, 0x62dfe07f, + 0x593e1790, 0xc5ceaa9c, 0xab03806f, 0xc9a6e5a0]; + assert_eq!(results, expected); + } + + #[test] + fn test_hc128_true_values_u64() { + let seed = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv + let mut rng = Hc128Rng::from_seed(seed); + + let mut results = [0u64; 8]; + for i in results.iter_mut() { *i = rng.next_u64(); } + let expected = [0x3bfd03a073150082, 0xaa63af0efb2fd77f, + 0xa7dc29b6de122fc6, 0x8b75ec6862a68527, + 0x818960059036db1e, 0x491fbf9a00ade078, + 0x6c3d6e241cdc3013, 0x9cd5710290f664b2]; + assert_eq!(results, expected); + + // The RNG operates in a P block of 512 results and next a Q block. + // After skipping 2*800 u32 results we end up somewhere in the Q block + // of the second round + for _ in 0..800 { rng.next_u64(); } + + for i in results.iter_mut() { *i = rng.next_u64(); } + let expected = [0xd8c4d6ca84d0fc10, 0xf16a5d91dc66e8e7, + 0xd800de5bc37a8653, 0x7bae1f88c0dfbb4c, + 0x3bfe1f374e6d4d14, 0x424b55676be3fa06, + 0xe3a1e8758cbff579, 0x417f7198c5652bcd]; + assert_eq!(results, expected); + } + + #[test] + fn test_hc128_true_values_bytes() { + let seed = [0x55,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv + let mut rng = Hc128Rng::from_seed(seed); + let expected = [0x31, 0xf9, 0x2a, 0xb0, 0x32, 0xf0, 0x39, 0x06, + 0x7a, 0xa4, 0xb4, 0xbc, 0x0b, 0x48, 0x22, 0x57, + 0x72, 0x9f, 0xf9, 0x2b, 0x66, 0xe5, 0xc0, 0xcd, + 0x56, 0x0c, 0x0f, 0x31, 0xe8, 0x83, 0xcc, 0xd3, + 0xef, 0xb8, 0x3d, 0x66, 0x7f, 0xe0, 0xdf, 0x62, + 0x90, 0x17, 0x3e, 0x59, 0x9c, 0xaa, 0xce, 0xc5, + 0x6f, 0x80, 0x03, 0xab, 0xa0, 0xe5, 0xa6, 0xc9, + 0x60, 0x95, 0x84, 0x7a, 0xa5, 0x68, 0x5a, 0x84, + 0xea, 0xd5, 0xf3, 0xea, 0x73, 0xa9, 0xad, 0x01, + 0x79, 0x7d, 0xbe, 0x9f, 0xea, 0xe3, 0xf9, 0x74, + 0x0e, 0xda, 0x2f, 0xa0, 0xe4, 0x7b, 0x4b, 0x1b, + 0xdd, 0x17, 0x69, 0x4a, 0xfe, 0x9f, 0x56, 0x95, + 0xad, 0x83, 0x6b, 0x9d, 0x60, 0xa1, 0x99, 0x96, + 0x90, 0x00, 0x66, 0x7f, 0xfa, 0x7e, 0x65, 0xe9, + 0xac, 0x8b, 0x92, 0x34, 0x77, 0xb4, 0x23, 0xd0, + 0xb9, 0xab, 0xb1, 0x47, 0x7d, 0x4a, 0x13, 0x0a]; + + // Pick a somewhat large buffer so we can test filling with the + // remainder from `state.results`, directly filling the buffer, and + // filling the remainder of the buffer. + let mut buffer = [0u8; 16*4*2]; + // Consume a value so that we have a remainder. + assert!(rng.next_u64() == 0x04b4930a518251a4); + rng.fill_bytes(&mut buffer); + + // [u8; 128] doesn't implement PartialEq + assert_eq!(buffer.len(), expected.len()); + for (b, e) in buffer.iter().zip(expected.iter()) { + assert_eq!(b, e); + } + } + + #[test] + fn test_hc128_clone() { + let seed = [0x55,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv + let mut rng1 = Hc128Rng::from_seed(seed); + let mut rng2 = rng1.clone(); + for _ in 0..16 { + assert_eq!(rng1.next_u32(), rng2.next_u32()); + } + } +} diff --git a/third_party/rust/rand_hc/src/lib.rs b/third_party/rust/rand_hc/src/lib.rs new file mode 100644 index 000000000000..15ca34ebe0ad --- /dev/null +++ b/third_party/rust/rand_hc/src/lib.rs @@ -0,0 +1,25 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The HC128 random number generator. + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://docs.rs/rand_hc/0.1.0")] + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +#![no_std] + +extern crate rand_core; + +mod hc128; + +pub use hc128::{Hc128Rng, Hc128Core}; diff --git a/third_party/rust/rand_isaac/.cargo-checksum.json b/third_party/rust/rand_isaac/.cargo-checksum.json new file mode 100644 index 000000000000..c5527188f7dc --- /dev/null +++ b/third_party/rust/rand_isaac/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"1f98689d52278352079e5235ffe00537bd3b64c1807a87d5707e3e74c7fce1d8","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.toml":"c3fb66104a60aa0dd91b83645be897023e7eb001aa6be108a1948999e86d2512","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"9a1c416b5930337e94fe559673a32a136d3ddd513f19dbd1b37039f8fc3501a1","src/isaac.rs":"40b00c02dc1ce29786c2e5e4c4d642588709397d6bf276a1610743b9b76ab9c6","src/isaac64.rs":"61a11f4a34dc2f009771d41c8d200c1c4815cdc23dfbe96aec03219cfeee4daa","src/isaac_array.rs":"89d20f07eb4dacd42f4cdc25b59796d51bca708f218e6e6dd4a445113b5123d6","src/lib.rs":"840a9c5a5ef2150cc4fb4a3edf34bda7e48bfaa49a3ee7ef8b182743aeaf73dd"},"package":"ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"} \ No newline at end of file diff --git a/third_party/rust/rand_isaac/CHANGELOG.md b/third_party/rust/rand_isaac/CHANGELOG.md new file mode 100644 index 000000000000..fb1ab3f3c572 --- /dev/null +++ b/third_party/rust/rand_isaac/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.1.1] - 2018-11-26 +- Fix `rand_core` version requirement +- Fix doc links + +## [0.1.0] - 2018-10-17 +- Pulled out of the Rand crate diff --git a/third_party/rust/rand_isaac/COPYRIGHT b/third_party/rust/rand_isaac/COPYRIGHT new file mode 100644 index 000000000000..468d907caf99 --- /dev/null +++ b/third_party/rust/rand_isaac/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 or + or the MIT license + or , at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/third_party/rust/rand_isaac/Cargo.toml b/third_party/rust/rand_isaac/Cargo.toml new file mode 100644 index 000000000000..79a541decee3 --- /dev/null +++ b/third_party/rust/rand_isaac/Cargo.toml @@ -0,0 +1,45 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand_isaac" +version = "0.1.1" +authors = ["The Rand Project Developers", "The Rust Project Developers"] +description = "ISAAC random number generator\n" +homepage = "https://crates.io/crates/rand_isaac" +documentation = "https://rust-random.github.io/rand/rand_isaac" +readme = "README.md" +keywords = ["random", "rng", "isaac"] +categories = ["algorithms", "no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-random/rand" +[dependencies.rand_core] +version = "0.3" +default-features = false + +[dependencies.serde] +version = "1" +optional = true + +[dependencies.serde_derive] +version = "^1.0.38" +optional = true +[dev-dependencies.bincode] +version = "1" + +[features] +serde1 = ["serde", "serde_derive", "rand_core/serde1"] +[badges.appveyor] +repository = "rust-random/rand" + +[badges.travis-ci] +repository = "rust-random/rand" diff --git a/third_party/rust/rand_isaac/LICENSE-APACHE b/third_party/rust/rand_isaac/LICENSE-APACHE new file mode 100644 index 000000000000..17d74680f8cf --- /dev/null +++ b/third_party/rust/rand_isaac/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/rand_isaac/LICENSE-MIT b/third_party/rust/rand_isaac/LICENSE-MIT new file mode 100644 index 000000000000..d93b5baf341d --- /dev/null +++ b/third_party/rust/rand_isaac/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright 2018 Developers of the Rand project +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/rand_isaac/README.md b/third_party/rust/rand_isaac/README.md new file mode 100644 index 000000000000..02d1230335e8 --- /dev/null +++ b/third_party/rust/rand_isaac/README.md @@ -0,0 +1,47 @@ +# rand_isaac + +[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Latest version](https://img.shields.io/crates/v/rand_isaac.svg)](https://crates.io/crates/rand_isaac) +[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) +[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_isaac) +[![API](https://docs.rs/rand_isaac/badge.svg)](https://docs.rs/rand_isaac) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) + +Implements the ISAAC and ISAAC-64 random number generators. + +ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are +the principal bitwise operations employed. It is the most advanced of a +series of array based random number generator designed by Robert Jenkins +in 1996[^1][^2]. + +ISAAC is notably fast and produces excellent quality random numbers for +non-cryptographic applications. + +Links: + +- [API documentation (master)](https://rust-random.github.io/rand/rand_isaac) +- [API documentation (docs.rs)](https://docs.rs/rand_isaac) +- [Changelog](CHANGELOG.md) + +[rand]: https://crates.io/crates/rand +[^1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number generator*](http://burtleburtle.net/bob/rand/isaacafa.html) +[^2]: Bob Jenkins, [*ISAAC and RC4*](http://burtleburtle.net/bob/rand/isaac.html) + + +## Crate Features + +`rand_isaac` is `no_std` compatible. It does not require any functionality +outside of the `core` lib, thus there are no features to configure. + +The `serde1` feature includes implementations of `Serialize` and `Deserialize` +for the included RNGs. + + +# License + +`rand_isaac` is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/third_party/rust/rand_isaac/src/isaac.rs b/third_party/rust/rand_isaac/src/isaac.rs new file mode 100644 index 000000000000..2bfdd9435090 --- /dev/null +++ b/third_party/rust/rand_isaac/src/isaac.rs @@ -0,0 +1,484 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013-2018 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The ISAAC random number generator. + +use core::{fmt, slice}; +use core::num::Wrapping as w; +use rand_core::{RngCore, SeedableRng, Error, le}; +use rand_core::block::{BlockRngCore, BlockRng}; +use isaac_array::IsaacArray; + +#[allow(non_camel_case_types)] +type w32 = w; + +const RAND_SIZE_LEN: usize = 8; +const RAND_SIZE: usize = 1 << RAND_SIZE_LEN; + +/// A random number generator that uses the ISAAC algorithm. +/// +/// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are +/// the principal bitwise operations employed. It is the most advanced of a +/// series of array based random number generator designed by Robert Jenkins +/// in 1996[^1][^2]. +/// +/// ISAAC is notably fast and produces excellent quality random numbers for +/// non-cryptographic applications. +/// +/// In spite of being designed with cryptographic security in mind, ISAAC hasn't +/// been stringently cryptanalyzed and thus cryptographers do not not +/// consensually trust it to be secure. When looking for a secure RNG, prefer +/// [`Hc128Rng`] instead, which, like ISAAC, is an array-based RNG and one of +/// the stream-ciphers selected the by eSTREAM contest. +/// +/// In 2006 an improvement to ISAAC was suggested by Jean-Philippe Aumasson, +/// named ISAAC+[^3]. But because the specification is not complete, because +/// there is no good implementation, and because the suggested bias may not +/// exist, it is not implemented here. +/// +/// ## Overview of the ISAAC algorithm: +/// (in pseudo-code) +/// +/// ```text +/// Input: a, b, c, s[256] // state +/// Output: r[256] // results +/// +/// mix(a,i) = a ^ a << 13 if i = 0 mod 4 +/// a ^ a >> 6 if i = 1 mod 4 +/// a ^ a << 2 if i = 2 mod 4 +/// a ^ a >> 16 if i = 3 mod 4 +/// +/// c = c + 1 +/// b = b + c +/// +/// for i in 0..256 { +/// x = s_[i] +/// a = f(a,i) + s[i+128 mod 256] +/// y = a + b + s[x>>2 mod 256] +/// s[i] = y +/// b = x + s[y>>10 mod 256] +/// r[i] = b +/// } +/// ``` +/// +/// Numbers are generated in blocks of 256. This means the function above only +/// runs once every 256 times you ask for a next random number. In all other +/// circumstances the last element of the results array is returned. +/// +/// ISAAC therefore needs a lot of memory, relative to other non-crypto RNGs. +/// 2 * 256 * 4 = 2 kb to hold the state and results. +/// +/// This implementation uses [`BlockRng`] to implement the [`RngCore`] methods. +/// +/// ## References +/// [^1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number generator*]( +/// http://burtleburtle.net/bob/rand/isaacafa.html) +/// +/// [^2]: Bob Jenkins, [*ISAAC and RC4*]( +/// http://burtleburtle.net/bob/rand/isaac.html) +/// +/// [^3]: Jean-Philippe Aumasson, [*On the pseudo-random generator ISAAC*]( +/// https://eprint.iacr.org/2006/438) +/// +/// [`Hc128Rng`]: ../../rand_hc/struct.Hc128Rng.html +/// [`BlockRng`]: ../../rand_core/block/struct.BlockRng.html +/// [`RngCore`]: ../../rand_core/trait.RngCore.html +#[derive(Clone, Debug)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct IsaacRng(BlockRng); + +impl RngCore for IsaacRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for IsaacRng { + type Seed = ::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + IsaacRng(BlockRng::::from_seed(seed)) + } + + /// Create an ISAAC random number generator using an `u64` as seed. + /// If `seed == 0` this will produce the same stream of random numbers as + /// the reference implementation when used unseeded. + fn seed_from_u64(seed: u64) -> Self { + IsaacRng(BlockRng::::seed_from_u64(seed)) + } + + fn from_rng(rng: S) -> Result { + BlockRng::::from_rng(rng).map(|rng| IsaacRng(rng)) + } +} + +impl IsaacRng { + /// Create an ISAAC random number generator using an `u64` as seed. + /// If `seed == 0` this will produce the same stream of random numbers as + /// the reference implementation when used unseeded. + #[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")] + pub fn new_from_u64(seed: u64) -> Self { + Self::seed_from_u64(seed) + } +} + +/// The core of `IsaacRng`, used with `BlockRng`. +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct IsaacCore { + #[cfg_attr(feature="serde1",serde(with="super::isaac_array::isaac_array_serde"))] + mem: [w32; RAND_SIZE], + a: w32, + b: w32, + c: w32, +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for IsaacCore { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "IsaacCore {{}}") + } +} + +impl BlockRngCore for IsaacCore { + type Item = u32; + type Results = IsaacArray; + + /// Refills the output buffer, `results`. See also the pseudocode desciption + /// of the algorithm in the [`IsaacRng`] documentation. + /// + /// Optimisations used (similar to the reference implementation): + /// + /// - The loop is unrolled 4 times, once for every constant of mix(). + /// - The contents of the main loop are moved to a function `rngstep`, to + /// reduce code duplication. + /// - We use local variables for a and b, which helps with optimisations. + /// - We split the main loop in two, one that operates over 0..128 and one + /// over 128..256. This way we can optimise out the addition and modulus + /// from `s[i+128 mod 256]`. + /// - We maintain one index `i` and add `m` or `m2` as base (m2 for the + /// `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer + /// arithmetic. + /// - We fill `results` backwards. The reference implementation reads values + /// from `results` in reverse. We read them in the normal direction, to + /// make `fill_bytes` a memcopy. To maintain compatibility we fill in + /// reverse. + /// + /// [`IsaacRng`]: struct.IsaacRng.html + fn generate(&mut self, results: &mut IsaacArray) { + self.c += w(1); + // abbreviations + let mut a = self.a; + let mut b = self.b + self.c; + const MIDPOINT: usize = RAND_SIZE / 2; + + #[inline] + fn ind(mem:&[w32; RAND_SIZE], v: w32, amount: usize) -> w32 { + let index = (v >> amount).0 as usize % RAND_SIZE; + mem[index] + } + + #[inline] + fn rngstep(mem: &mut [w32; RAND_SIZE], + results: &mut [u32; RAND_SIZE], + mix: w32, + a: &mut w32, + b: &mut w32, + base: usize, + m: usize, + m2: usize) { + let x = mem[base + m]; + *a = mix + mem[base + m2]; + let y = *a + *b + ind(&mem, x, 2); + mem[base + m] = y; + *b = x + ind(&mem, y, 2 + RAND_SIZE_LEN); + results[RAND_SIZE - 1 - base - m] = (*b).0; + } + + let mut m = 0; + let mut m2 = MIDPOINT; + for i in (0..MIDPOINT/4).map(|i| i * 4) { + rngstep(&mut self.mem, results, a ^ (a << 13), &mut a, &mut b, i + 0, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 6 ), &mut a, &mut b, i + 1, m, m2); + rngstep(&mut self.mem, results, a ^ (a << 2 ), &mut a, &mut b, i + 2, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 16), &mut a, &mut b, i + 3, m, m2); + } + + m = MIDPOINT; + m2 = 0; + for i in (0..MIDPOINT/4).map(|i| i * 4) { + rngstep(&mut self.mem, results, a ^ (a << 13), &mut a, &mut b, i + 0, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 6 ), &mut a, &mut b, i + 1, m, m2); + rngstep(&mut self.mem, results, a ^ (a << 2 ), &mut a, &mut b, i + 2, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 16), &mut a, &mut b, i + 3, m, m2); + } + + self.a = a; + self.b = b; + } +} + +impl IsaacCore { + /// Create a new ISAAC random number generator. + /// + /// The author Bob Jenkins describes how to best initialize ISAAC here: + /// + /// The answer is included here just in case: + /// + /// "No, you don't need a full 8192 bits of seed data. Normal key sizes will + /// do fine, and they should have their expected strength (eg a 40-bit key + /// will take as much time to brute force as 40-bit keys usually will). You + /// could fill the remainder with 0, but set the last array element to the + /// length of the key provided (to distinguish keys that differ only by + /// different amounts of 0 padding). You do still need to call `randinit()` + /// to make sure the initial state isn't uniform-looking." + /// "After publishing ISAAC, I wanted to limit the key to half the size of + /// `r[]`, and repeat it twice. That would have made it hard to provide a + /// key that sets the whole internal state to anything convenient. But I'd + /// already published it." + /// + /// And his answer to the question "For my code, would repeating the key + /// over and over to fill 256 integers be a better solution than + /// zero-filling, or would they essentially be the same?": + /// "If the seed is under 32 bytes, they're essentially the same, otherwise + /// repeating the seed would be stronger. randinit() takes a chunk of 32 + /// bytes, mixes it, and combines that with the next 32 bytes, et cetera. + /// Then loops over all the elements the same way a second time." + #[inline] + fn init(mut mem: [w32; RAND_SIZE], rounds: u32) -> Self { + fn mix(a: &mut w32, b: &mut w32, c: &mut w32, d: &mut w32, + e: &mut w32, f: &mut w32, g: &mut w32, h: &mut w32) { + *a ^= *b << 11; *d += *a; *b += *c; + *b ^= *c >> 2; *e += *b; *c += *d; + *c ^= *d << 8; *f += *c; *d += *e; + *d ^= *e >> 16; *g += *d; *e += *f; + *e ^= *f << 10; *h += *e; *f += *g; + *f ^= *g >> 4; *a += *f; *g += *h; + *g ^= *h << 8; *b += *g; *h += *a; + *h ^= *a >> 9; *c += *h; *a += *b; + } + + // These numbers are the result of initializing a...h with the + // fractional part of the golden ratio in binary (0x9e3779b9) + // and applying mix() 4 times. + let mut a = w(0x1367df5a); + let mut b = w(0x95d90059); + let mut c = w(0xc3163e4b); + let mut d = w(0x0f421ad8); + let mut e = w(0xd92a4a78); + let mut f = w(0xa51a3c49); + let mut g = w(0xc4efea1b); + let mut h = w(0x30609119); + + // Normally this should do two passes, to make all of the seed effect + // all of `mem` + for _ in 0..rounds { + for i in (0..RAND_SIZE/8).map(|i| i * 8) { + a += mem[i ]; b += mem[i+1]; + c += mem[i+2]; d += mem[i+3]; + e += mem[i+4]; f += mem[i+5]; + g += mem[i+6]; h += mem[i+7]; + mix(&mut a, &mut b, &mut c, &mut d, + &mut e, &mut f, &mut g, &mut h); + mem[i ] = a; mem[i+1] = b; + mem[i+2] = c; mem[i+3] = d; + mem[i+4] = e; mem[i+5] = f; + mem[i+6] = g; mem[i+7] = h; + } + } + + Self { mem, a: w(0), b: w(0), c: w(0) } + } +} + +impl SeedableRng for IsaacCore { + type Seed = [u8; 32]; + + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_u32 = [0u32; 8]; + le::read_u32_into(&seed, &mut seed_u32); + // Convert the seed to `Wrapping` and zero-extend to `RAND_SIZE`. + let mut seed_extended = [w(0); RAND_SIZE]; + for (x, y) in seed_extended.iter_mut().zip(seed_u32.iter()) { + *x = w(*y); + } + Self::init(seed_extended, 2) + } + + /// Create an ISAAC random number generator using an `u64` as seed. + /// If `seed == 0` this will produce the same stream of random numbers as + /// the reference implementation when used unseeded. + fn seed_from_u64(seed: u64) -> Self { + let mut key = [w(0); RAND_SIZE]; + key[0] = w(seed as u32); + key[1] = w((seed >> 32) as u32); + // Initialize with only one pass. + // A second pass does not improve the quality here, because all of the + // seed was already available in the first round. + // Not doing the second pass has the small advantage that if + // `seed == 0` this method produces exactly the same state as the + // reference implementation when used unseeded. + Self::init(key, 1) + } + + fn from_rng(mut rng: R) -> Result { + // Custom `from_rng` implementation that fills a seed with the same size + // as the entire state. + let mut seed = [w(0u32); RAND_SIZE]; + unsafe { + let ptr = seed.as_mut_ptr() as *mut u8; + + let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE * 4); + rng.try_fill_bytes(slice)?; + } + for i in seed.iter_mut() { + *i = w(i.0.to_le()); + } + + Ok(Self::init(seed, 2)) + } +} + +#[cfg(test)] +mod test { + use rand_core::{RngCore, SeedableRng}; + use super::IsaacRng; + + #[test] + fn test_isaac_construction() { + // Test that various construction techniques produce a working RNG. + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng1 = IsaacRng::from_seed(seed); + assert_eq!(rng1.next_u32(), 2869442790); + + let mut rng2 = IsaacRng::from_rng(rng1).unwrap(); + assert_eq!(rng2.next_u32(), 3094074039); + } + + #[test] + fn test_isaac_true_values_32() { + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng1 = IsaacRng::from_seed(seed); + let mut results = [0u32; 10]; + for i in results.iter_mut() { *i = rng1.next_u32(); } + let expected = [ + 2558573138, 873787463, 263499565, 2103644246, 3595684709, + 4203127393, 264982119, 2765226902, 2737944514, 3900253796]; + assert_eq!(results, expected); + + let seed = [57,48,0,0, 50,9,1,0, 49,212,0,0, 148,38,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng2 = IsaacRng::from_seed(seed); + // skip forward to the 10000th number + for _ in 0..10000 { rng2.next_u32(); } + + for i in results.iter_mut() { *i = rng2.next_u32(); } + let expected = [ + 3676831399, 3183332890, 2834741178, 3854698763, 2717568474, + 1576568959, 3507990155, 179069555, 141456972, 2478885421]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac_true_values_64() { + // As above, using little-endian versions of above values + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng = IsaacRng::from_seed(seed); + let mut results = [0u64; 5]; + for i in results.iter_mut() { *i = rng.next_u64(); } + let expected = [ + 3752888579798383186, 9035083239252078381,18052294697452424037, + 11876559110374379111, 16751462502657800130]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac_true_bytes() { + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng = IsaacRng::from_seed(seed); + let mut results = [0u8; 32]; + rng.fill_bytes(&mut results); + // Same as first values in test_isaac_true_values as bytes in LE order + let expected = [82, 186, 128, 152, 71, 240, 20, 52, + 45, 175, 180, 15, 86, 16, 99, 125, + 101, 203, 81, 214, 97, 162, 134, 250, + 103, 78, 203, 15, 150, 3, 210, 164]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac_new_uninitialized() { + // Compare the results from initializing `IsaacRng` with + // `seed_from_u64(0)`, to make sure it is the same as the reference + // implementation when used uninitialized. + // Note: We only test the first 16 integers, not the full 256 of the + // first block. + let mut rng = IsaacRng::seed_from_u64(0); + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected: [u32; 16] = [ + 0x71D71FD2, 0xB54ADAE7, 0xD4788559, 0xC36129FA, + 0x21DC1EA9, 0x3CB879CA, 0xD83B237F, 0xFA3CE5BD, + 0x8D048509, 0xD82E9489, 0xDB452848, 0xCA20E846, + 0x500F972E, 0x0EEFF940, 0x00D6B993, 0xBC12C17F]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac_clone() { + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng1 = IsaacRng::from_seed(seed); + let mut rng2 = rng1.clone(); + for _ in 0..16 { + assert_eq!(rng1.next_u32(), rng2.next_u32()); + } + } + + #[test] + #[cfg(feature="serde1")] + fn test_isaac_serde() { + use bincode; + use std::io::{BufWriter, BufReader}; + + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng = IsaacRng::from_seed(seed); + + let buf: Vec = Vec::new(); + let mut buf = BufWriter::new(buf); + bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); + + let buf = buf.into_inner().unwrap(); + let mut read = BufReader::new(&buf[..]); + let mut deserialized: IsaacRng = bincode::deserialize_from(&mut read).expect("Could not deserialize"); + + for _ in 0..300 { // more than the 256 buffered results + assert_eq!(rng.next_u32(), deserialized.next_u32()); + } + } +} diff --git a/third_party/rust/rand_isaac/src/isaac64.rs b/third_party/rust/rand_isaac/src/isaac64.rs new file mode 100644 index 000000000000..2712762ab328 --- /dev/null +++ b/third_party/rust/rand_isaac/src/isaac64.rs @@ -0,0 +1,481 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013-2018 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The ISAAC-64 random number generator. + +use core::{fmt, slice}; +use core::num::Wrapping as w; +use rand_core::{RngCore, SeedableRng, Error, le}; +use rand_core::block::{BlockRngCore, BlockRng64}; +use isaac_array::IsaacArray; + +#[allow(non_camel_case_types)] +type w64 = w; + +const RAND_SIZE_LEN: usize = 8; +const RAND_SIZE: usize = 1 << RAND_SIZE_LEN; + +/// A random number generator that uses ISAAC-64, the 64-bit variant of the +/// ISAAC algorithm. +/// +/// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are +/// the principal bitwise operations employed. It is the most advanced of a +/// series of array based random number generator designed by Robert Jenkins +/// in 1996[^1]. +/// +/// ISAAC-64 is mostly similar to ISAAC. Because it operates on 64-bit integers +/// instead of 32-bit, it uses twice as much memory to hold its state and +/// results. Also it uses different constants for shifts and indirect indexing, +/// optimized to give good results for 64bit arithmetic. +/// +/// ISAAC-64 is notably fast and produces excellent quality random numbers for +/// non-cryptographic applications. +/// +/// In spite of being designed with cryptographic security in mind, ISAAC hasn't +/// been stringently cryptanalyzed and thus cryptographers do not not +/// consensually trust it to be secure. When looking for a secure RNG, prefer +/// [`Hc128Rng`] instead, which, like ISAAC, is an array-based RNG and one of +/// the stream-ciphers selected the by eSTREAM contest. +/// +/// ## Overview of the ISAAC-64 algorithm: +/// (in pseudo-code) +/// +/// ```text +/// Input: a, b, c, s[256] // state +/// Output: r[256] // results +/// +/// mix(a,i) = !(a ^ a << 21) if i = 0 mod 4 +/// a ^ a >> 5 if i = 1 mod 4 +/// a ^ a << 12 if i = 2 mod 4 +/// a ^ a >> 33 if i = 3 mod 4 +/// +/// c = c + 1 +/// b = b + c +/// +/// for i in 0..256 { +/// x = s_[i] +/// a = mix(a,i) + s[i+128 mod 256] +/// y = a + b + s[x>>3 mod 256] +/// s[i] = y +/// b = x + s[y>>11 mod 256] +/// r[i] = b +/// } +/// ``` +/// +/// This implementation uses [`BlockRng64`] to implement the [`RngCore`] methods. +/// +/// See for more information the documentation of [`IsaacRng`]. +/// +/// [^1]: Bob Jenkins, [*ISAAC and RC4*]( +/// http://burtleburtle.net/bob/rand/isaac.html) +/// +/// [`IsaacRng`]: ../isaac/struct.IsaacRng.html +/// [`Hc128Rng`]: ../../rand_hc/struct.Hc128Rng.html +/// [`BlockRng64`]: ../../rand_core/block/struct.BlockRng64.html +/// [`RngCore`]: ../../rand_core/trait.RngCore.html +#[derive(Clone, Debug)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct Isaac64Rng(BlockRng64); + +impl RngCore for Isaac64Rng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for Isaac64Rng { + type Seed = ::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + Isaac64Rng(BlockRng64::::from_seed(seed)) + } + + /// Create an ISAAC random number generator using an `u64` as seed. + /// If `seed == 0` this will produce the same stream of random numbers as + /// the reference implementation when used unseeded. + fn seed_from_u64(seed: u64) -> Self { + Isaac64Rng(BlockRng64::::seed_from_u64(seed)) + } + + fn from_rng(rng: S) -> Result { + BlockRng64::::from_rng(rng).map(|rng| Isaac64Rng(rng)) + } +} + +impl Isaac64Rng { + /// Create an ISAAC-64 random number generator using an `u64` as seed. + /// If `seed == 0` this will produce the same stream of random numbers as + /// the reference implementation when used unseeded. + #[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")] + pub fn new_from_u64(seed: u64) -> Self { + Self::seed_from_u64(seed) + } +} + +/// The core of `Isaac64Rng`, used with `BlockRng`. +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct Isaac64Core { + #[cfg_attr(feature="serde1",serde(with="super::isaac_array::isaac_array_serde"))] + mem: [w64; RAND_SIZE], + a: w64, + b: w64, + c: w64, +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for Isaac64Core { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Isaac64Core {{}}") + } +} + +impl BlockRngCore for Isaac64Core { + type Item = u64; + type Results = IsaacArray; + + /// Refills the output buffer, `results`. See also the pseudocode desciption + /// of the algorithm in the [`Isaac64Rng`] documentation. + /// + /// Optimisations used (similar to the reference implementation): + /// + /// - The loop is unrolled 4 times, once for every constant of mix(). + /// - The contents of the main loop are moved to a function `rngstep`, to + /// reduce code duplication. + /// - We use local variables for a and b, which helps with optimisations. + /// - We split the main loop in two, one that operates over 0..128 and one + /// over 128..256. This way we can optimise out the addition and modulus + /// from `s[i+128 mod 256]`. + /// - We maintain one index `i` and add `m` or `m2` as base (m2 for the + /// `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer + /// arithmetic. + /// - We fill `results` backwards. The reference implementation reads values + /// from `results` in reverse. We read them in the normal direction, to + /// make `fill_bytes` a memcopy. To maintain compatibility we fill in + /// reverse. + /// + /// [`Isaac64Rng`]: struct.Isaac64Rng.html + fn generate(&mut self, results: &mut IsaacArray) { + self.c += w(1); + // abbreviations + let mut a = self.a; + let mut b = self.b + self.c; + const MIDPOINT: usize = RAND_SIZE / 2; + + #[inline] + fn ind(mem:&[w64; RAND_SIZE], v: w64, amount: usize) -> w64 { + let index = (v >> amount).0 as usize % RAND_SIZE; + mem[index] + } + + #[inline] + fn rngstep(mem: &mut [w64; RAND_SIZE], + results: &mut [u64; RAND_SIZE], + mix: w64, + a: &mut w64, + b: &mut w64, + base: usize, + m: usize, + m2: usize) { + let x = mem[base + m]; + *a = mix + mem[base + m2]; + let y = *a + *b + ind(&mem, x, 3); + mem[base + m] = y; + *b = x + ind(&mem, y, 3 + RAND_SIZE_LEN); + results[RAND_SIZE - 1 - base - m] = (*b).0; + } + + let mut m = 0; + let mut m2 = MIDPOINT; + for i in (0..MIDPOINT/4).map(|i| i * 4) { + rngstep(&mut self.mem, results, !(a ^ (a << 21)), &mut a, &mut b, i + 0, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 5 ), &mut a, &mut b, i + 1, m, m2); + rngstep(&mut self.mem, results, a ^ (a << 12), &mut a, &mut b, i + 2, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 33), &mut a, &mut b, i + 3, m, m2); + } + + m = MIDPOINT; + m2 = 0; + for i in (0..MIDPOINT/4).map(|i| i * 4) { + rngstep(&mut self.mem, results, !(a ^ (a << 21)), &mut a, &mut b, i + 0, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 5 ), &mut a, &mut b, i + 1, m, m2); + rngstep(&mut self.mem, results, a ^ (a << 12), &mut a, &mut b, i + 2, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 33), &mut a, &mut b, i + 3, m, m2); + } + + self.a = a; + self.b = b; + } +} + +impl Isaac64Core { + /// Create a new ISAAC-64 random number generator. + fn init(mut mem: [w64; RAND_SIZE], rounds: u32) -> Self { + fn mix(a: &mut w64, b: &mut w64, c: &mut w64, d: &mut w64, + e: &mut w64, f: &mut w64, g: &mut w64, h: &mut w64) { + *a -= *e; *f ^= *h >> 9; *h += *a; + *b -= *f; *g ^= *a << 9; *a += *b; + *c -= *g; *h ^= *b >> 23; *b += *c; + *d -= *h; *a ^= *c << 15; *c += *d; + *e -= *a; *b ^= *d >> 14; *d += *e; + *f -= *b; *c ^= *e << 20; *e += *f; + *g -= *c; *d ^= *f >> 17; *f += *g; + *h -= *d; *e ^= *g << 14; *g += *h; + } + + // These numbers are the result of initializing a...h with the + // fractional part of the golden ratio in binary (0x9e3779b97f4a7c13) + // and applying mix() 4 times. + let mut a = w(0x647c4677a2884b7c); + let mut b = w(0xb9f8b322c73ac862); + let mut c = w(0x8c0ea5053d4712a0); + let mut d = w(0xb29b2e824a595524); + let mut e = w(0x82f053db8355e0ce); + let mut f = w(0x48fe4a0fa5a09315); + let mut g = w(0xae985bf2cbfc89ed); + let mut h = w(0x98f5704f6c44c0ab); + + // Normally this should do two passes, to make all of the seed effect + // all of `mem` + for _ in 0..rounds { + for i in (0..RAND_SIZE/8).map(|i| i * 8) { + a += mem[i ]; b += mem[i+1]; + c += mem[i+2]; d += mem[i+3]; + e += mem[i+4]; f += mem[i+5]; + g += mem[i+6]; h += mem[i+7]; + mix(&mut a, &mut b, &mut c, &mut d, + &mut e, &mut f, &mut g, &mut h); + mem[i ] = a; mem[i+1] = b; + mem[i+2] = c; mem[i+3] = d; + mem[i+4] = e; mem[i+5] = f; + mem[i+6] = g; mem[i+7] = h; + } + } + + Self { mem, a: w(0), b: w(0), c: w(0) } + } + + /// Create an ISAAC-64 random number generator using an `u64` as seed. + /// If `seed == 0` this will produce the same stream of random numbers as + /// the reference implementation when used unseeded. + #[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")] + pub fn new_from_u64(seed: u64) -> Self { + Self::seed_from_u64(seed) + } +} + +impl SeedableRng for Isaac64Core { + type Seed = [u8; 32]; + + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_u64 = [0u64; 4]; + le::read_u64_into(&seed, &mut seed_u64); + // Convert the seed to `Wrapping` and zero-extend to `RAND_SIZE`. + let mut seed_extended = [w(0); RAND_SIZE]; + for (x, y) in seed_extended.iter_mut().zip(seed_u64.iter()) { + *x = w(*y); + } + Self::init(seed_extended, 2) + } + + fn seed_from_u64(seed: u64) -> Self { + let mut key = [w(0); RAND_SIZE]; + key[0] = w(seed); + // Initialize with only one pass. + // A second pass does not improve the quality here, because all of the + // seed was already available in the first round. + // Not doing the second pass has the small advantage that if + // `seed == 0` this method produces exactly the same state as the + // reference implementation when used unseeded. + Self::init(key, 1) + } + + fn from_rng(mut rng: R) -> Result { + // Custom `from_rng` implementation that fills a seed with the same size + // as the entire state. + let mut seed = [w(0u64); RAND_SIZE]; + unsafe { + let ptr = seed.as_mut_ptr() as *mut u8; + let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE * 8); + rng.try_fill_bytes(slice)?; + } + for i in seed.iter_mut() { + *i = w(i.0.to_le()); + } + + Ok(Self::init(seed, 2)) + } +} + +#[cfg(test)] +mod test { + use rand_core::{RngCore, SeedableRng}; + use super::Isaac64Rng; + + #[test] + fn test_isaac64_construction() { + // Test that various construction techniques produce a working RNG. + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng1 = Isaac64Rng::from_seed(seed); + assert_eq!(rng1.next_u64(), 14964555543728284049); + + let mut rng2 = Isaac64Rng::from_rng(rng1).unwrap(); + assert_eq!(rng2.next_u64(), 919595328260451758); + } + + #[test] + fn test_isaac64_true_values_64() { + let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, + 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; + let mut rng1 = Isaac64Rng::from_seed(seed); + let mut results = [0u64; 10]; + for i in results.iter_mut() { *i = rng1.next_u64(); } + let expected = [ + 15071495833797886820, 7720185633435529318, + 10836773366498097981, 5414053799617603544, + 12890513357046278984, 17001051845652595546, + 9240803642279356310, 12558996012687158051, + 14673053937227185542, 1677046725350116783]; + assert_eq!(results, expected); + + let seed = [57,48,0,0, 0,0,0,0, 50,9,1,0, 0,0,0,0, + 49,212,0,0, 0,0,0,0, 148,38,0,0, 0,0,0,0]; + let mut rng2 = Isaac64Rng::from_seed(seed); + // skip forward to the 10000th number + for _ in 0..10000 { rng2.next_u64(); } + + for i in results.iter_mut() { *i = rng2.next_u64(); } + let expected = [ + 18143823860592706164, 8491801882678285927, 2699425367717515619, + 17196852593171130876, 2606123525235546165, 15790932315217671084, + 596345674630742204, 9947027391921273664, 11788097613744130851, + 10391409374914919106]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac64_true_values_32() { + let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, + 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; + let mut rng = Isaac64Rng::from_seed(seed); + let mut results = [0u32; 12]; + for i in results.iter_mut() { *i = rng.next_u32(); } + // Subset of above values, as an LE u32 sequence + let expected = [ + 3477963620, 3509106075, + 687845478, 1797495790, + 227048253, 2523132918, + 4044335064, 1260557630, + 4079741768, 3001306521, + 69157722, 3958365844]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac64_true_values_mixed() { + let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, + 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; + let mut rng = Isaac64Rng::from_seed(seed); + // Test alternating between `next_u64` and `next_u32` works as expected. + // Values are the same as `test_isaac64_true_values` and + // `test_isaac64_true_values_32`. + assert_eq!(rng.next_u64(), 15071495833797886820); + assert_eq!(rng.next_u32(), 687845478); + assert_eq!(rng.next_u32(), 1797495790); + assert_eq!(rng.next_u64(), 10836773366498097981); + assert_eq!(rng.next_u32(), 4044335064); + // Skip one u32 + assert_eq!(rng.next_u64(), 12890513357046278984); + assert_eq!(rng.next_u32(), 69157722); + } + + #[test] + fn test_isaac64_true_bytes() { + let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, + 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; + let mut rng = Isaac64Rng::from_seed(seed); + let mut results = [0u8; 32]; + rng.fill_bytes(&mut results); + // Same as first values in test_isaac64_true_values as bytes in LE order + let expected = [100, 131, 77, 207, 155, 181, 40, 209, + 102, 176, 255, 40, 238, 155, 35, 107, + 61, 123, 136, 13, 246, 243, 99, 150, + 216, 167, 15, 241, 62, 149, 34, 75]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac64_new_uninitialized() { + // Compare the results from initializing `IsaacRng` with + // `seed_from_u64(0)`, to make sure it is the same as the reference + // implementation when used uninitialized. + // Note: We only test the first 16 integers, not the full 256 of the + // first block. + let mut rng = Isaac64Rng::seed_from_u64(0); + let mut results = [0u64; 16]; + for i in results.iter_mut() { *i = rng.next_u64(); } + let expected: [u64; 16] = [ + 0xF67DFBA498E4937C, 0x84A5066A9204F380, 0xFEE34BD5F5514DBB, + 0x4D1664739B8F80D6, 0x8607459AB52A14AA, 0x0E78BC5A98529E49, + 0xFE5332822AD13777, 0x556C27525E33D01A, 0x08643CA615F3149F, + 0xD0771FAF3CB04714, 0x30E86F68A37B008D, 0x3074EBC0488A3ADF, + 0x270645EA7A2790BC, 0x5601A0A8D3763C6A, 0x2F83071F53F325DD, + 0xB9090F3D42D2D2EA]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac64_clone() { + let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, + 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; + let mut rng1 = Isaac64Rng::from_seed(seed); + let mut rng2 = rng1.clone(); + for _ in 0..16 { + assert_eq!(rng1.next_u64(), rng2.next_u64()); + } + } + + #[test] + #[cfg(feature="serde1")] + fn test_isaac64_serde() { + use bincode; + use std::io::{BufWriter, BufReader}; + + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng = Isaac64Rng::from_seed(seed); + + let buf: Vec = Vec::new(); + let mut buf = BufWriter::new(buf); + bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); + + let buf = buf.into_inner().unwrap(); + let mut read = BufReader::new(&buf[..]); + let mut deserialized: Isaac64Rng = bincode::deserialize_from(&mut read).expect("Could not deserialize"); + + for _ in 0..300 { // more than the 256 buffered results + assert_eq!(rng.next_u64(), deserialized.next_u64()); + } + } +} diff --git a/third_party/rust/rand_isaac/src/isaac_array.rs b/third_party/rust/rand_isaac/src/isaac_array.rs new file mode 100644 index 000000000000..0fa6147075c6 --- /dev/null +++ b/third_party/rust/rand_isaac/src/isaac_array.rs @@ -0,0 +1,136 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2017-2018 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! ISAAC helper functions for 256-element arrays. + +// Terrible workaround because arrays with more than 32 elements do not +// implement `AsRef`, `Default`, `Serialize`, `Deserialize`, or any other +// traits for that matter. + +#[cfg(feature="serde1")] use serde::{Serialize, Deserialize}; + +const RAND_SIZE_LEN: usize = 8; +const RAND_SIZE: usize = 1 << RAND_SIZE_LEN; + + +#[derive(Copy, Clone)] +#[allow(missing_debug_implementations)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct IsaacArray { + #[cfg_attr(feature="serde1",serde(with="isaac_array_serde"))] + #[cfg_attr(feature="serde1", serde(bound( + serialize = "T: Serialize", + deserialize = "T: Deserialize<'de> + Copy + Default")))] + inner: [T; RAND_SIZE] +} + +impl ::core::convert::AsRef<[T]> for IsaacArray { + #[inline(always)] + fn as_ref(&self) -> &[T] { + &self.inner[..] + } +} + +impl ::core::convert::AsMut<[T]> for IsaacArray { + #[inline(always)] + fn as_mut(&mut self) -> &mut [T] { + &mut self.inner[..] + } +} + +impl ::core::ops::Deref for IsaacArray { + type Target = [T; RAND_SIZE]; + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl ::core::ops::DerefMut for IsaacArray { + #[inline(always)] + fn deref_mut(&mut self) -> &mut [T; RAND_SIZE] { + &mut self.inner + } +} + +impl ::core::default::Default for IsaacArray where T: Copy + Default { + fn default() -> IsaacArray { + IsaacArray { inner: [T::default(); RAND_SIZE] } + } +} + + +#[cfg(feature="serde1")] +pub(super) mod isaac_array_serde { + const RAND_SIZE_LEN: usize = 8; + const RAND_SIZE: usize = 1 << RAND_SIZE_LEN; + + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + use serde::de::{Visitor,SeqAccess}; + use serde::de; + + use core::fmt; + + pub fn serialize(arr: &[T;RAND_SIZE], ser: S) -> Result + where + T: Serialize, + S: Serializer + { + use serde::ser::SerializeTuple; + + let mut seq = ser.serialize_tuple(RAND_SIZE)?; + + for e in arr.iter() { + seq.serialize_element(&e)?; + } + + seq.end() + } + + #[inline] + pub fn deserialize<'de, T, D>(de: D) -> Result<[T;RAND_SIZE], D::Error> + where + T: Deserialize<'de>+Default+Copy, + D: Deserializer<'de>, + { + use core::marker::PhantomData; + struct ArrayVisitor { + _pd: PhantomData, + }; + impl<'de,T> Visitor<'de> for ArrayVisitor + where + T: Deserialize<'de>+Default+Copy + { + type Value = [T; RAND_SIZE]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Isaac state array") + } + + #[inline] + fn visit_seq(self, mut seq: A) -> Result<[T; RAND_SIZE], A::Error> + where + A: SeqAccess<'de>, + { + let mut out = [Default::default();RAND_SIZE]; + + for i in 0..RAND_SIZE { + match seq.next_element()? { + Some(val) => out[i] = val, + None => return Err(de::Error::invalid_length(i, &self)), + }; + } + + Ok(out) + } + } + + de.deserialize_tuple(RAND_SIZE, ArrayVisitor{_pd: PhantomData}) + } +} diff --git a/third_party/rust/rand_isaac/src/lib.rs b/third_party/rust/rand_isaac/src/lib.rs new file mode 100644 index 000000000000..ec82d8e7b157 --- /dev/null +++ b/third_party/rust/rand_isaac/src/lib.rs @@ -0,0 +1,36 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The ISAAC and ISAAC-64 random number generators. + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://rust-random.github.io/rand/")] + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +#![cfg_attr(not(all(feature="serde1", test)), no_std)] + +extern crate rand_core; + +#[cfg(feature="serde1")] extern crate serde; +#[cfg(feature="serde1")] #[macro_use] extern crate serde_derive; + +// To test serialization we need bincode and the standard library +#[cfg(all(feature="serde1", test))] extern crate bincode; +#[cfg(all(feature="serde1", test))] extern crate std as core; + +pub mod isaac; +pub mod isaac64; + +mod isaac_array; + +pub use self::isaac::IsaacRng; +pub use self::isaac64::Isaac64Rng; diff --git a/third_party/rust/rand_jitter/.cargo-checksum.json b/third_party/rust/rand_jitter/.cargo-checksum.json new file mode 100644 index 000000000000..bf963361250a --- /dev/null +++ b/third_party/rust/rand_jitter/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"dd1714225c7cca47c349ddbca2b5ab8a546e0c7b1c52cf05cafca1e05c48f2b0","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.toml":"d524ddfe62a9ca58ff86d9ad37532081bae35bfcca2a1e68ca0ffaf0e981d477","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"7b685b3204fc1bb9a09b40eb586bf55358f076b276866c1c2afb20f57e8357b2","benches/mod.rs":"caea9aa8c327d4af18eeabe798cf7919d5f64225c3e5f4685814592a1595b9bf","src/dummy_log.rs":"4e26589c18de568b7da7f0ccc9b77bb430961739a6510c2b043a43dee300c6fa","src/error.rs":"e632a67e30528bed8c2a74b04b04e4e67f6c184d21234d74cc28f5f292e47666","src/lib.rs":"6655eb8d1fba653dda788c885ae380b017e6482baa6e2885019d33dbd829b0e6","src/platform.rs":"8c7b75567a28391176de17a3df2a8c6b3517f2c1f044b792db50de19844e9660","tests/mod.rs":"f3f99c64b250b2ddea43e724c47497de3d68cbaf05a0a8a255d360861cd979ec"},"package":"1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"} \ No newline at end of file diff --git a/third_party/rust/rand_jitter/CHANGELOG.md b/third_party/rust/rand_jitter/CHANGELOG.md new file mode 100644 index 000000000000..bbb21dcbf2f8 --- /dev/null +++ b/third_party/rust/rand_jitter/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.1.4] - 2019-05-02 +- Change error conversion code to partially fix #738 + +## [0.1.3] - 2019-02-05 +- Use libc in `no_std` mode to fix #723 + +## [0.1.2] - 2019-01-31 +- Fix for older rustc compilers on Windows (#722) + +## [0.1.1] - 2019-01-29 +- Fix for older rustc compilers on Mac OSX / iOS (#720) +- Misc. doc fixes + +## [0.1.0] - 2019-01-24 +Initial release. diff --git a/third_party/rust/rand_jitter/COPYRIGHT b/third_party/rust/rand_jitter/COPYRIGHT new file mode 100644 index 000000000000..468d907caf99 --- /dev/null +++ b/third_party/rust/rand_jitter/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 or + or the MIT license + or , at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/third_party/rust/rand_jitter/Cargo.toml b/third_party/rust/rand_jitter/Cargo.toml new file mode 100644 index 000000000000..387b8073ff4f --- /dev/null +++ b/third_party/rust/rand_jitter/Cargo.toml @@ -0,0 +1,42 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand_jitter" +version = "0.1.4" +authors = ["The Rand Project Developers"] +description = "Random number generator based on timing jitter" +documentation = "https://docs.rs/rand_jitter" +readme = "README.md" +keywords = ["random", "rng", "os"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-random/rand" +[dependencies.log] +version = "0.4" +optional = true + +[dependencies.rand_core] +version = "0.4" + +[features] +std = ["rand_core/std"] +[target."cfg(any(target_os = \"macos\", target_os = \"ios\"))".dependencies.libc] +version = "0.2" +default_features = false +[target."cfg(target_os = \"windows\")".dependencies.winapi] +version = "0.3" +features = ["profileapi"] +[badges.appveyor] +repository = "rust-random/rand" + +[badges.travis-ci] +repository = "rust-random/rand" diff --git a/third_party/rust/rand_jitter/LICENSE-APACHE b/third_party/rust/rand_jitter/LICENSE-APACHE new file mode 100644 index 000000000000..17d74680f8cf --- /dev/null +++ b/third_party/rust/rand_jitter/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/rand_jitter/LICENSE-MIT b/third_party/rust/rand_jitter/LICENSE-MIT new file mode 100644 index 000000000000..d93b5baf341d --- /dev/null +++ b/third_party/rust/rand_jitter/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright 2018 Developers of the Rand project +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/rand_jitter/README.md b/third_party/rust/rand_jitter/README.md new file mode 100644 index 000000000000..8e0805faeb7b --- /dev/null +++ b/third_party/rust/rand_jitter/README.md @@ -0,0 +1,104 @@ +# rand_jitter +[![Build Status](https://travis-ci.org/rust-random/rand.svg?branch=master)](https://travis-ci.org/rust-random/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Latest version](https://img.shields.io/crates/v/rand_jitter.svg)](https://crates.io/crates/rand_jitter) +[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) +[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_jitter) +[![API](https://docs.rs/rand_jitter/badge.svg)](https://docs.rs/rand_jitter) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.32+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) + +Non-physical true random number generator based on timing jitter. + +This crate depends on [rand_core](https://crates.io/crates/rand_core) and is +part of the [Rand project](https://github.com/rust-random/rand). + +This crate aims to support all of Rust's `std` platforms with a system-provided +entropy source. Unlike other Rand crates, this crate does not support `no_std` +(handling this gracefully is a current discussion topic). + +Links: + +- [API documentation (master)](https://rust-random.github.io/rand/rand_jitter) +- [API documentation (docs.rs)](https://docs.rs/rand_jitter) +- [Changelog](CHANGELOG.md) + +## Features + +This crate has optional `std` support which is *disabled by default*; +this feature is required to provide the `JitterRng::new` function; +without `std` support a timer must be supplied via `JitterRng::new_with_timer`. + +## Quality testing + +`JitterRng::new()` has build-in, but limited, quality testing, however +before using `JitterRng` on untested hardware, or after changes that could +effect how the code is optimized (such as a new LLVM version), it is +recommend to run the much more stringent +[NIST SP 800-90B Entropy Estimation Suite](https://github.com/usnistgov/SP800-90B_EntropyAssessment). + +Use the following code using `timer_stats` to collect the data: + +```rust +use rand_jitter::JitterRng; + +use std::error::Error; +use std::fs::File; +use std::io::Write; + +fn main() -> Result<(), Box> { + let mut rng = JitterRng::new()?; + + // 1_000_000 results are required for the + // NIST SP 800-90B Entropy Estimation Suite + const ROUNDS: usize = 1_000_000; + let mut deltas_variable: Vec = Vec::with_capacity(ROUNDS); + let mut deltas_minimal: Vec = Vec::with_capacity(ROUNDS); + + for _ in 0..ROUNDS { + deltas_variable.push(rng.timer_stats(true) as u8); + deltas_minimal.push(rng.timer_stats(false) as u8); + } + + // Write out after the statistics collection loop, to not disturb the + // test results. + File::create("jitter_rng_var.bin")?.write(&deltas_variable)?; + File::create("jitter_rng_min.bin")?.write(&deltas_minimal)?; + Ok(()) +} +``` + +This will produce two files: `jitter_rng_var.bin` and `jitter_rng_min.bin`. +Run the Entropy Estimation Suite in three configurations, as outlined below. +Every run has two steps. One step to produce an estimation, another to +validate the estimation. + +1. Estimate the expected amount of entropy that is at least available with + each round of the entropy collector. This number should be greater than + the amount estimated with `64 / test_timer()`. + ```sh + python noniid_main.py -v jitter_rng_var.bin 8 + restart.py -v jitter_rng_var.bin 8 + ``` +2. Estimate the expected amount of entropy that is available in the last 4 + bits of the timer delta after running noice sources. Note that a value of + `3.70` is the minimum estimated entropy for true randomness. + ```sh + python noniid_main.py -v -u 4 jitter_rng_var.bin 4 + restart.py -v -u 4 jitter_rng_var.bin 4 + ``` +3. Estimate the expected amount of entropy that is available to the entropy + collector if both noise sources only run their minimal number of times. + This measures the absolute worst-case, and gives a lower bound for the + available entropy. + ```sh + python noniid_main.py -v -u 4 jitter_rng_min.bin 4 + restart.py -v -u 4 jitter_rng_min.bin 4 + ``` + +## License + +`rand_jitter` is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/third_party/rust/rand_jitter/benches/mod.rs b/third_party/rust/rand_jitter/benches/mod.rs new file mode 100644 index 000000000000..23b34472bdc4 --- /dev/null +++ b/third_party/rust/rand_jitter/benches/mod.rs @@ -0,0 +1,18 @@ +#![feature(test)] +extern crate test; +extern crate rand_jitter; + +use test::Bencher; +use rand_jitter::rand_core::RngCore; + +#[bench] +fn bench_add_two(b: &mut Bencher) { + let mut rng = rand_jitter::JitterRng::new().unwrap(); + let mut buf = [0u8; 1024]; + b.iter(|| { + rng.fill_bytes(&mut buf[..]); + test::black_box(&buf); + }); + b.bytes = buf.len() as u64; +} + diff --git a/third_party/rust/rand_jitter/src/dummy_log.rs b/third_party/rust/rand_jitter/src/dummy_log.rs new file mode 100644 index 000000000000..ccfe4baeff20 --- /dev/null +++ b/third_party/rust/rand_jitter/src/dummy_log.rs @@ -0,0 +1,10 @@ +#[allow(unused)] +macro_rules! trace { ($($x:tt)*) => () } +#[allow(unused)] +macro_rules! debug { ($($x:tt)*) => () } +#[allow(unused)] +macro_rules! info { ($($x:tt)*) => () } +#[allow(unused)] +macro_rules! warn { ($($x:tt)*) => () } +#[allow(unused)] +macro_rules! error { ($($x:tt)*) => () } diff --git a/third_party/rust/rand_jitter/src/error.rs b/third_party/rust/rand_jitter/src/error.rs new file mode 100644 index 000000000000..a3483e84d0fc --- /dev/null +++ b/third_party/rust/rand_jitter/src/error.rs @@ -0,0 +1,70 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013-2015 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rand_core::{Error, ErrorKind}; +use core::fmt; + +/// An error that can occur when [`JitterRng::test_timer`] fails. +/// +/// [`JitterRng::test_timer`]: crate::JitterRng::test_timer +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum TimerError { + /// No timer available. + NoTimer, + /// Timer too coarse to use as an entropy source. + CoarseTimer, + /// Timer is not monotonically increasing. + NotMonotonic, + /// Variations of deltas of time too small. + TinyVariantions, + /// Too many stuck results (indicating no added entropy). + TooManyStuck, + #[doc(hidden)] + __Nonexhaustive, +} + +impl TimerError { + fn description(&self) -> &'static str { + match *self { + TimerError::NoTimer => "no timer available", + TimerError::CoarseTimer => "coarse timer", + TimerError::NotMonotonic => "timer not monotonic", + TimerError::TinyVariantions => "time delta variations too small", + TimerError::TooManyStuck => "too many stuck results", + TimerError::__Nonexhaustive => unreachable!(), + } + } +} + +impl fmt::Display for TimerError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + +#[cfg(feature = "std")] +impl ::std::error::Error for TimerError { + fn description(&self) -> &str { + self.description() + } +} + +impl From for Error { + fn from(err: TimerError) -> Error { + // Timer check is already quite permissive of failures so we don't + // expect false-positive failures, i.e. any error is irrecoverable. + #[cfg(feature = "std")] { + Error::with_cause(ErrorKind::Unavailable, "timer jitter failed basic quality tests", err) + } + #[cfg(not(feature = "std"))] { + Error::new(ErrorKind::Unavailable, "timer jitter failed basic quality tests") + } + } +} + diff --git a/third_party/rust/rand_jitter/src/lib.rs b/third_party/rust/rand_jitter/src/lib.rs new file mode 100644 index 000000000000..338a6b966a17 --- /dev/null +++ b/third_party/rust/rand_jitter/src/lib.rs @@ -0,0 +1,718 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// Based on jitterentropy-library, http://www.chronox.de/jent.html. +// Copyright Stephan Mueller , 2014 - 2017. +// +// With permission from Stephan Mueller to relicense the Rust translation under +// the MIT license. + +//! Non-physical true random number generator based on timing jitter. +//! +//! This is a true random number generator, as opposed to pseudo-random +//! generators. Random numbers generated by `JitterRng` can be seen as fresh +//! entropy. A consequence is that it is orders of magnitude slower than `OsRng` +//! and PRNGs (about 103..106 slower). +//! +//! There are very few situations where using this RNG is appropriate. Only very +//! few applications require true entropy. A normal PRNG can be statistically +//! indistinguishable, and a cryptographic PRNG should also be as impossible to +//! predict. +//! +//! Use of `JitterRng` is recommended for initializing cryptographic PRNGs when +//! `OsRng` is not available. +//! +//! `JitterRng` can be used without the standard library, but not conveniently, +//! you must provide a high-precision timer and carefully have to follow the +//! instructions of [`JitterRng::new_with_timer`]. +//! +//! This implementation is based on [Jitterentropy] version 2.1.0. +//! +//! Note: There is no accurate timer available on WASM platforms, to help +//! prevent fingerprinting or timing side-channel attacks. Therefore +//! [`JitterRng::new()`] is not available on WASM. It is also unavailable +//! with disabled `std` feature. +//! +//! [Jitterentropy]: http://www.chronox.de/jent.html + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://rust-random.github.io/rand/")] + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +// Note: the C implementation of `Jitterentropy` relies on being compiled +// without optimizations. This implementation goes through lengths to make the +// compiler not optimize out code which does influence timing jitter, but is +// technically dead code. +#![no_std] +pub extern crate rand_core; +#[cfg(feature = "std")] +extern crate std; +#[cfg(feature = "log")] +#[macro_use] extern crate log; +#[cfg(any(target_os = "macos", target_os = "ios"))] +extern crate libc; +#[cfg(target_os = "windows")] +extern crate winapi; + + +#[cfg(not(feature = "log"))] +#[macro_use] mod dummy_log; +#[cfg(feature = "std")] +mod platform; +mod error; + +use rand_core::{RngCore, CryptoRng, Error, impls}; +pub use error::TimerError; + +use core::{fmt, mem, ptr}; +#[cfg(feature = "std")] +use std::sync::atomic::{AtomicUsize, Ordering}; +#[cfg(feature = "std")] +#[allow(deprecated)] // Required for compatibility with Rust < 1.24. +use std::sync::atomic::ATOMIC_USIZE_INIT; + +const MEMORY_BLOCKS: usize = 64; +const MEMORY_BLOCKSIZE: usize = 32; +const MEMORY_SIZE: usize = MEMORY_BLOCKS * MEMORY_BLOCKSIZE; + +/// A true random number generator based on jitter in the CPU execution time, +/// and jitter in memory access time. +pub struct JitterRng { + data: u64, // Actual random number + // Number of rounds to run the entropy collector per 64 bits + rounds: u8, + // Timer used by `measure_jitter` + timer: fn() -> u64, + // Memory for the Memory Access noise source + mem_prev_index: u16, + // Make `next_u32` not waste 32 bits + data_half_used: bool, +} + +// Note: `JitterRng` maintains a small 64-bit entropy pool. With every +// `generate` 64 new bits should be integrated in the pool. If a round of +// `generate` were to collect less than the expected 64 bit, then the returned +// value, and the new state of the entropy pool, would be in some way related to +// the initial state. It is therefore better if the initial state of the entropy +// pool is different on each call to `generate`. This has a few implications: +// - `generate` should be called once before using `JitterRng` to produce the +// first usable value (this is done by default in `new`); +// - We do not zero the entropy pool after generating a result. The reference +// implementation also does not support zeroing, but recommends generating a +// new value without using it if you want to protect a previously generated +// 'secret' value from someone inspecting the memory; +// - Implementing `Clone` seems acceptable, as it would not cause the systematic +// bias a constant might cause. Only instead of one value that could be +// potentially related to the same initial state, there are now two. + +// Entropy collector state. +// These values are not necessary to preserve across runs. +struct EcState { + // Previous time stamp to determine the timer delta + prev_time: u64, + // Deltas used for the stuck test + last_delta: i32, + last_delta2: i32, + // Memory for the Memory Access noise source + mem: [u8; MEMORY_SIZE], +} + +impl EcState { + // Stuck test by checking the: + // - 1st derivation of the jitter measurement (time delta) + // - 2nd derivation of the jitter measurement (delta of time deltas) + // - 3rd derivation of the jitter measurement (delta of delta of time + // deltas) + // + // All values must always be non-zero. + // This test is a heuristic to see whether the last measurement holds + // entropy. + fn stuck(&mut self, current_delta: i32) -> bool { + let delta2 = self.last_delta - current_delta; + let delta3 = delta2 - self.last_delta2; + + self.last_delta = current_delta; + self.last_delta2 = delta2; + + current_delta == 0 || delta2 == 0 || delta3 == 0 + } +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for JitterRng { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "JitterRng {{}}") + } +} + +impl Clone for JitterRng { + fn clone(&self) -> JitterRng { + JitterRng { + data: self.data, + rounds: self.rounds, + timer: self.timer, + mem_prev_index: self.mem_prev_index, + // The 32 bits that may still be unused from the previous round are + // for the original to use, not for the clone. + data_half_used: false, + } + } +} + +// Initialise to zero; must be positive +#[cfg(all(feature = "std", not(target_arch = "wasm32")))] +#[allow(deprecated)] +static JITTER_ROUNDS: AtomicUsize = ATOMIC_USIZE_INIT; + +impl JitterRng { + /// Create a new `JitterRng`. Makes use of `std::time` for a timer, or a + /// platform-specific function with higher accuracy if necessary and + /// available. + /// + /// During initialization CPU execution timing jitter is measured a few + /// hundred times. If this does not pass basic quality tests, an error is + /// returned. The test result is cached to make subsequent calls faster. + #[cfg(all(feature = "std", not(target_arch = "wasm32")))] + pub fn new() -> Result { + if cfg!(target_arch = "wasm32") { + return Err(TimerError::NoTimer); + } + let mut state = JitterRng::new_with_timer(platform::get_nstime); + let mut rounds = JITTER_ROUNDS.load(Ordering::Relaxed) as u8; + if rounds == 0 { + // No result yet: run test. + // This allows the timer test to run multiple times; we don't care. + rounds = state.test_timer()?; + JITTER_ROUNDS.store(rounds as usize, Ordering::Relaxed); + info!("JitterRng: using {} rounds per u64 output", rounds); + } + state.set_rounds(rounds); + + // Fill `data` with a non-zero value. + state.gen_entropy(); + Ok(state) + } + + /// Create a new `JitterRng`. + /// A custom timer can be supplied, making it possible to use `JitterRng` in + /// `no_std` environments. + /// + /// The timer must have nanosecond precision. + /// + /// This method is more low-level than `new()`. It is the responsibility of + /// the caller to run [`test_timer`] before using any numbers generated with + /// `JitterRng`, and optionally call [`set_rounds`]. Also it is important to + /// consume at least one `u64` before using the first result to initialize + /// the entropy collection pool. + /// + /// # Example + /// + /// ``` + /// # use rand_jitter::rand_core::{RngCore, Error}; + /// use rand_jitter::JitterRng; + /// + /// # fn try_inner() -> Result<(), Error> { + /// fn get_nstime() -> u64 { + /// use std::time::{SystemTime, UNIX_EPOCH}; + /// + /// let dur = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + /// // The correct way to calculate the current time is + /// // `dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64` + /// // But this is faster, and the difference in terms of entropy is + /// // negligible (log2(10^9) == 29.9). + /// dur.as_secs() << 30 | dur.subsec_nanos() as u64 + /// } + /// + /// let mut rng = JitterRng::new_with_timer(get_nstime); + /// let rounds = rng.test_timer()?; + /// rng.set_rounds(rounds); // optional + /// let _ = rng.next_u64(); + /// + /// // Ready for use + /// let v: u64 = rng.next_u64(); + /// # Ok(()) + /// # } + /// + /// # let _ = try_inner(); + /// ``` + /// + /// [`test_timer`]: JitterRng::test_timer + /// [`set_rounds`]: JitterRng::set_rounds + pub fn new_with_timer(timer: fn() -> u64) -> JitterRng { + JitterRng { + data: 0, + rounds: 64, + timer, + mem_prev_index: 0, + data_half_used: false, + } + } + + /// Configures how many rounds are used to generate each 64-bit value. + /// This must be greater than zero, and has a big impact on performance + /// and output quality. + /// + /// [`new_with_timer`] conservatively uses 64 rounds, but often less rounds + /// can be used. The `test_timer()` function returns the minimum number of + /// rounds required for full strength (platform dependent), so one may use + /// `rng.set_rounds(rng.test_timer()?);` or cache the value. + /// + /// [`new_with_timer`]: JitterRng::new_with_timer + pub fn set_rounds(&mut self, rounds: u8) { + assert!(rounds > 0); + self.rounds = rounds; + } + + // Calculate a random loop count used for the next round of an entropy + // collection, based on bits from a fresh value from the timer. + // + // The timer is folded to produce a number that contains at most `n_bits` + // bits. + // + // Note: A constant should be added to the resulting random loop count to + // prevent loops that run 0 times. + #[inline(never)] + fn random_loop_cnt(&mut self, n_bits: u32) -> u32 { + let mut rounds = 0; + + let mut time = (self.timer)(); + // Mix with the current state of the random number balance the random + // loop counter a bit more. + time ^= self.data; + + // We fold the time value as much as possible to ensure that as many + // bits of the time stamp are included as possible. + let folds = (64 + n_bits - 1) / n_bits; + let mask = (1 << n_bits) - 1; + for _ in 0..folds { + rounds ^= time & mask; + time >>= n_bits; + } + + rounds as u32 + } + + // CPU jitter noise source + // Noise source based on the CPU execution time jitter + // + // This function injects the individual bits of the time value into the + // entropy pool using an LFSR. + // + // The code is deliberately inefficient with respect to the bit shifting. + // This function not only acts as folding operation, but this function's + // execution is used to measure the CPU execution time jitter. Any change to + // the loop in this function implies that careful retesting must be done. + #[inline(never)] + fn lfsr_time(&mut self, time: u64, var_rounds: bool) { + fn lfsr(mut data: u64, time: u64) -> u64{ + for i in 1..65 { + let mut tmp = time << (64 - i); + tmp >>= 64 - 1; + + // Fibonacci LSFR with polynomial of + // x^64 + x^61 + x^56 + x^31 + x^28 + x^23 + 1 which is + // primitive according to + // http://poincare.matf.bg.ac.rs/~ezivkovm/publications/primpol1.pdf + // (the shift values are the polynomial values minus one + // due to counting bits from 0 to 63). As the current + // position is always the LSB, the polynomial only needs + // to shift data in from the left without wrap. + data ^= tmp; + data ^= (data >> 63) & 1; + data ^= (data >> 60) & 1; + data ^= (data >> 55) & 1; + data ^= (data >> 30) & 1; + data ^= (data >> 27) & 1; + data ^= (data >> 22) & 1; + data = data.rotate_left(1); + } + data + } + + // Note: in the reference implementation only the last round effects + // `self.data`, all the other results are ignored. To make sure the + // other rounds are not optimised out, we first run all but the last + // round on a throw-away value instead of the real `self.data`. + let mut lfsr_loop_cnt = 0; + if var_rounds { lfsr_loop_cnt = self.random_loop_cnt(4) }; + + let mut throw_away: u64 = 0; + for _ in 0..lfsr_loop_cnt { + throw_away = lfsr(throw_away, time); + } + black_box(throw_away); + + self.data = lfsr(self.data, time); + } + + // Memory Access noise source + // This is a noise source based on variations in memory access times + // + // This function performs memory accesses which will add to the timing + // variations due to an unknown amount of CPU wait states that need to be + // added when accessing memory. The memory size should be larger than the L1 + // caches as outlined in the documentation and the associated testing. + // + // The L1 cache has a very high bandwidth, albeit its access rate is usually + // slower than accessing CPU registers. Therefore, L1 accesses only add + // minimal variations as the CPU has hardly to wait. Starting with L2, + // significant variations are added because L2 typically does not belong to + // the CPU any more and therefore a wider range of CPU wait states is + // necessary for accesses. L3 and real memory accesses have even a wider + // range of wait states. However, to reliably access either L3 or memory, + // the `self.mem` memory must be quite large which is usually not desirable. + #[inline(never)] + fn memaccess(&mut self, mem: &mut [u8; MEMORY_SIZE], var_rounds: bool) { + let mut acc_loop_cnt = 128; + if var_rounds { acc_loop_cnt += self.random_loop_cnt(4) }; + + let mut index = self.mem_prev_index as usize; + for _ in 0..acc_loop_cnt { + // Addition of memblocksize - 1 to index with wrap around logic to + // ensure that every memory location is hit evenly. + // The modulus also allows the compiler to remove the indexing + // bounds check. + index = (index + MEMORY_BLOCKSIZE - 1) % MEMORY_SIZE; + + // memory access: just add 1 to one byte + // memory access implies read from and write to memory location + mem[index] = mem[index].wrapping_add(1); + } + self.mem_prev_index = index as u16; + } + + // This is the heart of the entropy generation: calculate time deltas and + // use the CPU jitter in the time deltas. The jitter is injected into the + // entropy pool. + // + // Ensure that `ec.prev_time` is primed before using the output of this + // function. This can be done by calling this function and not using its + // result. + fn measure_jitter(&mut self, ec: &mut EcState) -> Option<()> { + // Invoke one noise source before time measurement to add variations + self.memaccess(&mut ec.mem, true); + + // Get time stamp and calculate time delta to previous + // invocation to measure the timing variations + let time = (self.timer)(); + // Note: wrapping_sub combined with a cast to `i64` generates a correct + // delta, even in the unlikely case this is a timer that is not strictly + // monotonic. + let current_delta = time.wrapping_sub(ec.prev_time) as i64 as i32; + ec.prev_time = time; + + // Call the next noise source which also injects the data + self.lfsr_time(current_delta as u64, true); + + // Check whether we have a stuck measurement (i.e. does the last + // measurement holds entropy?). + if ec.stuck(current_delta) { return None }; + + // Rotate the data buffer by a prime number (any odd number would + // do) to ensure that every bit position of the input time stamp + // has an even chance of being merged with a bit position in the + // entropy pool. We do not use one here as the adjacent bits in + // successive time deltas may have some form of dependency. The + // chosen value of 7 implies that the low 7 bits of the next + // time delta value is concatenated with the current time delta. + self.data = self.data.rotate_left(7); + + Some(()) + } + + // Shuffle the pool a bit by mixing some value with a bijective function + // (XOR) into the pool. + // + // The function generates a mixer value that depends on the bits set and + // the location of the set bits in the random number generated by the + // entropy source. Therefore, based on the generated random number, this + // mixer value can have 2^64 different values. That mixer value is + // initialized with the first two SHA-1 constants. After obtaining the + // mixer value, it is XORed into the random number. + // + // The mixer value is not assumed to contain any entropy. But due to the + // XOR operation, it can also not destroy any entropy present in the + // entropy pool. + #[inline(never)] + fn stir_pool(&mut self) { + // This constant is derived from the first two 32 bit initialization + // vectors of SHA-1 as defined in FIPS 180-4 section 5.3.1 + // The order does not really matter as we do not rely on the specific + // numbers. We just pick the SHA-1 constants as they have a good mix of + // bit set and unset. + const CONSTANT: u64 = 0x67452301efcdab89; + + // The start value of the mixer variable is derived from the third + // and fourth 32 bit initialization vector of SHA-1 as defined in + // FIPS 180-4 section 5.3.1 + let mut mixer = 0x98badcfe10325476; + + // This is a constant time function to prevent leaking timing + // information about the random number. + // The normal code is: + // ``` + // for i in 0..64 { + // if ((self.data >> i) & 1) == 1 { mixer ^= CONSTANT; } + // } + // ``` + // This is a bit fragile, as LLVM really wants to use branches here, and + // we rely on it to not recognise the opportunity. + for i in 0..64 { + let apply = (self.data >> i) & 1; + let mask = !apply.wrapping_sub(1); + mixer ^= CONSTANT & mask; + mixer = mixer.rotate_left(1); + } + + self.data ^= mixer; + } + + fn gen_entropy(&mut self) -> u64 { + trace!("JitterRng: collecting entropy"); + + // Prime `ec.prev_time`, and run the noice sources to make sure the + // first loop round collects the expected entropy. + let mut ec = EcState { + prev_time: (self.timer)(), + last_delta: 0, + last_delta2: 0, + mem: [0; MEMORY_SIZE], + }; + let _ = self.measure_jitter(&mut ec); + + for _ in 0..self.rounds { + // If a stuck measurement is received, repeat measurement + // Note: we do not guard against an infinite loop, that would mean + // the timer suddenly became broken. + while self.measure_jitter(&mut ec).is_none() {} + } + + // Do a single read from `self.mem` to make sure the Memory Access noise + // source is not optimised out. + black_box(ec.mem[0]); + + self.stir_pool(); + self.data + } + + /// Basic quality tests on the timer, by measuring CPU timing jitter a few + /// hundred times. + /// + /// If successful, this will return the estimated number of rounds necessary + /// to collect 64 bits of entropy. Otherwise a [`TimerError`] with the cause + /// of the failure will be returned. + pub fn test_timer(&mut self) -> Result { + debug!("JitterRng: testing timer ..."); + // We could add a check for system capabilities such as `clock_getres` + // or check for `CONFIG_X86_TSC`, but it does not make much sense as the + // following sanity checks verify that we have a high-resolution timer. + + let mut delta_sum = 0; + let mut old_delta = 0; + + let mut time_backwards = 0; + let mut count_mod = 0; + let mut count_stuck = 0; + + let mut ec = EcState { + prev_time: (self.timer)(), + last_delta: 0, + last_delta2: 0, + mem: [0; MEMORY_SIZE], + }; + + // TESTLOOPCOUNT needs some loops to identify edge systems. + // 100 is definitely too little. + const TESTLOOPCOUNT: u64 = 300; + const CLEARCACHE: u64 = 100; + + for i in 0..(CLEARCACHE + TESTLOOPCOUNT) { + // Measure time delta of core entropy collection logic + let time = (self.timer)(); + self.memaccess(&mut ec.mem, true); + self.lfsr_time(time, true); + let time2 = (self.timer)(); + + // Test whether timer works + if time == 0 || time2 == 0 { + return Err(TimerError::NoTimer); + } + let delta = time2.wrapping_sub(time) as i64 as i32; + + // Test whether timer is fine grained enough to provide delta even + // when called shortly after each other -- this implies that we also + // have a high resolution timer + if delta == 0 { + return Err(TimerError::CoarseTimer); + } + + // Up to here we did not modify any variable that will be + // evaluated later, but we already performed some work. Thus we + // already have had an impact on the caches, branch prediction, + // etc. with the goal to clear it to get the worst case + // measurements. + if i < CLEARCACHE { continue; } + + if ec.stuck(delta) { count_stuck += 1; } + + // Test whether we have an increasing timer. + if !(time2 > time) { time_backwards += 1; } + + // Count the number of times the counter increases in steps of 100ns + // or greater. + if (delta % 100) == 0 { count_mod += 1; } + + // Ensure that we have a varying delta timer which is necessary for + // the calculation of entropy -- perform this check only after the + // first loop is executed as we need to prime the old_delta value + delta_sum += (delta - old_delta).abs() as u64; + old_delta = delta; + } + + // Do a single read from `self.mem` to make sure the Memory Access noise + // source is not optimised out. + black_box(ec.mem[0]); + + // We allow the time to run backwards for up to three times. + // This can happen if the clock is being adjusted by NTP operations. + // If such an operation just happens to interfere with our test, it + // should not fail. The value of 3 should cover the NTP case being + // performed during our test run. + if time_backwards > 3 { + return Err(TimerError::NotMonotonic); + } + + // Test that the available amount of entropy per round does not get to + // low. We expect 1 bit of entropy per round as a reasonable minimum + // (although less is possible, it means the collector loop has to run + // much more often). + // `assert!(delta_average >= log2(1))` + // `assert!(delta_sum / TESTLOOPCOUNT >= 1)` + // `assert!(delta_sum >= TESTLOOPCOUNT)` + if delta_sum < TESTLOOPCOUNT { + return Err(TimerError::TinyVariantions); + } + + // Ensure that we have variations in the time stamp below 100 for at + // least 10% of all checks -- on some platforms, the counter increments + // in multiples of 100, but not always + if count_mod > (TESTLOOPCOUNT * 9 / 10) { + return Err(TimerError::CoarseTimer); + } + + // If we have more than 90% stuck results, then this Jitter RNG is + // likely to not work well. + if count_stuck > (TESTLOOPCOUNT * 9 / 10) { + return Err(TimerError::TooManyStuck); + } + + // Estimate the number of `measure_jitter` rounds necessary for 64 bits + // of entropy. + // + // We don't try very hard to come up with a good estimate of the + // available bits of entropy per round here for two reasons: + // 1. Simple estimates of the available bits (like Shannon entropy) are + // too optimistic. + // 2. Unless we want to waste a lot of time during intialization, there + // only a small number of samples are available. + // + // Therefore we use a very simple and conservative estimate: + // `let bits_of_entropy = log2(delta_average) / 2`. + // + // The number of rounds `measure_jitter` should run to collect 64 bits + // of entropy is `64 / bits_of_entropy`. + let delta_average = delta_sum / TESTLOOPCOUNT; + + if delta_average >= 16 { + let log2 = 64 - delta_average.leading_zeros(); + // Do something similar to roundup(64/(log2/2)): + Ok( ((64u32 * 2 + log2 - 1) / log2) as u8) + } else { + // For values < 16 the rounding error becomes too large, use a + // lookup table. + // Values 0 and 1 are invalid, and filtered out by the + // `delta_sum < TESTLOOPCOUNT` test above. + let log2_lookup = [0, 0, 128, 81, 64, 56, 50, 46, + 43, 41, 39, 38, 36, 35, 34, 33]; + Ok(log2_lookup[delta_average as usize]) + } + } + + /// Statistical test: return the timer delta of one normal run of the + /// `JitterRng` entropy collector. + /// + /// Setting `var_rounds` to `true` will execute the memory access and the + /// CPU jitter noice sources a variable amount of times (just like a real + /// `JitterRng` round). + /// + /// Setting `var_rounds` to `false` will execute the noice sources the + /// minimal number of times. This can be used to measure the minimum amount + /// of entropy one round of the entropy collector can collect in the worst + /// case. + /// + /// See this crate's README on how to use `timer_stats` to test the quality + /// of `JitterRng`. + pub fn timer_stats(&mut self, var_rounds: bool) -> i64 { + let mut mem = [0; MEMORY_SIZE]; + + let time = (self.timer)(); + self.memaccess(&mut mem, var_rounds); + self.lfsr_time(time, var_rounds); + let time2 = (self.timer)(); + time2.wrapping_sub(time) as i64 + } +} + +// A function that is opaque to the optimizer to assist in avoiding dead-code +// elimination. Taken from `bencher`. +fn black_box(dummy: T) -> T { + unsafe { + let ret = ptr::read_volatile(&dummy); + mem::forget(dummy); + ret + } +} + +impl RngCore for JitterRng { + fn next_u32(&mut self) -> u32 { + // We want to use both parts of the generated entropy + if self.data_half_used { + self.data_half_used = false; + (self.data >> 32) as u32 + } else { + self.data = self.next_u64(); + self.data_half_used = true; + self.data as u32 + } + } + + fn next_u64(&mut self) -> u64 { + self.data_half_used = false; + self.gen_entropy() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + // Fill using `next_u32`. This is faster for filling small slices (four + // bytes or less), while the overhead is negligible. + // + // This is done especially for wrappers that implement `next_u32` + // themselves via `fill_bytes`. + impls::fill_bytes_via_next(self, dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} + +impl CryptoRng for JitterRng {} + diff --git a/third_party/rust/rand_jitter/src/platform.rs b/third_party/rust/rand_jitter/src/platform.rs new file mode 100644 index 000000000000..8e3d0fb22fc9 --- /dev/null +++ b/third_party/rust/rand_jitter/src/platform.rs @@ -0,0 +1,44 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013-2015 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))] +pub fn get_nstime() -> u64 { + use std::time::{SystemTime, UNIX_EPOCH}; + + let dur = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + // The correct way to calculate the current time is + // `dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64` + // But this is faster, and the difference in terms of entropy is + // negligible (log2(10^9) == 29.9). + dur.as_secs() << 30 | dur.subsec_nanos() as u64 +} + +#[cfg(any(target_os = "macos", target_os = "ios"))] +pub fn get_nstime() -> u64 { + use libc; + + // On Mac OS and iOS std::time::SystemTime only has 1000ns resolution. + // We use `mach_absolute_time` instead. This provides a CPU dependent + // unit, to get real nanoseconds the result should by multiplied by + // numer/denom from `mach_timebase_info`. + // But we are not interested in the exact nanoseconds, just entropy. So + // we use the raw result. + unsafe { libc::mach_absolute_time() } +} + +#[cfg(target_os = "windows")] +pub fn get_nstime() -> u64 { + use winapi; + + unsafe { + let mut t = super::mem::zeroed(); + winapi::um::profileapi::QueryPerformanceCounter(&mut t); + *t.QuadPart() as u64 + } +} diff --git a/third_party/rust/rand_jitter/tests/mod.rs b/third_party/rust/rand_jitter/tests/mod.rs new file mode 100644 index 000000000000..6820c2080a5b --- /dev/null +++ b/third_party/rust/rand_jitter/tests/mod.rs @@ -0,0 +1,31 @@ +extern crate rand_jitter; +extern crate rand_core; + +use rand_jitter::JitterRng; +#[cfg(feature = "std")] +use rand_core::RngCore; + +#[cfg(feature = "std")] +#[test] +fn test_jitter_init() { + // Because this is a debug build, measurements here are not representive + // of the final release build. + // Don't fail this test if initializing `JitterRng` fails because of a + // bad timer (the timer from the standard library may not have enough + // accuracy on all platforms). + match JitterRng::new() { + Ok(ref mut rng) => { + // false positives are possible, but extremely unlikely + assert!(rng.next_u32() | rng.next_u32() != 0); + }, + Err(_) => {}, + } +} + +#[test] +fn test_jitter_bad_timer() { + fn bad_timer() -> u64 { 0 } + let mut rng = JitterRng::new_with_timer(bad_timer); + assert!(rng.test_timer().is_err()); +} + diff --git a/third_party/rust/rand_os/.cargo-checksum.json b/third_party/rust/rand_os/.cargo-checksum.json new file mode 100644 index 000000000000..6adb38d128bd --- /dev/null +++ b/third_party/rust/rand_os/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"b109ac9f2501be2151402585c5278ba9db30d1b880139f0f67aadcd7a9f85506","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.toml":"cb81ac6d2ae3ccec84cb897d1c2c4fe53986065424b46fea3ca4e15bca47db05","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"91ccce04b8ea75d26b78f155b578b92be283b2e740d94192ade9eaa3d59c8c27","src/cloudabi.rs":"4f9f9991a1ef7dc330e81ee5208fcc23ad6acc2c73c257b019a3aa488f3a1291","src/dragonfly_haiku_emscripten.rs":"8e693952f38b2576ce7c454cc51d0209917ec40f2a3224ff0f138f798d2c82b3","src/dummy_log.rs":"4e26589c18de568b7da7f0ccc9b77bb430961739a6510c2b043a43dee300c6fa","src/freebsd.rs":"6b1e0a3735d798d8297a9426721e01672424cc289707dae86e336a207cd43436","src/fuchsia.rs":"61159ae3fa469a40214b7ad2f9b0445ed952944c0d5738cd3b7c045eb3e5034a","src/lib.rs":"7d5bd0b5565f7dff4dc352608ab2fb95737dba9b5576fe70b57dcd90e1f11411","src/linux_android.rs":"24b113ef388a2b734ac7a47e045527edac4fe5f29e5ca7948c9a6edf3f69a111","src/macos.rs":"17ccfd5a69068db0580480f680398e20d9ed5219abd726c90e5d9db509539608","src/netbsd.rs":"1b00923bd48673e709cc3f4efd47111093d5bfb86643c8647dd30aeaf5aa6fce","src/openbsd_bitrig.rs":"b9601aa0c6cc0129913341adba838aa0fadd698563eca7f0b046e31c97f0ac92","src/random_device.rs":"bc9cf2470619a90bb8444a632a873e431f801cc3230977851e20d54d86093321","src/redox.rs":"c3fd6f418f085d3b5ffaa6ff4540380cf437cbd65c8b87f89c1dbe16222539e4","src/sgx.rs":"140cf6529ebbf28a19c112e6f325ecd9d84427cc962895795e427cb5b1fa8500","src/solarish.rs":"2c39d2b28a4b9568a378b78b2021bf633fef505d9c5fed2e0a50e90ed9711359","src/wasm32_bindgen.rs":"befe5b8a90ed23c2b3adf40281651966a5ee15ae520101704b68890ec4fb4529","src/wasm32_stdweb.rs":"8684b8ce392941c9d7864d45f82e5a4577fc63b0f0bb709fa627f8b9c9e154a6","src/windows.rs":"d72d555013440aeffe764d961a0a095f8a11417d28a13c2a8882abce2dc000f0","tests/mod.rs":"b8a6caeb5aafd13de775488168b0b46592336568ded37be713e422f724f6f086"},"package":"7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"} \ No newline at end of file diff --git a/third_party/rust/rand_os/CHANGELOG.md b/third_party/rust/rand_os/CHANGELOG.md new file mode 100644 index 000000000000..1ce36fc6cc72 --- /dev/null +++ b/third_party/rust/rand_os/CHANGELOG.md @@ -0,0 +1,22 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + +## [0.1.3] - 2019-03-05 +### Changes +- Fix support for Illumos (#730) +- Fix deprecation warnings from atomic init (#739) + +## [0.1.2] - 2019-01-28 +### Changes +- Fuchsia: Replaced fuchsia-zircon with fuchsia-cprng + +## [0.1.1] - 2019-01-08 +### Additions +- Add support for x86_64-fortanix-unknown-sgx target (#670) + +## [0.1.0] - 2019-01-04 +Initial release. diff --git a/third_party/rust/rand_os/COPYRIGHT b/third_party/rust/rand_os/COPYRIGHT new file mode 100644 index 000000000000..468d907caf99 --- /dev/null +++ b/third_party/rust/rand_os/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 or + or the MIT license + or , at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/third_party/rust/rand_os/Cargo.toml b/third_party/rust/rand_os/Cargo.toml new file mode 100644 index 000000000000..d0f1dfe7ae3f --- /dev/null +++ b/third_party/rust/rand_os/Cargo.toml @@ -0,0 +1,53 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand_os" +version = "0.1.3" +authors = ["The Rand Project Developers"] +description = "OS backed Random Number Generator" +homepage = "https://crates.io/crates/rand_os" +documentation = "https://docs.rs/rand_os" +readme = "README.md" +keywords = ["random", "rng", "os"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-random/rand" +[dependencies.log] +version = "0.4" +optional = true + +[dependencies.rand_core] +version = "0.4" +features = ["std"] +[target."cfg(target_env = \"sgx\")".dependencies.rdrand] +version = "0.4.0" +[target."cfg(target_os = \"cloudabi\")".dependencies.cloudabi] +version = "0.0.3" +[target."cfg(target_os = \"fuchsia\")".dependencies.fuchsia-cprng] +version = "0.1.0" +[target."cfg(unix)".dependencies.libc] +version = "0.2" +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["minwindef", "ntsecapi", "winnt"] +[target.wasm32-unknown-unknown.dependencies.stdweb] +version = "0.4" +optional = true + +[target.wasm32-unknown-unknown.dependencies.wasm-bindgen] +version = "0.2.12" +optional = true +[badges.appveyor] +repository = "rust-random/rand" + +[badges.travis-ci] +repository = "rust-random/rand" diff --git a/third_party/rust/rand_os/LICENSE-APACHE b/third_party/rust/rand_os/LICENSE-APACHE new file mode 100644 index 000000000000..17d74680f8cf --- /dev/null +++ b/third_party/rust/rand_os/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/rand_os/LICENSE-MIT b/third_party/rust/rand_os/LICENSE-MIT new file mode 100644 index 000000000000..d93b5baf341d --- /dev/null +++ b/third_party/rust/rand_os/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright 2018 Developers of the Rand project +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/rand_os/README.md b/third_party/rust/rand_os/README.md new file mode 100644 index 000000000000..4f48b63decad --- /dev/null +++ b/third_party/rust/rand_os/README.md @@ -0,0 +1,33 @@ +# rand_os + +[![Build Status](https://travis-ci.org/rust-random/rand.svg?branch=master)](https://travis-ci.org/rust-random/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Latest version](https://img.shields.io/crates/v/rand_os.svg)](https://crates.io/crates/rand_os) +[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) +[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_os) +[![API](https://docs.rs/rand_os/badge.svg)](https://docs.rs/rand_os) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) + +A random number generator that retrieves randomness straight from the +operating system. + +This crate depends on [rand_core](https://crates.io/crates/rand_core) and is +part of the [Rand project](https://github.com/rust-random/rand). + +This crate aims to support all of Rust's `std` platforms with a system-provided +entropy source. Unlike other Rand crates, this crate does not support `no_std` +(handling this gracefully is a current discussion topic). + +Links: + +- [API documentation (master)](https://rust-random.github.io/rand/rand_os) +- [API documentation (docs.rs)](https://docs.rs/rand_os) +- [Changelog](CHANGELOG.md) + +## License + +`rand_os` is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/third_party/rust/rand_os/src/cloudabi.rs b/third_party/rust/rand_os/src/cloudabi.rs new file mode 100644 index 000000000000..8b96a2bc9ca4 --- /dev/null +++ b/third_party/rust/rand_os/src/cloudabi.rs @@ -0,0 +1,39 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for CloudABI + +extern crate cloudabi; + +use std::io; +use rand_core::{Error, ErrorKind}; +use super::OsRngImpl; + +#[derive(Clone, Debug)] +pub struct OsRng; + +impl OsRngImpl for OsRng { + fn new() -> Result { Ok(OsRng) } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + let errno = unsafe { cloudabi::random_get(dest) }; + if errno == cloudabi::errno::SUCCESS { + Ok(()) + } else { + // Cloudlibc provides its own `strerror` implementation so we + // can use `from_raw_os_error` here. + Err(Error::with_cause( + ErrorKind::Unavailable, + "random_get() system call failed", + io::Error::from_raw_os_error(errno as i32), + )) + } + } + + fn method_str(&self) -> &'static str { "cloudabi::random_get" } +} diff --git a/third_party/rust/rand_os/src/dragonfly_haiku_emscripten.rs b/third_party/rust/rand_os/src/dragonfly_haiku_emscripten.rs new file mode 100644 index 000000000000..6132d7ac3bcd --- /dev/null +++ b/third_party/rust/rand_os/src/dragonfly_haiku_emscripten.rs @@ -0,0 +1,39 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for DragonFly / Haiku / Emscripten + +use rand_core::Error; +use super::random_device; +use super::OsRngImpl; +use std::fs::File; + +#[derive(Clone, Debug)] +pub struct OsRng(); + +impl OsRngImpl for OsRng { + fn new() -> Result { + random_device::open("/dev/random", &|p| File::open(p))?; + Ok(OsRng()) + } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + random_device::read(dest) + } + + #[cfg(target_os = "emscripten")] + fn max_chunk_size(&self) -> usize { + // `Crypto.getRandomValues` documents `dest` should be at most 65536 + // bytes. `crypto.randomBytes` documents: "To minimize threadpool + // task length variation, partition large randomBytes requests when + // doing so as part of fulfilling a client request. + 65536 + } + + fn method_str(&self) -> &'static str { "/dev/random" } +} diff --git a/third_party/rust/rand_os/src/dummy_log.rs b/third_party/rust/rand_os/src/dummy_log.rs new file mode 100644 index 000000000000..ccfe4baeff20 --- /dev/null +++ b/third_party/rust/rand_os/src/dummy_log.rs @@ -0,0 +1,10 @@ +#[allow(unused)] +macro_rules! trace { ($($x:tt)*) => () } +#[allow(unused)] +macro_rules! debug { ($($x:tt)*) => () } +#[allow(unused)] +macro_rules! info { ($($x:tt)*) => () } +#[allow(unused)] +macro_rules! warn { ($($x:tt)*) => () } +#[allow(unused)] +macro_rules! error { ($($x:tt)*) => () } diff --git a/third_party/rust/rand_os/src/freebsd.rs b/third_party/rust/rand_os/src/freebsd.rs new file mode 100644 index 000000000000..6b8e6728a427 --- /dev/null +++ b/third_party/rust/rand_os/src/freebsd.rs @@ -0,0 +1,45 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for FreeBSD + +extern crate libc; + +use rand_core::{Error, ErrorKind}; +use super::OsRngImpl; + +use std::ptr; +use std::io; + +#[derive(Clone, Debug)] +pub struct OsRng; + +impl OsRngImpl for OsRng { + fn new() -> Result { Ok(OsRng) } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + let mib = [libc::CTL_KERN, libc::KERN_ARND]; + let mut len = dest.len(); + let ret = unsafe { + libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint, + dest.as_mut_ptr() as *mut _, &mut len, + ptr::null(), 0) + }; + if ret == -1 || len != dest.len() { + return Err(Error::with_cause( + ErrorKind::Unavailable, + "kern.arandom sysctl failed", + io::Error::last_os_error())); + } + Ok(()) + } + + fn max_chunk_size(&self) -> usize { 256 } + + fn method_str(&self) -> &'static str { "kern.arandom" } +} diff --git a/third_party/rust/rand_os/src/fuchsia.rs b/third_party/rust/rand_os/src/fuchsia.rs new file mode 100644 index 000000000000..ada367761298 --- /dev/null +++ b/third_party/rust/rand_os/src/fuchsia.rs @@ -0,0 +1,28 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for Fuchsia Zircon + +extern crate fuchsia_cprng; + +use rand_core::Error; +use super::OsRngImpl; + +#[derive(Clone, Debug)] +pub struct OsRng; + +impl OsRngImpl for OsRng { + fn new() -> Result { Ok(OsRng) } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + fuchsia_cprng::cprng_draw(dest); + Ok(()) + } + + fn method_str(&self) -> &'static str { "cprng_draw" } +} diff --git a/third_party/rust/rand_os/src/lib.rs b/third_party/rust/rand_os/src/lib.rs new file mode 100644 index 000000000000..1b9cb2548278 --- /dev/null +++ b/third_party/rust/rand_os/src/lib.rs @@ -0,0 +1,440 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013-2015 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Interface to the random number generator of the operating system. +//! +//! [`OsRng`] is the preferred external source of entropy for most applications. +//! Commonly it is used to initialize a user-space RNG, which can then be used +//! to generate random values with much less overhead than `OsRng`. +//! +//! You may prefer to use [`EntropyRng`] instead of `OsRng`. It is unlikely, but +//! not entirely theoretical, for `OsRng` to fail. In such cases [`EntropyRng`] +//! falls back on a good alternative entropy source. +//! +//! [`OsRng::new()`] is guaranteed to be very cheap (after the first successful +//! call), and will never consume more than one file handle per process. +//! +//! # Usage example +//! ``` +//! use rand_os::OsRng; +//! use rand_os::rand_core::RngCore; +//! +//! let mut os_rng = OsRng::new().unwrap(); +//! let mut key = [0u8; 16]; +//! os_rng.fill_bytes(&mut key); +//! let random_u64 = os_rng.next_u64(); +//! ``` +//! +//! # Platform sources +//! +//! | OS | interface +//! |------------------|--------------------------------------------------------- +//! | Linux, Android | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after reading from `/dev/random` once +//! | Windows | [`RtlGenRandom`][3] +//! | macOS, iOS | [`SecRandomCopyBytes`][4] +//! | FreeBSD | [`kern.arandom`][5] +//! | OpenBSD, Bitrig | [`getentropy`][6] +//! | NetBSD | [`/dev/urandom`][7] after reading from `/dev/random` once +//! | Dragonfly BSD | [`/dev/random`][8] +//! | Solaris, illumos | [`getrandom`][9] system call if available, otherwise [`/dev/random`][10] +//! | Fuchsia OS | [`cprng_draw`][11] +//! | Redox | [`rand:`][12] +//! | CloudABI | [`random_get`][13] +//! | Haiku | `/dev/random` (identical to `/dev/urandom`) +//! | Web browsers | [`Crypto.getRandomValues`][14] (see [Support for WebAssembly and ams.js][14]) +//! | Node.js | [`crypto.randomBytes`][15] (see [Support for WebAssembly and ams.js][16]) +//! +//! Rand doesn't have a blanket implementation for all Unix-like operating +//! systems that reads from `/dev/urandom`. This ensures all supported operating +//! systems are using the recommended interface and respect maximum buffer +//! sizes. +//! +//! ## Support for WebAssembly and ams.js +//! +//! The three Emscripten targets `asmjs-unknown-emscripten`, +//! `wasm32-unknown-emscripten` and `wasm32-experimental-emscripten` use +//! Emscripten's emulation of `/dev/random` on web browsers and Node.js. +//! +//! The bare WASM target `wasm32-unknown-unknown` tries to call the javascript +//! methods directly, using either `stdweb` or `wasm-bindgen` depending on what +//! features are activated for this crate. Note that if both features are +//! enabled `wasm-bindgen` will be used. +//! +//! ## Early boot +//! +//! It is possible that early in the boot process the OS hasn't had enough time +//! yet to collect entropy to securely seed its RNG, especially on virtual +//! machines. +//! +//! Some operating systems always block the thread until the RNG is securely +//! seeded. This can take anywhere from a few seconds to more than a minute. +//! Others make a best effort to use a seed from before the shutdown and don't +//! document much. +//! +//! A few, Linux, NetBSD and Solaris, offer a choice between blocking, and +//! getting an error. With `try_fill_bytes` we choose to get the error +//! ([`ErrorKind::NotReady`]), while the other methods use a blocking interface. +//! +//! On Linux (when the `genrandom` system call is not available) and on NetBSD +//! reading from `/dev/urandom` never blocks, even when the OS hasn't collected +//! enough entropy yet. As a countermeasure we try to do a single read from +//! `/dev/random` until we know the OS RNG is initialized (and store this in a +//! global static). +//! +//! # Panics and error handling +//! +//! We cannot guarantee that `OsRng` will fail, but if it does, it will likely +//! be either when `OsRng::new()` is first called or when data is first read. +//! If you wish to catch errors early, then test reading of at least one byte +//! from `OsRng` via [`try_fill_bytes`]. If this succeeds, it is extremely +//! unlikely that any further errors will occur. +//! +//! Only [`try_fill_bytes`] is able to report the cause of an error; the other +//! [`RngCore`] methods may (depending on the error kind) retry several times, +//! but must eventually panic if the error persists. +//! +//! [`EntropyRng`]: ../rand/rngs/struct.EntropyRng.html +//! [`try_fill_bytes`]: RngCore::try_fill_bytes +//! [`ErrorKind::NotReady`]: rand_core::ErrorKind +//! +//! [1]: http://man7.org/linux/man-pages/man2/getrandom.2.html +//! [2]: http://man7.org/linux/man-pages/man4/urandom.4.html +//! [3]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx +//! [4]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc +//! [5]: https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4 +//! [6]: https://man.openbsd.org/getentropy.2 +//! [7]: http://netbsd.gw.com/cgi-bin/man-cgi?random+4+NetBSD-current +//! [8]: https://leaf.dragonflybsd.org/cgi/web-man?command=random§ion=4 +//! [9]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html +//! [10]: https://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.html +//! [11]: https://fuchsia.googlesource.com/zircon/+/HEAD/docs/syscalls/cprng_draw.md +//! [12]: https://github.com/redox-os/randd/blob/master/src/main.rs +//! [13]: https://github.com/NuxiNL/cloudabi/blob/v0.20/cloudabi.txt#L1826 +//! [14]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues +//! [15]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback +//! [16]: #support-for-webassembly-and-amsjs +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://rust-random.github.io/rand/")] +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +#![cfg_attr(feature = "stdweb", recursion_limit="128")] + +pub extern crate rand_core; +#[cfg(feature = "log")] +#[macro_use] extern crate log; + +// We have to do it here because we load macros +#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten"), + feature = "wasm-bindgen"))] +extern crate wasm_bindgen; +#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten"), + not(feature = "wasm-bindgen"), + feature = "stdweb"))] +#[macro_use] extern crate stdweb; + +#[cfg(target_env = "sgx")] +extern crate rdrand; + +#[cfg(not(feature = "log"))] +#[macro_use] +mod dummy_log; + +use std::fmt; +use rand_core::{CryptoRng, RngCore, Error, impls}; + +/// A random number generator that retrieves randomness straight from the +/// operating system. +#[derive(Clone)] +pub struct OsRng(imp::OsRng); + +impl fmt::Debug for OsRng { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl OsRng { + /// Create a new `OsRng`. + pub fn new() -> Result { + imp::OsRng::new().map(OsRng) + } +} + +impl CryptoRng for OsRng {} + +impl RngCore for OsRng { + fn next_u32(&mut self) -> u32 { + impls::next_u32_via_fill(self) + } + + fn next_u64(&mut self) -> u64 { + impls::next_u64_via_fill(self) + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + use std::{time, thread}; + + // We cannot return Err(..), so we try to handle before panicking. + const MAX_RETRY_PERIOD: u32 = 10; // max 10s + const WAIT_DUR_MS: u32 = 100; // retry every 100ms + let wait_dur = time::Duration::from_millis(WAIT_DUR_MS as u64); + const RETRY_LIMIT: u32 = (MAX_RETRY_PERIOD * 1000) / WAIT_DUR_MS; + const TRANSIENT_RETRIES: u32 = 8; + let mut err_count = 0; + let mut error_logged = false; + + // Maybe block until the OS RNG is initialized + let mut read = 0; + if let Ok(n) = self.0.test_initialized(dest, true) { read = n }; + let dest = &mut dest[read..]; + + loop { + if let Err(e) = self.try_fill_bytes(dest) { + if err_count >= RETRY_LIMIT { + error!("OsRng failed too many times; last error: {}", e); + panic!("OsRng failed too many times; last error: {}", e); + } + + if e.kind.should_wait() { + if !error_logged { + warn!("OsRng failed; waiting up to {}s and retrying. Error: {}", + MAX_RETRY_PERIOD, e); + error_logged = true; + } + err_count += 1; + thread::sleep(wait_dur); + continue; + } else if e.kind.should_retry() { + if !error_logged { + warn!("OsRng failed; retrying up to {} times. Error: {}", + TRANSIENT_RETRIES, e); + error_logged = true; + } + err_count += (RETRY_LIMIT + TRANSIENT_RETRIES - 1) + / TRANSIENT_RETRIES; // round up + continue; + } else { + error!("OsRng failed: {}", e); + panic!("OsRng fatal error: {}", e); + } + } + + break; + } + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + // Some systems do not support reading 0 random bytes. + // (And why waste a system call?) + if dest.len() == 0 { return Ok(()); } + + let read = self.0.test_initialized(dest, false)?; + let dest = &mut dest[read..]; + + let max = self.0.max_chunk_size(); + if dest.len() <= max { + trace!("OsRng: reading {} bytes via {}", + dest.len(), self.0.method_str()); + } else { + trace!("OsRng: reading {} bytes via {} in {} chunks of {} bytes", + dest.len(), self.0.method_str(), (dest.len() + max) / max, max); + } + for slice in dest.chunks_mut(max) { + self.0.fill_chunk(slice)?; + } + Ok(()) + } +} + +trait OsRngImpl where Self: Sized { + // Create a new `OsRng` platform interface. + fn new() -> Result; + + // Fill a chunk with random bytes. + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error>; + + // Test whether the OS RNG is initialized. This method may not be possible + // to support cheaply (or at all) on all operating systems. + // + // If `blocking` is set, this will cause the OS the block execution until + // its RNG is initialized. + // + // Random values that are read while this are stored in `dest`, the amount + // of read bytes is returned. + fn test_initialized(&mut self, _dest: &mut [u8], _blocking: bool) + -> Result { Ok(0) } + + // Maximum chunk size supported. + fn max_chunk_size(&self) -> usize { ::std::usize::MAX } + + // Name of the OS interface (used for logging). + fn method_str(&self) -> &'static str; +} + +#[cfg(any(target_os = "linux", target_os = "android", + target_os = "netbsd", target_os = "dragonfly", + target_os = "solaris", target_os = "redox", + target_os = "haiku", target_os = "emscripten", + target_os = "illumos"))] +mod random_device; + +macro_rules! mod_use { + ($cond:meta, $module:ident) => { + #[$cond] + mod $module; + #[$cond] + use $module as imp; + } +} + +mod_use!(cfg(target_os = "android"), linux_android); +mod_use!(cfg(target_os = "bitrig"), openbsd_bitrig); +mod_use!(cfg(target_os = "cloudabi"), cloudabi); +mod_use!(cfg(target_os = "dragonfly"), dragonfly_haiku_emscripten); +mod_use!(cfg(target_os = "emscripten"), dragonfly_haiku_emscripten); +mod_use!(cfg(target_os = "freebsd"), freebsd); +mod_use!(cfg(target_os = "fuchsia"), fuchsia); +mod_use!(cfg(target_os = "haiku"), dragonfly_haiku_emscripten); +mod_use!(cfg(target_os = "ios"), macos); +mod_use!(cfg(target_os = "linux"), linux_android); +mod_use!(cfg(target_os = "macos"), macos); +mod_use!(cfg(target_os = "netbsd"), netbsd); +mod_use!(cfg(target_os = "openbsd"), openbsd_bitrig); +mod_use!(cfg(target_os = "redox"), redox); +mod_use!(cfg(any(target_os = "solaris", target_os = "illumos")), solarish); +mod_use!(cfg(windows), windows); +mod_use!(cfg(target_env = "sgx"), sgx); + +mod_use!( + cfg(all( + target_arch = "wasm32", + not(target_os = "emscripten"), + feature = "wasm-bindgen" + )), + wasm32_bindgen +); + +mod_use!( + cfg(all( + target_arch = "wasm32", + not(target_os = "emscripten"), + not(feature = "wasm-bindgen"), + feature = "stdweb", + )), + wasm32_stdweb +); + +/// Per #678 we use run-time failure where WASM bindings are missing +#[cfg(all( + target_arch = "wasm32", + not(target_os = "emscripten"), + not(feature = "wasm-bindgen"), + not(feature = "stdweb"), +))] +mod imp { + use rand_core::{Error, ErrorKind}; + use super::OsRngImpl; + + #[derive(Clone, Debug)] + pub struct OsRng; + + impl OsRngImpl for OsRng { + fn new() -> Result { + Err(Error::new(ErrorKind::Unavailable, + "OsRng: support for wasm32 requires emscripten, stdweb or wasm-bindgen")) + } + + fn fill_chunk(&mut self, _dest: &mut [u8]) -> Result<(), Error> { + unimplemented!() + } + + fn method_str(&self) -> &'static str { unimplemented!() } + } +} + +#[cfg(not(any( + target_os = "android", + target_os = "bitrig", + target_os = "cloudabi", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "illumos", + windows, + target_arch = "wasm32", + target_env = "sgx" +)))] +compile_error!("OS RNG support is not available for this platform"); + +// 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 "C" { + pub type Function; + #[wasm_bindgen(constructor)] + pub fn new(s: &str) -> Function; + #[wasm_bindgen(method)] + pub fn call(this: &Function, self_: &JsValue) -> JsValue; + + pub type 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; + + #[derive(Clone, Debug)] + 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; + + #[derive(Clone, Debug)] + pub type NodeCrypto; + + #[wasm_bindgen(method, js_name = randomFillSync, structural)] + pub fn random_fill_sync(me: &NodeCrypto, buf: &mut [u8]); + } + } +} diff --git a/third_party/rust/rand_os/src/linux_android.rs b/third_party/rust/rand_os/src/linux_android.rs new file mode 100644 index 000000000000..255c2200210c --- /dev/null +++ b/third_party/rust/rand_os/src/linux_android.rs @@ -0,0 +1,186 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for Linux / Android + +extern crate libc; + +use rand_core::{Error, ErrorKind}; +use super::random_device; +use super::OsRngImpl; + +use std::io; +use std::io::Read; +use std::fs::{File, OpenOptions}; +use std::os::unix::fs::OpenOptionsExt; +use std::sync::atomic::{AtomicBool, Ordering}; +#[allow(deprecated)] // Required for compatibility with Rust < 1.24. +use std::sync::atomic::ATOMIC_BOOL_INIT; +use std::sync::{Once, ONCE_INIT}; + +#[derive(Clone, Debug)] +pub struct OsRng { + method: OsRngMethod, + initialized: bool, +} + +#[derive(Clone, Debug)] +enum OsRngMethod { + GetRandom, + RandomDevice, +} + +impl OsRngImpl for OsRng { + fn new() -> Result { + if is_getrandom_available() { + return Ok(OsRng { method: OsRngMethod::GetRandom, + initialized: false }); + } + random_device::open("/dev/urandom", &|p| File::open(p))?; + Ok(OsRng { method: OsRngMethod::RandomDevice, initialized: false }) + } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + match self.method { + OsRngMethod::GetRandom => getrandom_try_fill(dest, false), + OsRngMethod::RandomDevice => random_device::read(dest), + } + } + + fn test_initialized(&mut self, dest: &mut [u8], blocking: bool) + -> Result + { + #[allow(deprecated)] + static OS_RNG_INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT; + if !self.initialized { + self.initialized = OS_RNG_INITIALIZED.load(Ordering::Relaxed); + } + if self.initialized { return Ok(0); } + + let result = match self.method { + OsRngMethod::GetRandom => { + getrandom_try_fill(dest, blocking)?; + Ok(dest.len()) + } + OsRngMethod::RandomDevice => { + info!("OsRng: testing random device /dev/random"); + let mut file = OpenOptions::new() + .read(true) + .custom_flags(if blocking { 0 } else { libc::O_NONBLOCK }) + .open("/dev/random") + .map_err(random_device::map_err)?; + file.read(&mut dest[..1]).map_err(random_device::map_err)?; + Ok(1) + } + }; + OS_RNG_INITIALIZED.store(true, Ordering::Relaxed); + self.initialized = true; + result + } + + fn method_str(&self) -> &'static str { + match self.method { + OsRngMethod::GetRandom => "getrandom", + OsRngMethod::RandomDevice => "/dev/urandom", + } + } +} + +#[cfg(target_arch = "x86_64")] +const NR_GETRANDOM: libc::c_long = 318; +#[cfg(target_arch = "x86")] +const NR_GETRANDOM: libc::c_long = 355; +#[cfg(target_arch = "arm")] +const NR_GETRANDOM: libc::c_long = 384; +#[cfg(target_arch = "aarch64")] +const NR_GETRANDOM: libc::c_long = 278; + #[cfg(target_arch = "s390x")] +const NR_GETRANDOM: libc::c_long = 349; +#[cfg(target_arch = "powerpc")] +const NR_GETRANDOM: libc::c_long = 359; +#[cfg(target_arch = "powerpc64")] +const NR_GETRANDOM: libc::c_long = 359; +#[cfg(target_arch = "mips")] // old ABI +const NR_GETRANDOM: libc::c_long = 4353; +#[cfg(target_arch = "mips64")] +const NR_GETRANDOM: libc::c_long = 5313; +#[cfg(target_arch = "sparc")] +const NR_GETRANDOM: libc::c_long = 347; +#[cfg(target_arch = "sparc64")] +const NR_GETRANDOM: libc::c_long = 347; +#[cfg(not(any(target_arch = "x86_64", target_arch = "x86", + target_arch = "arm", target_arch = "aarch64", + target_arch = "s390x", target_arch = "powerpc", + target_arch = "powerpc64", target_arch = "mips", + target_arch = "mips64", target_arch = "sparc", + target_arch = "sparc64")))] +const NR_GETRANDOM: libc::c_long = 0; + +fn getrandom(buf: &mut [u8], blocking: bool) -> libc::c_long { + const GRND_NONBLOCK: libc::c_uint = 0x0001; + + if NR_GETRANDOM == 0 { return -1 }; + + unsafe { + libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), + if blocking { 0 } else { GRND_NONBLOCK }) + } +} + +fn getrandom_try_fill(dest: &mut [u8], blocking: bool) -> Result<(), Error> { + let mut read = 0; + while read < dest.len() { + let result = getrandom(&mut dest[read..], blocking); + if result == -1 { + let err = io::Error::last_os_error(); + let kind = err.kind(); + if kind == io::ErrorKind::Interrupted { + continue; + } else if kind == io::ErrorKind::WouldBlock { + return Err(Error::with_cause( + ErrorKind::NotReady, + "getrandom not ready", + err, + )); + } else { + return Err(Error::with_cause( + ErrorKind::Unavailable, + "unexpected getrandom error", + err, + )); + } + } else { + read += result as usize; + } + } + Ok(()) +} + +fn is_getrandom_available() -> bool { + static CHECKER: Once = ONCE_INIT; + #[allow(deprecated)] + static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT; + + if NR_GETRANDOM == 0 { return false }; + + CHECKER.call_once(|| { + debug!("OsRng: testing getrandom"); + let mut buf: [u8; 0] = []; + let result = getrandom(&mut buf, false); + let available = if result == -1 { + let err = io::Error::last_os_error().raw_os_error(); + err != Some(libc::ENOSYS) + } else { + true + }; + AVAILABLE.store(available, Ordering::Relaxed); + info!("OsRng: using {}", if available { "getrandom" } else { "/dev/urandom" }); + }); + + AVAILABLE.load(Ordering::Relaxed) +} diff --git a/third_party/rust/rand_os/src/macos.rs b/third_party/rust/rand_os/src/macos.rs new file mode 100644 index 000000000000..6c67251c0a76 --- /dev/null +++ b/third_party/rust/rand_os/src/macos.rs @@ -0,0 +1,53 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for MacOS / iOS + +extern crate libc; + +use rand_core::{Error, ErrorKind}; +use super::OsRngImpl; + +use std::io; +use self::libc::{c_int, size_t}; + +#[derive(Clone, Debug)] +pub struct OsRng; + +enum SecRandom {} + +#[allow(non_upper_case_globals)] +const kSecRandomDefault: *const SecRandom = 0 as *const SecRandom; + +#[link(name = "Security", kind = "framework")] +extern { + fn SecRandomCopyBytes(rnd: *const SecRandom, + count: size_t, bytes: *mut u8) -> c_int; +} + +impl OsRngImpl for OsRng { + fn new() -> Result { Ok(OsRng) } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + let ret = unsafe { + SecRandomCopyBytes(kSecRandomDefault, + dest.len() as size_t, + dest.as_mut_ptr()) + }; + if ret == -1 { + Err(Error::with_cause( + ErrorKind::Unavailable, + "couldn't generate random bytes", + io::Error::last_os_error())) + } else { + Ok(()) + } + } + + fn method_str(&self) -> &'static str { "SecRandomCopyBytes" } +} diff --git a/third_party/rust/rand_os/src/netbsd.rs b/third_party/rust/rand_os/src/netbsd.rs new file mode 100644 index 000000000000..34517bfeb3fd --- /dev/null +++ b/third_party/rust/rand_os/src/netbsd.rs @@ -0,0 +1,57 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for NetBSD + +use rand_core::Error; +use super::random_device; +use super::OsRngImpl; + +use std::fs::File; +use std::io::Read; +use std::sync::atomic::{AtomicBool, Ordering}; +#[allow(deprecated)] // Required for compatibility with Rust < 1.24. +use std::sync::atomic::ATOMIC_BOOL_INIT; + +#[derive(Clone, Debug)] +pub struct OsRng { initialized: bool } + +impl OsRngImpl for OsRng { + fn new() -> Result { + random_device::open("/dev/urandom", &|p| File::open(p))?; + Ok(OsRng { initialized: false }) + } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + random_device::read(dest) + } + + // Read a single byte from `/dev/random` to determine if the OS RNG is + // already seeded. NetBSD always blocks if not yet ready. + fn test_initialized(&mut self, dest: &mut [u8], _blocking: bool) + -> Result + { + #[allow(deprecated)] + static OS_RNG_INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT; + if !self.initialized { + self.initialized = OS_RNG_INITIALIZED.load(Ordering::Relaxed); + } + if self.initialized { return Ok(0); } + + info!("OsRng: testing random device /dev/random"); + let mut file = + File::open("/dev/random").map_err(random_device::map_err)?; + file.read(&mut dest[..1]).map_err(random_device::map_err)?; + + OS_RNG_INITIALIZED.store(true, Ordering::Relaxed); + self.initialized = true; + Ok(1) + } + + fn method_str(&self) -> &'static str { "/dev/urandom" } +} diff --git a/third_party/rust/rand_os/src/openbsd_bitrig.rs b/third_party/rust/rand_os/src/openbsd_bitrig.rs new file mode 100644 index 000000000000..c9b35a6c5694 --- /dev/null +++ b/third_party/rust/rand_os/src/openbsd_bitrig.rs @@ -0,0 +1,40 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for OpenBSD / Bitrig + +extern crate libc; + +use rand_core::{Error, ErrorKind}; +use super::OsRngImpl; + +use std::io; + +#[derive(Clone, Debug)] +pub struct OsRng; + +impl OsRngImpl for OsRng { + fn new() -> Result { Ok(OsRng) } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + let ret = unsafe { + libc::getentropy(dest.as_mut_ptr() as *mut libc::c_void, dest.len()) + }; + if ret == -1 { + return Err(Error::with_cause( + ErrorKind::Unavailable, + "getentropy failed", + io::Error::last_os_error())); + } + Ok(()) + } + + fn max_chunk_size(&self) -> usize { 256 } + + fn method_str(&self) -> &'static str { "getentropy" } +} diff --git a/third_party/rust/rand_os/src/random_device.rs b/third_party/rust/rand_os/src/random_device.rs new file mode 100644 index 000000000000..5da91940f2d2 --- /dev/null +++ b/third_party/rust/rand_os/src/random_device.rs @@ -0,0 +1,70 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Helper functions to read from a random device such as `/dev/urandom`. +//! +//! All instances use a single internal file handle, to prevent possible +//! exhaustion of file descriptors. +use rand_core::{Error, ErrorKind}; +use std::fs::File; +use std::io; +use std::io::Read; +use std::sync::{Once, Mutex, ONCE_INIT}; + +// TODO: remove outer Option when `Mutex::new(None)` is a constant expression +static mut READ_RNG_FILE: Option>> = None; +static READ_RNG_ONCE: Once = ONCE_INIT; + +#[allow(unused)] +pub fn open(path: &'static str, open_fn: F) -> Result<(), Error> + where F: Fn(&'static str) -> Result +{ + READ_RNG_ONCE.call_once(|| { + unsafe { READ_RNG_FILE = Some(Mutex::new(None)) } + }); + + // We try opening the file outside the `call_once` fn because we cannot + // clone the error, thus we must retry on failure. + + let mutex = unsafe { READ_RNG_FILE.as_ref().unwrap() }; + let mut guard = mutex.lock().unwrap(); + if (*guard).is_none() { + info!("OsRng: opening random device {}", path); + let file = open_fn(path).map_err(map_err)?; + *guard = Some(file); + }; + Ok(()) +} + +pub fn read(dest: &mut [u8]) -> Result<(), Error> { + // We expect this function only to be used after `random_device::open` + // was succesful. Therefore we can assume that our memory was set with a + // valid object. + let mutex = unsafe { READ_RNG_FILE.as_ref().unwrap() }; + let mut guard = mutex.lock().unwrap(); + let file = (*guard).as_mut().unwrap(); + + // Use `std::io::read_exact`, which retries on `ErrorKind::Interrupted`. + file.read_exact(dest).map_err(|err| { + Error::with_cause(ErrorKind::Unavailable, + "error reading random device", err) + }) + +} + +pub fn map_err(err: io::Error) -> Error { + match err.kind() { + io::ErrorKind::Interrupted => + Error::new(ErrorKind::Transient, "interrupted"), + io::ErrorKind::WouldBlock => + Error::with_cause(ErrorKind::NotReady, + "OS RNG not yet seeded", err), + _ => Error::with_cause(ErrorKind::Unavailable, + "error while opening random device", err) + } +} diff --git a/third_party/rust/rand_os/src/redox.rs b/third_party/rust/rand_os/src/redox.rs new file mode 100644 index 000000000000..36fae2666d62 --- /dev/null +++ b/third_party/rust/rand_os/src/redox.rs @@ -0,0 +1,30 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for Redox + +use rand_core::Error; +use super::random_device; +use super::OsRngImpl; +use std::fs::File; + +#[derive(Clone, Debug)] +pub struct OsRng(); + +impl OsRngImpl for OsRng { + fn new() -> Result { + random_device::open("rand:", &|p| File::open(p))?; + Ok(OsRng()) + } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + random_device::read(dest) + } + + fn method_str(&self) -> &'static str { "'rand:'" } +} diff --git a/third_party/rust/rand_os/src/sgx.rs b/third_party/rust/rand_os/src/sgx.rs new file mode 100644 index 000000000000..43ae0ef79f17 --- /dev/null +++ b/third_party/rust/rand_os/src/sgx.rs @@ -0,0 +1,38 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::OsRngImpl; +use Error; +use rdrand::RdRand; +use rand_core::RngCore; +use std::fmt::{Debug, Formatter, Result as FmtResult}; + +#[derive(Clone)] +pub struct OsRng{ + gen: RdRand +} + +impl OsRngImpl for OsRng { + fn new() -> Result { + let rng = RdRand::new()?; + Ok(OsRng{ gen: rng }) + } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.gen.try_fill_bytes(dest) + } + + fn method_str(&self) -> &'static str { "RDRAND" } +} + +impl Debug for OsRng { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + f.debug_struct("OsRng") + .finish() + } +} diff --git a/third_party/rust/rand_os/src/solarish.rs b/third_party/rust/rand_os/src/solarish.rs new file mode 100644 index 000000000000..471768adc7dc --- /dev/null +++ b/third_party/rust/rand_os/src/solarish.rs @@ -0,0 +1,195 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for the Solaris family +//! +//! Read from `/dev/random`, with chunks of limited size (1040 bytes). +//! `/dev/random` uses the Hash_DRBG with SHA512 algorithm from NIST SP 800-90A. +//! `/dev/urandom` uses the FIPS 186-2 algorithm, which is considered less +//! secure. We choose to read from `/dev/random`. +//! +//! Since Solaris 11.3 the `getrandom` syscall is available. To make sure we can +//! compile on both Solaris and on OpenSolaris derivatives, that do not have the +//! function, we do a direct syscall instead of calling a library function. +//! +//! We have no way to differentiate between Solaris, illumos, SmartOS, etc. +extern crate libc; + +use rand_core::{Error, ErrorKind}; +use super::random_device; +use super::OsRngImpl; + +use std::io; +use std::io::Read; +use std::fs::{File, OpenOptions}; +use std::os::unix::fs::OpenOptionsExt; +use std::sync::atomic::{AtomicBool, Ordering, AtomicUsize}; +#[allow(deprecated)] // Required for compatibility with Rust < 1.24. +use std::sync::atomic::ATOMIC_BOOL_INIT; +use std::cmp; +use std::mem; + +#[derive(Clone, Debug)] +pub struct OsRng { + method: OsRngMethod, + initialized: bool, +} + +#[derive(Clone, Debug)] +enum OsRngMethod { + GetRandom, + RandomDevice, +} + +impl OsRngImpl for OsRng { + fn new() -> Result { + if is_getrandom_available() { + return Ok(OsRng { method: OsRngMethod::GetRandom, + initialized: false }); + } + let open = |p| OpenOptions::new() + .read(true) + .custom_flags(libc::O_NONBLOCK) + .open(p); + random_device::open("/dev/random", &open)?; + Ok(OsRng { method: OsRngMethod::RandomDevice, initialized: false }) + } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + match self.method { + OsRngMethod::GetRandom => getrandom_try_fill(dest, false), + OsRngMethod::RandomDevice => random_device::read(dest), + } + } + + fn test_initialized(&mut self, dest: &mut [u8], blocking: bool) + -> Result + { + #[allow(deprecated)] + static OS_RNG_INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT; + if !self.initialized { + self.initialized = OS_RNG_INITIALIZED.load(Ordering::Relaxed); + } + if self.initialized { return Ok(0); } + + let chunk_len = cmp::min(1024, dest.len()); + let dest = &mut dest[..chunk_len]; + + match self.method { + OsRngMethod::GetRandom => getrandom_try_fill(dest, blocking)?, + OsRngMethod::RandomDevice => { + if blocking { + info!("OsRng: testing random device /dev/random"); + // We already have a non-blocking handle, but now need a + // blocking one. Not much choice except opening it twice + let mut file = File::open("/dev/random") + .map_err(random_device::map_err)?; + file.read(dest).map_err(random_device::map_err)?; + } else { + self.fill_chunk(dest)?; + } + } + }; + OS_RNG_INITIALIZED.store(true, Ordering::Relaxed); + self.initialized = true; + Ok(chunk_len) + } + + fn max_chunk_size(&self) -> usize { + // This is the largest size that's guaranteed to not block across + // all the Solarish platforms, though some may allow for larger + // sizes. + 256 + } + + fn method_str(&self) -> &'static str { + match self.method { + OsRngMethod::GetRandom => "getrandom", + OsRngMethod::RandomDevice => "/dev/random", + } + } +} + +#[cfg(target_os = "illumos")] +type GetRandomFn = unsafe extern fn(*mut u8, libc::size_t, libc::c_uint) + -> libc::ssize_t; +#[cfg(target_os = "solaris")] +type GetRandomFn = unsafe extern fn(*mut u8, libc::size_t, libc::c_uint) + -> libc::c_int; + +// Use dlsym to determine if getrandom(2) is present in libc. On Solarish +// systems, the syscall interface is not stable and can change between +// updates. Even worse, issuing unsupported syscalls will cause the system +// to generate a SIGSYS signal (usually terminating the program). +// Instead the stable APIs are exposed via libc. Cache the result of the +// lookup for future calls. This is loosely modeled after the +// libstd::sys::unix::weak macro which unfortunately is not exported. +fn fetch() -> Option { + static FPTR: AtomicUsize = AtomicUsize::new(1); + + if FPTR.load(Ordering::SeqCst) == 1 { + let name = "getrandom\0"; + let addr = unsafe { + libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _) as usize + }; + FPTR.store(addr, Ordering::SeqCst); + } + + let ptr = FPTR.load(Ordering::SeqCst); + unsafe { + mem::transmute::>(ptr) + } +} + +fn getrandom(buf: &mut [u8], blocking: bool) -> libc::ssize_t { + const GRND_NONBLOCK: libc::c_uint = 0x0001; + const GRND_RANDOM: libc::c_uint = 0x0002; + + if let Some(rand) = fetch() { + let flag = if blocking { 0 } else { GRND_NONBLOCK } | GRND_RANDOM; + unsafe { + rand(buf.as_mut_ptr(), buf.len(), flag) as libc::ssize_t + } + } else { + -1 + } +} + +fn getrandom_try_fill(dest: &mut [u8], blocking: bool) -> Result<(), Error> { + let result = getrandom(dest, blocking); + if result == -1 || result == 0 { + let err = io::Error::last_os_error(); + let kind = err.kind(); + if kind == io::ErrorKind::WouldBlock { + return Err(Error::with_cause( + ErrorKind::NotReady, + "getrandom not ready", + err, + )); + } else { + return Err(Error::with_cause( + ErrorKind::Unavailable, + "unexpected getrandom error", + err, + )); + } + } else if result != dest.len() as libc::ssize_t { + return Err(Error::new(ErrorKind::Unavailable, + "unexpected getrandom error")); + } + Ok(()) +} + +fn is_getrandom_available() -> bool { + let available = match fetch() { + Some(_) => true, + None => false, + }; + info!("OsRng: using {}", if available { "getrandom" } else { "/dev/random" }); + available +} diff --git a/third_party/rust/rand_os/src/wasm32_bindgen.rs b/third_party/rust/rand_os/src/wasm32_bindgen.rs new file mode 100644 index 000000000000..5ab2d84173b1 --- /dev/null +++ b/third_party/rust/rand_os/src/wasm32_bindgen.rs @@ -0,0 +1,92 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for WASM via wasm-bindgen + +use rand_core::{Error, ErrorKind}; +use super::OsRngImpl; +use super::__wbg_shims::*; + +use wasm_bindgen::prelude::*; + + +#[derive(Clone, Debug)] +pub enum OsRng { + Node(NodeCrypto), + Browser(BrowserCrypto), +} + +impl OsRngImpl for OsRng { + fn new() -> Result { + // First up we need to detect if we're running in node.js or a + // browser. To do this we get ahold of the `this` object (in a bit + // of a roundabout fashion). + // + // Once we have `this` we look at its `self` property, which is + // only defined on the web (either a main window or web worker). + let this = Function::new("return this").call(&JsValue::undefined()); + assert!(this != JsValue::undefined()); + let this = This::from(this); + let is_browser = this.self_() != JsValue::undefined(); + + if !is_browser { + return Ok(OsRng::Node(node_require("crypto"))) + } + + // If `self` is defined then we're in a browser somehow (main window + // or web worker). Here we want to try to use + // `crypto.getRandomValues`, but if `crypto` isn't defined we assume + // we're in an older web browser and the OS RNG isn't available. + let crypto = this.crypto(); + if crypto.is_undefined() { + let msg = "self.crypto is undefined"; + return Err(Error::new(ErrorKind::Unavailable, msg)) + } + + // Test if `crypto.getRandomValues` is undefined as well + let crypto: BrowserCrypto = crypto.into(); + if crypto.get_random_values_fn().is_undefined() { + let msg = "crypto.getRandomValues is undefined"; + return Err(Error::new(ErrorKind::Unavailable, msg)) + } + + // Ok! `self.crypto.getRandomValues` is a defined value, so let's + // assume we can do browser crypto. + Ok(OsRng::Browser(crypto)) + } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + match *self { + OsRng::Node(ref n) => n.random_fill_sync(dest), + OsRng::Browser(ref n) => n.get_random_values(dest), + } + Ok(()) + } + + fn max_chunk_size(&self) -> usize { + match *self { + OsRng::Node(_) => usize::max_value(), + OsRng::Browser(_) => { + // see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues + // + // where it says: + // + // > A QuotaExceededError DOMException is thrown if the + // > requested length is greater than 65536 bytes. + 65536 + } + } + } + + fn method_str(&self) -> &'static str { + match *self { + OsRng::Node(_) => "crypto.randomFillSync", + OsRng::Browser(_) => "crypto.getRandomValues", + } + } +} diff --git a/third_party/rust/rand_os/src/wasm32_stdweb.rs b/third_party/rust/rand_os/src/wasm32_stdweb.rs new file mode 100644 index 000000000000..3be0ce6a6fa0 --- /dev/null +++ b/third_party/rust/rand_os/src/wasm32_stdweb.rs @@ -0,0 +1,107 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for WASM via stdweb + +use std::mem; +use stdweb::unstable::TryInto; +use stdweb::web::error::Error as WebError; +use rand_core::{Error, ErrorKind}; +use super::OsRngImpl; + +#[derive(Clone, Debug)] +enum OsRngMethod { + Browser, + Node +} + +#[derive(Clone, Debug)] +pub struct OsRng(OsRngMethod); + +impl OsRngImpl for OsRng { + fn new() -> Result { + let result = js! { + try { + if ( + typeof self === "object" && + typeof self.crypto === "object" && + typeof self.crypto.getRandomValues === "function" + ) { + return { success: true, ty: 1 }; + } + + if (typeof require("crypto").randomBytes === "function") { + return { success: true, ty: 2 }; + } + + return { success: false, error: new Error("not supported") }; + } catch(err) { + return { success: false, error: err }; + } + }; + + if js!{ return @{ result.as_ref() }.success } == true { + let ty = js!{ return @{ result }.ty }; + + if ty == 1 { Ok(OsRng(OsRngMethod::Browser)) } + else if ty == 2 { Ok(OsRng(OsRngMethod::Node)) } + else { unreachable!() } + } else { + let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); + Err(Error::with_cause(ErrorKind::Unavailable, "WASM Error", err)) + } + } + + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + assert_eq!(mem::size_of::(), 4); + + let len = dest.len() as u32; + let ptr = dest.as_mut_ptr() as i32; + + let result = match self.0 { + OsRngMethod::Browser => js! { + try { + let array = new Uint8Array(@{ len }); + self.crypto.getRandomValues(array); + HEAPU8.set(array, @{ ptr }); + + return { success: true }; + } catch(err) { + return { success: false, error: err }; + } + }, + OsRngMethod::Node => js! { + try { + let bytes = require("crypto").randomBytes(@{ len }); + HEAPU8.set(new Uint8Array(bytes), @{ ptr }); + + return { success: true }; + } catch(err) { + return { success: false, error: err }; + } + } + }; + + if js!{ return @{ result.as_ref() }.success } == true { + Ok(()) + } else { + let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); + Err(Error::with_cause(ErrorKind::Unexpected, "WASM Error", err)) + } + } + + fn max_chunk_size(&self) -> usize { 65536 } + + fn method_str(&self) -> &'static str { + match self.0 { + OsRngMethod::Browser => "Crypto.getRandomValues", + OsRngMethod::Node => "crypto.randomBytes", + } + } +} diff --git a/third_party/rust/rand_os/src/windows.rs b/third_party/rust/rand_os/src/windows.rs new file mode 100644 index 000000000000..6b06c7abf68f --- /dev/null +++ b/third_party/rust/rand_os/src/windows.rs @@ -0,0 +1,44 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for Windows + +extern crate winapi; + +use rand_core::{Error, ErrorKind}; +use super::OsRngImpl; + +use std::io; + +use self::winapi::shared::minwindef::ULONG; +use self::winapi::um::ntsecapi::RtlGenRandom; +use self::winapi::um::winnt::PVOID; + +#[derive(Clone, Debug)] +pub struct OsRng; + +impl OsRngImpl for OsRng { + fn new() -> Result { Ok(OsRng) } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + let ret = unsafe { + RtlGenRandom(dest.as_mut_ptr() as PVOID, dest.len() as ULONG) + }; + if ret == 0 { + return Err(Error::with_cause( + ErrorKind::Unavailable, + "couldn't generate random bytes", + io::Error::last_os_error())); + } + Ok(()) + } + + fn max_chunk_size(&self) -> usize { ::max_value() as usize } + + fn method_str(&self) -> &'static str { "RtlGenRandom" } +} diff --git a/third_party/rust/rand_os/tests/mod.rs b/third_party/rust/rand_os/tests/mod.rs new file mode 100644 index 000000000000..2130e169bbfc --- /dev/null +++ b/third_party/rust/rand_os/tests/mod.rs @@ -0,0 +1,80 @@ +extern crate rand_os; + +use rand_os::rand_core::RngCore; +use rand_os::OsRng; + +#[test] +fn test_os_rng() { + let mut r = OsRng::new().unwrap(); + + r.next_u32(); + r.next_u64(); + + let mut v1 = [0u8; 1000]; + r.fill_bytes(&mut v1); + + let mut v2 = [0u8; 1000]; + r.fill_bytes(&mut v2); + + let mut n_diff_bits = 0; + for i in 0..v1.len() { + n_diff_bits += (v1[i] ^ v2[i]).count_ones(); + } + + // Check at least 1 bit per byte differs. p(failure) < 1e-1000 with random input. + assert!(n_diff_bits >= v1.len() as u32); +} + +#[test] +fn test_os_rng_empty() { + let mut r = OsRng::new().unwrap(); + + let mut empty = [0u8; 0]; + r.fill_bytes(&mut empty); +} + +#[test] +fn test_os_rng_huge() { + let mut r = OsRng::new().unwrap(); + + let mut huge = [0u8; 100_000]; + r.fill_bytes(&mut huge); +} + +#[cfg(not(any(target_arch = "wasm32", target_arch = "asmjs")))] +#[test] +fn test_os_rng_tasks() { + use std::sync::mpsc::channel; + use std::thread; + + let mut txs = vec!(); + for _ in 0..20 { + let (tx, rx) = channel(); + txs.push(tx); + + thread::spawn(move|| { + // wait until all the tasks are ready to go. + rx.recv().unwrap(); + + // deschedule to attempt to interleave things as much + // as possible (XXX: is this a good test?) + let mut r = OsRng::new().unwrap(); + thread::yield_now(); + let mut v = [0u8; 1000]; + + for _ in 0..100 { + r.next_u32(); + thread::yield_now(); + r.next_u64(); + thread::yield_now(); + r.fill_bytes(&mut v); + thread::yield_now(); + } + }); + } + + // start all the tasks + for tx in txs.iter() { + tx.send(()).unwrap(); + } +} diff --git a/third_party/rust/rand_pcg/.cargo-checksum.json b/third_party/rust/rand_pcg/.cargo-checksum.json new file mode 100644 index 000000000000..a21533e5699c --- /dev/null +++ b/third_party/rust/rand_pcg/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"f95c32b93b4ba4aac59fcf1d28b1818a8551a450198c075cf5720e71a5db17ef","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.toml":"82101af38b08afd05d0b09aae70b578f3d08d7fdc98ed643498e52175d85c09c","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"2234e3cefee876aeb686ad89e978bdb07bf118a1186ab1cf161bcdf69d4b4f57","README.md":"8da8a3dce4abed17df07963b65637cc150093d04d1d7354450afdcee26b0af4f","build.rs":"003108281c4f4bd7a40a93529012acc9d2555c7a4f4b3bfc3ab81d0ed92b8864","src/lib.rs":"443c6e23da72f86d4c0b24698c0d188ee984fce69e4f52d633191399b0051c6c","src/pcg128.rs":"71bc1063e56b0b906aab333438178bb3e636dd1fcdbae2c2452af9143aea5855","src/pcg64.rs":"0b36d28ec2e1cdd630473530785b3143966a4657e52f032e020bb5524be2e044","tests/lcg64xsh32.rs":"5770fb1dd2cce4843de89dccb05f79ffce9c0b8dc68487d09b30b376e8e982e3","tests/mcg128xsl64.rs":"8276f9ce83df0f76b0a242ec35fbbd6a6fcd5aacd9cd9a3b0812b538dc5a70f0"},"package":"abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"} \ No newline at end of file diff --git a/third_party/rust/rand_pcg/CHANGELOG.md b/third_party/rust/rand_pcg/CHANGELOG.md new file mode 100644 index 000000000000..69572248012b --- /dev/null +++ b/third_party/rust/rand_pcg/CHANGELOG.md @@ -0,0 +1,19 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.1.2] - 2019-02-23 +- require `bincode` 1.1.2 for i128 auto-detection +- make `bincode` a dev-dependency again #663 +- clean up tests and Serde support + +## [0.1.1] - 2018-10-04 +- make `bincode` an explicit dependency when using Serde + +## [0.1.0] - 2018-10-04 +Initial release, including: + +- `Lcg64Xsh32` aka `Pcg32` +- `Mcg128Xsl64` aka `Pcg64Mcg` diff --git a/third_party/rust/rand_pcg/COPYRIGHT b/third_party/rust/rand_pcg/COPYRIGHT new file mode 100644 index 000000000000..468d907caf99 --- /dev/null +++ b/third_party/rust/rand_pcg/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 or + or the MIT license + or , at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/third_party/rust/rand_pcg/Cargo.toml b/third_party/rust/rand_pcg/Cargo.toml new file mode 100644 index 000000000000..346f2f7bc2af --- /dev/null +++ b/third_party/rust/rand_pcg/Cargo.toml @@ -0,0 +1,47 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand_pcg" +version = "0.1.2" +authors = ["The Rand Project Developers"] +build = "build.rs" +description = "Selected PCG random number generators\n" +homepage = "https://crates.io/crates/rand_pcg" +documentation = "https://rust-random.github.io/rand/rand_pcg" +readme = "README.md" +keywords = ["random", "rng", "pcg"] +categories = ["algorithms", "no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-random/rand" +[dependencies.rand_core] +version = "0.4" + +[dependencies.serde] +version = "1" +optional = true + +[dependencies.serde_derive] +version = "^1.0.38" +optional = true +[dev-dependencies.bincode] +version = "1.1.2" +[build-dependencies.autocfg] +version = "0.1" + +[features] +serde1 = ["serde", "serde_derive"] +[badges.appveyor] +repository = "rust-random/rand" + +[badges.travis-ci] +repository = "rust-random/rand" diff --git a/third_party/rust/rand_pcg/LICENSE-APACHE b/third_party/rust/rand_pcg/LICENSE-APACHE new file mode 100644 index 000000000000..17d74680f8cf --- /dev/null +++ b/third_party/rust/rand_pcg/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/rand_pcg/LICENSE-MIT b/third_party/rust/rand_pcg/LICENSE-MIT new file mode 100644 index 000000000000..d46f058e98cc --- /dev/null +++ b/third_party/rust/rand_pcg/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright (c) 2014-2017 Melissa O'Neill and PCG Project contributors +Copyright 2018 Developers of the Rand project + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/rand_pcg/README.md b/third_party/rust/rand_pcg/README.md new file mode 100644 index 000000000000..ae583a1a4b8b --- /dev/null +++ b/third_party/rust/rand_pcg/README.md @@ -0,0 +1,43 @@ +# rand_pcg + +[![Build Status](https://travis-ci.org/rust-random/rand.svg?branch=master)](https://travis-ci.org/rust-random/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Latest version](https://img.shields.io/crates/v/rand_pcg.svg)](https://crates.io/crates/rand_pcg) +[[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) +[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_pcg) +[![API](https://docs.rs/rand_pcg/badge.svg)](https://docs.rs/rand_pcg) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) + +Implements a selection of PCG random number generators. + +> PCG is a family of simple fast space-efficient statistically good algorithms +> for random number generation. [Melissa O'Neill, Harvey Mudd College, 2014]. + +The PCG algorithms are not suitable for cryptographic uses, but perform well +in statistical tests, use little memory and are fairly fast. +See the [pcg-random website](http://www.pcg-random.org/). + +This crate depends on [rand_core](https://crates.io/crates/rand_core) and is +part of the [Rand project](https://github.com/rust-random/rand). + +Links: + +- [API documentation (master)](https://rust-random.github.io/rand/rand_pcg) +- [API documentation (docs.rs)](https://docs.rs/rand_pcg) +- [Changelog](CHANGELOG.md) + + +## Crate Features + +`rand_pcg` is `no_std` compatible by default. + +The `serde1` feature includes implementations of `Serialize` and `Deserialize` +for the included RNGs. + +## License + +`rand_pcg` is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/third_party/rust/rand_pcg/build.rs b/third_party/rust/rand_pcg/build.rs new file mode 100644 index 000000000000..06e12a47b6e8 --- /dev/null +++ b/third_party/rust/rand_pcg/build.rs @@ -0,0 +1,7 @@ +extern crate autocfg; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + let ac = autocfg::new(); + ac.emit_rustc_version(1, 26); +} diff --git a/third_party/rust/rand_pcg/src/lib.rs b/third_party/rust/rand_pcg/src/lib.rs new file mode 100644 index 000000000000..9648e85d2671 --- /dev/null +++ b/third_party/rust/rand_pcg/src/lib.rs @@ -0,0 +1,48 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The PCG random number generators. +//! +//! This is a native Rust implementation of a small selection of PCG generators. +//! The primary goal of this crate is simple, minimal, well-tested code; in +//! other words it is explicitly not a goal to re-implement all of PCG. +//! +//! This crate provides: +//! +//! - `Pcg32` aka `Lcg64Xsh32`, officially known as `pcg32`, a general +//! purpose RNG. This is a good choice on both 32-bit and 64-bit CPUs +//! (for 32-bit output). +//! - `Pcg64Mcg` aka `Mcg128Xsl64`, officially known as `mcg_xsl_rr_128_64`, +//! a general purpose RNG using 128-bit multiplications. This has poor +//! performance on 32-bit CPUs but is a good choice on 64-bit CPUs for +//! both 32-bit and 64-bit output. (Note: this RNG is only available using +//! Rust 1.26 or later.) +//! +//! Both of these use 16 bytes of state and 128-bit seeds, and are considered +//! value-stable (i.e. any change affecting the output given a fixed seed would +//! be considered a breaking change to the crate). + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://rust-random.github.io/rand/")] + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] + +#![no_std] + +pub extern crate rand_core; + +#[cfg(feature="serde1")] extern crate serde; +#[cfg(feature="serde1")] #[macro_use] extern crate serde_derive; + +mod pcg64; +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] mod pcg128; + +pub use self::pcg64::{Pcg32, Lcg64Xsh32}; +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] pub use self::pcg128::{Pcg64Mcg, Mcg128Xsl64}; diff --git a/third_party/rust/rand_pcg/src/pcg128.rs b/third_party/rust/rand_pcg/src/pcg128.rs new file mode 100644 index 000000000000..9aff506077e4 --- /dev/null +++ b/third_party/rust/rand_pcg/src/pcg128.rs @@ -0,0 +1,122 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2017 Paul Dicker. +// Copyright 2014-2017 Melissa O'Neill and PCG Project contributors +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! PCG random number generators + +// This is the default multiplier used by PCG for 64-bit state. +const MULTIPLIER: u128 = 0x2360_ED05_1FC6_5DA4_4385_DF64_9FCC_F645; + +use core::fmt; +use core::mem::transmute; +use rand_core::{RngCore, SeedableRng, Error, le}; + +/// A PCG random number generator (XSL 128/64 (MCG) variant). +/// +/// Permuted Congruential Generator with 128-bit state, internal Multiplicative +/// Congruential Generator, and 64-bit output via "xorshift low (bits), +/// random rotation" output function. +/// +/// This is a 128-bit MCG with the PCG-XSL-RR output function. +/// Note that compared to the standard `pcg64` (128-bit LCG with PCG-XSL-RR +/// output function), this RNG is faster, also has a long cycle, and still has +/// good performance on statistical tests. +/// +/// Note: this RNG is only available using Rust 1.26 or later. +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize,Deserialize))] +pub struct Mcg128Xsl64 { + state: u128, +} + +/// A friendly name for `Mcg128Xsl64`. +pub type Pcg64Mcg = Mcg128Xsl64; + +impl Mcg128Xsl64 { + /// Construct an instance compatible with PCG seed. + /// + /// Note that PCG specifies a default value for the parameter: + /// + /// - `state = 0xcafef00dd15ea5e5` + pub fn new(state: u128) -> Self { + // Force low bit to 1, as in C version (C++ uses `state | 3` instead). + Mcg128Xsl64 { state: state | 1 } + } +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for Mcg128Xsl64 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Mcg128Xsl64 {{}}") + } +} + +/// We use a single 126-bit seed to initialise the state and select a stream. +/// Two `seed` bits (lowest order of last byte) are ignored. +impl SeedableRng for Mcg128Xsl64 { + type Seed = [u8; 16]; + + fn from_seed(seed: Self::Seed) -> Self { + // Read as if a little-endian u128 value: + let mut seed_u64 = [0u64; 2]; + le::read_u64_into(&seed, &mut seed_u64); + let state = (seed_u64[0] as u128) | + (seed_u64[1] as u128) << 64; + Mcg128Xsl64::new(state) + } +} + +impl RngCore for Mcg128Xsl64 { + #[inline] + fn next_u32(&mut self) -> u32 { + self.next_u64() as u32 + } + + #[inline] + fn next_u64(&mut self) -> u64 { + // prepare the LCG for the next round + let state = self.state.wrapping_mul(MULTIPLIER); + self.state = state; + + // Output function XSL RR ("xorshift low (bits), random rotation") + // Constants are for 128-bit state, 64-bit output + const XSHIFT: u32 = 64; // (128 - 64 + 64) / 2 + const ROTATE: u32 = 122; // 128 - 6 + + let rot = (state >> ROTATE) as u32; + let xsl = ((state >> XSHIFT) as u64) ^ (state as u64); + xsl.rotate_right(rot) + } + + #[inline] + fn fill_bytes(&mut self, dest: &mut [u8]) { + // specialisation of impls::fill_bytes_via_next; approx 3x faster + let mut left = dest; + while left.len() >= 8 { + let (l, r) = {left}.split_at_mut(8); + left = r; + let chunk: [u8; 8] = unsafe { + transmute(self.next_u64().to_le()) + }; + l.copy_from_slice(&chunk); + } + let n = left.len(); + if n > 0 { + let chunk: [u8; 8] = unsafe { + transmute(self.next_u64().to_le()) + }; + left.copy_from_slice(&chunk[..n]); + } + } + + #[inline] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} diff --git a/third_party/rust/rand_pcg/src/pcg64.rs b/third_party/rust/rand_pcg/src/pcg64.rs new file mode 100644 index 000000000000..9177ec248818 --- /dev/null +++ b/third_party/rust/rand_pcg/src/pcg64.rs @@ -0,0 +1,141 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2017 Paul Dicker. +// Copyright 2014-2017 Melissa O'Neill and PCG Project contributors +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! PCG random number generators + +use core::fmt; +use core::mem::transmute; +use rand_core::{RngCore, SeedableRng, Error, le, impls}; + +// This is the default multiplier used by PCG for 64-bit state. +const MULTIPLIER: u64 = 6364136223846793005; + +/// A PCG random number generator (XSH RR 64/32 (LCG) variant). +/// +/// Permuted Congruential Generator with 64-bit state, internal Linear +/// Congruential Generator, and 32-bit output via "xorshift high (bits), +/// random rotation" output function. +/// +/// This is a 64-bit LCG with explicitly chosen stream with the PCG-XSH-RR +/// output function. This combination is the standard `pcg32`. +/// +/// Despite the name, this implementation uses 16 bytes (128 bit) space +/// comprising 64 bits of state and 64 bits stream selector. These are both set +/// by `SeedableRng`, using a 128-bit seed. +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize,Deserialize))] +pub struct Lcg64Xsh32 { + state: u64, + increment: u64, +} + +/// `Lcg64Xsh32` is also officially known as `pcg32`. +pub type Pcg32 = Lcg64Xsh32; + +impl Lcg64Xsh32 { + /// Construct an instance compatible with PCG seed and stream. + /// + /// Note that PCG specifies default values for both parameters: + /// + /// - `state = 0xcafef00dd15ea5e5` + /// - `stream = 721347520444481703` + pub fn new(state: u64, stream: u64) -> Self { + // The increment must be odd, hence we discard one bit: + let increment = (stream << 1) | 1; + Lcg64Xsh32::from_state_incr(state, increment) + } + + #[inline] + fn from_state_incr(state: u64, increment: u64) -> Self { + let mut pcg = Lcg64Xsh32 { state, increment }; + // Move away from inital value: + pcg.state = pcg.state.wrapping_add(pcg.increment); + pcg.step(); + pcg + } + + #[inline] + fn step(&mut self) { + // prepare the LCG for the next round + self.state = self.state + .wrapping_mul(MULTIPLIER) + .wrapping_add(self.increment); + } +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for Lcg64Xsh32 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Lcg64Xsh32 {{}}") + } +} + +/// We use a single 127-bit seed to initialise the state and select a stream. +/// One `seed` bit (lowest bit of `seed[8]`) is ignored. +impl SeedableRng for Lcg64Xsh32 { + type Seed = [u8; 16]; + + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_u64 = [0u64; 2]; + le::read_u64_into(&seed, &mut seed_u64); + + // The increment must be odd, hence we discard one bit: + Lcg64Xsh32::from_state_incr(seed_u64[0], seed_u64[1] | 1) + } +} + +impl RngCore for Lcg64Xsh32 { + #[inline] + fn next_u32(&mut self) -> u32 { + let state = self.state; + self.step(); + + // Output function XSH RR: xorshift high (bits), followed by a random rotate + // Constants are for 64-bit state, 32-bit output + const ROTATE: u32 = 59; // 64 - 5 + const XSHIFT: u32 = 18; // (5 + 32) / 2 + const SPARE: u32 = 27; // 64 - 32 - 5 + + let rot = (state >> ROTATE) as u32; + let xsh = (((state >> XSHIFT) ^ state) >> SPARE) as u32; + xsh.rotate_right(rot) + } + + #[inline] + fn next_u64(&mut self) -> u64 { + impls::next_u64_via_u32(self) + } + + #[inline] + fn fill_bytes(&mut self, dest: &mut [u8]) { + // specialisation of impls::fill_bytes_via_next; approx 40% faster + let mut left = dest; + while left.len() >= 4 { + let (l, r) = {left}.split_at_mut(4); + left = r; + let chunk: [u8; 4] = unsafe { + transmute(self.next_u32().to_le()) + }; + l.copy_from_slice(&chunk); + } + let n = left.len(); + if n > 0 { + let chunk: [u8; 4] = unsafe { + transmute(self.next_u32().to_le()) + }; + left.copy_from_slice(&chunk[..n]); + } + } + + #[inline] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} diff --git a/third_party/rust/rand_pcg/tests/lcg64xsh32.rs b/third_party/rust/rand_pcg/tests/lcg64xsh32.rs new file mode 100644 index 000000000000..775b12c99861 --- /dev/null +++ b/third_party/rust/rand_pcg/tests/lcg64xsh32.rs @@ -0,0 +1,58 @@ +extern crate rand_pcg; +extern crate rand_core; +#[cfg(all(feature="serde1", test))] extern crate bincode; + +use rand_core::{RngCore, SeedableRng}; +use rand_pcg::{Lcg64Xsh32, Pcg32}; + +#[test] +fn test_lcg64xsh32_construction() { + // Test that various construction techniques produce a working RNG. + let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16]; + let mut rng1 = Lcg64Xsh32::from_seed(seed); + assert_eq!(rng1.next_u64(), 1204678643940597513); + + let mut rng2 = Lcg64Xsh32::from_rng(&mut rng1).unwrap(); + assert_eq!(rng2.next_u64(), 12384929573776311845); + + let mut rng3 = Lcg64Xsh32::seed_from_u64(0); + assert_eq!(rng3.next_u64(), 18195738587432868099); + + // This is the same as Lcg64Xsh32, so we only have a single test: + let mut rng4 = Pcg32::seed_from_u64(0); + assert_eq!(rng4.next_u64(), 18195738587432868099); +} + +#[test] +fn test_lcg64xsh32_true_values() { + // Numbers copied from official test suite. + let mut rng = Lcg64Xsh32::new(42, 54); + + let mut results = [0u32; 6]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected: [u32; 6] = [0xa15c02b7, 0x7b47f409, 0xba1d3330, + 0x83d2f293, 0xbfa4784b, 0xcbed606e]; + assert_eq!(results, expected); +} + +#[cfg(feature="serde1")] +#[test] +fn test_lcg64xsh32_serde() { + use bincode; + use std::io::{BufWriter, BufReader}; + + let mut rng = Lcg64Xsh32::seed_from_u64(0); + + let buf: Vec = Vec::new(); + let mut buf = BufWriter::new(buf); + bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); + + let buf = buf.into_inner().unwrap(); + let mut read = BufReader::new(&buf[..]); + let mut deserialized: Lcg64Xsh32 = bincode::deserialize_from(&mut read) + .expect("Could not deserialize"); + + for _ in 0..16 { + assert_eq!(rng.next_u64(), deserialized.next_u64()); + } +} diff --git a/third_party/rust/rand_pcg/tests/mcg128xsl64.rs b/third_party/rust/rand_pcg/tests/mcg128xsl64.rs new file mode 100644 index 000000000000..3279536fcaa5 --- /dev/null +++ b/third_party/rust/rand_pcg/tests/mcg128xsl64.rs @@ -0,0 +1,59 @@ +#![cfg(rustc_1_26)] +extern crate rand_pcg; +extern crate rand_core; +#[cfg(all(feature="serde1", test))] extern crate bincode; + +use rand_core::{RngCore, SeedableRng}; +use rand_pcg::{Mcg128Xsl64, Pcg64Mcg}; + +#[test] +fn test_mcg128xsl64_construction() { + // Test that various construction techniques produce a working RNG. + let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16]; + let mut rng1 = Mcg128Xsl64::from_seed(seed); + assert_eq!(rng1.next_u64(), 7071994460355047496); + + let mut rng2 = Mcg128Xsl64::from_rng(&mut rng1).unwrap(); + assert_eq!(rng2.next_u64(), 12300796107712034932); + + let mut rng3 = Mcg128Xsl64::seed_from_u64(0); + assert_eq!(rng3.next_u64(), 6198063878555692194); + + // This is the same as Mcg128Xsl64, so we only have a single test: + let mut rng4 = Pcg64Mcg::seed_from_u64(0); + assert_eq!(rng4.next_u64(), 6198063878555692194); +} + +#[test] +fn test_mcg128xsl64_true_values() { + // Numbers copied from official test suite (C version). + let mut rng = Mcg128Xsl64::new(42); + + let mut results = [0u64; 6]; + for i in results.iter_mut() { *i = rng.next_u64(); } + let expected: [u64; 6] = [0x63b4a3a813ce700a, 0x382954200617ab24, + 0xa7fd85ae3fe950ce, 0xd715286aa2887737, 0x60c92fee2e59f32c, 0x84c4e96beff30017]; + assert_eq!(results, expected); +} + +#[cfg(feature="serde1")] +#[test] +fn test_mcg128xsl64_serde() { + use bincode; + use std::io::{BufWriter, BufReader}; + + let mut rng = Mcg128Xsl64::seed_from_u64(0); + + let buf: Vec = Vec::new(); + let mut buf = BufWriter::new(buf); + bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); + + let buf = buf.into_inner().unwrap(); + let mut read = BufReader::new(&buf[..]); + let mut deserialized: Mcg128Xsl64 = bincode::deserialize_from(&mut read) + .expect("Could not deserialize"); + + for _ in 0..16 { + assert_eq!(rng.next_u64(), deserialized.next_u64()); + } +} diff --git a/third_party/rust/rand_xorshift/.cargo-checksum.json b/third_party/rust/rand_xorshift/.cargo-checksum.json new file mode 100644 index 000000000000..ce75b59711be --- /dev/null +++ b/third_party/rust/rand_xorshift/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"8b36d20dea31334f1dabb3c4ef2c5d4f373432e5fc4f16ea247f0c8550f21e1a","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.toml":"3fdcb1949fd24244fb3e608a0bb950f3466799207f6f93759addc26fa89cea68","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"d15ff53ca6f8a7d4791343836e29fe86ce7528029a05f9f327064aaaa01a5368","src/lib.rs":"642ec47c3419708550926cc03f26ca4915e6471dd796d1f1e83b675fb5633649","tests/mod.rs":"533eb0d703ff6154c21d9655c863223e79f81da026dc4abf79c24d2705ae3813"},"package":"cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"} \ No newline at end of file diff --git a/third_party/rust/rand_xorshift/CHANGELOG.md b/third_party/rust/rand_xorshift/CHANGELOG.md new file mode 100644 index 000000000000..539af41313bd --- /dev/null +++ b/third_party/rust/rand_xorshift/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.1.1] - 2019-01-04 +- Reorganise code and tests; tweak doc + +## [0.1.0] - 2018-07-16 +- Pulled out of the Rand crate diff --git a/third_party/rust/rand_xorshift/COPYRIGHT b/third_party/rust/rand_xorshift/COPYRIGHT new file mode 100644 index 000000000000..468d907caf99 --- /dev/null +++ b/third_party/rust/rand_xorshift/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 or + or the MIT license + or , at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/third_party/rust/rand_xorshift/Cargo.toml b/third_party/rust/rand_xorshift/Cargo.toml new file mode 100644 index 000000000000..26aa48129e20 --- /dev/null +++ b/third_party/rust/rand_xorshift/Cargo.toml @@ -0,0 +1,45 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand_xorshift" +version = "0.1.1" +authors = ["The Rand Project Developers", "The Rust Project Developers"] +description = "Xorshift random number generator\n" +homepage = "https://crates.io/crates/rand_xorshift" +documentation = "https://rust-random.github.io/rand/rand_xorshift" +readme = "README.md" +keywords = ["random", "rng", "xorshift"] +categories = ["algorithms", "no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-random/rand" +[dependencies.rand_core] +version = ">=0.2, <0.4" +default-features = false + +[dependencies.serde] +version = "1" +optional = true + +[dependencies.serde_derive] +version = "^1.0.38" +optional = true +[dev-dependencies.bincode] +version = "1" + +[features] +serde1 = ["serde", "serde_derive"] +[badges.appveyor] +repository = "rust-random/rand" + +[badges.travis-ci] +repository = "rust-random/rand" diff --git a/third_party/rust/rand_xorshift/LICENSE-APACHE b/third_party/rust/rand_xorshift/LICENSE-APACHE new file mode 100644 index 000000000000..17d74680f8cf --- /dev/null +++ b/third_party/rust/rand_xorshift/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/rand_xorshift/LICENSE-MIT b/third_party/rust/rand_xorshift/LICENSE-MIT new file mode 100644 index 000000000000..d93b5baf341d --- /dev/null +++ b/third_party/rust/rand_xorshift/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright 2018 Developers of the Rand project +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/rand_xorshift/README.md b/third_party/rust/rand_xorshift/README.md new file mode 100644 index 000000000000..573ee1231dc3 --- /dev/null +++ b/third_party/rust/rand_xorshift/README.md @@ -0,0 +1,45 @@ +# rand_xorshift + +[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Latest version](https://img.shields.io/crates/v/rand_xorshift.svg)](https://crates.io/crates/rand_xorshift) +[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) +[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_xorshift) +[![API](https://docs.rs/rand_xorshift/badge.svg)](https://docs.rs/rand_xorshift) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) + +Implements the Xorshift random number generator. + +The Xorshift[^1] algorithm is not suitable for cryptographic purposes +but is very fast. If you do not know for sure that it fits your +requirements, use a more secure one such as `StdRng` or `OsRng`. + +[^1]: Marsaglia, George (July 2003). + ["Xorshift RNGs"](https://www.jstatsoft.org/v08/i14/paper). + *Journal of Statistical Software*. Vol. 8 (Issue 14). + +Links: + +- [API documentation (master)](https://rust-random.github.io/rand/rand_xorshift) +- [API documentation (docs.rs)](https://docs.rs/rand_xorshift) +- [Changelog](CHANGELOG.md) + +[rand]: https://crates.io/crates/rand + + +## Crate Features + +`rand_xorshift` is `no_std` compatible. It does not require any functionality +outside of the `core` lib, thus there are no features to configure. + +The `serde1` feature includes implementations of `Serialize` and `Deserialize` +for the included RNGs. + + +## License + +`rand_xorshift` is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/third_party/rust/rand_xorshift/src/lib.rs b/third_party/rust/rand_xorshift/src/lib.rs new file mode 100644 index 000000000000..aad74e49f620 --- /dev/null +++ b/third_party/rust/rand_xorshift/src/lib.rs @@ -0,0 +1,123 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The xorshift random number generator. + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://rust-random.github.io/rand/")] + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] + +#![no_std] + +extern crate rand_core; + +#[cfg(feature="serde1")] extern crate serde; +#[cfg(feature="serde1")] #[macro_use] extern crate serde_derive; + +use core::num::Wrapping as w; +use core::{fmt, slice}; +use rand_core::{RngCore, SeedableRng, Error, impls, le}; + +/// An Xorshift random number generator. +/// +/// The Xorshift[^1] algorithm is not suitable for cryptographic purposes +/// but is very fast. If you do not know for sure that it fits your +/// requirements, use a more secure one such as `StdRng` or `OsRng`. +/// +/// [^1]: Marsaglia, George (July 2003). +/// ["Xorshift RNGs"](https://www.jstatsoft.org/v08/i14/paper). +/// *Journal of Statistical Software*. Vol. 8 (Issue 14). +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize,Deserialize))] +pub struct XorShiftRng { + x: w, + y: w, + z: w, + w: w, +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for XorShiftRng { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "XorShiftRng {{}}") + } +} + +impl RngCore for XorShiftRng { + #[inline] + fn next_u32(&mut self) -> u32 { + let x = self.x; + let t = x ^ (x << 11); + self.x = self.y; + self.y = self.z; + self.z = self.w; + let w_ = self.w; + self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8)); + self.w.0 + } + + #[inline] + fn next_u64(&mut self) -> u64 { + impls::next_u64_via_u32(self) + } + + #[inline] + fn fill_bytes(&mut self, dest: &mut [u8]) { + impls::fill_bytes_via_next(self, dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} + +impl SeedableRng for XorShiftRng { + type Seed = [u8; 16]; + + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_u32 = [0u32; 4]; + le::read_u32_into(&seed, &mut seed_u32); + + // Xorshift cannot be seeded with 0 and we cannot return an Error, but + // also do not wish to panic (because a random seed can legitimately be + // 0); our only option is therefore to use a preset value. + if seed_u32.iter().all(|&x| x == 0) { + seed_u32 = [0xBAD_5EED, 0xBAD_5EED, 0xBAD_5EED, 0xBAD_5EED]; + } + + XorShiftRng { + x: w(seed_u32[0]), + y: w(seed_u32[1]), + z: w(seed_u32[2]), + w: w(seed_u32[3]), + } + } + + fn from_rng(mut rng: R) -> Result { + let mut seed_u32 = [0u32; 4]; + loop { + unsafe { + let ptr = seed_u32.as_mut_ptr() as *mut u8; + + let slice = slice::from_raw_parts_mut(ptr, 4 * 4); + rng.try_fill_bytes(slice)?; + } + if !seed_u32.iter().all(|&x| x == 0) { break; } + } + + Ok(XorShiftRng { + x: w(seed_u32[0]), + y: w(seed_u32[1]), + z: w(seed_u32[2]), + w: w(seed_u32[3]), + }) + } +} diff --git a/third_party/rust/rand_xorshift/tests/mod.rs b/third_party/rust/rand_xorshift/tests/mod.rs new file mode 100644 index 000000000000..8374b64104af --- /dev/null +++ b/third_party/rust/rand_xorshift/tests/mod.rs @@ -0,0 +1,92 @@ +extern crate rand_core; +extern crate rand_xorshift; +#[cfg(all(feature="serde1", test))] extern crate bincode; + +use rand_core::{RngCore, SeedableRng}; +use rand_xorshift::XorShiftRng; + +#[test] +fn test_xorshift_construction() { + // Test that various construction techniques produce a working RNG. + let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16]; + let mut rng1 = XorShiftRng::from_seed(seed); + assert_eq!(rng1.next_u64(), 4325440999699518727); + + let _rng2 = XorShiftRng::from_rng(rng1).unwrap(); + // Note: we cannot test the state of _rng2 because from_rng does not + // fix Endianness. This is allowed in the trait specification. +} + +#[test] +fn test_xorshift_true_values() { + let seed = [16,15,14,13, 12,11,10,9, 8,7,6,5, 4,3,2,1]; + let mut rng = XorShiftRng::from_seed(seed); + + let mut results = [0u32; 9]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected: [u32; 9] = [ + 2081028795, 620940381, 269070770, 16943764, 854422573, 29242889, + 1550291885, 1227154591, 271695242]; + assert_eq!(results, expected); + + let mut results = [0u64; 9]; + for i in results.iter_mut() { *i = rng.next_u64(); } + let expected: [u64; 9] = [ + 9247529084182843387, 8321512596129439293, 14104136531997710878, + 6848554330849612046, 343577296533772213, 17828467390962600268, + 9847333257685787782, 7717352744383350108, 1133407547287910111]; + assert_eq!(results, expected); + + let mut results = [0u8; 32]; + rng.fill_bytes(&mut results); + let expected = [102, 57, 212, 16, 233, 130, 49, 183, + 158, 187, 44, 203, 63, 149, 45, 17, + 117, 129, 131, 160, 70, 121, 158, 155, + 224, 209, 192, 53, 10, 62, 57, 72]; + assert_eq!(results, expected); +} + +#[test] +fn test_xorshift_zero_seed() { + // Xorshift does not work with an all zero seed. + // Assert it does not panic. + let seed = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng = XorShiftRng::from_seed(seed); + let a = rng.next_u64(); + let b = rng.next_u64(); + assert!(a != 0); + assert!(b != a); +} + +#[test] +fn test_xorshift_clone() { + let seed = [1,2,3,4, 5,5,7,8, 8,7,6,5, 4,3,2,1]; + let mut rng1 = XorShiftRng::from_seed(seed); + let mut rng2 = rng1.clone(); + for _ in 0..16 { + assert_eq!(rng1.next_u64(), rng2.next_u64()); + } +} + +#[cfg(feature="serde1")] +#[test] +fn test_xorshift_serde() { + use bincode; + use std::io::{BufWriter, BufReader}; + + let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16]; + let mut rng = XorShiftRng::from_seed(seed); + + let buf: Vec = Vec::new(); + let mut buf = BufWriter::new(buf); + bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); + + let buf = buf.into_inner().unwrap(); + let mut read = BufReader::new(&buf[..]); + let mut deserialized: XorShiftRng = bincode::deserialize_from(&mut read) + .expect("Could not deserialize"); + + for _ in 0..16 { + assert_eq!(rng.next_u64(), deserialized.next_u64()); + } +} diff --git a/third_party/rust/rdrand/.cargo-checksum.json b/third_party/rust/rdrand/.cargo-checksum.json new file mode 100644 index 000000000000..c7b5a11ac8cb --- /dev/null +++ b/third_party/rust/rdrand/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"f11ed31fc1b481c7d0e24251d7d60d34442f1d25747c887c49dc9fbad7e13e59","LICENSE":"00d7b0c8bf95ea93162fccc84da96b906b15add708eade04f7ee6141f7b53141","README.mkd":"93853e9e773543ed0d0cf696b5fb151b15bddc1ad9c39996c9eb11b20a3c7ff6","appveyor.yml":"f502d8a0755b98e904a40b07e8ba270bccd729045b03c24a7db0dfbb4047b515","benches/rdrand.rs":"f3684c360d43bc8a780868c0a3af43b20d56975e03575122cee87277787cc8d0","benches/rdseed.rs":"520097b15a3f11c0c6a357e6cd23add598be22f37839bbc71040b827b05d1064","benches/std.rs":"6a5b52b070b2a594e735aa617f16fc6a861e64534634cdb61801c3297444f6fe","src/changelog.rs":"644e08c06836ecdf94f9a43aec109e9f05f9d85f00541683c72d0d3893ff8d6a","src/lib.rs":"8fc306db8a304d24c28fcefaec1849c0d8bbca97417420af7b81449c352b2e92"},"package":"678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"} \ No newline at end of file diff --git a/third_party/rust/rdrand/Cargo.toml b/third_party/rust/rdrand/Cargo.toml new file mode 100644 index 000000000000..6b3c80a872b9 --- /dev/null +++ b/third_party/rust/rdrand/Cargo.toml @@ -0,0 +1,28 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rdrand" +version = "0.4.0" +authors = ["Simonas Kazlauskas "] +description = "An implementation of random number generator based on rdrand and rdseed instructions" +documentation = "https://docs.rs/rdrand/0.4.0/" +keywords = ["rand", "rdrand", "rdseed", "random"] +license = "ISC" +repository = "https://github.com/nagisa/rust_rdrand/" +[dependencies.rand_core] +version = "0.3" +default-features = false + +[features] +default = ["std"] +std = [] diff --git a/third_party/rust/rdrand/LICENSE b/third_party/rust/rdrand/LICENSE new file mode 100644 index 000000000000..4d6f40d43b67 --- /dev/null +++ b/third_party/rust/rdrand/LICENSE @@ -0,0 +1,12 @@ +Copyright © 2014, Simonas Kazlauskas + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without +fee is hereby granted, provided that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. diff --git a/third_party/rust/rdrand/README.mkd b/third_party/rust/rdrand/README.mkd new file mode 100644 index 000000000000..55ab48b8e976 --- /dev/null +++ b/third_party/rust/rdrand/README.mkd @@ -0,0 +1,8 @@ +An implementation of random number generators based on `rdrand` and `rdseed` instructions. + +The random number generators provided by this crate are fairly slow (the latency for these +instructions is pretty high), but provide high quality random bits. Caveat is: neither AMD’s +nor Intel’s designs are public and therefore are not verifiable for lack of backdoors. + +Unless you know what you are doing, use the random number generators provided by the `rand` +crate (such as `EntropyRng`) instead. diff --git a/third_party/rust/rdrand/appveyor.yml b/third_party/rust/rdrand/appveyor.yml new file mode 100644 index 000000000000..2e915cf4f9e1 --- /dev/null +++ b/third_party/rust/rdrand/appveyor.yml @@ -0,0 +1,27 @@ +environment: + matrix: + - TARGET: 1.30.0-x86_64-pc-windows-msvc + - TARGET: 1.30.0-i686-pc-windows-msvc + - TARGET: 1.30.0-x86_64-pc-windows-gnu + - TARGET: 1.30.0-i686-pc-windows-gnu + - TARGET: nightly-x86_64-pc-windows-msvc + - TARGET: nightly-i686-pc-windows-msvc +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:TARGET}.exe" -FileName "rust.exe" + - ps: .\rust.exe /VERYSILENT /NORESTART /DIR="C:\rust" | Out-Null + - ps: $env:PATH="$env:PATH;C:\rust\bin" + - rustc -vV + - cargo -vV +build: off + +test_script: +- cargo test +- cargo test --no-default-features + +for: +- matrix: + only: + - TARGET: nightly-x86_64-pc-windows-msvc + - TARGET: nightly-i686-pc-windows-msvc + test_script: + - cargo bench diff --git a/third_party/rust/rdrand/benches/rdrand.rs b/third_party/rust/rdrand/benches/rdrand.rs new file mode 100644 index 000000000000..7e70c233e530 --- /dev/null +++ b/third_party/rust/rdrand/benches/rdrand.rs @@ -0,0 +1,49 @@ +#![feature(test)] +extern crate rand_core; +extern crate rdrand; +extern crate test; + +use rand_core::RngCore; +use test::Bencher; + +#[bench] +fn bench_u16(b : &mut Bencher) { + if let Ok(gen) = rdrand::RdRand::new() { + b.bytes = 2; + b.iter(|| { + gen.try_next_u16().unwrap() + }); + } +} + +#[bench] +fn bench_u32(b : &mut Bencher) { + if let Ok(mut gen) = rdrand::RdRand::new() { + b.bytes = 4; + b.iter(|| { + gen.next_u32() + }); + } +} + +#[bench] +fn bench_u64(b : &mut Bencher) { + if let Ok(mut gen) = rdrand::RdRand::new() { + b.bytes = 8; + b.iter(|| { + gen.next_u64() + }); + } +} + +#[bench] +fn bench_fill(b : &mut Bencher) { + if let Ok(mut gen) = rdrand::RdRand::new() { + let mut buffer = [0; 128]; + b.bytes = 128; + b.iter(|| { + gen.fill_bytes(&mut buffer); + buffer + }); + } +} diff --git a/third_party/rust/rdrand/benches/rdseed.rs b/third_party/rust/rdrand/benches/rdseed.rs new file mode 100644 index 000000000000..6bf8cebf9b05 --- /dev/null +++ b/third_party/rust/rdrand/benches/rdseed.rs @@ -0,0 +1,49 @@ +#![feature(test)] +extern crate rand_core; +extern crate rdrand; +extern crate test; + +use rand_core::RngCore; +use test::Bencher; + +#[bench] +fn bench_rdseed_u16(b : &mut Bencher) { + if let Ok(gen) = rdrand::RdSeed::new() { + b.bytes = 2; + b.iter(|| { + gen.try_next_u16().unwrap() + }); + } +} + +#[bench] +fn bench_rdseed_u32(b : &mut Bencher) { + if let Ok(mut gen) = rdrand::RdSeed::new() { + b.bytes = 4; + b.iter(|| { + gen.next_u32() + }); + } +} + +#[bench] +fn bench_rdseed_u64(b : &mut Bencher) { + if let Ok(mut gen) = rdrand::RdSeed::new() { + b.bytes = 8; + b.iter(|| { + gen.next_u64() + }); + } +} + +#[bench] +fn bench_fill(b : &mut Bencher) { + if let Ok(mut gen) = rdrand::RdSeed::new() { + let mut buffer = [0; 128]; + b.bytes = 128; + b.iter(|| { + gen.fill_bytes(&mut buffer); + buffer + }); + } +} diff --git a/third_party/rust/rdrand/benches/std.rs b/third_party/rust/rdrand/benches/std.rs new file mode 100644 index 000000000000..3fa8fadd952d --- /dev/null +++ b/third_party/rust/rdrand/benches/std.rs @@ -0,0 +1,31 @@ +// #![feature(test)] +// extern crate rand; +// extern crate test; +// +// use test::Bencher; +// use test::black_box; +// use rand::Rng; +// use rand::StdRng; +// use rand::OsRng; +// +// // OsRng is supposed to be the default for crypto uses. +// #[bench] +// fn bench_osrng_u64(b : &mut Bencher) { +// if let Ok(mut gen) = OsRng::new() { +// b.bytes = 8; +// b.iter(|| { +// black_box(gen.next_u64()); +// }); +// } +// } +// +// // StdRng is the default for everything else. +// #[bench] +// fn bench_stdrng_u64(b : &mut Bencher) { +// if let Ok(mut gen) = StdRng::new() { +// b.bytes = 8; +// b.iter(|| { +// gen.next_u64(); +// }); +// } +// } diff --git a/third_party/rust/rdrand/src/changelog.rs b/third_party/rust/rdrand/src/changelog.rs new file mode 100644 index 000000000000..503f738106a2 --- /dev/null +++ b/third_party/rust/rdrand/src/changelog.rs @@ -0,0 +1,25 @@ +//! Project changelog + +/// ## Breaking changes +/// +/// Crate gained an enabled-by-default `std` feature. If you relied on rdrand being `core`-able +/// change your dependency to appear as such: +/// +/// ```toml +/// rdrand = { version = "0.4", default-features = false } +/// ``` +/// +/// This is done so that an advantage of the common feature detection functionality could be +/// employed by users that are not constrained by `core`. This functionality is faster, caches the +/// results and is shared between all users of the functionality. +/// +/// For `core` usage the feature detection has also been improved and will not be done if e.g. +/// crate is built with `rdrand` instructions enabled globally. +pub mod r0_4_0 {} + +/// Crate now works on stable! +/// +/// ## Breaking changes +/// +/// * Updated to `rand_core = ^0.3`. +pub mod r0_3_0 {} diff --git a/third_party/rust/rdrand/src/lib.rs b/third_party/rust/rdrand/src/lib.rs new file mode 100644 index 000000000000..423ae2139b22 --- /dev/null +++ b/third_party/rust/rdrand/src/lib.rs @@ -0,0 +1,472 @@ +// Copyright © 2014, Simonas Kazlauskas +// +// Permission to use, copy, modify, and/or distribute this software for any purpose with or without +// fee is hereby granted, provided that the above copyright notice and this permission notice +// appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +// SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +// NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +// OF THIS SOFTWARE. +//! An implementation of random number generators based on `rdrand` and `rdseed` instructions. +//! +//! The random number generators provided by this crate are fairly slow (the latency for these +//! instructions is pretty high), but provide high quality random bits. Caveat is: neither AMD’s +//! nor Intel’s designs are public and therefore are not verifiable for lack of backdoors. +//! +//! Unless you know what you are doing, use the random number generators provided by the `rand` +//! crate (such as `OsRng`) instead. +//! +//! Here are a measurements for select processor architectures. Check [Agner’s instruction tables] +//! for up-to-date listings. +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//! +//!
ArchitectureLatency (cycles)Maximum throughput (per core)
u16u32u64
AMD Ryzen~1200~1200~2500~12MB/s @ 3.7GHz
Intel Skylake460460460~72MB/s @ 4.2GHz
Intel Haswell320320320~110MB/s @ 4.4GHz
+//! +//! [Agner’s instruction tables]: http://agner.org/optimize/ +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate rand_core; + +#[cfg(feature = "std")] +extern crate core; + +pub mod changelog; + +use rand_core::{RngCore, CryptoRng, Error, ErrorKind}; +use core::slice; + +const RETRY_LIMIT: u8 = 127; + +#[cold] +#[inline(never)] +pub(crate) fn busy_loop_fail() -> ! { + panic!("hardware generator failure"); +} + +/// A cryptographically secure statistically uniform, non-periodic and non-deterministic random bit +/// generator. +/// +/// Note that this generator may be implemented using a deterministic algorithm that is reseeded +/// routinely from a non-deterministic entropy source to achieve the desirable properties. +/// +/// This generator is a viable replacement to any generator, however, since nobody has audited +/// Intel or AMD hardware yet, the usual disclaimers as to their suitability apply. +/// +/// It is potentially faster than `OsRng`, but is only supported on more recent Intel (Ivy Bridge +/// and later) and AMD (Ryzen and later) processors. +#[derive(Clone, Copy)] +pub struct RdRand(()); + +/// A cryptographically secure non-deterministic random bit generator. +/// +/// This generator produces high-entropy output and is suited to seed other pseudo-random +/// generators. +/// +/// This instruction currently is only available in Intel Broadwell (and later) and AMD Ryzen +/// processors. +/// +/// This generator is not intended for general random number generation purposes and should be used +/// to seed other generators implementing [rand_core::SeedableRng]. +#[derive(Clone, Copy)] +pub struct RdSeed(()); + +impl CryptoRng for RdRand {} +impl CryptoRng for RdSeed {} + +mod arch { + #[cfg(target_arch = "x86_64")] + pub use core::arch::x86_64::*; + #[cfg(target_arch = "x86")] + pub use core::arch::x86::*; + + #[cfg(target_arch = "x86")] + pub(crate) unsafe fn _rdrand64_step(dest: &mut u64) -> i32 { + let mut ret1: u32 = ::core::mem::uninitialized(); + let mut ret2: u32 = ::core::mem::uninitialized(); + if _rdrand32_step(&mut ret1) != 0 && _rdrand32_step(&mut ret2) != 0 { + *dest = (ret1 as u64) << 32 | (ret2 as u64); + 1 + } else { + 0 + } + } + + #[cfg(target_arch = "x86")] + pub(crate) unsafe fn _rdseed64_step(dest: &mut u64) -> i32 { + let mut ret1: u32 = ::core::mem::uninitialized(); + let mut ret2: u32 = ::core::mem::uninitialized(); + if _rdseed32_step(&mut ret1) != 0 && _rdseed32_step(&mut ret2) != 0 { + *dest = (ret1 as u64) << 32 | (ret2 as u64); + 1 + } else { + 0 + } + } +} + +#[cfg(not(feature = "std"))] +macro_rules! is_x86_feature_detected { + ("rdrand") => {{ + if cfg!(target_feature="rdrand") { + true + } else if cfg!(target_env = "sgx") { + false + } else { + const FLAG : u32 = 1 << 30; + unsafe { ::arch::__cpuid(1).ecx & FLAG == FLAG } + } + }}; + ("rdseed") => {{ + if cfg!(target_feature = "rdseed") { + true + } else if cfg!(target_env = "sgx") { + false + } else { + const FLAG : u32 = 1 << 18; + unsafe { ::arch::__cpuid(7).ebx & FLAG == FLAG } + } + }}; +} + +macro_rules! loop_rand { + ($el: ty, $step: path) => { { + let mut idx = 0; + loop { + let mut el: $el = ::core::mem::uninitialized(); + if $step(&mut el) != 0 { + break Some(el); + } else if idx == RETRY_LIMIT { + break None; + } + idx += 1; + } + } } +} + +macro_rules! impl_rand { + ($gen:ident, $feat:tt, $step16: path, $step32:path, $step64:path, + maxstep = $maxstep:path, maxty = $maxty: ty) => { + impl $gen { + /// Create a new instance of the random number generator. + /// + /// This constructor checks whether the CPU the program is running on supports the + /// instruction necessary for this generator to operate. If the instruction is not + /// supported, an error is returned. + pub fn new() -> Result { + if is_x86_feature_detected!($feat) { + Ok($gen(())) + } else { + Err(Error::new(rand_core::ErrorKind::Unavailable, + "the instruction is not supported")) + } + } + + /// Generate a single random `u16` value. + /// + /// The underlying instruction may fail for variety reasons (such as actual hardware + /// failure or exhausted entropy), however the exact reason for the failure is not + /// usually exposed. + /// + /// This method will retry calling the instruction a few times, however if all the + /// attempts fail, it will return `None`. + /// + /// In case `None` is returned, the caller should assume that an non-recoverable + /// hardware failure has occured and use another random number genrator instead. + #[inline(always)] + pub fn try_next_u16(&self) -> Option { + #[target_feature(enable = $feat)] + unsafe fn imp() + -> Option { + loop_rand!(u16, $step16) + } + unsafe { imp() } + } + + /// Generate a single random `u32` value. + /// + /// The underlying instruction may fail for variety reasons (such as actual hardware + /// failure or exhausted entropy), however the exact reason for the failure is not + /// usually exposed. + /// + /// This method will retry calling the instruction a few times, however if all the + /// attempts fail, it will return `None`. + /// + /// In case `None` is returned, the caller should assume that an non-recoverable + /// hardware failure has occured and use another random number genrator instead. + #[inline(always)] + pub fn try_next_u32(&self) -> Option { + #[target_feature(enable = $feat)] + unsafe fn imp() + -> Option { + loop_rand!(u32, $step32) + } + unsafe { imp() } + } + + /// Generate a single random `u64` value. + /// + /// The underlying instruction may fail for variety reasons (such as actual hardware + /// failure or exhausted entropy), however the exact reason for the failure is not + /// usually exposed. + /// + /// This method will retry calling the instruction a few times, however if all the + /// attempts fail, it will return `None`. + /// + /// In case `None` is returned, the caller should assume that an non-recoverable + /// hardware failure has occured and use another random number genrator instead. + /// + /// Note, that on 32-bit targets, there’s no underlying instruction to generate a + /// 64-bit number, so it is emulated with the 32-bit version of the instruction. + #[inline(always)] + pub fn try_next_u64(&self) -> Option { + #[target_feature(enable = $feat)] + unsafe fn imp() + -> Option { + loop_rand!(u64, $step64) + } + unsafe { imp() } + } + } + + impl RngCore for $gen { + /// Generate a single random `u32` value. + /// + /// The underlying instruction may fail for variety reasons (such as actual hardware + /// failure or exhausted entropy), however the exact reason for the failure is not + /// usually exposed. + /// + /// # Panic + /// + /// This method will retry calling the instruction a few times, however if all the + /// attempts fail, it will `panic`. + /// + /// In case `panic` occurs, the caller should assume that an non-recoverable + /// hardware failure has occured and use another random number genrator instead. + #[inline(always)] + fn next_u32(&mut self) -> u32 { + if let Some(result) = self.try_next_u32() { + result + } else { + busy_loop_fail() + } + } + + /// Generate a single random `u64` value. + /// + /// The underlying instruction may fail for variety reasons (such as actual hardware + /// failure or exhausted entropy), however the exact reason for the failure is not + /// usually exposed. + /// + /// Note, that on 32-bit targets, there’s no underlying instruction to generate a + /// 64-bit number, so it is emulated with the 32-bit version of the instruction. + /// + /// # Panic + /// + /// This method will retry calling the instruction a few times, however if all the + /// attempts fail, it will `panic`. + /// + /// In case `panic` occurs, the caller should assume that an non-recoverable + /// hardware failure has occured and use another random number genrator instead. + #[inline(always)] + fn next_u64(&mut self) -> u64 { + if let Some(result) = self.try_next_u64() { + result + } else { + busy_loop_fail() + } + } + + /// Fill a buffer `dest` with random data. + /// + /// See `try_fill_bytes` for a more extensive documentation. + /// + /// # Panic + /// + /// This method will panic any time `try_fill_bytes` would return an error. + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + if let Err(_) = self.try_fill_bytes(dest) { + busy_loop_fail() + } + } + + /// Fill a buffer `dest` with random data. + /// + /// This method will use the most appropriate variant of the instruction available on + /// the machine to achieve the greatest single-core throughput, however it has a + /// slightly higher setup cost than the plain `next_u32` or `next_u64` methods. + /// + /// The underlying instruction may fail for variety reasons (such as actual hardware + /// failure or exhausted entropy), however the exact reason for the failure is not + /// usually exposed. + /// + /// This method will retry calling the instruction a few times, however if all the + /// attempts fail, it will return an error. + /// + /// If an error is returned, the caller should assume that an non-recoverable hardware + /// failure has occured and use another random number genrator instead. + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) + -> Result<(), Error> { + #[target_feature(enable = $feat)] + unsafe fn imp(dest: &mut [u8]) + -> Result<(), Error> + { + unsafe fn imp_less_fast(mut dest: &mut [u8], word: &mut $maxty, + buffer: &mut &[u8]) + -> Result<(), Error> + { + while !dest.is_empty() { + if buffer.is_empty() { + if let Some(w) = loop_rand!($maxty, $maxstep) { + *word = w; + *buffer = slice::from_raw_parts( + word as *const _ as *const u8, + ::core::mem::size_of::<$maxty>() + ); + } else { + return Err(Error::new(ErrorKind::Unexpected, + "hardware generator failure")); + } + } + + let len = dest.len().min(buffer.len()); + let (copy_src, leftover) = buffer.split_at(len); + let (copy_dest, dest_leftover) = { dest }.split_at_mut(len); + *buffer = leftover; + dest = dest_leftover; + ::core::ptr::copy_nonoverlapping( + copy_src.as_ptr(), copy_dest.as_mut_ptr(), len + ); + } + Ok(()) + } + + let destlen = dest.len(); + if destlen > ::core::mem::size_of::<$maxty>() { + let (left, mid, right) = dest.align_to_mut(); + let mut word = 0; + let mut buffer: &[u8] = &[]; + + for el in mid { + if let Some(val) = loop_rand!($maxty, $maxstep) { + *el = val; + } else { + return Err(Error::new(ErrorKind::Unexpected, + "hardware generator failure")); + } + } + + imp_less_fast(left, &mut word, &mut buffer)?; + imp_less_fast(right, &mut word, &mut buffer) + } else { + let mut word = 0; + let mut buffer: &[u8] = &[]; + imp_less_fast(dest, &mut word, &mut buffer) + } + } + unsafe { imp(dest) } + } + } + } +} + +#[cfg(target_arch = "x86_64")] +impl_rand!(RdRand, "rdrand", + ::arch::_rdrand16_step, ::arch::_rdrand32_step, ::arch::_rdrand64_step, + maxstep = ::arch::_rdrand64_step, maxty = u64); +#[cfg(target_arch = "x86_64")] +impl_rand!(RdSeed, "rdseed", + ::arch::_rdseed16_step, ::arch::_rdseed32_step, ::arch::_rdseed64_step, + maxstep = ::arch::_rdseed64_step, maxty = u64); +#[cfg(target_arch = "x86")] +impl_rand!(RdRand, "rdrand", + ::arch::_rdrand16_step, ::arch::_rdrand32_step, ::arch::_rdrand64_step, + maxstep = ::arch::_rdrand32_step, maxty = u32); +#[cfg(target_arch = "x86")] +impl_rand!(RdSeed, "rdseed", + ::arch::_rdseed16_step, ::arch::_rdseed32_step, ::arch::_rdseed64_step, + maxstep = ::arch::_rdseed32_step, maxty = u32); + +#[test] +fn rdrand_works() { + let _ = RdRand::new().map(|mut r| { + r.next_u32(); + r.next_u64(); + }); +} + +#[test] +fn fill_fills_all_bytes() { + let _ = RdRand::new().map(|mut r| { + let mut peach; + let mut banana; + let mut start = 0; + let mut end = 128; + 'outer: while start < end { + banana = [0; 128]; + for _ in 0..512 { + peach = [0; 128]; + r.fill_bytes(&mut peach[start..end]); + for (b, p) in banana.iter_mut().zip(peach.iter()) { + *b = *b | *p; + } + if (&banana[start..end]).iter().all(|x| *x != 0) { + assert!(banana[..start].iter().all(|x| *x == 0), "all other values must be 0"); + assert!(banana[end..].iter().all(|x| *x == 0), "all other values must be 0"); + if start < 17 { + start += 1; + } else { + end -= 3; + } + continue 'outer; + } + } + panic!("wow, we broke it? {} {} {:?}", start, end, &banana[..]) + } + }); +} + +#[test] +fn rdseed_works() { + let _ = RdSeed::new().map(|mut r| { + r.next_u32(); + r.next_u64(); + }); +} diff --git a/third_party/rust/sha-1/.cargo-checksum.json b/third_party/rust/sha-1/.cargo-checksum.json new file mode 100644 index 000000000000..91d5ce5930da --- /dev/null +++ b/third_party/rust/sha-1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"28ae6963bea0184292792e08970420b1bcae9372d1f74df02e5522c295ad9a58","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"b4eb00df6e2a4d22518fcaa6a2b4646f249b3a3c9814509b22bd2091f1392ff1","benches/lib.rs":"a37a0e99c673a3049d4ffa229eb1b3e1a3006f611a76b881f12440fcb075c361","examples/sha1sum.rs":"3b52d8ba4cc4271d3111b5cb578095761eab7ded2fede3c498d11eaf68a120b8","src/consts.rs":"2cffe9241961386df327c7e1e8c852498b2f897e0a7d6db173c2d684b30b5672","src/lib.rs":"d09ef0953c78d45dde4bfa061f8b59838b6e0372d0cf7a1cccac1a1f6922a561","src/utils.rs":"a38e6d9df1994357f292c846e9fce3026bc02374fae8cbca18b9884e8a4759c6","tests/data/one_million_a.bin":"e53c99dcb3ee1436b1c01e53799a07891009be5cdb244133e5eda0ec56d7233a","tests/data/sha1.blb":"b620d6ab76fd26fea6b7be1be720652926b6cea9901a294ff8ba855666ddf19a","tests/lib.rs":"adce369751e6faab77582c03436abcd7dae816843501e1c63cbfd72942b76100"},"package":"23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68"} \ No newline at end of file diff --git a/third_party/rust/sha-1/Cargo.toml b/third_party/rust/sha-1/Cargo.toml new file mode 100644 index 000000000000..ccdeb9aee8c0 --- /dev/null +++ b/third_party/rust/sha-1/Cargo.toml @@ -0,0 +1,53 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "sha-1" +version = "0.8.1" +authors = ["RustCrypto Developers"] +description = "SHA-1 hash function" +documentation = "https://docs.rs/sha-1" +keywords = ["crypto", "sha1", "hash", "digest"] +categories = ["cryptography", "no-std"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/RustCrypto/hashes" + +[lib] +name = "sha1" +[dependencies.block-buffer] +version = "0.7" + +[dependencies.digest] +version = "0.8" + +[dependencies.fake-simd] +version = "0.1" + +[dependencies.opaque-debug] +version = "0.2" + +[dependencies.sha1-asm] +version = "0.4" +optional = true +[dev-dependencies.digest] +version = "0.8" +features = ["dev"] + +[dev-dependencies.hex-literal] +version = "0.1" + +[features] +asm = ["sha1-asm"] +default = ["std"] +std = ["digest/std"] +[badges.travis-ci] +repository = "RustCrypto/hashes" diff --git a/third_party/rust/sha-1/LICENSE-APACHE b/third_party/rust/sha-1/LICENSE-APACHE new file mode 100644 index 000000000000..78173fa2e753 --- /dev/null +++ b/third_party/rust/sha-1/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/sha-1/LICENSE-MIT b/third_party/rust/sha-1/LICENSE-MIT new file mode 100644 index 000000000000..66cf75563b39 --- /dev/null +++ b/third_party/rust/sha-1/LICENSE-MIT @@ -0,0 +1,27 @@ +Copyright (c) 2006-2009 Graydon Hoare +Copyright (c) 2009-2013 Mozilla Foundation +Copyright (c) 2016 Artyom Pavlov + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/sha-1/benches/lib.rs b/third_party/rust/sha-1/benches/lib.rs new file mode 100644 index 000000000000..e204e565a48a --- /dev/null +++ b/third_party/rust/sha-1/benches/lib.rs @@ -0,0 +1,7 @@ +#![no_std] +#![feature(test)] +#[macro_use] +extern crate digest; +extern crate sha1; + +bench!(sha1::Sha1); diff --git a/third_party/rust/sha-1/examples/sha1sum.rs b/third_party/rust/sha-1/examples/sha1sum.rs new file mode 100644 index 000000000000..bde1ab4f603f --- /dev/null +++ b/third_party/rust/sha-1/examples/sha1sum.rs @@ -0,0 +1,49 @@ +extern crate sha1; + +use sha1::{Sha1, Digest}; +use std::env; +use std::fs; +use std::io::{self, Read}; + +const BUFFER_SIZE: usize = 1024; + +/// Print digest result as hex string and name pair +fn print_result(sum: &[u8], name: &str) { + for byte in sum { + print!("{:02x}", byte); + } + println!("\t{}", name); +} + +/// Compute digest value for given `Reader` and print it +/// On any error simply return without doing anything +fn process(reader: &mut R, name: &str) { + let mut sh = D::default(); + let mut buffer = [0u8; BUFFER_SIZE]; + loop { + let n = match reader.read(&mut buffer) { + Ok(n) => n, + Err(_) => return, + }; + sh.input(&buffer[..n]); + if n == 0 || n < BUFFER_SIZE { + break; + } + } + print_result(&sh.result(), name); +} + +fn main() { + let args = env::args(); + // Process files listed in command line arguments one by one + // If no files provided process input from stdin + if args.len() > 1 { + for path in args.skip(1) { + if let Ok(mut file) = fs::File::open(&path) { + process::(&mut file, &path); + } + } + } else { + process::(&mut io::stdin(), "-"); + } +} diff --git a/third_party/rust/sha-1/src/consts.rs b/third_party/rust/sha-1/src/consts.rs new file mode 100644 index 000000000000..7a1bb3435cf7 --- /dev/null +++ b/third_party/rust/sha-1/src/consts.rs @@ -0,0 +1,19 @@ +#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))] + +pub const STATE_LEN: usize = 5; + +#[cfg(not(feature = "asm"))] +pub const BLOCK_LEN: usize = 16; + +#[cfg(not(feature = "asm"))] +pub const K0: u32 = 0x5A827999u32; +#[cfg(not(feature = "asm"))] +pub const K1: u32 = 0x6ED9EBA1u32; +#[cfg(not(feature = "asm"))] +pub const K2: u32 = 0x8F1BBCDCu32; +#[cfg(not(feature = "asm"))] +pub const K3: u32 = 0xCA62C1D6u32; + +pub const H: [u32; STATE_LEN] = [ + 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 +]; diff --git a/third_party/rust/sha-1/src/lib.rs b/third_party/rust/sha-1/src/lib.rs new file mode 100644 index 000000000000..a1a7068a06a6 --- /dev/null +++ b/third_party/rust/sha-1/src/lib.rs @@ -0,0 +1,115 @@ +//! An implementation of the [SHA-1][1] cryptographic hash algorithm. +//! +//! # Usage +//! +//! ```rust +//! # #[macro_use] extern crate hex_literal; +//! # extern crate sha1; +//! # fn main() { +//! use sha1::{Sha1, Digest}; +//! +//! // create a Sha1 object +//! let mut hasher = Sha1::new(); +//! +//! // process input message +//! hasher.input(b"hello world"); +//! +//! // acquire hash digest in the form of GenericArray, +//! // which in this case is equivalent to [u8; 20] +//! let result = hasher.result(); +//! assert_eq!(result[..], hex!("2aae6c35c94fcfb415dbe95f408b9ce91ee846ed")); +//! # } +//! ``` +//! +//! Also see [RustCrypto/hashes][2] readme. +//! +//! [1]: https://en.wikipedia.org/wiki/SHA-1 +//! [2]: https://github.com/RustCrypto/hashes +#![no_std] +#![doc(html_logo_url = + "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")] +extern crate block_buffer; +#[macro_use] extern crate opaque_debug; +#[macro_use] pub extern crate digest; +#[cfg(feature = "std")] +extern crate std; +#[cfg(not(feature = "asm"))] +extern crate fake_simd as simd; + +#[cfg(feature = "asm")] +extern crate sha1_asm; +#[cfg(feature = "asm")] +#[inline(always)] +fn compress(state: &mut [u32; 5], block: &GenericArray) { + let block: &[u8; 64] = unsafe { core::mem::transmute(block) }; + sha1_asm::compress(state, block); +} + +#[cfg(not(feature = "asm"))] +mod utils; +#[cfg(not(feature = "asm"))] +use utils::compress; + +pub use digest::Digest; +use digest::{Input, BlockInput, FixedOutput, Reset}; +use digest::generic_array::GenericArray; +use digest::generic_array::typenum::{U20, U64}; +use block_buffer::BlockBuffer; +use block_buffer::byteorder::{BE, ByteOrder}; + +mod consts; +use consts::{STATE_LEN, H}; + +/// Structure representing the state of a SHA-1 computation +#[derive(Clone)] +pub struct Sha1 { + h: [u32; STATE_LEN], + len: u64, + buffer: BlockBuffer, +} + +impl Default for Sha1 { + fn default() -> Self { + Sha1{ h: H, len: 0u64, buffer: Default::default() } + } +} + +impl BlockInput for Sha1 { + type BlockSize = U64; +} + +impl Input for Sha1 { + fn input>(&mut self, input: B) { + let input = input.as_ref(); + // Assumes that `length_bits<<3` will not overflow + self.len += input.len() as u64; + let state = &mut self.h; + self.buffer.input(input, |d| compress(state, d)); + } +} + +impl FixedOutput for Sha1 { + type OutputSize = U20; + + fn fixed_result(mut self) -> GenericArray { + { + let state = &mut self.h; + let l = self.len << 3; + self.buffer.len64_padding::(l, |d| compress(state, d)); + } + let mut out = GenericArray::default(); + BE::write_u32_into(&self.h,&mut out); + out + } +} + +impl Reset for Sha1 { + fn reset(&mut self) { + self.h = H; + self.len = 0; + self.buffer.reset(); + } +} + +impl_opaque_debug!(Sha1); +impl_write!(Sha1); diff --git a/third_party/rust/sha-1/src/utils.rs b/third_party/rust/sha-1/src/utils.rs new file mode 100644 index 000000000000..e8b941a6ee80 --- /dev/null +++ b/third_party/rust/sha-1/src/utils.rs @@ -0,0 +1,300 @@ +#![cfg_attr(feature = "cargo-clippy", allow(many_single_char_names))] + +use consts::{BLOCK_LEN, K0, K1, K2, K3}; +use block_buffer::byteorder::{BE, ByteOrder}; +use simd::u32x4; +use digest::generic_array::GenericArray; +use digest::generic_array::typenum::U64; + +type Block = GenericArray; + +/// Not an intrinsic, but gets the first element of a vector. +#[inline] +pub fn sha1_first(w0: u32x4) -> u32 { + w0.0 +} + +/// Not an intrinsic, but adds a word to the first element of a vector. +#[inline] +pub fn sha1_first_add(e: u32, w0: u32x4) -> u32x4 { + let u32x4(a, b, c, d) = w0; + u32x4(e.wrapping_add(a), b, c, d) +} + +/// Emulates `llvm.x86.sha1msg1` intrinsic. +fn sha1msg1(a: u32x4, b: u32x4) -> u32x4 { + let u32x4(_, _, w2, w3) = a; + let u32x4(w4, w5, _, _) = b; + a ^ u32x4(w2, w3, w4, w5) +} + +/// Emulates `llvm.x86.sha1msg2` intrinsic. +fn sha1msg2(a: u32x4, b: u32x4) -> u32x4 { + let u32x4(x0, x1, x2, x3) = a; + let u32x4(_, w13, w14, w15) = b; + + let w16 = (x0 ^ w13).rotate_left(1); + let w17 = (x1 ^ w14).rotate_left(1); + let w18 = (x2 ^ w15).rotate_left(1); + let w19 = (x3 ^ w16).rotate_left(1); + + u32x4(w16, w17, w18, w19) +} + +/// Performs 4 rounds of the message schedule update. +/* +pub fn sha1_schedule_x4(v0: u32x4, v1: u32x4, v2: u32x4, v3: u32x4) -> u32x4 { + sha1msg2(sha1msg1(v0, v1) ^ v2, v3) +} +*/ + +/// Emulates `llvm.x86.sha1nexte` intrinsic. +#[inline] +fn sha1_first_half(abcd: u32x4, msg: u32x4) -> u32x4 { + sha1_first_add(sha1_first(abcd).rotate_left(30), msg) +} + +/// Emulates `llvm.x86.sha1rnds4` intrinsic. +/// Performs 4 rounds of the message block digest. +fn sha1_digest_round_x4(abcd: u32x4, work: u32x4, i: i8) -> u32x4 { + const K0V: u32x4 = u32x4(K0, K0, K0, K0); + const K1V: u32x4 = u32x4(K1, K1, K1, K1); + const K2V: u32x4 = u32x4(K2, K2, K2, K2); + const K3V: u32x4 = u32x4(K3, K3, K3, K3); + + match i { + 0 => sha1rnds4c(abcd, work + K0V), + 1 => sha1rnds4p(abcd, work + K1V), + 2 => sha1rnds4m(abcd, work + K2V), + 3 => sha1rnds4p(abcd, work + K3V), + _ => unreachable!("unknown icosaround index"), + } +} + +/// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic. +fn sha1rnds4c(abcd: u32x4, msg: u32x4) -> u32x4 { + let u32x4(mut a, mut b, mut c, mut d) = abcd; + let u32x4(t, u, v, w) = msg; + let mut e = 0u32; + + macro_rules! bool3ary_202 { + ($a:expr, $b:expr, $c:expr) => ($c ^ ($a & ($b ^ $c))) + } // Choose, MD5F, SHA1C + + e = e.wrapping_add(a.rotate_left(5)) + .wrapping_add(bool3ary_202!(b, c, d)) + .wrapping_add(t); + b = b.rotate_left(30); + + d = d.wrapping_add(e.rotate_left(5)) + .wrapping_add(bool3ary_202!(a, b, c)) + .wrapping_add(u); + a = a.rotate_left(30); + + c = c.wrapping_add(d.rotate_left(5)) + .wrapping_add(bool3ary_202!(e, a, b)) + .wrapping_add(v); + e = e.rotate_left(30); + + b = b.wrapping_add(c.rotate_left(5)) + .wrapping_add(bool3ary_202!(d, e, a)) + .wrapping_add(w); + d = d.rotate_left(30); + + u32x4(b, c, d, e) +} + +/// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic. +fn sha1rnds4p(abcd: u32x4, msg: u32x4) -> u32x4 { + let u32x4(mut a, mut b, mut c, mut d) = abcd; + let u32x4(t, u, v, w) = msg; + let mut e = 0u32; + + macro_rules! bool3ary_150 { + ($a:expr, $b:expr, $c:expr) => ($a ^ $b ^ $c) + } // Parity, XOR, MD5H, SHA1P + + e = e.wrapping_add(a.rotate_left(5)) + .wrapping_add(bool3ary_150!(b, c, d)) + .wrapping_add(t); + b = b.rotate_left(30); + + d = d.wrapping_add(e.rotate_left(5)) + .wrapping_add(bool3ary_150!(a, b, c)) + .wrapping_add(u); + a = a.rotate_left(30); + + c = c.wrapping_add(d.rotate_left(5)) + .wrapping_add(bool3ary_150!(e, a, b)) + .wrapping_add(v); + e = e.rotate_left(30); + + b = b.wrapping_add(c.rotate_left(5)) + .wrapping_add(bool3ary_150!(d, e, a)) + .wrapping_add(w); + d = d.rotate_left(30); + + u32x4(b, c, d, e) +} + +/// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic. +fn sha1rnds4m(abcd: u32x4, msg: u32x4) -> u32x4 { + let u32x4(mut a, mut b, mut c, mut d) = abcd; + let u32x4(t, u, v, w) = msg; + let mut e = 0u32; + + macro_rules! bool3ary_232 { + ($a:expr, $b:expr, $c:expr) => (($a & $b) ^ ($a & $c) ^ ($b & $c)) + } // Majority, SHA1M + + e = e.wrapping_add(a.rotate_left(5)) + .wrapping_add(bool3ary_232!(b, c, d)) + .wrapping_add(t); + b = b.rotate_left(30); + + d = d.wrapping_add(e.rotate_left(5)) + .wrapping_add(bool3ary_232!(a, b, c)) + .wrapping_add(u); + a = a.rotate_left(30); + + c = c.wrapping_add(d.rotate_left(5)) + .wrapping_add(bool3ary_232!(e, a, b)) + .wrapping_add(v); + e = e.rotate_left(30); + + b = b.wrapping_add(c.rotate_left(5)) + .wrapping_add(bool3ary_232!(d, e, a)) + .wrapping_add(w); + d = d.rotate_left(30); + + u32x4(b, c, d, e) +} + +/// Process a block with the SHA-1 algorithm. +fn sha1_digest_block_u32(state: &mut [u32; 5], block: &[u32; 16]) { + + macro_rules! schedule { + ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => ( + sha1msg2(sha1msg1($v0, $v1) ^ $v2, $v3) + ) + } + + macro_rules! rounds4 { + ($h0:ident, $h1:ident, $wk:expr, $i:expr) => ( + sha1_digest_round_x4($h0, sha1_first_half($h1, $wk), $i) + ) + } + + // Rounds 0..20 + // TODO: replace with `u32x4::load` + let mut h0 = u32x4(state[0], state[1], state[2], state[3]); + let mut w0 = u32x4(block[0], block[1], block[2], block[3]); + let mut h1 = sha1_digest_round_x4(h0, sha1_first_add(state[4], w0), 0); + let mut w1 = u32x4(block[4], block[5], block[6], block[7]); + h0 = rounds4!(h1, h0, w1, 0); + let mut w2 = u32x4(block[8], block[9], block[10], block[11]); + h1 = rounds4!(h0, h1, w2, 0); + let mut w3 = u32x4(block[12], block[13], block[14], block[15]); + h0 = rounds4!(h1, h0, w3, 0); + let mut w4 = schedule!(w0, w1, w2, w3); + h1 = rounds4!(h0, h1, w4, 0); + + // Rounds 20..40 + w0 = schedule!(w1, w2, w3, w4); + h0 = rounds4!(h1, h0, w0, 1); + w1 = schedule!(w2, w3, w4, w0); + h1 = rounds4!(h0, h1, w1, 1); + w2 = schedule!(w3, w4, w0, w1); + h0 = rounds4!(h1, h0, w2, 1); + w3 = schedule!(w4, w0, w1, w2); + h1 = rounds4!(h0, h1, w3, 1); + w4 = schedule!(w0, w1, w2, w3); + h0 = rounds4!(h1, h0, w4, 1); + + // Rounds 40..60 + w0 = schedule!(w1, w2, w3, w4); + h1 = rounds4!(h0, h1, w0, 2); + w1 = schedule!(w2, w3, w4, w0); + h0 = rounds4!(h1, h0, w1, 2); + w2 = schedule!(w3, w4, w0, w1); + h1 = rounds4!(h0, h1, w2, 2); + w3 = schedule!(w4, w0, w1, w2); + h0 = rounds4!(h1, h0, w3, 2); + w4 = schedule!(w0, w1, w2, w3); + h1 = rounds4!(h0, h1, w4, 2); + + // Rounds 60..80 + w0 = schedule!(w1, w2, w3, w4); + h0 = rounds4!(h1, h0, w0, 3); + w1 = schedule!(w2, w3, w4, w0); + h1 = rounds4!(h0, h1, w1, 3); + w2 = schedule!(w3, w4, w0, w1); + h0 = rounds4!(h1, h0, w2, 3); + w3 = schedule!(w4, w0, w1, w2); + h1 = rounds4!(h0, h1, w3, 3); + w4 = schedule!(w0, w1, w2, w3); + h0 = rounds4!(h1, h0, w4, 3); + + let e = sha1_first(h1).rotate_left(30); + let u32x4(a, b, c, d) = h0; + + state[0] = state[0].wrapping_add(a); + state[1] = state[1].wrapping_add(b); + state[2] = state[2].wrapping_add(c); + state[3] = state[3].wrapping_add(d); + state[4] = state[4].wrapping_add(e); +} + +/// Process a block with the SHA-1 algorithm. (See more...) +/// +/// SHA-1 is a cryptographic hash function, and as such, it operates +/// on an arbitrary number of bytes. This function operates on a fixed +/// number of bytes. If you call this function with anything other than +/// 64 bytes, then it will panic! This function takes two arguments: +/// +/// * `state` is reference to an **array** of 5 words. +/// * `block` is reference to a **slice** of 64 bytes. +/// +/// If you want the function that performs a message digest on an arbitrary +/// number of bytes, then see also the `Sha1` struct above. +/// +/// # Implementation +/// +/// First, some background. Both ARM and Intel are releasing documentation +/// that they plan to include instruction set extensions for SHA1 and SHA256 +/// sometime in the near future. Second, LLVM won't lower these intrinsics yet, +/// so these functions were written emulate these instructions. Finally, +/// the block function implemented with these emulated intrinsics turned out +/// to be quite fast! What follows is a discussion of this CPU-level view +/// of the SHA-1 algorithm and how it relates to the mathematical definition. +/// +/// The SHA instruction set extensions can be divided up into two categories: +/// +/// * message work schedule update calculation ("schedule" v., "work" n.) +/// * message block 80-round digest calculation ("digest" v., "block" n.) +/// +/// The schedule-related functions can be used to easily perform 4 rounds +/// of the message work schedule update calculation, as shown below: +/// +/// ```ignore +/// macro_rules! schedule_x4 { +/// ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => ( +/// sha1msg2(sha1msg1($v0, $v1) ^ $v2, $v3) +/// ) +/// } +/// +/// macro_rules! round_x4 { +/// ($h0:ident, $h1:ident, $wk:expr, $i:expr) => ( +/// sha1rnds4($h0, sha1_first_half($h1, $wk), $i) +/// ) +/// } +/// ``` +/// +/// and also shown above is how the digest-related functions can be used to +/// perform 4 rounds of the message block digest calculation. +/// +pub fn compress(state: &mut [u32; 5], block: &Block) { + let mut block_u32 = [0u32; BLOCK_LEN]; + BE::read_u32_into(block, &mut block_u32[..]); + sha1_digest_block_u32(state, &block_u32); +} diff --git a/third_party/rust/sha-1/tests/data/one_million_a.bin b/third_party/rust/sha-1/tests/data/one_million_a.bin new file mode 100644 index 000000000000..0c759d80ff97 --- /dev/null +++ b/third_party/rust/sha-1/tests/data/one_million_a.bin @@ -0,0 +1 @@ +4ª—<ÔÄÚ¤öë+Û­'1e4o \ No newline at end of file diff --git a/third_party/rust/sha-1/tests/data/sha1.blb b/third_party/rust/sha-1/tests/data/sha1.blb new file mode 100644 index 000000000000..13ae2df262cc --- /dev/null +++ b/third_party/rust/sha-1/tests/data/sha1.blb @@ -0,0 +1 @@ +blobby1abc©™>6Gjº>%qxPÂlœÐØ8abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq„˜>D;Ònº®J¡ùQ)ååFpñ+The quick brown fox jumps over the lazy dog/ÔáÆz-(üí„žá»vç9“ë+The quick brown fox jumps over the lazy cogÞŸ,Ò^:úÓèZ Ñ}› ´³ \ No newline at end of file diff --git a/third_party/rust/sha-1/tests/lib.rs b/third_party/rust/sha-1/tests/lib.rs new file mode 100644 index 000000000000..348684b1f219 --- /dev/null +++ b/third_party/rust/sha-1/tests/lib.rs @@ -0,0 +1,14 @@ +#![no_std] +#[macro_use] +extern crate digest; +extern crate sha1; + +use digest::dev::{one_million_a, digest_test}; + +new_test!(sha1_main, "sha1", sha1::Sha1, digest_test); + +#[test] +fn sha1_1million_a() { + let output = include_bytes!("data/one_million_a.bin"); + one_million_a::(output); +} diff --git a/third_party/rust/sha1/.cargo-checksum.json b/third_party/rust/sha1/.cargo-checksum.json deleted file mode 100644 index c22818ff1a7f..000000000000 --- a/third_party/rust/sha1/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"389ab75b5d5d709b3eec65ee4bbe3fce7cd441996bdd38170b6dd83005929c2b","LICENSE":"a7a063c63ddbb0e3b183bd4890c5a0f4265540b923c7a6998c8808d129a88f54","README.md":"57577b316b8594705731362581e6b51e02ff5abcb326fa5ff68e5a7c8abb4591","src/lib.rs":"284d41e2c30dd95ab54c1100b551b79e432550725b9f62601634d842adc32b47"},"package":"cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c"} \ No newline at end of file diff --git a/third_party/rust/sha1/Cargo.toml b/third_party/rust/sha1/Cargo.toml deleted file mode 100644 index 2fd41d1bd95d..000000000000 --- a/third_party/rust/sha1/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "sha1" -version = "0.2.0" -authors = ["Armin Ronacher "] -keywords = ["sha1"] -description = "Minimal implementation of SHA1 for Rust." -license = "BSD-3-Clause" -repository = "https://github.com/mitsuhiko/rust-sha1" - -[dev-dependencies] -openssl = "0.7" -rand = "0.3" diff --git a/third_party/rust/sha1/README.md b/third_party/rust/sha1/README.md deleted file mode 100644 index 54c56409b7bf..000000000000 --- a/third_party/rust/sha1/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# rust-sha1 - -Minimal implementation of SHA1 for Rust. This might go away in the future -if rust-crypto or some libraries like that split into smaller parts. - -Right now SHA1 is quite frequently used and many things want to have an -implementation of it, that does not pull in too much other stuff. - -This is largely based on the hash code in crypto-rs by Koka El Kiwi. diff --git a/third_party/rust/sha1/src/lib.rs b/third_party/rust/sha1/src/lib.rs deleted file mode 100644 index 33f24d1e2a10..000000000000 --- a/third_party/rust/sha1/src/lib.rs +++ /dev/null @@ -1,334 +0,0 @@ -//! A minimal implementation of SHA1 for rust. -//! -//! Example: -//! -//! ```rust -//! extern crate sha1; -//! # fn main() { -//! -//! let mut m = sha1::Sha1::new(); -//! m.update(b"Hello World!"); -//! assert_eq!(m.digest().to_string(), -//! "2ef7bde608ce5404e97d5f042f95f89f1c232871"); -//! # } -//! ``` - -#![no_std] -#![deny(missing_docs)] - -use core::cmp; -use core::fmt; - -/// Represents a Sha1 hash object in memory. -#[derive(Clone)] -pub struct Sha1 { - state: Sha1State, - blocks: Blocks, - len: u64, -} - -struct Blocks { - len: u32, - block: [u8; 64], -} - -#[derive(Copy, Clone)] -struct Sha1State { - state: [u32; 5], -} - -/// Digest generated from a `Sha1` instance. -/// -/// A digest can be formatted to view the digest as a hex string, or the bytes -/// can be extracted for later processing. -pub struct Digest { - data: Sha1State, -} - -const DEFAULT_STATE: Sha1State = Sha1State { - state: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0], -}; - -impl Sha1 { - /// Creates an fresh sha1 hash object. - pub fn new() -> Sha1 { - Sha1 { - state: DEFAULT_STATE, - len: 0, - blocks: Blocks { - len: 0, - block: [0; 64], - }, - } - } - - /// Resets the hash object to it's initial state. - pub fn reset(&mut self) { - self.state = DEFAULT_STATE; - self.len = 0; - self.blocks.len = 0; - } - - /// Update hash with input data. - pub fn update(&mut self, data: &[u8]) { - let len = &mut self.len; - let state = &mut self.state; - self.blocks.input(data, |chunk| { - *len += 64; - state.process(chunk); - }) - } - - /// Retrieve digest result. - pub fn digest(&self) -> Digest { - let mut state = self.state; - let bits = (self.len + (self.blocks.len as u64)) * 8; - let extra = [ - (bits >> 56) as u8, - (bits >> 48) as u8, - (bits >> 40) as u8, - (bits >> 32) as u8, - (bits >> 24) as u8, - (bits >> 16) as u8, - (bits >> 8) as u8, - (bits >> 0) as u8, - ]; - let mut last = [0; 128]; - let blocklen = self.blocks.len as usize; - last[..blocklen].clone_from_slice(&self.blocks.block[..blocklen]); - last[blocklen] = 0x80; - - if blocklen < 56 { - last[56..64].clone_from_slice(&extra); - state.process(&last[0..64]); - } else { - last[120..128].clone_from_slice(&extra); - state.process(&last[0..64]); - state.process(&last[64..128]); - } - - Digest { data: state } - } -} - -impl Digest { - /// Returns the 160 bit (20 byte) digest as a byte array. - pub fn bytes(&self) -> [u8; 20] { - [ - (self.data.state[0] >> 24) as u8, - (self.data.state[0] >> 16) as u8, - (self.data.state[0] >> 8) as u8, - (self.data.state[0] >> 0) as u8, - (self.data.state[1] >> 24) as u8, - (self.data.state[1] >> 16) as u8, - (self.data.state[1] >> 8) as u8, - (self.data.state[1] >> 0) as u8, - (self.data.state[2] >> 24) as u8, - (self.data.state[2] >> 16) as u8, - (self.data.state[2] >> 8) as u8, - (self.data.state[2] >> 0) as u8, - (self.data.state[3] >> 24) as u8, - (self.data.state[3] >> 16) as u8, - (self.data.state[3] >> 8) as u8, - (self.data.state[3] >> 0) as u8, - (self.data.state[4] >> 24) as u8, - (self.data.state[4] >> 16) as u8, - (self.data.state[4] >> 8) as u8, - (self.data.state[4] >> 0) as u8, - ] - } -} - -impl Blocks { - fn input(&mut self, mut input: &[u8], mut f: F) where F: FnMut(&[u8]) { - if self.len > 0 { - let len = self.len as usize; - let amt = cmp::min(input.len(), self.block.len() - len); - self.block[len..len + amt].clone_from_slice(&input[..amt]); - if len + amt == self.block.len() { - f(&self.block); - self.len = 0; - input = &input[amt..]; - } else { - self.len += amt as u32; - return - } - } - assert_eq!(self.len, 0); - for chunk in input.chunks(64) { - if chunk.len() == 64 { - f(chunk) - } else { - self.block[..chunk.len()].clone_from_slice(chunk); - self.len = chunk.len() as u32; - } - } - } -} - -impl Sha1State { - fn process(&mut self, block: &[u8]) { - let mut words = [0u32; 80]; - for (i, chunk) in block.chunks(4).enumerate() { - words[i] = (chunk[3] as u32) | - ((chunk[2] as u32) << 8) | - ((chunk[1] as u32) << 16) | - ((chunk[0] as u32) << 24); - } - - fn ff(b: u32, c: u32, d: u32) -> u32 { d ^ (b & (c ^ d)) } - fn gg(b: u32, c: u32, d: u32) -> u32 { b ^ c ^ d } - fn hh(b: u32, c: u32, d: u32) -> u32 { (b & c) | (d & (b | c)) } - fn ii(b: u32, c: u32, d: u32) -> u32 { b ^ c ^ d } - - for i in 16..80 { - let n = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16]; - words[i] = n.rotate_left(1); - } - - let mut a = self.state[0]; - let mut b = self.state[1]; - let mut c = self.state[2]; - let mut d = self.state[3]; - let mut e = self.state[4]; - - for i in 0..80 { - let (f, k) = match i { - 0 ... 19 => (ff(b, c, d), 0x5a827999), - 20 ... 39 => (gg(b, c, d), 0x6ed9eba1), - 40 ... 59 => (hh(b, c, d), 0x8f1bbcdc), - 60 ... 79 => (ii(b, c, d), 0xca62c1d6), - _ => (0, 0), - }; - - let tmp = a.rotate_left(5) - .wrapping_add(f) - .wrapping_add(e) - .wrapping_add(k) - .wrapping_add(words[i]); - e = d; - d = c; - c = b.rotate_left(30); - b = a; - a = tmp; - } - - self.state[0] = self.state[0].wrapping_add(a); - self.state[1] = self.state[1].wrapping_add(b); - self.state[2] = self.state[2].wrapping_add(c); - self.state[3] = self.state[3].wrapping_add(d); - self.state[4] = self.state[4].wrapping_add(e); - } -} - -impl Clone for Blocks { - fn clone(&self) -> Blocks { - Blocks { ..*self } - } -} - -impl fmt::Display for Digest { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for byte in self.data.state.iter() { - try!(write!(f, "{:08x}", byte)); - } - Ok(()) - } -} - -#[cfg(test)] -mod tests { - extern crate std; - extern crate rand; - extern crate openssl; - - use self::std::prelude::v1::*; - use self::std::io::Write; - - use Sha1; - - #[test] - fn test_simple() { - let mut m = Sha1::new(); - - let tests = [ - ("The quick brown fox jumps over the lazy dog", - "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"), - ("The quick brown fox jumps over the lazy cog", - "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3"), - ("", "da39a3ee5e6b4b0d3255bfef95601890afd80709"), - ("testing\n", "9801739daae44ec5293d4e1f53d3f4d2d426d91c"), - ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", - "025ecbd5d70f8fb3c5457cd96bab13fda305dc59"), - ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", - "4300320394f7ee239bcdce7d3b8bcee173a0cd5c"), - ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", - "cef734ba81a024479e09eb5a75b6ddae62e6abf1"), - ]; - - for &(s, ref h) in tests.iter() { - let data = s.as_bytes(); - - m.reset(); - m.update(data); - let hh = m.digest().to_string(); - - assert_eq!(hh.len(), h.len()); - assert_eq!(hh, *h); - } - } - - #[test] - fn test_multiple_updates() { - let mut m = Sha1::new(); - - m.reset(); - m.update("The quick brown ".as_bytes()); - m.update("fox jumps over ".as_bytes()); - m.update("the lazy dog".as_bytes()); - let hh = m.digest().to_string(); - - - let h = "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"; - assert_eq!(hh.len(), h.len()); - assert_eq!(hh, &*h); - } - - #[test] - fn test_sha1_loop() { - let mut m = Sha1::new(); - let s = "The quick brown fox jumps over the lazy dog."; - let n = 1000u64; - - for _ in 0..3 { - m.reset(); - for _ in 0..n { - m.update(s.as_bytes()); - } - assert_eq!(m.digest().to_string(), - "7ca27655f67fceaa78ed2e645a81c7f1d6e249d2"); - } - } - - #[test] - fn spray_and_pray() { - use self::rand::Rng; - - let mut rng = rand::thread_rng(); - let mut m = Sha1::new(); - let mut bytes = [0; 512]; - - for _ in 0..20 { - let ty = openssl::crypto::hash::Type::SHA1; - let mut r = openssl::crypto::hash::Hasher::new(ty); - m.reset(); - for _ in 0..50 { - let len = rng.gen::() % bytes.len(); - rng.fill_bytes(&mut bytes[..len]); - m.update(&bytes[..len]); - r.write(&bytes[..len]).unwrap(); - } - assert_eq!(r.finish(), m.digest().bytes()); - } - } -} diff --git a/third_party/rust/ws/.cargo-checksum.json b/third_party/rust/ws/.cargo-checksum.json index 878ebd2c64d8..44cca0fb0779 100644 --- a/third_party/rust/ws/.cargo-checksum.json +++ b/third_party/rust/ws/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"0f1093166e74acbdf671734be67f4d8f7094f68da06ef3b2a90cbb5d7505f4f4","Cargo.toml":"13c13614ec88babb7324cba3acae5c06f7222c8a6cd24aab898833090204bbde","LICENSE":"87bf8937aeabfcf53266f58d5c336e80b0be36f3005af4af6ee1bcd6e5a51b0e","README.md":"d585e1d18fee34e22afc3910ad678934c676f3d15b21c712d99dbb8bfd86e672","examples/autobahn-client.rs":"bab7be45a01e4a81805691f9e2507bbde300f9ec358d8ea779326501c2c33478","examples/autobahn-server.rs":"d383129817d15bbcc83da8943d0680378c717c00a2e6c0a7c336836f78e40356","examples/bench-server.rs":"34a5bd6d5965cfe2cbd99b609a637f78d7b08faadc669ae1f7089f5ff1763875","examples/bench.rs":"4363819d7052c34ff2a06efd595e7ef43a252f2c0116cd40c565c3e3d68d0a8a","examples/channel.rs":"678f15b9a016c607c8982f691176814ae03941af0dbd67c74d8d78c9060a4ef4","examples/cli.rs":"c71f29c2c1dbfdb40883e001d788c41d0672d59f847c8c855ed9b5a3649e6e14","examples/client.rs":"c5eb382bf6ceff17105c129e72ca6e990f68298b3d102dea492e2642e46028e7","examples/external_shutdown.rs":"9b9f0e99f3cbce0fe988b76f9329067cd9538ad27dc85c6da5f505b62d7d6d24","examples/peer2peer.rs":"57a05ada8bfe0131aa60389a742b055d2c73813df618326d9bcd98b72d2f6577","examples/pong.rs":"73f06df64981666ffa34c17bdb103c87301710c920a390ce645824cb766cf5b0","examples/remote_addr.rs":"0d0ad8c33dda261b1d2029982acaa86ebde9270a6bc7e2ea4eda02b932b38089","examples/router.rs":"32bf6f736dafd4cdb305da56013944d33c218063cea9cda3f6f3545a3fbf2e64","examples/server.rs":"3c3e3f74faf012e2f41c235f84f92f05d95d554a8762d32dc748aa55a3652ebd","examples/shared.rs":"149c2ba8251811121dff3a196760d5143ef2dfb68b11042eac01cecf0839c2a1","examples/ssl-server.rs":"7fac0020f93f4708fd0644d240f6ffb721b9a2734f63307afd5509717eec0823","examples/threaded.rs":"e9ef17c4f652e9c2991efa76fe6b1e4a6b44205d31b03985092ce5fa53929ef4","examples/unsafe-ssl-client.rs":"289e7b2b31e68737546e68964d65e635cfc64aa1be96b47ef899c76a6b9926f6","src/communication.rs":"f2ed457469d4b2af3a3edd2e1cc7d5224947480c5bb8312c5b929b307ce9fc7f","src/connection.rs":"1d88ba035385981c62583c8e6eae05044e7e5c41675349d140b0ad86ca632f4b","src/deflate/context.rs":"6ff4164aec4f0934cacaa30837f5af3e7007c0a70bd7300ec918dc4b03810817","src/deflate/extension.rs":"6a81716614590fbe33d13c88cb3f2de0a3ede9b2c00e3af43a587d4e1302e1dc","src/deflate/mod.rs":"1ae8d1faba680ae0265fdc947ca75010c9c6b7f89d5168a112cf128f1827503b","src/factory.rs":"df097918ce023132a8c9ed5a2e0c790ebc559408f5cc6371908f23ecb589a4d1","src/frame.rs":"3d6aaeb34dc6b8bd1cfd9fa6c15b5e84b3ddb38c8cc6539c565a8a5853265b88","src/handler.rs":"45fb34f72297285b192048aaa3adb11383cfa8e4b293d4ca9dd10f828daca036","src/handshake.rs":"8218157bf80f331d5a62ceb769d85b479af898892f3819bef1e000d3039bc6a8","src/io.rs":"ff4c9df764d94037dd573f408d56976bbe1554d2768d4eec28d65a99204e2337","src/lib.rs":"b79f03755319c8f728f0d93ecba1f068a3f8ea794b7d0ffb705d46ef9017f463","src/message.rs":"9164b89f076c42d48dd35edc77009b7c644c8c1d877fc6e34fbcbb8e2f4ef255","src/protocol.rs":"0e6d59e2388bd7dc102f2ec3d05e219c45936287de886e5c16c7c10cab7921af","src/result.rs":"e7b069cd6652307d451e89ddf2eeb261cf5bc42cf3540375a95fea7bddf4dd31","src/stream.rs":"e5cb02db069aadd2d7b1157e845ce477583e1537499e33348320855ab3a2537d","src/util.rs":"f5e8a942a571ec6fb02baae9e869a68151878639d842eb7e9fb6e08833d77c32","tests/bind.rs":"ceea3d8da1f216e5c919220a8f3b360d8e752c7c32f045d4bcf638b0f86ae434","tests/deflate.rs":"0fda11be7605303dc9479a5bcb391ac13d00ee310f2bf7a6165f00a955c8458d","tests/fuzzingclient.json":"524dfc4da9385ccab2ecac941114ca2bd6be3bd553d06f637ad26d3243407261","tests/fuzzingserver.json":"0574cb0b8deb9a99b70e4d300f4877905b69d59a093a6937e4cbdac4cd2123af","tests/shutdown.rs":"375bd9056a9416b68a79850fcc3ea680ce637bb805b4b4c3adcaf23c7696708e"},"package":"89c48c53bf9dee34411a08993c10b879c36e105d609b46e25673befe3a5c1320"} \ No newline at end of file +{"files":{"CHANGELOG.md":"28a9bf7420eb71562ab146188cbc7cf9f299c90a3a46d92f32eb8ea48d70c77f","Cargo.toml":"b196eca72b170d5d05abee2b233f66e6f1fd7ba95fb9562b93a3cbf8743edb54","LICENSE":"87bf8937aeabfcf53266f58d5c336e80b0be36f3005af4af6ee1bcd6e5a51b0e","README.md":"b68b23e68eb79683ba4de6797427a466812deaa7daa1c6bacbf9bce40bbf90b6","examples/autobahn-client.rs":"adca1e305f45277326c5cc11df1ae214258e6412b9aa0c9094144d0d6d95aaca","examples/autobahn-server.rs":"c7dd24bddbabd141746f57ca74d72cbdffd8a8d280e1bcf03f37ea663ab89ba0","examples/bench-server.rs":"1d9759223718a9677f308435a39de83841552fc0664e542c434a5af741f0b282","examples/bench.rs":"6b12d7edbe7dbf3917ab2f6a0c6867bb426dbf278bba98c65cdc458b0dbaa302","examples/channel.rs":"00ec08f63064688b61c807fad51edf25ed3a1afba0c7b5ebe4099bdaaa0438f8","examples/cli.rs":"e9fdb6b47dc67a9f896f56e152f85ead4497ef994c9f3617efac7bf8a974db44","examples/client.rs":"b9ca005dcdc637a1ae6efdd1b3c984c249be5fe718981d8073899357aff559eb","examples/external_shutdown.rs":"125ca6605f5540d30f347365fee8ee0e71bac2d3afc7a34ddc4ee03e453e5637","examples/html_chat.rs":"4347f092659bf402f29c5d874f85e2add96817d1e8a42c413b3e69dec5e98fdd","examples/peer2peer.rs":"6202a73534f38e8ddb1a8aad2507cbca39a2a75238e3243af30640a2dc38218a","examples/pong.rs":"64e7b1355759433327282209d2549bd0134a5d85c28bb6e691ebc04f2a8e9c5b","examples/remote_addr.rs":"59e0365093cfac1cb357c3a48caa6fe9d03d75cc7e61763b6b20ac9b011cdf78","examples/router.rs":"62b184b8e12315c7cb2064e490b491c75fe93de11fd315f42b79a0688d086580","examples/server.rs":"4bbc26ef67f7033692df7bfca1a80315ad6aaafe564a15deb9d6341421a1d7fd","examples/shared.rs":"5ad4866b2f187906d81b95c92afb2f2b8fe27c0703e37c865f026bcdbd9dcb9f","examples/ssl-server.rs":"58746d094393bc1ee14011abd41a438c86137ffdbf0c45a08f7415d10881c751","examples/threaded.rs":"c55cd396b23ece7270c7a779e1c39eafe50c9860dac805c5a2c67bda1d83d395","examples/unsafe-ssl-client.rs":"d703abe42ae2ba28a3e419ac6efba0f8b02cc0c61a8772688100cacfaa522a8d","src/communication.rs":"bb86c10ca0cdecef6eb5aa94b9c78857ca011036e3e78b70d9fb747e11439446","src/connection.rs":"2e9fcdb5b3577de0380bea41658c44a314b0e43146fe55d25533a891435924c4","src/deflate/context.rs":"dc9e678c143db4c8c78214fb9fdb7b3d9544fc8fbb48ce285b7e7aa3d00fce9b","src/deflate/extension.rs":"131a9525b8234f686e59bb7ac848d1daf2b30d1a8a9729a82b84b678936f82bb","src/deflate/mod.rs":"fc927311d2d1ecee787bda54524681ead33b3d62154a90fab458fca4d00ccc04","src/factory.rs":"bff726225c632e2ee94984820cc7aa647c234ab69b75c5cb9cfff8d97eceadb6","src/frame.rs":"c97015c2be9ccfb3f5dbfbe6eeebee526a9bc9cbd7f65e8f5d9423ff6d96b284","src/handler.rs":"e69a8d8d64987c4ed6d2429db8c5408688f1fe4dbe1369dee290bbcc13eb5c42","src/handshake.rs":"33b64ad48fa11ebd14f02c5e386cc9c50c9149405aaab53918a0ccdaff65e4c4","src/io.rs":"0b8389e0b42cb4edbea2529bf983262db3c7bf8fc0a02d214689ecc00feba3e7","src/lib.rs":"96437b3777df6453e81989c62fcff343751ef247ac213b50f496e8832ad286c8","src/message.rs":"b08cd9b7426b8fb2c13bfed45ba81e59fc262988c2a46cdbe77c5161fc08d9b0","src/protocol.rs":"5096c4a96ac0c4296909bdc0d30a808da6dee44ff5550ac345f4ef4020cbe173","src/result.rs":"120d47ebb442f9a07c3e854c61fc3ec73683d6d44fa5554cbb59cfc44f008a4b","src/stream.rs":"e648eaeec372adb1fa3e441695248af44456d781c3ef50845b4b40d185f72a37","src/util.rs":"428a5d4465aebf29e1af940a06b0f82e758e7aa9953169b9d5c61858f57ded7b","tests/bind.rs":"ceea3d8da1f216e5c919220a8f3b360d8e752c7c32f045d4bcf638b0f86ae434","tests/deflate.rs":"dcf9f5139d1a5d63cf1c75f450781933d6e0730dc710ac8a01ad6ff2ec2774a0","tests/fuzzingclient.json":"524dfc4da9385ccab2ecac941114ca2bd6be3bd553d06f637ad26d3243407261","tests/fuzzingserver.json":"0574cb0b8deb9a99b70e4d300f4877905b69d59a093a6937e4cbdac4cd2123af","tests/shutdown.rs":"7338f9feec52c405ab17c1f00a8ce4494c89f50043bd7423b470dd2a26f97b3b"},"package":"ec91ea61b83ce033c43c06c52ddc7532f465c0153281610d44c58b74083aee1a"} \ No newline at end of file diff --git a/third_party/rust/ws/CHANGELOG.md b/third_party/rust/ws/CHANGELOG.md index 390da14e3a67..019c2ca6f433 100644 --- a/third_party/rust/ws/CHANGELOG.md +++ b/third_party/rust/ws/CHANGELOG.md @@ -1,3 +1,36 @@ +
+### v0.8.0 (2018-10-15) + +#### Features +* Update rand to 0.6 +* Upgrade native-tls to 0.2 +* Add a maximal size for fragments exposed via the `max_fragment_size` setting + +#### Bug fixes +* Don't try to parse response when the socket not ready + + +### v0.7.9 (2018-10-15) + + +#### Features +* Update openssl to 0.10 +* Implement `Debug` for `Sender` + + +### v0.7.8 (2018-08-15) + + +#### Bug fixes + +* Fixed an infinite loop when connections were closed during a handshake + + +#### Features +* `Websocket::from_url` will now add an `Authorization` header if necessary +* Added support for native-tls via the `nativetls` feature + + ### v0.7.3 (2017-06-07) diff --git a/third_party/rust/ws/Cargo.toml b/third_party/rust/ws/Cargo.toml index faa0717a83dc..08c6405a89b3 100644 --- a/third_party/rust/ws/Cargo.toml +++ b/third_party/rust/ws/Cargo.toml @@ -1,44 +1,84 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + [package] +name = "ws" +version = "0.8.1" authors = ["Jason Housley "] description = "Lightweight, event-driven WebSockets for Rust." documentation = "https://ws-rs.org/docs" +readme = "README.md" keywords = ["websocket", "mio", "event-driven", "io", "web"] license = "MIT" -name = "ws" -readme = "README.md" repository = "https://github.com/housleyjk/ws-rs" -version = "0.7.3" +[dependencies.byteorder] +version = "1.2.1" -[dependencies] -httparse = "1.0" -log = "0.3.1" -mio = "0.6" -rand = "0.3.10" -sha1 = "0.2" -url = "1.0" -slab = "0.3" -bytes = "0.4" -byteorder = "1.0" +[dependencies.bytes] +version = "0.4.6" -[dev-dependencies] -clap = "2.0" -env_logger = "0.4" -term = "0.4" -time = "0.1.25" +[dependencies.httparse] +version = "1.2.4" [dependencies.libc] +version = "0.2.40" optional = true -version = "0.2.20" [dependencies.libz-sys] +version = "1.0.18" +optional = true + +[dependencies.log] +version = "0.4.1" + +[dependencies.mio] +version = "0.6.14" + +[dependencies.mio-extras] +version = "2.0" + +[dependencies.native-tls] +version = "0.2" optional = true -version = "1.0.13" [dependencies.openssl] +version = "0.10" optional = true -version = "0.9" + +[dependencies.rand] +version = "0.6" + +[dependencies.sha-1] +version = "0.8.0" + +[dependencies.slab] +version = "0.4" + +[dependencies.url] +version = "1.7.0" +[dev-dependencies.clap] +version = "2.31.2" + +[dev-dependencies.env_logger] +version = "0.6" + +[dev-dependencies.term] +version = "0.5.1" + +[dev-dependencies.time] +version = "0.1.39" [features] default = [] +nativetls = ["native-tls"] permessage-deflate = ["libz-sys", "libc"] ssl = ["openssl"] diff --git a/third_party/rust/ws/README.md b/third_party/rust/ws/README.md index 4d33c1c19f09..4e1a4034218f 100644 --- a/third_party/rust/ws/README.md +++ b/third_party/rust/ws/README.md @@ -1,6 +1,6 @@ # WS-RS -Lightweight, event-driven WebSockets for [Rust](http://www.rust-lang.org). +Lightweight, event-driven WebSockets for [Rust](https://www.rust-lang.org). ```rust /// A WebSocket echo server @@ -45,7 +45,7 @@ WS-RS provides a complete implementation of the WebSocket specification. There i Testing ------- -WS-RS is thoroughly tested and passes the [Autobahn Test Suite](http://autobahn.ws/testsuite/) for +WS-RS is thoroughly tested and passes the [Autobahn Test Suite](https://crossbar.io/autobahn/) for WebSockets, including the tests for `permessage-deflate`. Visit [ws-rs.org](https://ws-rs.org/testing/autobahn/results) to view the results of the latest test run. diff --git a/third_party/rust/ws/examples/autobahn-client.rs b/third_party/rust/ws/examples/autobahn-client.rs index f6d0f5dd3aeb..110592d7a607 100644 --- a/third_party/rust/ws/examples/autobahn-client.rs +++ b/third_party/rust/ws/examples/autobahn-client.rs @@ -1,32 +1,27 @@ /// WebSocket client used for testing against the Autobahn Test Suite - extern crate ws; -use std::rc::Rc; use std::cell::Cell; +use std::rc::Rc; use ws::{connect, CloseCode, Message, Result}; -#[cfg(feature="permessage-deflate")] +#[cfg(feature = "permessage-deflate")] use ws::deflate::DeflateHandler; -const AGENT: &'static str = "WS-RS"; - -#[cfg(not(feature="permessage-deflate"))] -fn main () { +const AGENT: &str = "WS-RS"; +#[cfg(not(feature = "permessage-deflate"))] +fn main() { let total = get_case_count().unwrap(); let mut case_id = 1; - while case_id <= total { + let case_url = format!( + "ws://127.0.0.1:9001/runCase?case={}&agent={}", + case_id, AGENT + ); - let case_url = format!("ws://127.0.0.1:9001/runCase?case={}&agent={}", case_id, AGENT); - - connect(case_url, |out| { - move |msg| { - out.send(msg) - } - }).unwrap(); + connect(case_url, |out| move |msg| out.send(msg)).unwrap(); case_id += 1 } @@ -34,21 +29,19 @@ fn main () { update_reports().unwrap(); } -#[cfg(feature="permessage-deflate")] -fn main () { - +#[cfg(feature = "permessage-deflate")] +fn main() { let total = get_case_count().unwrap(); let mut case_id = 1; - while case_id <= total { - - let case_url = format!("ws://127.0.0.1:9001/runCase?case={}&agent={}", case_id, AGENT); + let case_url = format!( + "ws://127.0.0.1:9001/runCase?case={}&agent={}", + case_id, AGENT + ); connect(case_url, |out| { - DeflateHandler::new(move |msg| { - out.send(msg) - }) + DeflateHandler::new(move |msg| out.send(msg)) }).unwrap(); case_id += 1 @@ -58,24 +51,20 @@ fn main () { } fn get_case_count() -> Result { - // sadly we need to use a Cell because we need to set the total, and RC is immutable let total = Rc::new(Cell::new(0)); - try!(connect("ws://127.0.0.1:9001/getCaseCount", |out| { - + connect("ws://127.0.0.1:9001/getCaseCount", |out| { let my_total = total.clone(); move |msg: Message| { - - let count = try!(msg.as_text()); + let count = msg.as_text()?; my_total.set(count.parse::().unwrap()); out.close(CloseCode::Normal) } - - })); + })?; Ok(total.get()) } @@ -83,9 +72,5 @@ fn get_case_count() -> Result { fn update_reports() -> Result<()> { let report_url = format!("ws://127.0.0.1:9001/updateReports?agent={}", AGENT); - connect(report_url, |out| { - move |_| { - out.close(CloseCode::Normal) - } - }) + connect(report_url, |out| move |_| out.close(CloseCode::Normal)) } diff --git a/third_party/rust/ws/examples/autobahn-server.rs b/third_party/rust/ws/examples/autobahn-server.rs index 86931c7f5876..c0a9a0009b40 100644 --- a/third_party/rust/ws/examples/autobahn-server.rs +++ b/third_party/rust/ws/examples/autobahn-server.rs @@ -1,30 +1,25 @@ +extern crate env_logger; /// WebSocket server used for testing against the Autobahn Test Suite. This is basically the server /// example without printing output or comments. - extern crate ws; -extern crate env_logger; -#[cfg(feature="permessage-deflate")] +#[cfg(feature = "permessage-deflate")] use ws::deflate::DeflateHandler; -#[cfg(not(feature="permessage-deflate"))] -fn main () { - env_logger::init().unwrap(); +#[cfg(not(feature = "permessage-deflate"))] +fn main() { + env_logger::init(); ws::listen("127.0.0.1:3012", |out| { - move |msg| { - out.send(msg) - } + move |msg| out.send(msg) }).unwrap() } -#[cfg(feature="permessage-deflate")] -fn main () { - env_logger::init().unwrap(); +#[cfg(feature = "permessage-deflate")] +fn main() { + env_logger::init(); ws::listen("127.0.0.1:3012", |out| { - DeflateHandler::new(move |msg| { - out.send(msg) - }) + DeflateHandler::new(move |msg| out.send(msg)) }).unwrap(); } diff --git a/third_party/rust/ws/examples/bench-server.rs b/third_party/rust/ws/examples/bench-server.rs index cf7fe24fd06a..bccfe66fb6b3 100644 --- a/third_party/rust/ws/examples/bench-server.rs +++ b/third_party/rust/ws/examples/bench-server.rs @@ -1,16 +1,16 @@ - /// WebSocket server used for testing the bench example. extern crate ws; -use ws::{Builder, Settings, Sender}; +use ws::{Builder, Sender, Settings}; -fn main () { - Builder::new().with_settings(Settings { - max_connections: 10_000, - ..Settings::default() - }).build(|out: Sender| { - move |msg| { - out.send(msg) - } - }).unwrap().listen("127.0.0.1:3012").unwrap(); +fn main() { + Builder::new() + .with_settings(Settings { + max_connections: 10_000, + ..Settings::default() + }) + .build(|out: Sender| move |msg| out.send(msg)) + .unwrap() + .listen("127.0.0.1:3012") + .unwrap(); } diff --git a/third_party/rust/ws/examples/bench.rs b/third_party/rust/ws/examples/bench.rs index 6a423b2f1fb9..427f84147f54 100644 --- a/third_party/rust/ws/examples/bench.rs +++ b/third_party/rust/ws/examples/bench.rs @@ -1,11 +1,10 @@ +extern crate env_logger; +extern crate time; +extern crate url; /// A simple, but immature, benchmark client for destroying other WebSocket frameworks and proving /// WS-RS's performance excellence. ;) /// Make sure you allow for enough connections in your OS (e.g. ulimit -Sn 10000). - extern crate ws; -extern crate url; -extern crate time; -extern crate env_logger; // Try this against node for some fun @@ -13,14 +12,14 @@ extern crate env_logger; // TODO: num threads, num connections per thread, num concurrent connections per thread, num // messages per connection, length of message, text or binary -use ws::{Builder, Settings, Sender, CloseCode, Handler, Message, Handshake, Result}; +use ws::{Builder, CloseCode, Handler, Handshake, Message, Result, Sender, Settings}; const CONNECTIONS: usize = 10_000; // simultaneous const MESSAGES: u32 = 10; static MESSAGE: &'static str = "TEST TEST TEST TEST TEST TEST TEST TEST"; -fn main () { - env_logger::init().unwrap(); +fn main() { + env_logger::init(); let url = url::Url::parse("ws://127.0.0.1:3012").unwrap(); @@ -32,19 +31,19 @@ fn main () { } impl Handler for Connection { - fn on_open(&mut self, _: Handshake) -> Result<()> { - try!(self.out.send(MESSAGE)); + self.out.send(MESSAGE)?; self.count += 1; - Ok(self.time = time::precise_time_ns()) + self.time = time::precise_time_ns(); + Ok(()) } fn on_message(&mut self, msg: Message) -> Result<()> { assert_eq!(msg.as_text().unwrap(), MESSAGE); if self.count > MESSAGES { - try!(self.out.close(CloseCode::Normal)); + self.out.close(CloseCode::Normal)?; } else { - try!(self.out.send(MESSAGE)); + self.out.send(MESSAGE)?; let time = time::precise_time_ns(); // println!("time {}", time -self.time); self.total += time - self.time; @@ -55,23 +54,26 @@ fn main () { } } - let mut ws = Builder::new().with_settings(Settings { - max_connections: CONNECTIONS, - ..Settings::default() - }).build(|out| { - Connection { - out: out, + let mut ws = Builder::new() + .with_settings(Settings { + max_connections: CONNECTIONS, + ..Settings::default() + }) + .build(|out| Connection { + out, count: 0, time: 0, total: 0, - } - }).unwrap(); - + }) + .unwrap(); for _ in 0..CONNECTIONS { ws.connect(url.clone()).unwrap(); } let start = time::precise_time_ns(); ws.run().unwrap(); - println!("Total time. {}", (time::precise_time_ns() - start) / 1_000_000) + println!( + "Total time. {}", + (time::precise_time_ns() - start) / 1_000_000 + ) } diff --git a/third_party/rust/ws/examples/channel.rs b/third_party/rust/ws/examples/channel.rs index b9fafbba441a..fb21901297bb 100644 --- a/third_party/rust/ws/examples/channel.rs +++ b/third_party/rust/ws/examples/channel.rs @@ -1,3 +1,4 @@ +extern crate env_logger; /// An example of using channels to transfer data between three parts of some system. /// /// A WebSocket server echoes data back to a client and tees that data to a logging system. @@ -7,23 +8,19 @@ /// /// This example demonstrates how to use threads, channels, and WebSocket handlers to create a /// complex system from simple, composable parts. - extern crate ws; -extern crate env_logger; +use std::sync::mpsc::Sender as ThreadOut; +use std::sync::mpsc::channel; use std::thread; use std::thread::sleep; use std::time::Duration; -use std::sync::mpsc::channel; -use std::sync::mpsc::Sender as ThreadOut; -use ws::{connect, listen, CloseCode, Message, Sender, Handler, Handshake, Result}; - - -fn main () { +use ws::{connect, listen, CloseCode, Handler, Handshake, Message, Result, Sender}; +fn main() { // Setup logging - env_logger::init().unwrap(); + env_logger::init(); // Data to be sent across WebSockets and channels let data = vec![1, 2, 3, 4, 5]; @@ -37,7 +34,6 @@ fn main () { } impl Handler for Server { - fn on_message(&mut self, msg: Message) -> Result<()> { println!("Server got message '{}'. ", msg); @@ -54,16 +50,19 @@ fn main () { } // Server thread - let server = thread::Builder::new().name("server".to_owned()).spawn(move || { - listen("127.0.0.1:3012", |out| { - Server { - ws: out, - // we need to clone the channel because - // in theory, there could be many active connections - log: log_in.clone(), - } - }).unwrap() - }).unwrap(); + let server = thread::Builder::new() + .name("server".to_owned()) + .spawn(move || { + listen("127.0.0.1:3012", |out| { + Server { + ws: out, + // we need to clone the channel because + // in theory, there could be many active connections + log: log_in.clone(), + } + }).unwrap() + }) + .unwrap(); // Give the server a little time to get going sleep(Duration::from_millis(10)); @@ -76,28 +75,22 @@ fn main () { } impl Client { - // Core business logic for client, keeping it DRY fn increment(&mut self) -> Result<()> { if let Some(num) = self.data.get(self.ind) { - // Advance the index self.ind += 1; // Send the number to the server self.out.send(num.to_string()) - } else { - // All of the data has been sent, let's close self.out.close(CloseCode::Normal) } } - } impl Handler for Client { - fn on_open(&mut self, _: Handshake) -> Result<()> { self.increment() } @@ -113,36 +106,40 @@ fn main () { let client_data = data.clone(); // Client thread - let client = thread::Builder::new().name("client".to_owned()).spawn(move || { - connect("ws://127.0.0.1:3012", |out| { - - Client { - out: out, - ind: 0, - // we need to clone again because - // in theory, there could be many client connections sending off the data - data: client_data.clone(), - } - - }).unwrap() - }).unwrap(); + let client = thread::Builder::new() + .name("client".to_owned()) + .spawn(move || { + connect("ws://127.0.0.1:3012", |out| { + Client { + out, + ind: 0, + // we need to clone again because + // in theory, there could be many client connections sending off the data + data: client_data.clone(), + } + }).unwrap() + }) + .unwrap(); // Logger thread - let logger = thread::Builder::new().name("logger".to_owned()).spawn(move || { - // Make a new vector to store the numbers - let mut log: Vec = Vec::new(); + let logger = thread::Builder::new() + .name("logger".to_owned()) + .spawn(move || { + // Make a new vector to store the numbers + let mut log: Vec = Vec::new(); - // Receive data and push it to the log, this only works if we have one WebSocket - // connection, otherwise the log would have data from all connections. But for our example, - // we know we only have one :) - while let Ok(string) = log_out.recv() { - println!("Logger is storing {}", string); - log.push(string.parse().unwrap()); - } + // Receive data and push it to the log, this only works if we have one WebSocket + // connection, otherwise the log would have data from all connections. But for our example, + // we know we only have one :) + while let Ok(string) = log_out.recv() { + println!("Logger is storing {}", string); + log.push(string.parse().unwrap()); + } - println!("Logger sending final log result."); - final_in.send(log).unwrap(); - }).unwrap(); + println!("Logger sending final log result."); + final_in.send(log).unwrap(); + }) + .unwrap(); // Wait for the worker threads to finish what they are doing let _ = server.join(); @@ -157,4 +154,3 @@ fn main () { println!("All done.") } - diff --git a/third_party/rust/ws/examples/cli.rs b/third_party/rust/ws/examples/cli.rs index c9c830ad2f3d..80ebf8cc6bf0 100644 --- a/third_party/rust/ws/examples/cli.rs +++ b/third_party/rust/ws/examples/cli.rs @@ -1,46 +1,36 @@ +extern crate clap; +extern crate env_logger; +extern crate term; /// Run this cli like this: /// cargo run --example server /// cargo run --example cli -- ws://127.0.0.1:3012 - extern crate ws; -extern crate clap; -extern crate term; -extern crate env_logger; use std::io; use std::io::prelude::*; -use std::thread; -use std::sync::mpsc::channel; use std::sync::mpsc::Sender as TSender; +use std::sync::mpsc::channel; +use std::thread; use clap::{App, Arg}; -use ws::{ - connect, - Sender, - CloseCode, - Handler, - Message, - Handshake, - Result, - Error, - ErrorKind, -}; - +use ws::{connect, CloseCode, Error, ErrorKind, Handler, Handshake, Message, Result, Sender}; fn main() { - // Setup logging - env_logger::init().unwrap(); + env_logger::init(); // setup command line arguments let matches = App::new("WS Command Line Client") .version("1.1") .author("Jason Housley ") .about("Connect to a WebSocket and send messages from the command line.") - .arg(Arg::with_name("URL") - .help("The URL of the WebSocket server.") - .required(true) - .index(1)).get_matches(); + .arg( + Arg::with_name("URL") + .help("The URL of the WebSocket server.") + .required(true) + .index(1), + ) + .get_matches(); let url = matches.value_of("URL").unwrap().to_string(); @@ -49,11 +39,9 @@ fn main() { // Run client thread with channel to give it's WebSocket message sender back to us let client = thread::spawn(move || { println!("Connecting to {}", url); - connect(url, |sender| { - Client { - ws_out: sender, - thread_out: tx.clone(), - } + connect(url, |sender| Client { + ws_out: sender, + thread_out: tx.clone(), }).unwrap(); }); @@ -68,13 +56,12 @@ fn main() { io::stdin().read_line(&mut input).unwrap(); if let Ok(Event::Disconnect) = rx.try_recv() { - break + break; } if input.starts_with("/h") { // Show help instructions() - } else if input.starts_with("/c") { // If the close arguments are good, close the connection let args: Vec<&str> = input.split(' ').collect(); @@ -82,7 +69,6 @@ fn main() { // Simple close println!("Closing normally, please wait..."); sender.close(CloseCode::Normal).unwrap(); - } else if args.len() == 2 { // Close with a specific code if let Ok(code) = args[1].trim().parse::() { @@ -90,30 +76,33 @@ fn main() { println!("Closing with code: {:?}, please wait...", code); sender.close(code).unwrap(); } else { - display(format!("Unable to parse {} as close code.", args[1])); + display(&format!("Unable to parse {} as close code.", args[1])); // Keep accepting input if the close arguments are invalid - continue + continue; } - } else { // Close with a code and a reason if let Ok(code) = args[1].trim().parse::() { let code = CloseCode::from(code); let reason = args[2..].join(" "); - println!("Closing with code: {:?} and reason: {}, please wait...", code, reason.trim()); - sender.close_with_reason(code, reason.trim().to_string()).unwrap(); + println!( + "Closing with code: {:?} and reason: {}, please wait...", + code, + reason.trim() + ); + sender + .close_with_reason(code, reason.trim().to_string()) + .unwrap(); } else { - display(format!("Unable to parse {} as close code.", args[1])); + display(&format!("Unable to parse {} as close code.", args[1])); // Keep accepting input if the close arguments are invalid - continue + continue; } - } - break - + break; } else { // Send the message - display(format!(">>> {}", input.trim())); + display(&format!(">>> {}", input.trim())); sender.send(input.trim()).unwrap(); } } @@ -123,7 +112,7 @@ fn main() { client.join().unwrap(); } -fn display(string: String) { +fn display(string: &str) { let mut view = term::stdout().unwrap(); view.carriage_return().unwrap(); view.delete_line().unwrap(); @@ -146,35 +135,43 @@ struct Client { } impl Handler for Client { - fn on_open(&mut self, _: Handshake) -> Result<()> { self.thread_out .send(Event::Connect(self.ws_out.clone())) - .map_err(|err| Error::new( - ErrorKind::Internal, - format!("Unable to communicate between threads: {:?}.", err))) + .map_err(|err| { + Error::new( + ErrorKind::Internal, + format!("Unable to communicate between threads: {:?}.", err), + ) + }) } fn on_message(&mut self, msg: Message) -> Result<()> { - Ok(display(format!("<<< {}", msg))) + display(&format!("<<< {}", msg)); + Ok(()) } fn on_close(&mut self, code: CloseCode, reason: &str) { if reason.is_empty() { - display(format!("<<< Closing<({:?})>\nHit any key to end session.", code)); + display(&format!( + "<<< Closing<({:?})>\nHit any key to end session.", + code + )); } else { - display(format!("<<< Closing<({:?}) {}>\nHit any key to end session.", code, reason)); + display(&format!( + "<<< Closing<({:?}) {}>\nHit any key to end session.", + code, reason + )); } if let Err(err) = self.thread_out.send(Event::Disconnect) { - display(format!("{:?}", err)) + display(&format!("{:?}", err)) } } fn on_error(&mut self, err: Error) { - display(format!("<<< Error<{:?}>", err)) + display(&format!("<<< Error<{:?}>", err)) } - } enum Event { diff --git a/third_party/rust/ws/examples/client.rs b/third_party/rust/ws/examples/client.rs index 5a3b0b6bcc8c..5390af3a23ab 100644 --- a/third_party/rust/ws/examples/client.rs +++ b/third_party/rust/ws/examples/client.rs @@ -1,21 +1,18 @@ +extern crate env_logger; /// Simple WebSocket client with error handling. It is not necessary to setup logging, but doing /// so will allow you to see more details about the connection by using the RUST_LOG env variable. - extern crate ws; -extern crate env_logger; use ws::{connect, CloseCode}; -fn main () { - +fn main() { // Setup logging - env_logger::init().unwrap(); + env_logger::init(); // Connect to the url and call the closure if let Err(error) = connect("ws://127.0.0.1:3012", |out| { - // Queue a message to be sent when the WebSocket is open - if let Err(_) = out.send("Hello WebSocket") { + if out.send("Hello WebSocket").is_err() { println!("Websocket couldn't queue an initial message.") } else { println!("Client sent message 'Hello WebSocket'. ") @@ -23,17 +20,14 @@ fn main () { // The handler needs to take ownership of out, so we use move move |msg| { - // Handle messages received on this connection println!("Client got message '{}'. ", msg); // Close the connection out.close(CloseCode::Normal) } - }) { // Inform the user of failure println!("Failed to create WebSocket due to: {:?}", error); } - } diff --git a/third_party/rust/ws/examples/external_shutdown.rs b/third_party/rust/ws/examples/external_shutdown.rs index c19337fc2cf5..9e6f009ecd8a 100644 --- a/third_party/rust/ws/examples/external_shutdown.rs +++ b/third_party/rust/ws/examples/external_shutdown.rs @@ -1,22 +1,24 @@ extern crate ws; +use std::sync::mpsc::channel; use std::thread; use std::time::Duration; -use std::sync::mpsc::channel; - fn main() { let (tx, rx) = channel(); - let socket = ws::Builder::new().build(move |out: ws::Sender| { + let socket = ws::Builder::new() + .build(move |out: ws::Sender| { + // When we get a connection, send a handle to the parent thread + tx.send(out).unwrap(); - // When we get a connection, send a handle to the parent thread - tx.send(out).unwrap(); - - // Dummy message handler - move |_| Ok(println!("Message handler called.")) - - }).unwrap(); + // Dummy message handler + move |_| { + println!("Message handler called."); + Ok(()) + } + }) + .unwrap(); let handle = socket.broadcaster(); @@ -27,15 +29,12 @@ fn main() { // Wait for 5 seconds only for incoming connections; thread::sleep(Duration::from_millis(5000)); - if let Err(_) = rx.try_recv() { - + if rx.try_recv().is_err() { // shutdown the server from the outside handle.shutdown().unwrap(); println!("Shutting down server because no connections were established."); - } // Let the server finish up (whether it's waiting for new connections or going down) t.join().unwrap(); - } diff --git a/third_party/rust/ws/examples/html_chat.rs b/third_party/rust/ws/examples/html_chat.rs new file mode 100644 index 000000000000..7b7059b83a76 --- /dev/null +++ b/third_party/rust/ws/examples/html_chat.rs @@ -0,0 +1,66 @@ +/// An example of a chat web application server +extern crate ws; +use ws::{listen, Handler, Message, Request, Response, Result, Sender}; + +// This can be read from a file +static INDEX_HTML: &'static [u8] = br#" + + + + + + +

+			
+ + +
+ + + + "#; + +// Server web application handler +struct Server { + out: Sender, +} + +impl Handler for Server { + // + fn on_request(&mut self, req: &Request) -> Result<(Response)> { + // Using multiple handlers is better (see router example) + match req.resource() { + // The default trait implementation + "/ws" => Response::from_request(req), + + // Create a custom response + "/" => Ok(Response::new(200, "OK", INDEX_HTML.to_vec())), + + _ => Ok(Response::new(404, "Not Found", b"404 - Not Found".to_vec())), + } + } + + // Handle messages recieved in the websocket (in this case, only on /ws) + fn on_message(&mut self, msg: Message) -> Result<()> { + // Broadcast to all connections + self.out.broadcast(msg) + } +} + +fn main() { + // Listen on an address and call the closure for each connection + listen("127.0.0.1:8000", |out| Server { out }).unwrap() +} diff --git a/third_party/rust/ws/examples/peer2peer.rs b/third_party/rust/ws/examples/peer2peer.rs index 15cd9cfe26cf..076c3ac757dc 100644 --- a/third_party/rust/ws/examples/peer2peer.rs +++ b/third_party/rust/ws/examples/peer2peer.rs @@ -1,3 +1,6 @@ +extern crate clap; +extern crate env_logger; +extern crate url; /// An example of a client-server-agnostic WebSocket that takes input from stdin and sends that /// input to all other peers. /// @@ -23,12 +26,9 @@ /// Stdin on 3013 will be sent to 3012 and 3015 /// Stdin on 3014 will be sent to 3012 only /// Stdin on 3015 will be sent to 3012 and 2013 - extern crate ws; -extern crate url; -extern crate clap; -extern crate env_logger; -#[macro_use] extern crate log; +#[macro_use] +extern crate log; use std::io; use std::io::prelude::*; @@ -38,21 +38,25 @@ use clap::{App, Arg}; fn main() { // Setup logging - env_logger::init().unwrap(); + env_logger::init(); // Parse command line arguments let matches = App::new("Simple Peer 2 Peer") .version("1.0") .author("Jason Housley ") .about("Connect to other peers and listen for incoming connections.") - .arg(Arg::with_name("server") - .short("s") - .long("server") - .value_name("SERVER") - .help("Set the address to listen for new connections.")) - .arg(Arg::with_name("PEER") - .help("A WebSocket URL to attempt to connect to at start.") - .multiple(true)) + .arg( + Arg::with_name("server") + .short("s") + .long("server") + .value_name("SERVER") + .help("Set the address to listen for new connections."), + ) + .arg( + Arg::with_name("PEER") + .help("A WebSocket URL to attempt to connect to at start.") + .multiple(true), + ) .get_matches(); // Get address of this peer @@ -61,7 +65,8 @@ fn main() { // Create simple websocket that just prints out messages let mut me = ws::WebSocket::new(|_| { move |msg| { - Ok(info!("Peer {} got message: {}", my_addr, msg)) + info!("Peer {} got message: {}", my_addr, msg); + Ok(()) } }).unwrap(); @@ -88,5 +93,4 @@ fn main() { // Run the websocket me.listen(my_addr).unwrap(); input.join().unwrap(); - } diff --git a/third_party/rust/ws/examples/pong.rs b/third_party/rust/ws/examples/pong.rs index 3c10bdc157c6..5c9c62c2e08e 100644 --- a/third_party/rust/ws/examples/pong.rs +++ b/third_party/rust/ws/examples/pong.rs @@ -1,30 +1,30 @@ +extern crate env_logger; +extern crate mio_extras; +extern crate time; /// An example demonstrating how to send and recieve a custom ping/pong frame. extern crate ws; -extern crate env_logger; -extern crate time; use std::str::from_utf8; -use ws::{listen, CloseCode, OpCode, Sender, Frame, Handler, Handshake, Message, Result, Error, ErrorKind}; -use ws::util::{Token, Timeout}; +use mio_extras::timer::Timeout; + +use ws::util::Token; +use ws::{listen, CloseCode, Error, ErrorKind, Frame, Handler, Handshake, Message, OpCode, Result, + Sender}; const PING: Token = Token(1); const EXPIRE: Token = Token(2); -fn main () { - +fn main() { // Setup logging - env_logger::init().unwrap(); + env_logger::init(); // Run the WebSocket - listen("127.0.0.1:3012", |out| { - Server { - out: out, - ping_timeout: None, - expire_timeout: None, - } + listen("127.0.0.1:3012", |out| Server { + out, + ping_timeout: None, + expire_timeout: None, }).unwrap(); - } // Server WebSocket handler @@ -35,10 +35,9 @@ struct Server { } impl Handler for Server { - fn on_open(&mut self, _: Handshake) -> Result<()> { // schedule a timeout to send a ping every 5 seconds - try!(self.out.timeout(5_000, PING)); + self.out.timeout(5_000, PING)?; // schedule a timeout to close the connection if there is no activity for 30 seconds self.out.timeout(30_000, EXPIRE) } @@ -73,14 +72,17 @@ impl Handler for Server { match event { // PING timeout has occured, send a ping and reschedule PING => { - try!(self.out.ping(time::precise_time_ns().to_string().into())); + self.out.ping(time::precise_time_ns().to_string().into())?; self.ping_timeout.take(); self.out.timeout(5_000, PING) } // EXPIRE timeout has occured, this means that the connection is inactive, let's close EXPIRE => self.out.close(CloseCode::Away), // No other timeouts are possible - _ => Err(Error::new(ErrorKind::Internal, "Invalid timeout token encountered!")), + _ => Err(Error::new( + ErrorKind::Internal, + "Invalid timeout token encountered!", + )), } } @@ -88,13 +90,13 @@ impl Handler for Server { // Cancel the old timeout and replace. if event == EXPIRE { if let Some(t) = self.expire_timeout.take() { - try!(self.out.cancel(t)) + self.out.cancel(t)? } self.expire_timeout = Some(timeout) } else { // This ensures there is only one ping timeout at a time if let Some(t) = self.ping_timeout.take() { - try!(self.out.cancel(t)) + self.out.cancel(t)? } self.ping_timeout = Some(timeout) } @@ -106,7 +108,7 @@ impl Handler for Server { // If the frame is a pong, print the round-trip time. // The pong should contain data from out ping, but it isn't guaranteed to. if frame.opcode() == OpCode::Pong { - if let Ok(pong) = try!(from_utf8(frame.payload())).parse::() { + if let Ok(pong) = from_utf8(frame.payload())?.parse::() { let now = time::precise_time_ns(); println!("RTT is {:.3}ms.", (now - pong) as f64 / 1_000_000f64); } else { @@ -115,7 +117,7 @@ impl Handler for Server { } // Some activity has occured, so reset the expiration - try!(self.out.timeout(30_000, EXPIRE)); + self.out.timeout(30_000, EXPIRE)?; // Run default frame validation DefaultHandler.on_frame(frame) @@ -126,4 +128,3 @@ impl Handler for Server { struct DefaultHandler; impl Handler for DefaultHandler {} - diff --git a/third_party/rust/ws/examples/remote_addr.rs b/third_party/rust/ws/examples/remote_addr.rs index c1cd67a8ac91..d32e17af25c9 100644 --- a/third_party/rust/ws/examples/remote_addr.rs +++ b/third_party/rust/ws/examples/remote_addr.rs @@ -1,5 +1,4 @@ /// Example showing how to obtain the ip address of the client, where possible. - extern crate ws; struct Server { @@ -7,9 +6,8 @@ struct Server { } impl ws::Handler for Server { - fn on_open(&mut self, shake: ws::Handshake) -> ws::Result<()> { - if let Some(ip_addr) = try!(shake.remote_addr()) { + if let Some(ip_addr) = shake.remote_addr()? { println!("Connection opened from {}.", ip_addr) } else { println!("Unable to obtain client's IP address.") @@ -22,8 +20,6 @@ impl ws::Handler for Server { } } -fn main () { - ws::listen("127.0.0.1:3012", |out| { - Server { ws: out } - }).unwrap() +fn main() { + ws::listen("127.0.0.1:3012", |out| Server { ws: out }).unwrap() } diff --git a/third_party/rust/ws/examples/router.rs b/third_party/rust/ws/examples/router.rs index fb6f6b3733e8..8e699298e904 100644 --- a/third_party/rust/ws/examples/router.rs +++ b/third_party/rust/ws/examples/router.rs @@ -1,7 +1,7 @@ +extern crate env_logger; /// WebSocket server using trait objects to route /// to an infinitely extensible number of handlers extern crate ws; -extern crate env_logger; // A WebSocket handler that routes connections to different boxed handlers by resource struct Router { @@ -11,30 +11,35 @@ struct Router { impl ws::Handler for Router { fn on_request(&mut self, req: &ws::Request) -> ws::Result<(ws::Response)> { - // Clone the sender so that we can move it into the child handler let out = self.sender.clone(); match req.resource() { - "/echo" => self.inner = Box::new(Echo { ws: out } ), + "/echo" => self.inner = Box::new(Echo { ws: out }), // Route to a data handler - "/data/one" => self.inner = Box::new(Data { - ws: out, - data: vec!["one", "two", "three", "four", "five"] - }), + "/data/one" => { + self.inner = Box::new(Data { + ws: out, + data: vec!["one", "two", "three", "four", "five"], + }) + } // Route to another data handler - "/data/two" => self.inner = Box::new(Data { - ws: out, - data: vec!["ã„ã¡", "二", "ã•ã‚“", "å››", "ã”"] - }), + "/data/two" => { + self.inner = Box::new(Data { + ws: out, + data: vec!["ã„ã¡", "二", "ã•ã‚“", "å››", "ã”"], + }) + } // Use a closure as the child handler - "/closure" => self.inner = Box::new(move |msg: ws::Message| { - println!("Got a message on a closure handler: {}", msg); - out.close_with_reason(ws::CloseCode::Error, "Not Implemented.") - }), + "/closure" => { + self.inner = Box::new(move |msg: ws::Message| { + println!("Got a message on a closure handler: {}", msg); + out.close_with_reason(ws::CloseCode::Error, "Not Implemented.") + }) + } // Use the default child handler, NotFound _ => (), @@ -74,30 +79,25 @@ impl ws::Handler for Router { struct NotFound; impl ws::Handler for NotFound { - fn on_request(&mut self, req: &ws::Request) -> ws::Result<(ws::Response)> { // This handler responds to all requests with a 404 - let mut res = try!(ws::Response::from_request(req)); + let mut res = ws::Response::from_request(req)?; res.set_status(404); res.set_reason("Not Found"); Ok(res) } - } - // This handler simply echoes all messages back to the client struct Echo { ws: ws::Sender, } impl ws::Handler for Echo { - fn on_message(&mut self, msg: ws::Message) -> ws::Result<()> { println!("Echo handler received a message: {}", msg); self.ws.send(msg) } - } // This handler sends some data to the client and then terminates the connection on the first @@ -109,8 +109,8 @@ struct Data { impl ws::Handler for Data { fn on_open(&mut self, _: ws::Handshake) -> ws::Result<()> { - for msg in self.data.iter() { - try!(self.ws.send(*msg)) + for msg in &self.data { + self.ws.send(*msg)? } Ok(()) } @@ -122,14 +122,11 @@ impl ws::Handler for Data { } } - -fn main () { - - env_logger::init().unwrap(); +fn main() { + env_logger::init(); // Listen on an address and call the closure for each connection if let Err(error) = ws::listen("127.0.0.1:3012", |out| { - // Use our router as the handler to route the new connection Router { sender: out, @@ -137,7 +134,6 @@ fn main () { // You could default to any handler here. inner: Box::new(NotFound), } - }) { // Inform the user of failure println!("Failed to create WebSocket due to {:?}", error); diff --git a/third_party/rust/ws/examples/server.rs b/third_party/rust/ws/examples/server.rs index b890613e013f..fd9f5ae671e4 100644 --- a/third_party/rust/ws/examples/server.rs +++ b/third_party/rust/ws/examples/server.rs @@ -1,32 +1,26 @@ +extern crate env_logger; /// Simple WebSocket server with error handling. It is not necessary to setup logging, but doing /// so will allow you to see more details about the connection by using the RUST_LOG env variable. - extern crate ws; -extern crate env_logger; use ws::listen; -fn main () { - +fn main() { // Setup logging - env_logger::init().unwrap(); + env_logger::init(); // Listen on an address and call the closure for each connection if let Err(error) = listen("127.0.0.1:3012", |out| { - // The handler needs to take ownership of out, so we use move move |msg| { - // Handle messages received on this connection println!("Server got message '{}'. ", msg); // Use the out channel to send messages back out.send(msg) } - }) { // Inform the user of failure println!("Failed to create WebSocket due to {:?}", error); } - } diff --git a/third_party/rust/ws/examples/shared.rs b/third_party/rust/ws/examples/shared.rs index d0ec15440e46..e466f5ed4620 100644 --- a/third_party/rust/ws/examples/shared.rs +++ b/third_party/rust/ws/examples/shared.rs @@ -1,23 +1,20 @@ +extern crate env_logger; +extern crate url; /// A single-threaded client + server example showing how flexible closure handlers can be for /// trivial applications. - extern crate ws; -extern crate url; -extern crate env_logger; -use ws::{WebSocket, Sender}; - -fn main () { +use ws::{Sender, WebSocket}; +fn main() { // Setup logging - env_logger::init().unwrap(); + env_logger::init(); // A variable to distinguish the two halves let mut name = "Client"; // Create a WebSocket with a closure as the factory let mut ws = WebSocket::new(|output: Sender| { - // The first connection is named Client if name == "Client" { println!("{} sending 'Hello Websocket' ", name); diff --git a/third_party/rust/ws/examples/ssl-server.rs b/third_party/rust/ws/examples/ssl-server.rs index 25bea04433fe..ca788513e728 100644 --- a/third_party/rust/ws/examples/ssl-server.rs +++ b/third_party/rust/ws/examples/ssl-server.rs @@ -1,3 +1,7 @@ +extern crate clap; +extern crate env_logger; +#[cfg(feature = "ssl")] +extern crate openssl; /// WebSocket server to demonstrate ssl encryption within an a websocket server. /// /// The resulting executable takes three arguments: @@ -7,37 +11,32 @@ /// /// For more details concerning setting up the SSL context, see rust-openssl docs. extern crate ws; -extern crate clap; -#[cfg(feature="ssl")] -extern crate openssl; -extern crate env_logger; -#[cfg(feature="ssl")] -use std::rc::Rc; -#[cfg(feature="ssl")] -use std::io::Read; -#[cfg(feature="ssl")] +#[cfg(feature = "ssl")] use std::fs::File; +#[cfg(feature = "ssl")] +use std::io::Read; +#[cfg(feature = "ssl")] +use std::rc::Rc; -#[cfg(feature="ssl")] -use openssl::ssl::{SslAcceptor, SslAcceptorBuilder, SslMethod, SslStream}; -#[cfg(feature="ssl")] +#[cfg(feature = "ssl")] use openssl::pkey::PKey; -#[cfg(feature="ssl")] -use openssl::x509::{X509, X509Ref}; +#[cfg(feature = "ssl")] +use openssl::ssl::{SslAcceptor, SslMethod, SslStream}; +#[cfg(feature = "ssl")] +use openssl::x509::X509; -#[cfg(feature="ssl")] +#[cfg(feature = "ssl")] use ws::util::TcpStream; -#[cfg(feature="ssl")] +#[cfg(feature = "ssl")] struct Server { out: ws::Sender, ssl: Rc, } -#[cfg(feature="ssl")] +#[cfg(feature = "ssl")] impl ws::Handler for Server { - fn on_message(&mut self, msg: ws::Message) -> ws::Result<()> { self.out.send(msg) // simple echo } @@ -47,28 +46,34 @@ impl ws::Handler for Server { } } -#[cfg(feature="ssl")] -fn main () { +#[cfg(feature = "ssl")] +fn main() { // Setup logging - env_logger::init().unwrap(); + env_logger::init(); // setup command line arguments let matches = clap::App::new("WS-RS SSL Server Configuration") .version("1.0") .author("Jason Housley ") .about("Establish a WebSocket server that encrypts and decrypts messages.") - .arg(clap::Arg::with_name("ADDR") - .help("Address on which to bind the server.") - .required(true) - .index(1)) - .arg(clap::Arg::with_name("CERT") - .help("Path to the SSL certificate.") - .required(true) - .index(2)) - .arg(clap::Arg::with_name("KEY") - .help("Path to the SSL certificate key.") - .required(true) - .index(3)) + .arg( + clap::Arg::with_name("ADDR") + .help("Address on which to bind the server.") + .required(true) + .index(1), + ) + .arg( + clap::Arg::with_name("CERT") + .help("Path to the SSL certificate.") + .required(true) + .index(2), + ) + .arg( + clap::Arg::with_name("KEY") + .help("Path to the SSL certificate key.") + .required(true) + .index(3), + ) .get_matches(); let cert = { @@ -81,33 +86,37 @@ fn main () { PKey::private_key_from_pem(data.as_ref()).unwrap() }; - let acceptor = Rc::new(SslAcceptorBuilder::mozilla_intermediate( - SslMethod::tls(), - &pkey, - &cert, - std::iter::empty::(), - ).unwrap().build()); + let acceptor = Rc::new({ + let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); + builder.set_private_key(&pkey).unwrap(); + builder.set_certificate(&cert).unwrap(); - ws::Builder::new().with_settings(ws::Settings { - encrypt_server: true, - ..ws::Settings::default() - }).build(|out: ws::Sender| { - Server { + builder.build() + }); + + ws::Builder::new() + .with_settings(ws::Settings { + encrypt_server: true, + ..ws::Settings::default() + }) + .build(|out: ws::Sender| Server { out: out, ssl: acceptor.clone(), - } - }).unwrap().listen(matches.value_of("ADDR").unwrap()).unwrap(); + }) + .unwrap() + .listen(matches.value_of("ADDR").unwrap()) + .unwrap(); } -#[cfg(feature="ssl")] +#[cfg(feature = "ssl")] fn read_file(name: &str) -> std::io::Result> { - let mut file = try!(File::open(name)); + let mut file = File::open(name)?; let mut buf = Vec::new(); - try!(file.read_to_end(&mut buf)); + file.read_to_end(&mut buf)?; Ok(buf) } -#[cfg(not(feature="ssl"))] +#[cfg(not(feature = "ssl"))] fn main() { println!("SSL feature is not enabled.") } diff --git a/third_party/rust/ws/examples/threaded.rs b/third_party/rust/ws/examples/threaded.rs index 9c306b07c80b..35cf0002fcc3 100644 --- a/third_party/rust/ws/examples/threaded.rs +++ b/third_party/rust/ws/examples/threaded.rs @@ -1,19 +1,17 @@ +extern crate env_logger; /// A thread-based client + server example. It also demonstrates using a struct as a WebSocket /// handler to implement more handler methods than a closure handler allows. - extern crate ws; -extern crate env_logger; use std::thread; use std::thread::sleep; use std::time::Duration; -use ws::{connect, listen, CloseCode, Sender, Handler, Message, Result}; - -fn main () { +use ws::{connect, listen, CloseCode, Handler, Message, Result, Sender}; +fn main() { // Setup logging - env_logger::init().unwrap(); + env_logger::init(); // Server WebSocket handler struct Server { @@ -21,7 +19,6 @@ fn main () { } impl Handler for Server { - fn on_message(&mut self, msg: Message) -> Result<()> { println!("Server got message '{}'. ", msg); self.out.send(msg) @@ -35,31 +32,21 @@ fn main () { } // Server thread - let server = thread::spawn(move || { - listen("127.0.0.1:3012", |out| { - - Server { out: out } - - }).unwrap() - }); + let server = thread::spawn(move || listen("127.0.0.1:3012", |out| Server { out }).unwrap()); // Give the server a little time to get going sleep(Duration::from_millis(10)); // Client thread let client = thread::spawn(move || { - connect("ws://127.0.0.1:3012", |out| { - out.send("Hello WebSocket").unwrap(); move |msg| { println!("Client got message '{}'. ", msg); out.close(CloseCode::Normal) } - }).unwrap() - }); let _ = server.join(); @@ -67,4 +54,3 @@ fn main () { println!("All done.") } - diff --git a/third_party/rust/ws/examples/unsafe-ssl-client.rs b/third_party/rust/ws/examples/unsafe-ssl-client.rs index 0b195d43f0c5..c055cac54695 100644 --- a/third_party/rust/ws/examples/unsafe-ssl-client.rs +++ b/third_party/rust/ws/examples/unsafe-ssl-client.rs @@ -1,61 +1,69 @@ -extern crate ws; -#[cfg(feature="ssl")] -extern crate openssl; extern crate env_logger; +#[cfg(feature = "ssl")] +extern crate openssl; extern crate url; +extern crate ws; -#[cfg(feature="ssl")] -use openssl::ssl::{SslConnectorBuilder, SslMethod, SslStream, SslVerifyMode}; -#[cfg(feature="ssl")] +#[cfg(feature = "ssl")] +use openssl::ssl::{SslConnector, SslMethod, SslStream, SslVerifyMode}; +#[cfg(feature = "ssl")] use ws::util::TcpStream; -#[cfg(feature="ssl")] +#[cfg(feature = "ssl")] struct Client { out: ws::Sender, } -#[cfg(feature="ssl")] +#[cfg(feature = "ssl")] impl ws::Handler for Client { - fn on_message(&mut self, msg: ws::Message) -> ws::Result<()> { println!("msg = {}", msg); self.out.close(ws::CloseCode::Normal) } - fn upgrade_ssl_client(&mut self, sock: TcpStream, _: &url::Url) -> ws::Result> { - let mut builder = SslConnectorBuilder::new(SslMethod::tls()).map_err(|e| { - ws::Error::new(ws::ErrorKind::Internal, format!("Failed to upgrade client to SSL: {}", e)) + fn upgrade_ssl_client( + &mut self, + sock: TcpStream, + _: &url::Url, + ) -> ws::Result> { + let mut builder = SslConnector::builder(SslMethod::tls()).map_err(|e| { + ws::Error::new( + ws::ErrorKind::Internal, + format!("Failed to upgrade client to SSL: {}", e), + ) })?; - builder.builder_mut().set_verify(SslVerifyMode::empty()); + builder.set_verify(SslVerifyMode::empty()); let connector = builder.build(); connector - .danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(sock) + .configure() + .unwrap() + .use_server_name_indication(false) + .verify_hostname(false) + .connect("", sock) .map_err(From::from) } } -#[cfg(feature="ssl")] -fn main () { +#[cfg(feature = "ssl")] +fn main() { // Setup logging - env_logger::init().unwrap(); + env_logger::init(); if let Err(error) = ws::connect("wss://localhost:3443/api/websocket", |out| { - if let Err(_) = out.send("Hello WebSocket") { println!("Websocket couldn't queue an initial message.") } else { println!("Client sent message 'Hello WebSocket'. ") } - Client { out: out } - + Client { out } }) { println!("Failed to create WebSocket due to: {:?}", error); } } -#[cfg(not(feature="ssl"))] +#[cfg(not(feature = "ssl"))] fn main() { println!("SSL feature is not enabled.") } diff --git a/third_party/rust/ws/src/communication.rs b/third_party/rust/ws/src/communication.rs index 191a7ed98c12..2b2822f03c62 100644 --- a/third_party/rust/ws/src/communication.rs +++ b/third_party/rust/ws/src/communication.rs @@ -1,14 +1,18 @@ -use std::convert::Into; use std::borrow::Cow; +use std::convert::Into; -use url; use mio; use mio::Token; +use mio_extras::timer::Timeout; +use url; -use message; -use result::{Result, Error}; -use protocol::CloseCode; use io::ALL; +use message; +use protocol::CloseCode; +use result::{Error, Result}; +use std::cmp::PartialEq; +use std::hash::{Hash, Hasher}; +use std::fmt; #[derive(Debug, Clone)] pub enum Signal { @@ -18,11 +22,8 @@ pub enum Signal { Pong(Vec), Connect(url::Url), Shutdown, - Timeout { - delay: u64, - token: Token, - }, - Cancel(mio::timer::Timeout), + Timeout { delay: u64, token: Token }, + Cancel(Timeout), } #[derive(Debug, Clone)] @@ -55,15 +56,42 @@ pub struct Sender { connection_id: u32, } -impl Sender { +impl fmt::Debug for Sender { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, + "Sender {{ token: {:?}, channel: mio::channel::SyncSender, connection_id: {:?} }}", + self.token, self.connection_id) + } +} +impl PartialEq for Sender { + fn eq(&self, other: &Sender) -> bool { + self.token == other.token && self.connection_id == other.connection_id + } +} + +impl Eq for Sender { } + +impl Hash for Sender { + fn hash(&self, state: &mut H) { + self.connection_id.hash(state); + self.token.hash(state); + } +} + + +impl Sender { #[doc(hidden)] #[inline] - pub fn new(token: Token, channel: mio::channel::SyncSender, connection_id: u32) -> Sender { + pub fn new( + token: Token, + channel: mio::channel::SyncSender, + connection_id: u32, + ) -> Sender { Sender { - token: token, - channel: channel, - connection_id: connection_id + token, + channel, + connection_id, } } @@ -73,16 +101,25 @@ impl Sender { self.token } + /// A connection_id identifying this sender within the WebSocket. + #[inline] + pub fn connection_id(&self) -> u32 { + self.connection_id + } + /// Send a message over the connection. #[inline] pub fn send(&self, msg: M) -> Result<()> - where M: Into + where + M: Into, { - self.channel.send(Command { - token: self.token, - signal: Signal::Message(msg.into()), - connection_id: self.connection_id, - }).map_err(Error::from) + self.channel + .send(Command { + token: self.token, + signal: Signal::Message(msg.into()), + connection_id: self.connection_id, + }) + .map_err(Error::from) } /// Send a message to the endpoints of all connections. @@ -94,104 +131,119 @@ impl Sender { /// broadcast a copy of the message to all the clients connected and to that WebSocket server. #[inline] pub fn broadcast(&self, msg: M) -> Result<()> - where M: Into + where + M: Into, { - self.channel.send(Command { - token: ALL, - signal: Signal::Message(msg.into()), - connection_id: self.connection_id, - }).map_err(Error::from) + self.channel + .send(Command { + token: ALL, + signal: Signal::Message(msg.into()), + connection_id: self.connection_id, + }) + .map_err(Error::from) } /// Send a close code to the other endpoint. #[inline] pub fn close(&self, code: CloseCode) -> Result<()> { - self.channel.send(Command { - token: self.token, - signal: Signal::Close(code, "".into()), - connection_id: self.connection_id, - }).map_err(Error::from) + self.channel + .send(Command { + token: self.token, + signal: Signal::Close(code, "".into()), + connection_id: self.connection_id, + }) + .map_err(Error::from) } /// Send a close code and provide a descriptive reason for closing. #[inline] pub fn close_with_reason(&self, code: CloseCode, reason: S) -> Result<()> - where S: Into> + where + S: Into>, { - self.channel.send(Command { - token: self.token, - signal: Signal::Close(code, reason.into()), - connection_id: self.connection_id, - }).map_err(Error::from) + self.channel + .send(Command { + token: self.token, + signal: Signal::Close(code, reason.into()), + connection_id: self.connection_id, + }) + .map_err(Error::from) } /// Send a ping to the other endpoint with the given test data. #[inline] pub fn ping(&self, data: Vec) -> Result<()> { - self.channel.send(Command { - token: self.token, - signal: Signal::Ping(data), - connection_id: self.connection_id, - }).map_err(Error::from) + self.channel + .send(Command { + token: self.token, + signal: Signal::Ping(data), + connection_id: self.connection_id, + }) + .map_err(Error::from) } /// Send a pong to the other endpoint responding with the given test data. #[inline] pub fn pong(&self, data: Vec) -> Result<()> { - self.channel.send(Command { - token: self.token, - signal: Signal::Pong(data), - connection_id: self.connection_id, - }).map_err(Error::from) + self.channel + .send(Command { + token: self.token, + signal: Signal::Pong(data), + connection_id: self.connection_id, + }) + .map_err(Error::from) } /// Queue a new connection on this WebSocket to the specified URL. #[inline] pub fn connect(&self, url: url::Url) -> Result<()> { - self.channel.send(Command { - token: self.token, - signal: Signal::Connect(url), - connection_id: self.connection_id, - }).map_err(Error::from) + self.channel + .send(Command { + token: self.token, + signal: Signal::Connect(url), + connection_id: self.connection_id, + }) + .map_err(Error::from) } /// Request that all connections terminate and that the WebSocket stop running. #[inline] pub fn shutdown(&self) -> Result<()> { - self.channel.send(Command { - token: self.token, - signal: Signal::Shutdown, - connection_id: self.connection_id, - }).map_err(Error::from) + self.channel + .send(Command { + token: self.token, + signal: Signal::Shutdown, + connection_id: self.connection_id, + }) + .map_err(Error::from) } /// Schedule a `token` to be sent to the WebSocket Handler's `on_timeout` method /// after `ms` milliseconds #[inline] pub fn timeout(&self, ms: u64, token: Token) -> Result<()> { - self.channel.send(Command { - token: self.token, - signal: Signal::Timeout { - delay: ms, - token: token, - }, - connection_id: self.connection_id, - }).map_err(Error::from) + self.channel + .send(Command { + token: self.token, + signal: Signal::Timeout { delay: ms, token }, + connection_id: self.connection_id, + }) + .map_err(Error::from) } /// Queue the cancellation of a previously scheduled timeout. /// - /// This method is not guaranteed to prevent the timeout from occuring, because it is - /// possible to call this method after a timeout has already occured. It is still necessary to + /// This method is not guaranteed to prevent the timeout from occurring, because it is + /// possible to call this method after a timeout has already occurred. It is still necessary to /// handle spurious timeouts. #[inline] - pub fn cancel(&self, timeout: mio::timer::Timeout) -> Result<()> { - self.channel.send(Command { - token: self.token, - signal: Signal::Cancel(timeout), - connection_id: self.connection_id, - }).map_err(Error::from) + pub fn cancel(&self, timeout: Timeout) -> Result<()> { + self.channel + .send(Command { + token: self.token, + signal: Signal::Cancel(timeout), + connection_id: self.connection_id, + }) + .map_err(Error::from) } - } - diff --git a/third_party/rust/ws/src/connection.rs b/third_party/rust/ws/src/connection.rs index fd60840ed8b7..b639695e5c3c 100644 --- a/third_party/rust/ws/src/connection.rs +++ b/third_party/rust/ws/src/connection.rs @@ -1,28 +1,30 @@ -use std::mem::replace; use std::borrow::Borrow; -use std::io::{Write, Read, Cursor, Seek, SeekFrom}; -use std::net::SocketAddr; use std::collections::VecDeque; +use std::io::{Cursor, Read, Seek, SeekFrom, Write}; +use std::mem::replace; +use std::net::SocketAddr; use std::str::from_utf8; -use url; -use mio::{Token, Ready}; -use mio::timer::Timeout; use mio::tcp::TcpStream; +use mio::{Ready, Token}; +use mio_extras::timer::Timeout; +use url; -#[cfg(feature="ssl")] +#[cfg(feature = "nativetls")] +use native_tls::HandshakeError; +#[cfg(feature = "ssl")] use openssl::ssl::HandshakeError; -use message::Message; -use handshake::{Handshake, Request, Response}; use frame::Frame; -use protocol::{CloseCode, OpCode}; -use result::{Result, Error, Kind}; use handler::Handler; +use handshake::{Handshake, Request, Response}; +use message::Message; +use protocol::{CloseCode, OpCode}; +use result::{Error, Kind, Result}; use stream::{Stream, TryReadBuf, TryWriteBuf}; -use self::State::*; use self::Endpoint::*; +use self::State::*; use super::Settings; @@ -47,7 +49,6 @@ pub enum Endpoint { } impl State { - #[inline] pub fn is_connecting(&self) -> bool { match *self { @@ -68,15 +69,15 @@ impl State { #[inline] pub fn is_closing(&self) -> bool { match *self { - State::AwaitingClose => true, - State::FinishedClose => true, + State::AwaitingClose | State::FinishedClose => true, _ => false, } } } pub struct Connection - where H: Handler +where + H: Handler, { token: Token, socket: Stream, @@ -98,9 +99,16 @@ pub struct Connection } impl Connection - where H: Handler +where + H: Handler, { - pub fn new(tok: Token, sock: TcpStream, handler: H, settings: Settings, connection_id: u32) -> Connection { + pub fn new( + tok: Token, + sock: TcpStream, + handler: H, + settings: Settings, + connection_id: u32, + ) -> Connection { Connection { token: tok, socket: Stream::tcp(sock), @@ -113,15 +121,16 @@ impl Connection fragments: VecDeque::with_capacity(settings.fragments_capacity), in_buffer: Cursor::new(Vec::with_capacity(settings.in_buffer_capacity)), out_buffer: Cursor::new(Vec::with_capacity(settings.out_buffer_capacity)), - handler: handler, + handler, addresses: Vec::new(), - settings: settings, - connection_id: connection_id + settings, + connection_id, } } pub fn as_server(&mut self) -> Result<()> { - Ok(self.events.insert(Ready::readable())) + self.events.insert(Ready::readable()); + Ok(()) } pub fn as_client(&mut self, url: url::Url, addrs: Vec) -> Result<()> { @@ -134,29 +143,50 @@ impl Connection } else { Err(Error::new( Kind::Internal, - "Tried to set connection to client while not connecting.")) + "Tried to set connection to client while not connecting.", + )) } } - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] pub fn encrypt(&mut self) -> Result<()> { - let sock = try!(self.socket().try_clone()); + let sock = self.socket().try_clone()?; let ssl_stream = match self.endpoint { Server => self.handler.upgrade_ssl_server(sock), Client(ref url) => self.handler.upgrade_ssl_client(sock, url), }; match ssl_stream { - Ok(stream) => Ok(self.socket = Stream::tls_live(stream)), - Err(Error { kind: Kind::SslHandshake(handshake_err), details }) => { - match handshake_err { - HandshakeError::SetupFailure(_) => Err(Error::new( - Kind::SslHandshake(handshake_err), - details)), - HandshakeError::Failure(mid) | - HandshakeError::Interrupted(mid) => Ok(self.socket = Stream::tls(mid)), - } + Ok(stream) => { + self.socket = Stream::tls_live(stream); + Ok(()) } + #[cfg(feature = "ssl")] + Err(Error { + kind: Kind::SslHandshake(handshake_err), + details, + }) => match handshake_err { + HandshakeError::SetupFailure(_) => { + Err(Error::new(Kind::SslHandshake(handshake_err), details)) + } + HandshakeError::Failure(mid) | HandshakeError::WouldBlock(mid) => { + self.socket = Stream::tls(mid); + Ok(()) + } + }, + #[cfg(feature = "nativetls")] + Err(Error { + kind: Kind::SslHandshake(handshake_err), + details, + }) => match handshake_err { + HandshakeError::Failure(_) => { + Err(Error::new(Kind::SslHandshake(handshake_err), details)) + } + HandshakeError::WouldBlock(mid) => { + self.socket = Stream::tls(mid); + Ok(()) + } + }, Err(e) => Err(e), } } @@ -182,7 +212,7 @@ impl Connection } // Resetting may be necessary in order to try all possible addresses for a server - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] pub fn reset(&mut self) -> Result<()> { // if self.is_client() { if let Client(ref url) = self.endpoint { @@ -193,24 +223,45 @@ impl Connection self.events.insert(Ready::writable()); if let Some(ref addr) = self.addresses.pop() { - let sock = try!(TcpStream::connect(addr)); + let sock = TcpStream::connect(addr)?; if self.socket.is_tls() { let ssl_stream = self.handler.upgrade_ssl_client(sock, url); match ssl_stream { - Ok(stream) => Ok(self.socket = Stream::tls_live(stream)), - Err(Error { kind: Kind::SslHandshake(handshake_err), details }) => { - match handshake_err { - HandshakeError::SetupFailure(_) => Err(Error::new( - Kind::SslHandshake(handshake_err), - details)), - HandshakeError::Failure(mid) | - HandshakeError::Interrupted(mid) => Ok(self.socket = Stream::tls(mid)), - } + Ok(stream) => { + self.socket = Stream::tls_live(stream); + Ok(()) } + #[cfg(feature = "ssl")] + Err(Error { + kind: Kind::SslHandshake(handshake_err), + details, + }) => match handshake_err { + HandshakeError::SetupFailure(_) => { + Err(Error::new(Kind::SslHandshake(handshake_err), details)) + } + HandshakeError::Failure(mid) | HandshakeError::WouldBlock(mid) => { + self.socket = Stream::tls(mid); + Ok(()) + } + }, + #[cfg(feature = "nativetls")] + Err(Error { + kind: Kind::SslHandshake(handshake_err), + details, + }) => match handshake_err { + HandshakeError::Failure(_) => { + Err(Error::new(Kind::SslHandshake(handshake_err), details)) + } + HandshakeError::WouldBlock(mid) => { + self.socket = Stream::tls(mid); + Ok(()) + } + }, Err(e) => Err(e), } } else { - Ok(self.socket = Stream::tcp(sock)) + self.socket = Stream::tcp(sock); + Ok(()) } } else { if self.settings.panic_on_new_connection { @@ -219,14 +270,20 @@ impl Connection Err(Error::new(Kind::Internal, "Exhausted possible addresses.")) } } else { - Err(Error::new(Kind::Internal, "Unable to reset client connection because it is active.")) + Err(Error::new( + Kind::Internal, + "Unable to reset client connection because it is active.", + )) } } else { - Err(Error::new(Kind::Internal, "Server connections cannot be reset.")) + Err(Error::new( + Kind::Internal, + "Server connections cannot be reset.", + )) } } - #[cfg(not(feature="ssl"))] + #[cfg(not(any(feature = "ssl", feature = "nativetls")))] pub fn reset(&mut self) -> Result<()> { if self.is_client() { if let Connecting(ref mut req, ref mut res) = self.state { @@ -236,8 +293,9 @@ impl Connection self.events.insert(Ready::writable()); if let Some(ref addr) = self.addresses.pop() { - let sock = try!(TcpStream::connect(addr)); - Ok(self.socket = Stream::tcp(sock)) + let sock = TcpStream::connect(addr)?; + self.socket = Stream::tcp(sock); + Ok(()) } else { if self.settings.panic_on_new_connection { panic!("Unable to connect to server."); @@ -245,10 +303,16 @@ impl Connection Err(Error::new(Kind::Internal, "Exhausted possible addresses.")) } } else { - Err(Error::new(Kind::Internal, "Unable to reset client connection because it is active.")) + Err(Error::new( + Kind::Internal, + "Unable to reset client connection because it is active.", + )) } } else { - Err(Error::new(Kind::Internal, "Server connections cannot be reset.")) + Err(Error::new( + Kind::Internal, + "Server connections cannot be reset.", + )) } } @@ -290,53 +354,55 @@ impl Connection pub fn error(&mut self, err: Error) { match self.state { - Connecting(_, ref mut res) => { - match err.kind { - #[cfg(feature="ssl")] - Kind::Ssl(_) | Kind::Io(_) => { - self.handler.on_error(err); + Connecting(_, ref mut res) => match err.kind { + #[cfg(feature = "ssl")] + Kind::Ssl(_) => { + self.handler.on_error(err); + self.events = Ready::empty(); + } + Kind::Io(_) => { + self.handler.on_error(err); + self.events = Ready::empty(); + } + Kind::Protocol => { + let msg = err.to_string(); + self.handler.on_error(err); + if let Server = self.endpoint { + res.get_mut().clear(); + if let Err(err) = + write!(res.get_mut(), "HTTP/1.1 400 Bad Request\r\n\r\n{}", msg) + { + self.handler.on_error(Error::from(err)); + self.events = Ready::empty(); + } else { + self.events.remove(Ready::readable()); + self.events.insert(Ready::writable()); + } + } else { self.events = Ready::empty(); } - Kind::Protocol => { - let msg = err.to_string(); - self.handler.on_error(err); - if let Server = self.endpoint { - res.get_mut().clear(); - if let Err(err) = write!( - res.get_mut(), - "HTTP/1.1 400 Bad Request\r\n\r\n{}", msg) - { - self.handler.on_error(Error::from(err)); - self.events = Ready::empty(); - } else { - self.events.remove(Ready::readable()); - self.events.insert(Ready::writable()); - } - } else { + } + _ => { + let msg = err.to_string(); + self.handler.on_error(err); + if let Server = self.endpoint { + res.get_mut().clear(); + if let Err(err) = write!( + res.get_mut(), + "HTTP/1.1 500 Internal Server Error\r\n\r\n{}", + msg + ) { + self.handler.on_error(Error::from(err)); self.events = Ready::empty(); - } - } - _ => { - let msg = err.to_string(); - self.handler.on_error(err); - if let Server = self.endpoint { - res.get_mut().clear(); - if let Err(err) = write!( - res.get_mut(), - "HTTP/1.1 500 Internal Server Error\r\n\r\n{}", msg) { - self.handler.on_error(Error::from(err)); - self.events = Ready::empty(); - } else { - self.events.remove(Ready::readable()); - self.events.insert(Ready::writable()); - } } else { - self.events = Ready::empty(); + self.events.remove(Ready::readable()); + self.events.insert(Ready::writable()); } + } else { + self.events = Ready::empty(); } } - - } + }, _ => { match err.kind { Kind::Internal => { @@ -396,12 +462,6 @@ impl Connection Kind::Custom(_) => { self.handler.on_error(err); } - Kind::Timer(_) => { - if self.settings.panic_on_timeout { - panic!("Panicking on timer failure -- {}", err); - } - self.handler.on_error(err); - } Kind::Queue(_) => { if self.settings.panic_on_queue { panic!("Panicking on queue error -- {}", err); @@ -422,7 +482,7 @@ impl Connection pub fn disconnect(&mut self) { match self.state { - RespondingClose | FinishedClose | Connecting(_, _)=> (), + RespondingClose | FinishedClose | Connecting(_, _) => (), _ => { self.handler.on_close(CloseCode::Abnormal, ""); } @@ -439,34 +499,39 @@ impl Connection match self.endpoint { Server => { let mut done = false; - if let Some(_) = try!(self.socket.try_write_buf(res)) { + if self.socket.try_write_buf(res)?.is_some() { if res.position() as usize == res.get_ref().len() { done = true } } if !done { - return Ok(()) + return Ok(()); } } - Client(_) => { - if let Some(_) = try!(self.socket.try_write_buf(req)) { + Client(_) => { + if self.socket.try_write_buf(req)?.is_some() { if req.position() as usize == req.get_ref().len() { - trace!("Finished writing handshake request to {}", + trace!( + "Finished writing handshake request to {}", self.socket .peer_addr() .map(|addr| addr.to_string()) - .unwrap_or("UNKNOWN".into())); + .unwrap_or_else(|_| "UNKNOWN".into()) + ); self.events.insert(Ready::readable()); self.events.remove(Ready::writable()); } } - return Ok(()) + return Ok(()); } } } if let Connecting(ref req, ref res) = replace(&mut self.state, Open) { - trace!("Finished writing handshake response to {}", self.peer_addr()); + trace!( + "Finished writing handshake response to {}", + self.peer_addr() + ); let request = match Request::parse(req.get_ref()) { Ok(Some(req)) => req, @@ -475,29 +540,37 @@ impl Connection // parse. We don't call disconnect here because `on_open` hasn't been called yet. self.state = FinishedClose; self.events = Ready::empty(); - return Ok(()) + return Ok(()); } }; - let response = try!(try!(Response::parse(res.get_ref())).ok_or( - Error::new(Kind::Internal, "Failed to parse response after handshake is complete."))); + let response = Response::parse(res.get_ref())?.ok_or_else(|| { + Error::new( + Kind::Internal, + "Failed to parse response after handshake is complete.", + ) + })?; if response.status() != 101 { self.events = Ready::empty(); - return Ok(()) + return Ok(()); } else { - try!(self.handler.on_open(Handshake { - request: request, - response: response, + self.handler.on_open(Handshake { + request, + response, peer_addr: self.socket.peer_addr().ok(), local_addr: self.socket.local_addr().ok(), - })); + })?; debug!("Connection to {} is now open.", self.peer_addr()); self.events.insert(Ready::readable()); - return Ok(self.check_events()) + self.check_events(); + return Ok(()); } } else { - Err(Error::new(Kind::Internal, "Tried to write WebSocket handshake while not in connecting state!")) + Err(Error::new( + Kind::Internal, + "Tried to write WebSocket handshake while not in connecting state!", + )) } } @@ -505,47 +578,64 @@ impl Connection if let Connecting(ref mut req, ref mut res) = self.state { match self.endpoint { Server => { - if let Some(_) = try!(self.socket.try_read_buf(req.get_mut())) { - if let Some(ref request) = try!(Request::parse(req.get_ref())) { + if let Some(read) = self.socket.try_read_buf(req.get_mut())? { + if read == 0 { + self.events = Ready::empty(); + return Ok(()); + } + if let Some(ref request) = Request::parse(req.get_ref())? { trace!("Handshake request received: \n{}", request); - let response = try!(self.handler.on_request(request)); - try!(response.format(res.get_mut())); + let response = self.handler.on_request(request)?; + response.format(res.get_mut())?; self.events.remove(Ready::readable()); self.events.insert(Ready::writable()); } } - return Ok(()) + return Ok(()); } Client(_) => { - if let Some(_) = try!(self.socket.try_read_buf(res.get_mut())) { - + if self.socket.try_read_buf(res.get_mut())?.is_some() { // TODO: see if this can be optimized with drain let end = { let data = res.get_ref(); let end = data.iter() - .enumerate() - .take_while(|&(ind, _)| !data[..ind].ends_with(b"\r\n\r\n")) - .count(); + .enumerate() + .take_while(|&(ind, _)| !data[..ind].ends_with(b"\r\n\r\n")) + .count(); if !data[..end].ends_with(b"\r\n\r\n") { - return Ok(()) + return Ok(()); } self.in_buffer.get_mut().extend(&data[end..]); end }; res.get_mut().truncate(end); + } else { + // NOTE: wait to be polled again; response not ready. + return Ok(()); } } } } if let Connecting(ref req, ref res) = replace(&mut self.state, Open) { - trace!("Finished reading handshake response from {}", self.peer_addr()); + trace!( + "Finished reading handshake response from {}", + self.peer_addr() + ); - let request = try!(try!(Request::parse(req.get_ref())).ok_or( - Error::new(Kind::Internal, "Failed to parse request after handshake is complete."))); + let request = Request::parse(req.get_ref())?.ok_or_else(|| { + Error::new( + Kind::Internal, + "Failed to parse request after handshake is complete.", + ) + })?; - let response = try!(try!(Response::parse(res.get_ref())).ok_or( - Error::new(Kind::Internal, "Failed to parse response after handshake is complete."))); + let response = Response::parse(res.get_ref())?.ok_or_else(|| { + Error::new( + Kind::Internal, + "Failed to parse response after handshake is complete.", + ) + })?; trace!("Handshake response received: \n{}", response); @@ -553,40 +643,50 @@ impl Connection if response.status() != 301 && response.status() != 302 { return Err(Error::new(Kind::Protocol, "Handshake failed.")); } else { - return Ok(()) + return Ok(()); } } if self.settings.key_strict { - let req_key = try!(request.hashed_key()); - let res_key = try!(from_utf8(try!(response.key()))); + let req_key = request.hashed_key()?; + let res_key = from_utf8(response.key()?)?; if req_key != res_key { - return Err(Error::new(Kind::Protocol, format!("Received incorrect WebSocket Accept key: {} vs {}", req_key, res_key))); + return Err(Error::new( + Kind::Protocol, + format!( + "Received incorrect WebSocket Accept key: {} vs {}", + req_key, res_key + ), + )); } } - try!(self.handler.on_response(&response)); - try!(self.handler.on_open(Handshake { - request: request, - response: response, - peer_addr: self.socket.peer_addr().ok(), - local_addr: self.socket.local_addr().ok(), - })); + self.handler.on_response(&response)?; + self.handler.on_open(Handshake { + request, + response, + peer_addr: self.socket.peer_addr().ok(), + local_addr: self.socket.local_addr().ok(), + })?; // check to see if there is anything to read already if !self.in_buffer.get_ref().is_empty() { - try!(self.read_frames()); + self.read_frames()?; } - return Ok(self.check_events()) + self.check_events(); + return Ok(()); } - Err(Error::new(Kind::Internal, "Tried to read WebSocket handshake while not in connecting state!")) + Err(Error::new( + Kind::Internal, + "Tried to read WebSocket handshake while not in connecting state!", + )) } pub fn read(&mut self) -> Result<()> { if self.socket.is_negotiating() { trace!("Performing TLS negotiation on {}.", self.peer_addr()); - try!(self.socket.clear_negotiating()); + self.socket.clear_negotiating()?; self.write() } else { let res = if self.state.is_connecting() { @@ -594,15 +694,15 @@ impl Connection self.read_handshake() } else { trace!("Ready to read messages from {}.", self.peer_addr()); - while let Some(len) = try!(self.buffer_in()) { - try!(self.read_frames()); + while let Some(len) = self.buffer_in()? { + self.read_frames()?; if len == 0 { if self.events.is_writable() { self.events.remove(Ready::readable()); } else { self.disconnect() } - break + break; } } Ok(()) @@ -617,7 +717,8 @@ impl Connection } fn read_frames(&mut self) -> Result<()> { - while let Some(mut frame) = try!(Frame::parse(&mut self.in_buffer)) { + let max_size = self.settings.max_fragment_size as u64; + while let Some(mut frame) = Frame::parse(&mut self.in_buffer, max_size)? { match self.state { // Ignore data received after receiving close frame RespondingClose | FinishedClose => continue, @@ -627,11 +728,17 @@ impl Connection if self.settings.masking_strict { if frame.is_masked() { if self.is_client() { - return Err(Error::new(Kind::Protocol, "Received masked frame from a server endpoint.")) + return Err(Error::new( + Kind::Protocol, + "Received masked frame from a server endpoint.", + )); } } else { if self.is_server() { - return Err(Error::new(Kind::Protocol, "Received unmasked frame from a client endpoint.")) + return Err(Error::new( + Kind::Protocol, + "Received unmasked frame from a client endpoint.", + )); } } } @@ -639,7 +746,7 @@ impl Connection // This is safe whether or not a frame is masked. frame.remove_mask(); - if let Some(frame) = try!(self.handler.on_frame(frame)) { + if let Some(frame) = self.handler.on_frame(frame)? { if frame.is_final() { match frame.opcode() { // singleton data frames @@ -648,27 +755,27 @@ impl Connection // since we are going to handle this, there can't be an ongoing // message if !self.fragments.is_empty() { - return Err(Error::new(Kind::Protocol, "Received unfragmented text frame while processing fragmented message.")) + return Err(Error::new(Kind::Protocol, "Received unfragmented text frame while processing fragmented message.")); } - let msg = Message::text(try!(String::from_utf8(frame.into_data()).map_err(|err| err.utf8_error()))); - try!(self.handler.on_message(msg)); + let msg = Message::text(String::from_utf8(frame.into_data()) + .map_err(|err| err.utf8_error())?); + self.handler.on_message(msg)?; } OpCode::Binary => { trace!("Received binary frame {:?}", frame); // since we are going to handle this, there can't be an ongoing // message if !self.fragments.is_empty() { - return Err(Error::new(Kind::Protocol, "Received unfragmented binary frame while processing fragmented message.")) + return Err(Error::new(Kind::Protocol, "Received unfragmented binary frame while processing fragmented message.")); } let data = frame.into_data(); - try!(self.handler.on_message(Message::binary(data))); + self.handler.on_message(Message::binary(data))?; } // control frames OpCode::Close => { trace!("Received close frame {:?}", frame); // Closing handshake if self.state.is_closing() { - if self.is_server() { // Finished handshake, disconnect server side self.events = Ready::empty() @@ -676,32 +783,40 @@ impl Connection // We are a client, so we wait for the server to close the // connection } - } else { - // Starting handshake, will send the responding close frame self.state = RespondingClose; - } let mut close_code = [0u8; 2]; let mut data = Cursor::new(frame.into_data()); - if let 2 = try!(data.read(&mut close_code)) { - let raw_code: u16 = (close_code[0] as u16) << 8 | (close_code[1] as u16); - trace!("Connection to {} received raw close code: {:?}, {:?}", self.peer_addr(), raw_code, close_code); + if let 2 = data.read(&mut close_code)? { + let raw_code: u16 = + (u16::from(close_code[0]) << 8) | (u16::from(close_code[1])); + trace!( + "Connection to {} received raw close code: {:?}, {:?}", + self.peer_addr(), + raw_code, + close_code + ); let named = CloseCode::from(raw_code); if let CloseCode::Other(code) = named { - if - code < 1000 || + if code < 1000 || code >= 5000 || code == 1004 || code == 1014 || code == 1016 || // these below are here to pass the autobahn test suite code == 1100 || // we shouldn't need them later - code == 2000 || - code == 2999 + code == 2000 + || code == 2999 { - return Err(Error::new(Kind::Protocol, format!("Received invalid close code from endpoint: {}", code))) + return Err(Error::new( + Kind::Protocol, + format!( + "Received invalid close code from endpoint: {}", + code + ), + )); } } let has_reason = { @@ -715,22 +830,39 @@ impl Connection }; if let CloseCode::Abnormal = named { - return Err(Error::new(Kind::Protocol, "Received abnormal close code from endpoint.")) + return Err(Error::new( + Kind::Protocol, + "Received abnormal close code from endpoint.", + )); } else if let CloseCode::Status = named { - return Err(Error::new(Kind::Protocol, "Received no status close code from endpoint.")) + return Err(Error::new( + Kind::Protocol, + "Received no status close code from endpoint.", + )); } else if let CloseCode::Restart = named { - return Err(Error::new(Kind::Protocol, "Restart close code is not supported.")) + return Err(Error::new( + Kind::Protocol, + "Restart close code is not supported.", + )); } else if let CloseCode::Again = named { - return Err(Error::new(Kind::Protocol, "Try again later close code is not supported.")) + return Err(Error::new( + Kind::Protocol, + "Try again later close code is not supported.", + )); } else if let CloseCode::Tls = named { - return Err(Error::new(Kind::Protocol, "Received TLS close code outside of TLS handshake.")) + return Err(Error::new( + Kind::Protocol, + "Received TLS close code outside of TLS handshake.", + )); } else { if !self.state.is_closing() { if has_reason { - try!(self.send_close(named, "")); // note this drops any extra close data + self.send_close(named, "")?; // note this drops any extra close data } else { - try!(self.send_close(CloseCode::Invalid, "")); + self.send_close(CloseCode::Invalid, "")?; } + } else { + self.state = FinishedClose; } } } else { @@ -740,13 +872,15 @@ impl Connection // _The WebSocket Connection Close Reason_ is the empty string." self.handler.on_close(CloseCode::Status, ""); if !self.state.is_closing() { - try!(self.send_close(CloseCode::Empty, "")); + self.send_close(CloseCode::Empty, "")?; + } else { + self.state = FinishedClose; } } } OpCode::Ping => { trace!("Received ping frame {:?}", frame); - try!(self.send_pong(frame.into_data())); + self.send_pong(frame.into_data())?; } OpCode::Pong => { trace!("Received pong frame {:?}", frame); @@ -756,7 +890,10 @@ impl Connection OpCode::Continue => { trace!("Received final fragment {:?}", frame); if let Some(first) = self.fragments.pop_front() { - let size = self.fragments.iter().fold(first.payload().len() + frame.payload().len(), |len, frame| len + frame.payload().len()); + let size = self.fragments.iter().fold( + first.payload().len() + frame.payload().len(), + |len, frame| len + frame.payload().len(), + ); match first.opcode() { OpCode::Text => { trace!("Constructing text message from fragments: {:?} -> {:?} -> {:?}", first, self.fragments.iter().collect::>(), frame); @@ -767,13 +904,17 @@ impl Connection } data.extend(frame.into_data()); - let string = try!(String::from_utf8(data).map_err(|err| err.utf8_error())); + let string = String::from_utf8(data) + .map_err(|err| err.utf8_error())?; - trace!("Calling handler with constructed message: {:?}", string); - try!(self.handler.on_message(Message::text(string))); + trace!( + "Calling handler with constructed message: {:?}", + string + ); + self.handler.on_message(Message::text(string))?; } OpCode::Binary => { - trace!("Constructing text message from fragments: {:?} -> {:?} -> {:?}", first, self.fragments.iter().collect::>(), frame); + trace!("Constructing binary message from fragments: {:?} -> {:?} -> {:?}", first, self.fragments.iter().collect::>(), frame); let mut data = Vec::with_capacity(size); data.extend(first.into_data()); @@ -783,28 +924,40 @@ impl Connection data.extend(frame.into_data()); - trace!("Calling handler with constructed message: {:?}", data); - try!(self.handler.on_message(Message::binary(data))); + trace!( + "Calling handler with constructed message: {:?}", + data + ); + self.handler.on_message(Message::binary(data))?; } _ => { - return Err(Error::new(Kind::Protocol, "Encounted fragmented control frame.")) + return Err(Error::new( + Kind::Protocol, + "Encounted fragmented control frame.", + )) } } } else { - return Err(Error::new(Kind::Protocol, "Unable to reconstruct fragmented message. No first frame.")) + return Err(Error::new( + Kind::Protocol, + "Unable to reconstruct fragmented message. No first frame.", + )); } } _ => return Err(Error::new(Kind::Protocol, "Encountered invalid opcode.")), } } else { if frame.is_control() { - return Err(Error::new(Kind::Protocol, "Encounted fragmented control frame.")) + return Err(Error::new( + Kind::Protocol, + "Encounted fragmented control frame.", + )); } else { trace!("Received non-final fragment frame {:?}", frame); - if !self.settings.fragments_grow && - self.settings.fragments_capacity == self.fragments.len() + if !self.settings.fragments_grow + && self.settings.fragments_capacity == self.fragments.len() { - return Err(Error::new(Kind::Capacity, "Exceeded max fragments.")) + return Err(Error::new(Kind::Capacity, "Exceeded max fragments.")); } else { self.fragments.push_back(frame) } @@ -818,7 +971,7 @@ impl Connection pub fn write(&mut self) -> Result<()> { if self.socket.is_negotiating() { trace!("Performing TLS negotiation on {}.", self.peer_addr()); - try!(self.socket.clear_negotiating()); + self.socket.clear_negotiating()?; self.read() } else { let res = if self.state.is_connecting() { @@ -830,21 +983,26 @@ impl Connection // Start out assuming that this write will clear the whole buffer self.events.remove(Ready::writable()); - if let Some(len) = try!(self.socket.try_write_buf(&mut self.out_buffer)) { + if let Some(len) = self.socket.try_write_buf(&mut self.out_buffer)? { trace!("Wrote {} bytes to {}", len, self.peer_addr()); - let finished = len == 0 || self.out_buffer.position() == self.out_buffer.get_ref().len() as u64; + let finished = len == 0 + || self.out_buffer.position() == self.out_buffer.get_ref().len() as u64; if finished { match self.state { // we are are a server that is closing and just wrote out our confirming // close frame, let's disconnect - FinishedClose if self.is_server() => return Ok(self.events = Ready::empty()), + FinishedClose if self.is_server() => { + self.events = Ready::empty(); + return Ok(()); + } _ => (), } } } // Check if there is more to write so that the connection will be rescheduled - Ok(self.check_events()) + self.check_events(); + Ok(()) }; if self.socket.is_negotiating() && res.is_ok() { @@ -857,22 +1015,28 @@ impl Connection pub fn send_message(&mut self, msg: Message) -> Result<()> { if self.state.is_closing() { - trace!("Connection is closing. Ignoring request to send message {:?} to {}.", + trace!( + "Connection is closing. Ignoring request to send message {:?} to {}.", msg, - self.peer_addr()); - return Ok(()) + self.peer_addr() + ); + return Ok(()); } let opcode = msg.opcode(); trace!("Message opcode {:?}", opcode); let data = msg.into_data(); - if let Some(frame) = try!(self.handler.on_send_frame(Frame::message(data, opcode, true))) { - + if let Some(frame) = self.handler + .on_send_frame(Frame::message(data, opcode, true))? + { if frame.payload().len() > self.settings.fragment_size { trace!("Chunking at {:?}.", self.settings.fragment_size); // note this copies the data, so it's actually somewhat expensive to fragment - let mut chunks = frame.payload().chunks(self.settings.fragment_size).peekable(); + let mut chunks = frame + .payload() + .chunks(self.settings.fragment_size) + .peekable(); let chunk = chunks.next().expect("Unable to get initial chunk!"); let mut first = Frame::message(Vec::from(chunk), opcode, false); @@ -882,63 +1046,75 @@ impl Connection first.set_rsv2(frame.has_rsv2()); first.set_rsv3(frame.has_rsv3()); - try!(self.buffer_frame(first)); + self.buffer_frame(first)?; while let Some(chunk) = chunks.next() { - if let Some(_) = chunks.peek() { - try!(self.buffer_frame( - Frame::message(Vec::from(chunk), OpCode::Continue, false))); + if chunks.peek().is_some() { + self.buffer_frame(Frame::message( + Vec::from(chunk), + OpCode::Continue, + false, + ))?; } else { - try!(self.buffer_frame( - Frame::message(Vec::from(chunk), OpCode::Continue, true))); + self.buffer_frame(Frame::message( + Vec::from(chunk), + OpCode::Continue, + true, + ))?; } } - } else { trace!("Sending unfragmented message frame."); // true means that the message is done - try!(self.buffer_frame(frame)); + self.buffer_frame(frame)?; } - } - Ok(self.check_events()) + self.check_events(); + Ok(()) } #[inline] pub fn send_ping(&mut self, data: Vec) -> Result<()> { if self.state.is_closing() { - trace!("Connection is closing. Ignoring request to send ping {:?} to {}.", + trace!( + "Connection is closing. Ignoring request to send ping {:?} to {}.", data, - self.peer_addr()); - return Ok(()) + self.peer_addr() + ); + return Ok(()); } trace!("Sending ping to {}.", self.peer_addr()); - if let Some(frame) = try!(self.handler.on_send_frame(Frame::ping(data))) { - try!(self.buffer_frame(frame)); + if let Some(frame) = self.handler.on_send_frame(Frame::ping(data))? { + self.buffer_frame(frame)?; } - Ok(self.check_events()) + self.check_events(); + Ok(()) } #[inline] pub fn send_pong(&mut self, data: Vec) -> Result<()> { if self.state.is_closing() { - trace!("Connection is closing. Ignoring request to send pong {:?} to {}.", + trace!( + "Connection is closing. Ignoring request to send pong {:?} to {}.", data, - self.peer_addr()); - return Ok(()) + self.peer_addr() + ); + return Ok(()); } trace!("Sending pong to {}.", self.peer_addr()); - if let Some(frame) = try!(self.handler.on_send_frame(Frame::pong(data))) { - try!(self.buffer_frame(frame)); + if let Some(frame) = self.handler.on_send_frame(Frame::pong(data))? { + self.buffer_frame(frame)?; } - Ok(self.check_events()) + self.check_events(); + Ok(()) } #[inline] pub fn send_close(&mut self, code: CloseCode, reason: R) -> Result<()> - where R: Borrow + where + R: Borrow, { match self.state { // We are responding to a close frame the other endpoint, when this frame goes out, we @@ -946,11 +1122,14 @@ impl Connection RespondingClose => self.state = FinishedClose, // Multiple close frames are being sent from our end, ignore the later frames AwaitingClose | FinishedClose => { - trace!("Connection is already closing. Ignoring close {:?} -- {:?} to {}.", + trace!( + "Connection is already closing. Ignoring close {:?} -- {:?} to {}.", code, reason.borrow(), - self.peer_addr()); - return Ok(self.check_events()) + self.peer_addr() + ); + self.check_events(); + return Ok(()); } // We are initiating a closing handshake. Open => self.state = AwaitingClose, @@ -959,15 +1138,23 @@ impl Connection } } - trace!("Sending close {:?} -- {:?} to {}.", code, reason.borrow(), self.peer_addr()); + trace!( + "Sending close {:?} -- {:?} to {}.", + code, + reason.borrow(), + self.peer_addr() + ); - if let Some(frame) = try!(self.handler.on_send_frame(Frame::close(code, reason.borrow()))) { - try!(self.buffer_frame(frame)); + if let Some(frame) = self.handler + .on_send_frame(Frame::close(code, reason.borrow()))? + { + self.buffer_frame(frame)?; } trace!("Connection to {} is now closing.", self.peer_addr()); - Ok(self.check_events()) + self.check_events(); + Ok(()) } fn check_events(&mut self) { @@ -980,7 +1167,7 @@ impl Connection } fn buffer_frame(&mut self, mut frame: Frame) -> Result<()> { - try!(self.check_buffer_out(&frame)); + self.check_buffer_out(&frame)?; if self.is_client() { frame.set_mask(); @@ -989,23 +1176,25 @@ impl Connection trace!("Buffering frame to {}:\n{}", self.peer_addr(), frame); let pos = self.out_buffer.position(); - try!(self.out_buffer.seek(SeekFrom::End(0))); - try!(frame.format(&mut self.out_buffer)); - try!(self.out_buffer.seek(SeekFrom::Start(pos))); + self.out_buffer.seek(SeekFrom::End(0))?; + frame.format(&mut self.out_buffer)?; + self.out_buffer.seek(SeekFrom::Start(pos))?; Ok(()) } fn check_buffer_out(&mut self, frame: &Frame) -> Result<()> { - if self.out_buffer.get_ref().capacity() <= self.out_buffer.get_ref().len() + frame.len() { // extend let mut new = Vec::with_capacity(self.out_buffer.get_ref().capacity()); - new.extend(&self.out_buffer.get_ref()[self.out_buffer.position() as usize ..]); + new.extend(&self.out_buffer.get_ref()[self.out_buffer.position() as usize..]); if new.len() == new.capacity() { if self.settings.out_buffer_grow { new.reserve(self.settings.out_buffer_capacity) } else { - return Err(Error::new(Kind::Capacity, "Maxed out output buffer for connection.")) + return Err(Error::new( + Kind::Capacity, + "Maxed out output buffer for connection.", + )); } } self.out_buffer = Cursor::new(new); @@ -1014,19 +1203,21 @@ impl Connection } fn buffer_in(&mut self) -> Result> { - trace!("Reading buffer for connection to {}.", self.peer_addr()); - if let Some(len) = try!(self.socket.try_read_buf(self.in_buffer.get_mut())) { + if let Some(len) = self.socket.try_read_buf(self.in_buffer.get_mut())? { trace!("Buffered {}.", len); if self.in_buffer.get_ref().len() == self.in_buffer.get_ref().capacity() { // extend let mut new = Vec::with_capacity(self.in_buffer.get_ref().capacity()); - new.extend(&self.in_buffer.get_ref()[self.in_buffer.position() as usize ..]); + new.extend(&self.in_buffer.get_ref()[self.in_buffer.position() as usize..]); if new.len() == new.capacity() { if self.settings.in_buffer_grow { new.reserve(self.settings.in_buffer_capacity); } else { - return Err(Error::new(Kind::Capacity, "Maxed out input buffer for connection.")) + return Err(Error::new( + Kind::Capacity, + "Maxed out input buffer for connection.", + )); } } self.in_buffer = Cursor::new(new); diff --git a/third_party/rust/ws/src/deflate/context.rs b/third_party/rust/ws/src/deflate/context.rs index 1cbe3c870009..2fa2e2305636 100644 --- a/third_party/rust/ws/src/deflate/context.rs +++ b/third_party/rust/ws/src/deflate/context.rs @@ -2,9 +2,9 @@ use std::mem; use std::slice; use super::ffi; -use super::libc::{c_int, c_char, c_uint}; +use super::libc::{c_char, c_int, c_uint}; -use result::{Result, Error, Kind}; +use result::{Error, Kind, Result}; const ZLIB_VERSION: &'static str = "1.2.8\0"; @@ -12,7 +12,8 @@ trait Context { fn stream(&mut self) -> &mut ffi::z_stream; fn stream_apply(&mut self, input: &[u8], output: &mut Vec, each: F) -> Result<()> - where F: Fn(&mut ffi::z_stream) -> Option>, + where + F: Fn(&mut ffi::z_stream) -> Option>, { debug_assert!(output.len() == 0, "Output vector is not empty."); @@ -33,7 +34,8 @@ trait Context { let out_slice = unsafe { slice::from_raw_parts_mut( output.as_mut_ptr().offset(output_size as isize), - output.capacity() - output_size) + output.capacity() - output_size, + ) }; stream.next_out = out_slice.as_mut_ptr(); @@ -47,26 +49,27 @@ trait Context { } if let Some(result) = cont { - return result + return result; } } } } -pub struct Compresser { - stream: ffi::z_stream, +pub struct Compressor { + // Box the z_stream to ensure it isn't moved. Moving the z_stream + // causes zlib to fail, because it maintains internal pointers. + stream: Box, } -impl Compresser { - - pub fn new(window_bits: i8) -> Compresser { - debug_assert!(window_bits >= 8, "Received too small window size."); +impl Compressor { + pub fn new(window_bits: i8) -> Compressor { + debug_assert!(window_bits >= 9, "Received too small window size."); debug_assert!(window_bits <= 15, "Received too large window size."); unsafe { - let mut stream = mem::zeroed(); + let mut stream: Box = Box::new(mem::zeroed()); let result = ffi::deflateInit2_( - &mut stream, + stream.as_mut(), 9, ffi::Z_DEFLATED, -window_bits as c_int, @@ -75,55 +78,49 @@ impl Compresser { ZLIB_VERSION.as_ptr() as *const c_char, mem::size_of::() as c_int, ); - assert!( - result == ffi::Z_OK, - "Failed to initialize compresser."); - Compresser { stream: stream } + assert!(result == ffi::Z_OK, "Failed to initialize compresser."); + Compressor { stream: stream } } } pub fn compress(&mut self, input: &[u8], output: &mut Vec) -> Result<()> { - self.stream_apply(input, output, |stream| { - unsafe { - match ffi::deflate(stream, ffi::Z_SYNC_FLUSH) { - ffi::Z_OK | ffi::Z_BUF_ERROR => { - if stream.avail_in == 0 && stream.avail_out > 0{ - Some(Ok(())) - } else { - None - } + self.stream_apply(input, output, |stream| unsafe { + match ffi::deflate(stream, ffi::Z_SYNC_FLUSH) { + ffi::Z_OK | ffi::Z_BUF_ERROR => { + if stream.avail_in == 0 && stream.avail_out > 0 { + Some(Ok(())) + } else { + None } - code => Some(Err(Error::new( - Kind::Protocol, - format!("Failed to perform compression: {}", code)))), } + code => Some(Err(Error::new( + Kind::Protocol, + format!("Failed to perform compression: {}", code), + ))), } }) } pub fn reset(&mut self) -> Result<()> { - match unsafe { - ffi::deflateReset(&mut self.stream) - } { + match unsafe { ffi::deflateReset(self.stream.as_mut()) } { ffi::Z_OK => Ok(()), code => Err(Error::new( Kind::Protocol, - format!("Failed to reset compression context: {}", code))), + format!("Failed to reset compression context: {}", code), + )), } } } -impl Context for Compresser { +impl Context for Compressor { fn stream(&mut self) -> &mut ffi::z_stream { - &mut self.stream + self.stream.as_mut() } } -impl Drop for Compresser { +impl Drop for Compressor { fn drop(&mut self) { - match unsafe { - ffi::deflateEnd(&mut self.stream) - } { + match unsafe { ffi::deflateEnd(self.stream.as_mut()) } { ffi::Z_STREAM_ERROR => error!("Compression stream encountered bad state."), // Ignore discarded data error because we are raw ffi::Z_OK | ffi::Z_DATA_ERROR => trace!("Deallocated compression context."), @@ -132,72 +129,66 @@ impl Drop for Compresser { } } -pub struct Decompresser { - stream: ffi::z_stream, +pub struct Decompressor { + stream: Box, } -impl Decompresser { - pub fn new(window_bits: i8) -> Decompresser { +impl Decompressor { + pub fn new(window_bits: i8) -> Decompressor { debug_assert!(window_bits >= 8, "Received too small window size."); debug_assert!(window_bits <= 15, "Received too large window size."); unsafe { - let mut stream = mem::zeroed(); + let mut stream: Box = Box::new(mem::zeroed()); let result = ffi::inflateInit2_( - &mut stream, + stream.as_mut(), -window_bits as c_int, ZLIB_VERSION.as_ptr() as *const c_char, mem::size_of::() as c_int, ); - assert!( - result == ffi::Z_OK, - "Failed to initialize decompresser."); - Decompresser { stream: stream } + assert!(result == ffi::Z_OK, "Failed to initialize decompresser."); + Decompressor { stream: stream } } } pub fn decompress(&mut self, input: &[u8], output: &mut Vec) -> Result<()> { - self.stream_apply(input, output, |stream| { - unsafe { - match ffi::inflate(stream, ffi::Z_SYNC_FLUSH) { - ffi::Z_OK | ffi::Z_BUF_ERROR => { - if stream.avail_in == 0 && stream.avail_out > 0 { - Some(Ok(())) - } else { - None - } + self.stream_apply(input, output, |stream| unsafe { + match ffi::inflate(stream, ffi::Z_SYNC_FLUSH) { + ffi::Z_OK | ffi::Z_BUF_ERROR => { + if stream.avail_in == 0 && stream.avail_out > 0 { + Some(Ok(())) + } else { + None } - code => Some(Err(Error::new( - Kind::Protocol, - format!("Failed to perform decompression: {}", code)))), } + code => Some(Err(Error::new( + Kind::Protocol, + format!("Failed to perform decompression: {}", code), + ))), } }) } pub fn reset(&mut self) -> Result<()> { - match unsafe { - ffi::inflateReset(&mut self.stream) - } { + match unsafe { ffi::inflateReset(self.stream.as_mut()) } { ffi::Z_OK => Ok(()), code => Err(Error::new( Kind::Protocol, - format!("Failed to reset compression context: {}", code))), + format!("Failed to reset compression context: {}", code), + )), } } } -impl Context for Decompresser { +impl Context for Decompressor { fn stream(&mut self) -> &mut ffi::z_stream { - &mut self.stream + self.stream.as_mut() } } -impl Drop for Decompresser { +impl Drop for Decompressor { fn drop(&mut self) { - match unsafe { - ffi::inflateEnd(&mut self.stream) - } { + match unsafe { ffi::inflateEnd(self.stream.as_mut()) } { ffi::Z_STREAM_ERROR => error!("Decompression stream encountered bad state."), ffi::Z_OK => trace!("Deallocated decompression context."), code => error!("Bad zlib status encountered: {}", code), @@ -205,7 +196,6 @@ impl Drop for Decompresser { } } - mod test { #![allow(unused_imports, unused_variables, dead_code)] use super::*; @@ -224,13 +214,19 @@ mod test { let mut compressed = Vec::with_capacity(data.len()); let mut decompressed = Vec::with_capacity(data.len()); - let mut com = Compresser::new(i); + let com = Compressor::new(i); + let mut moved_com = com; - com.compress(&data, &mut compressed).expect("Failed to compress data."); + moved_com + .compress(&data, &mut compressed) + .expect("Failed to compress data."); - let mut dec = Decompresser::new(i); + let dec = Decompressor::new(i); + let mut moved_dec = dec; - dec.decompress(&compressed, &mut decompressed).expect("Failed to decompress data."); + moved_dec + .decompress(&compressed, &mut decompressed) + .expect("Failed to decompress data."); assert_eq!(data, &decompressed[..]); } @@ -248,19 +244,20 @@ mod test { let mut decompressed2 = Vec::with_capacity(data2.len()); let mut decompressed2_ind = Vec::with_capacity(data2.len()); - let mut com = Compresser::new(9); + let mut com = Compressor::new(9); com.compress(&data1, &mut compressed1).unwrap(); com.compress(&data2, &mut compressed2).unwrap(); com.reset().unwrap(); com.compress(&data2, &mut compressed2_ind).unwrap(); - let mut dec = Decompresser::new(9); + let mut dec = Decompressor::new(9); dec.decompress(&compressed1, &mut decompressed1).unwrap(); dec.decompress(&compressed2, &mut decompressed2).unwrap(); dec.reset().unwrap(); - dec.decompress(&compressed2_ind, &mut decompressed2_ind).unwrap(); + dec.decompress(&compressed2_ind, &mut decompressed2_ind) + .unwrap(); assert_eq!(data1, &decompressed1[..]); assert_eq!(data2, &decompressed2[..]); @@ -269,4 +266,3 @@ mod test { assert!(compressed2.len() < compressed2_ind.len()); } } - diff --git a/third_party/rust/ws/src/deflate/extension.rs b/third_party/rust/ws/src/deflate/extension.rs index d0824bbb45cf..712e11fb8eb4 100644 --- a/third_party/rust/ws/src/deflate/extension.rs +++ b/third_party/rust/ws/src/deflate/extension.rs @@ -1,28 +1,28 @@ use std::mem::replace; -use std::io::{Read, Write}; -#[cfg(feature="ssl")] +#[cfg(feature = "ssl")] use openssl::ssl::SslStream; +#[cfg(feature = "nativetls")] +use native_tls::TlsStream as SslStream; use url; -use handler::Handler; -use message::Message; use frame::Frame; -use protocol::{CloseCode, OpCode}; +use handler::Handler; use handshake::{Handshake, Request, Response}; -use result::{Result, Error, Kind}; -use util::{Token, Timeout}; -#[cfg(feature="ssl")] +use message::Message; +use protocol::{CloseCode, OpCode}; +use result::{Error, Kind, Result}; +#[cfg(any(feature = "ssl", feature = "nativetls"))] use util::TcpStream; +use util::{Timeout, Token}; -use super::context::{Compresser, Decompresser}; - +use super::context::{Compressor, Decompressor}; /// Deflate Extension Handler Settings #[derive(Debug, Clone, Copy)] pub struct DeflateSettings { /// The max size of the sliding window. If the other endpoint selects a smaller size, that size - /// will be used instead. This must be an integer between 8 and 15 inclusive. + /// will be used instead. This must be an integer between 9 and 15 inclusive. /// Default: 15 pub max_window_bits: u8, /// Indicates whether to ask the other endpoint to reset the sliding window for each message. @@ -46,7 +46,6 @@ pub struct DeflateSettings { } impl Default for DeflateSettings { - fn default() -> DeflateSettings { DeflateSettings { max_window_bits: 15, @@ -82,8 +81,8 @@ impl DeflateBuilder { /// Wrap another handler in with a deflate handler as configured. pub fn build(&self, handler: H) -> DeflateHandler { DeflateHandler { - com: Compresser::new(self.settings.max_window_bits as i8), - dec: Decompresser::new(self.settings.max_window_bits as i8), + com: Compressor::new(self.settings.max_window_bits as i8), + dec: Decompressor::new(self.settings.max_window_bits as i8), fragments: Vec::with_capacity(self.settings.fragments_capacity), compress_reset: false, decompress_reset: false, @@ -92,7 +91,6 @@ impl DeflateBuilder { inner: handler, } } - } /// A WebSocket handler that implements the permessage-deflate extension. @@ -102,8 +100,8 @@ impl DeflateBuilder { /// permessage-deflate specification and pass them to the child handler. Message frames sent from /// the child handler will be compressed and sent to the other endpoint using deflate compression. pub struct DeflateHandler { - com: Compresser, - dec: Decompresser, + com: Compressor, + dec: Decompressor, fragments: Vec, compress_reset: bool, decompress_reset: bool, @@ -113,14 +111,13 @@ pub struct DeflateHandler { } impl DeflateHandler { - /// Wrap a child handler to provide the permessage-deflate extension. pub fn new(handler: H) -> DeflateHandler { trace!("Using permessage-deflate handler."); let settings = DeflateSettings::default(); DeflateHandler { - com: Compresser::new(settings.max_window_bits as i8), - dec: Decompresser::new(settings.max_window_bits as i8), + com: Compressor::new(settings.max_window_bits as i8), + dec: Decompressor::new(settings.max_window_bits as i8), fragments: Vec::with_capacity(settings.fragments_capacity), compress_reset: false, decompress_reset: false, @@ -141,16 +138,15 @@ impl DeflateHandler { } impl Handler for DeflateHandler { - fn build_request(&mut self, url: &url::Url) -> Result { - let mut req = try!(self.inner.build_request(url)); + let mut req = self.inner.build_request(url)?; let mut req_ext = String::with_capacity(100); req_ext.push_str("permessage-deflate"); if self.settings.max_window_bits < 15 { req_ext.push_str(&format!( "; client_max_window_bits={}; server_max_window_bits={}", - self.settings.max_window_bits, - self.settings.max_window_bits)) + self.settings.max_window_bits, self.settings.max_window_bits + )) } else { req_ext.push_str("; client_max_window_bits") } @@ -162,9 +158,9 @@ impl Handler for DeflateHandler { } fn on_request(&mut self, req: &Request) -> Result { - let mut res = try!(Response::from_request(req)); + let mut res = self.inner.on_request(req)?; - 'ext: for req_ext in try!(req.extensions()) + 'ext: for req_ext in req.extensions()? .iter() .filter(|&&ext| ext.contains("permessage-deflate")) { @@ -179,20 +175,20 @@ impl Handler for DeflateHandler { "permessage-deflate" => res_ext.push_str("permessage-deflate"), "server_no_context_takeover" => { if s_takeover { - return self.decline(res) + return self.decline(res); } else { s_takeover = true; if self.settings.accept_no_context_takeover { self.compress_reset = true; res_ext.push_str("; server_no_context_takeover"); } else { - continue 'ext + continue 'ext; } } } "client_no_context_takeover" => { if c_takeover { - return self.decline(res) + return self.decline(res); } else { c_takeover = true; self.decompress_reset = true; @@ -201,91 +197,92 @@ impl Handler for DeflateHandler { } param if param.starts_with("server_max_window_bits") => { if s_max { - return self.decline(res) + return self.decline(res); } else { s_max = true; let mut param_iter = param.split('='); param_iter.next(); // we already know the name if let Some(window_bits_str) = param_iter.next() { if let Ok(window_bits) = window_bits_str.trim().parse() { - if window_bits >= 8 && window_bits <= 15 { + if window_bits >= 9 && window_bits <= 15 { if window_bits < self.settings.max_window_bits as i8 { - self.com = Compresser::new(window_bits); + self.com = Compressor::new(window_bits); res_ext.push_str("; "); res_ext.push_str(param) } } else { - return self.decline(res) + return self.decline(res); } } else { - return self.decline(res) + return self.decline(res); } } } } param if param.starts_with("client_max_window_bits") => { if c_max { - return self.decline(res) + return self.decline(res); } else { c_max = true; let mut param_iter = param.split('='); param_iter.next(); // we already know the name if let Some(window_bits_str) = param_iter.next() { if let Ok(window_bits) = window_bits_str.trim().parse() { - if window_bits >= 8 && window_bits <= 15 { + if window_bits >= 9 && window_bits <= 15 { if window_bits < self.settings.max_window_bits as i8 { - self.dec = Decompresser::new(window_bits); + self.dec = Decompressor::new(window_bits); res_ext.push_str("; "); res_ext.push_str(param); - continue + continue; } } else { - return self.decline(res) + return self.decline(res); } } else { - return self.decline(res) + return self.decline(res); } } res_ext.push_str("; "); - res_ext.push_str( - &format!( - "client_max_window_bits={}", - self.settings.max_window_bits)) + res_ext.push_str(&format!( + "client_max_window_bits={}", + self.settings.max_window_bits + )) } } _ => { // decline all extension offers because we got a bad parameter - return self.decline(res) + return self.decline(res); } } } - if !res_ext.contains("client_no_context_takeover") && self.settings.request_no_context_takeover { + if !res_ext.contains("client_no_context_takeover") + && self.settings.request_no_context_takeover + { self.decompress_reset = true; res_ext.push_str("; client_no_context_takeover"); } if !res_ext.contains("server_max_window_bits") { res_ext.push_str("; "); - res_ext.push_str( - &format!( - "server_max_window_bits={}", - self.settings.max_window_bits)) + res_ext.push_str(&format!( + "server_max_window_bits={}", + self.settings.max_window_bits + )) } if !res_ext.contains("client_max_window_bits") && self.settings.max_window_bits < 15 { - continue + continue; } res.add_extension(&res_ext); - return Ok(res) + return Ok(res); } self.decline(res) } fn on_response(&mut self, res: &Response) -> Result<()> { - - if let Some(res_ext) =try!(res.extensions()) + if let Some(res_ext) = res.extensions()? .iter() .find(|&&ext| ext.contains("permessage-deflate")) { @@ -301,7 +298,8 @@ impl Handler for DeflateHandler { if name { return Err(Error::new( Kind::Protocol, - format!("Duplicate extension name permessage-deflate"))) + format!("Duplicate extension name permessage-deflate"), + )); } else { name = true; } @@ -310,7 +308,8 @@ impl Handler for DeflateHandler { if s_takeover { return Err(Error::new( Kind::Protocol, - format!("Duplicate extension parameter server_no_context_takeover"))) + format!("Duplicate extension parameter server_no_context_takeover"), + )); } else { s_takeover = true; self.decompress_reset = true; @@ -320,7 +319,8 @@ impl Handler for DeflateHandler { if c_takeover { return Err(Error::new( Kind::Protocol, - format!("Duplicate extension parameter client_no_context_takeover"))) + format!("Duplicate extension parameter client_no_context_takeover"), + )); } else { c_takeover = true; if self.settings.accept_no_context_takeover { @@ -328,7 +328,8 @@ impl Handler for DeflateHandler { } else { return Err(Error::new( Kind::Protocol, - format!("The client requires context takeover."))) + format!("The client requires context takeover."), + )); } } } @@ -336,26 +337,35 @@ impl Handler for DeflateHandler { if s_max { return Err(Error::new( Kind::Protocol, - format!("Duplicate extension parameter server_max_window_bits"))) + format!("Duplicate extension parameter server_max_window_bits"), + )); } else { s_max = true; let mut param_iter = param.split('='); param_iter.next(); // we already know the name if let Some(window_bits_str) = param_iter.next() { if let Ok(window_bits) = window_bits_str.trim().parse() { - if window_bits >= 8 && window_bits <= 15 { + if window_bits >= 9 && window_bits <= 15 { if window_bits as u8 != self.settings.max_window_bits { - self.dec = Decompresser::new(window_bits); + self.dec = Decompressor::new(window_bits); } } else { return Err(Error::new( Kind::Protocol, - format!("Invalid server_max_window_bits parameter: {}", window_bits))) + format!( + "Invalid server_max_window_bits parameter: {}", + window_bits + ), + )); } } else { return Err(Error::new( Kind::Protocol, - format!("Invalid server_max_window_bits parameter: {}", window_bits_str))) + format!( + "Invalid server_max_window_bits parameter: {}", + window_bits_str + ), + )); } } } @@ -364,26 +374,35 @@ impl Handler for DeflateHandler { if c_max { return Err(Error::new( Kind::Protocol, - format!("Duplicate extension parameter client_max_window_bits"))) + format!("Duplicate extension parameter client_max_window_bits"), + )); } else { c_max = true; let mut param_iter = param.split('='); param_iter.next(); // we already know the name if let Some(window_bits_str) = param_iter.next() { if let Ok(window_bits) = window_bits_str.trim().parse() { - if window_bits >= 8 && window_bits <= 15 { + if window_bits >= 9 && window_bits <= 15 { if window_bits as u8 != self.settings.max_window_bits { - self.com = Compresser::new(window_bits); + self.com = Compressor::new(window_bits); } } else { return Err(Error::new( Kind::Protocol, - format!("Invalid client_max_window_bits parameter: {}", window_bits))) + format!( + "Invalid client_max_window_bits parameter: {}", + window_bits + ), + )); } } else { return Err(Error::new( Kind::Protocol, - format!("Invalid client_max_window_bits parameter: {}", window_bits_str))) + format!( + "Invalid client_max_window_bits parameter: {}", + window_bits_str + ), + )); } } } @@ -392,7 +411,8 @@ impl Handler for DeflateHandler { // fail the connection because we got a bad parameter return Err(Error::new( Kind::Protocol, - format!("Bad extension parameter: {}", param))) + format!("Bad extension parameter: {}", param), + )); } } } @@ -410,47 +430,52 @@ impl Handler for DeflateHandler { if !frame.is_final() { self.fragments.push(frame); - return Ok(None) + return Ok(None); } else { if frame.opcode() == OpCode::Continue { if self.fragments.is_empty() { return Err(Error::new( Kind::Protocol, - "Unable to reconstruct fragmented message. No first frame.")) + "Unable to reconstruct fragmented message. No first frame.", + )); } else { - if !self.settings.fragments_grow && self.settings.fragments_capacity == self.fragments.len() { - return Err(Error::new(Kind::Capacity, "Exceeded max fragments.")) + if !self.settings.fragments_grow + && self.settings.fragments_capacity == self.fragments.len() + { + return Err(Error::new(Kind::Capacity, "Exceeded max fragments.")); } else { self.fragments.push(frame); } // it's safe to unwrap because of the above check for empty let opcode = self.fragments.first().unwrap().opcode(); - let size = self.fragments.iter().fold(0, |len, frame| len + frame.payload().len()); + let size = self.fragments + .iter() + .fold(0, |len, frame| len + frame.payload().len()); let mut compressed = Vec::with_capacity(size); let mut decompressed = Vec::with_capacity(size * 2); for frag in replace( &mut self.fragments, - Vec::with_capacity(self.settings.fragments_capacity)) - { + Vec::with_capacity(self.settings.fragments_capacity), + ) { compressed.extend(frag.into_data()) } compressed.extend(&[0, 0, 255, 255]); - try!(self.dec.decompress(&compressed, &mut decompressed)); + self.dec.decompress(&compressed, &mut decompressed)?; frame = Frame::message(decompressed, opcode, true); } } else { let mut decompressed = Vec::with_capacity(frame.payload().len() * 2); frame.payload_mut().extend(&[0, 0, 255, 255]); - try!(self.dec.decompress(frame.payload(), &mut decompressed)); + self.dec.decompress(frame.payload(), &mut decompressed)?; *frame.payload_mut() = decompressed; } if self.decompress_reset { - try!(self.dec.reset()) + self.dec.reset()? } } } @@ -459,20 +484,26 @@ impl Handler for DeflateHandler { } fn on_send_frame(&mut self, frame: Frame) -> Result> { - if let Some(mut frame) = try!(self.inner.on_send_frame(frame)) { + if let Some(mut frame) = self.inner.on_send_frame(frame)? { if !self.pass && !frame.is_control() { - debug_assert!(frame.is_final(), "Received non-final frame from upstream handler!"); - debug_assert!(frame.opcode() != OpCode::Continue, "Received continue frame from upstream handler!"); + debug_assert!( + frame.is_final(), + "Received non-final frame from upstream handler!" + ); + debug_assert!( + frame.opcode() != OpCode::Continue, + "Received continue frame from upstream handler!" + ); frame.set_rsv1(true); let mut compressed = Vec::with_capacity(frame.payload().len()); - try!(self.com.compress(frame.payload(), &mut compressed)); + self.com.compress(frame.payload(), &mut compressed)?; let len = compressed.len(); compressed.truncate(len - 4); *frame.payload_mut() = compressed; if self.compress_reset { - try!(self.com.reset()) + self.com.reset()? } } Ok(Some(frame)) @@ -517,15 +548,18 @@ impl Handler for DeflateHandler { } #[inline] - #[cfg(feature="ssl")] - fn upgrade_ssl_client(&mut self, stream: TcpStream, url: &url::Url) -> Result> { + #[cfg(any(feature = "ssl", feature = "nativetls"))] + fn upgrade_ssl_client( + &mut self, + stream: TcpStream, + url: &url::Url, + ) -> Result> { self.inner.upgrade_ssl_client(stream, url) } #[inline] - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] fn upgrade_ssl_server(&mut self, stream: TcpStream) -> Result> { self.inner.upgrade_ssl_server(stream) } - } diff --git a/third_party/rust/ws/src/deflate/mod.rs b/third_party/rust/ws/src/deflate/mod.rs index 07041fb4c551..8d79012e737c 100644 --- a/third_party/rust/ws/src/deflate/mod.rs +++ b/third_party/rust/ws/src/deflate/mod.rs @@ -1,15 +1,9 @@ //! The deflate module provides tools for applying the permessage-deflate extension. -extern crate libz_sys as ffi; extern crate libc; +extern crate libz_sys as ffi; mod context; mod extension; -pub use self::extension::{DeflateHandler, DeflateBuilder, DeflateSettings}; - - - - - - +pub use self::extension::{DeflateBuilder, DeflateHandler, DeflateSettings}; diff --git a/third_party/rust/ws/src/factory.rs b/third_party/rust/ws/src/factory.rs index 860b6c66a8ee..048ac7811006 100644 --- a/third_party/rust/ws/src/factory.rs +++ b/third_party/rust/ws/src/factory.rs @@ -1,5 +1,5 @@ -use handler::Handler; use communication::Sender; +use handler::Handler; /// A trait for creating new WebSocket handlers. pub trait Factory { @@ -98,39 +98,39 @@ pub trait Factory { /// You can use this to track connections being destroyed or to finalize /// state that was not internally tracked by the handler. #[inline] - fn connection_lost(&mut self, _: Self::Handler) { - } - + fn connection_lost(&mut self, _: Self::Handler) {} } impl Factory for F - where H: Handler, F: FnMut(Sender) -> H +where + H: Handler, + F: FnMut(Sender) -> H, { type Handler = H; fn connection_made(&mut self, out: Sender) -> H { self(out) } - } mod test { #![allow(unused_imports, unused_variables, dead_code)] use super::*; - use mio; use communication::{Command, Sender}; - use handshake::{Request, Response, Handshake}; - use protocol::CloseCode; use frame; - use message; use handler::Handler; + use handshake::{Handshake, Request, Response}; + use message; + use mio; + use protocol::CloseCode; use result::Result; #[derive(Debug, Eq, PartialEq)] struct M; impl Handler for M { fn on_message(&mut self, _: message::Message) -> Result<()> { - Ok(println!("test")) + println!("test"); + Ok(()) } fn on_frame(&mut self, f: frame::Frame) -> Result> { @@ -140,7 +140,6 @@ mod test { #[test] fn impl_factory() { - struct X; impl Factory for X { @@ -153,9 +152,7 @@ mod test { let (chn, _) = mio::channel::sync_channel(42); let mut x = X; - let m = x.connection_made( - Sender::new(mio::Token(0), chn, 0) - ); + let m = x.connection_made(Sender::new(mio::Token(0), chn, 0)); assert_eq!(m, M); } @@ -163,13 +160,9 @@ mod test { fn closure_factory() { let (chn, _) = mio::channel::sync_channel(42); - let mut factory = |_| { - |_| {Ok(())} - }; + let mut factory = |_| |_| Ok(()); - factory.connection_made( - Sender::new(mio::Token(0), chn, 0) - ); + factory.connection_made(Sender::new(mio::Token(0), chn, 0)); } #[test] @@ -189,9 +182,7 @@ mod test { let (chn, _) = mio::channel::sync_channel(42); let mut x = X; - let m = x.connection_made( - Sender::new(mio::Token(0), chn, 0) - ); + let m = x.connection_made(Sender::new(mio::Token(0), chn, 0)); x.connection_lost(m); } } diff --git a/third_party/rust/ws/src/frame.rs b/third_party/rust/ws/src/frame.rs index 97410a8a5be9..154816c7adc5 100644 --- a/third_party/rust/ws/src/frame.rs +++ b/third_party/rust/ws/src/frame.rs @@ -1,12 +1,12 @@ -use std::fmt; -use std::io::{Cursor, Read, Write, ErrorKind}; use std::default::Default; +use std::fmt; +use std::io::{Cursor, ErrorKind, Read, Write}; -use rand; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use rand; -use result::{Result, Error, Kind}; -use protocol::{OpCode, CloseCode}; +use protocol::{CloseCode, OpCode}; +use result::{Error, Kind, Result}; use stream::TryReadBuf; fn apply_mask(buf: &mut [u8], mask: &[u8; 4]) { @@ -31,7 +31,6 @@ pub struct Frame { } impl Frame { - /// Get the length of the frame. /// This is the length of the header + the length of the payload. #[inline] @@ -53,6 +52,12 @@ impl Frame { header_length + payload_len } + /// Return `false`: a frame is never empty since it has a header. + #[inline] + pub fn is_empty(&self) -> bool { + false + } + /// Test whether the frame is a final frame. #[inline] pub fn is_final(&self) -> bool { @@ -171,10 +176,9 @@ impl Frame { #[doc(hidden)] #[inline] pub fn remove_mask(&mut self) -> &mut Frame { - self.mask.and_then(|mask| { - Some(apply_mask(&mut self.payload, &mask)) - }); - self.mask = None; + self.mask + .take() + .map(|mask| apply_mask(&mut self.payload, &mask)); self } @@ -186,16 +190,19 @@ impl Frame { /// Create a new data frame. #[inline] pub fn message(data: Vec, code: OpCode, finished: bool) -> Frame { - debug_assert!(match code { - OpCode::Text | OpCode::Binary | OpCode::Continue => true, - _ => false, - }, "Invalid opcode for data frame."); + debug_assert!( + match code { + OpCode::Text | OpCode::Binary | OpCode::Continue => true, + _ => false, + }, + "Invalid opcode for data frame." + ); Frame { - finished: finished, + finished, opcode: code, payload: data, - .. Frame::default() + ..Frame::default() } } @@ -205,7 +212,7 @@ impl Frame { Frame { opcode: OpCode::Pong, payload: data, - .. Frame::default() + ..Frame::default() } } @@ -215,7 +222,7 @@ impl Frame { Frame { opcode: OpCode::Ping, payload: data, - .. Frame::default() + ..Frame::default() } } @@ -231,21 +238,21 @@ impl Frame { }; Frame { - payload: payload, - .. Frame::default() + payload, + ..Frame::default() } } /// Parse the input stream into a frame. - pub fn parse(cursor: &mut Cursor>) -> Result> { + pub fn parse(cursor: &mut Cursor>, max_payload_length: u64) -> Result> { let size = cursor.get_ref().len() as u64 - cursor.position(); let initial = cursor.position(); trace!("Position in buffer {}", initial); let mut head = [0u8; 2]; - if try!(cursor.read(&mut head)) != 2 { + if cursor.read(&mut head)? != 2 { cursor.set_position(initial); - return Ok(None) + return Ok(None); } trace!("Parsed headers {:?}", head); @@ -269,7 +276,7 @@ impl Frame { let mut header_length = 2; - let mut length = (second & 0x7F) as u64; + let mut length = u64::from(second & 0x7F); if let Some(length_nbytes) = match length { 126 => Some(2), @@ -292,11 +299,21 @@ impl Frame { } trace!("Payload length: {}", length); + if length > max_payload_length { + return Err(Error::new( + Kind::Protocol, + format!( + "Rejected frame with payload length exceeding defined max: {}.", + max_payload_length + ), + )); + } + let mask = if masked { let mut mask_bytes = [0u8; 4]; - if try!(cursor.read(&mut mask_bytes)) != 4 { + if cursor.read(&mut mask_bytes)? != 4 { cursor.set_position(initial); - return Ok(None) + return Ok(None); } else { header_length += 4; Some(mask_bytes) @@ -305,52 +322,68 @@ impl Frame { None }; - if size < length + header_length { - cursor.set_position(initial); - return Ok(None) - } + match length.checked_add(header_length) { + Some(l) if size < l => { + cursor.set_position(initial); + return Ok(None); + } + Some(_) => (), + None => return Ok(None), + }; let mut data = Vec::with_capacity(length as usize); if length > 0 { - if let Some(read) = try!(cursor.try_read_buf(&mut data)) { + if let Some(read) = cursor.try_read_buf(&mut data)? { debug_assert!(read == length as usize, "Read incorrect payload length!"); } } // Disallow bad opcode if let OpCode::Bad = opcode { - return Err(Error::new(Kind::Protocol, format!("Encountered invalid opcode: {}", first & 0x0F))) + return Err(Error::new( + Kind::Protocol, + format!("Encountered invalid opcode: {}", first & 0x0F), + )); } // control frames must have length <= 125 match opcode { OpCode::Ping | OpCode::Pong if length > 125 => { - return Err(Error::new(Kind::Protocol, format!("Rejected WebSocket handshake.Received control frame with length: {}.", length))) + return Err(Error::new( + Kind::Protocol, + format!( + "Rejected WebSocket handshake.Received control frame with length: {}.", + length + ), + )) } OpCode::Close if length > 125 => { debug!("Received close frame with payload length exceeding 125. Morphing to protocol close frame."); - return Ok(Some(Frame::close(CloseCode::Protocol, "Received close frame with payload length exceeding 125."))) + return Ok(Some(Frame::close( + CloseCode::Protocol, + "Received close frame with payload length exceeding 125.", + ))); } - _ => () + _ => (), } let frame = Frame { - finished: finished, - rsv1: rsv1, - rsv2: rsv2, - rsv3: rsv3, - opcode: opcode, - mask: mask, + finished, + rsv1, + rsv2, + rsv3, + opcode, + mask, payload: data, }; - Ok(Some(frame)) } /// Write a frame out to a buffer pub fn format(&mut self, w: &mut W) -> Result<()> - where W: Write + where + W: Write, { let mut one = 0u8; let code: u8 = self.opcode.into(); @@ -384,23 +417,23 @@ impl Frame { two |= 127; } } - try!(w.write(&[one, two])); + w.write_all(&[one, two])?; if let Some(length_bytes) = match self.payload.len() { len if len < 126 => None, len if len <= 65535 => Some(2), _ => Some(8), } { - try!(w.write_uint::(self.payload.len() as u64, length_bytes)); + w.write_uint::(self.payload.len() as u64, length_bytes)?; } if self.is_masked() { let mask = self.mask.take().unwrap(); apply_mask(&mut self.payload, &mask); - try!(w.write(&mask)); + w.write_all(&mask)?; } - try!(w.write(&self.payload)); + w.write_all(&self.payload)?; Ok(()) } } @@ -421,7 +454,8 @@ impl Default for Frame { impl fmt::Display for Frame { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, + write!( + f, " final: {} @@ -439,7 +473,11 @@ payload: 0x{} // self.mask.map(|mask| format!("{:?}", mask)).unwrap_or("NONE".into()), self.len(), self.payload.len(), - self.payload.iter().map(|byte| format!("{:x}", byte)).collect::()) + self.payload + .iter() + .map(|byte| format!("{:x}", byte)) + .collect::() + ) } } diff --git a/third_party/rust/ws/src/handler.rs b/third_party/rust/ws/src/handler.rs index f2f88ef36428..7c1ef21b4b5c 100644 --- a/third_party/rust/ws/src/handler.rs +++ b/third_party/rust/ws/src/handler.rs @@ -1,23 +1,23 @@ +use log::Level::Error as ErrorLevel; +#[cfg(feature = "nativetls")] +use native_tls::{TlsConnector, TlsStream as SslStream}; +#[cfg(feature = "ssl")] +use openssl::ssl::{SslConnector, SslMethod, SslStream}; use url; -use log::LogLevel::Error as ErrorLevel; -#[cfg(feature="ssl")] -use openssl::ssl::{SslMethod, SslStream, SslConnectorBuilder}; -use message::Message; use frame::Frame; -use protocol::CloseCode; use handshake::{Handshake, Request, Response}; -use result::{Result, Error, Kind}; -use util::{Token, Timeout}; +use message::Message; +use protocol::CloseCode; +use result::{Error, Kind, Result}; +use util::{Timeout, Token}; -#[cfg(feature="ssl")] +#[cfg(any(feature = "ssl", feature = "nativetls"))] use util::TcpStream; - /// The core trait of this library. /// Implementing this trait provides the business logic of the WebSocket application. pub trait Handler { - // general /// Called when a request to shutdown all connections has been received. @@ -31,7 +31,7 @@ pub trait Handler { /// Called when the WebSocket handshake is successful and the connection is open for sending /// and receiving messages. fn on_open(&mut self, shake: Handshake) -> Result<()> { - if let Some(addr) = try!(shake.remote_addr()) { + if let Some(addr) = shake.remote_addr()? { debug!("Connection with {} now open", addr); } Ok(()) @@ -56,13 +56,16 @@ pub trait Handler { // overriding this method if they want if let Kind::Io(ref err) = err.kind { if let Some(104) = err.raw_os_error() { - return + return; } } error!("{:?}", err); if !log_enabled!(ErrorLevel) { - println!("Encountered an error: {}\nEnable a logger to see more information.", err); + println!( + "Encountered an error: {}\nEnable a logger to see more information.", + err + ); } } @@ -135,7 +138,7 @@ pub trait Handler { /// // reschedule the timeout /// self.ws.timeout(5_000, GRATI) /// } else { - /// Err(Error::new(ErrorKind::Internal, "Invalid timeout token encountered!")), + /// Err(Error::new(ErrorKind::Internal, "Invalid timeout token encountered!")) /// } /// } /// ``` @@ -216,7 +219,10 @@ pub trait Handler { debug!("Handler received: {}", frame); // default implementation doesn't allow for reserved bits to be set if frame.has_rsv1() || frame.has_rsv2() || frame.has_rsv3() { - Err(Error::new(Kind::Protocol, "Encountered frame with reserved bits set.")) + Err(Error::new( + Kind::Protocol, + "Encountered frame with reserved bits set.", + )) } else { Ok(Some(frame)) } @@ -239,10 +245,13 @@ pub trait Handler { /// By default this method simply ensures that no reserved bits are set. #[inline] fn on_send_frame(&mut self, frame: Frame) -> Result> { - debug!("Handler will send: {}", frame); + trace!("Handler will send: {}", frame); // default implementation doesn't allow for reserved bits to be set if frame.has_rsv1() || frame.has_rsv2() || frame.has_rsv3() { - Err(Error::new(Kind::Protocol, "Encountered frame with reserved bits set.")) + Err(Error::new( + Kind::Protocol, + "Encountered frame with reserved bits set.", + )) } else { Ok(Some(frame)) } @@ -253,7 +262,7 @@ pub trait Handler { /// A method for creating the initial handshake request for WebSocket clients. /// /// The default implementation provides conformance with the WebSocket protocol, but this - /// method may be overriden. In order to facilitate conformance, + /// method may be overridden. In order to facilitate conformance, /// implementors should use the `Request::from_url` method and then modify the resulting /// request as necessary. /// @@ -267,7 +276,7 @@ pub trait Handler { /// ``` #[inline] fn build_request(&mut self, url: &url::Url) -> Result { - debug!("Handler is building request to {}.", url); + trace!("Handler is building request to {}.", url); Request::from_url(url) } @@ -276,32 +285,62 @@ pub trait Handler { /// Override this method to customize how the connection is encrypted. By default /// this will use the Server Name Indication extension in conformance with RFC6455. #[inline] - #[cfg(feature="ssl")] - fn upgrade_ssl_client(&mut self, stream: TcpStream, url: &url::Url) -> Result> - { - let domain = try!(url.domain().ok_or(Error::new( + #[cfg(feature = "ssl")] + fn upgrade_ssl_client( + &mut self, + stream: TcpStream, + url: &url::Url, + ) -> Result> { + let domain = url.domain().ok_or(Error::new( Kind::Protocol, - format!("Unable to parse domain from {}. Needed for SSL.", url)))); - let connector = try!(SslConnectorBuilder::new(SslMethod::tls()).map_err(|e| { - Error::new(Kind::Internal, format!("Failed to upgrade client to SSL: {}", e)) - })).build(); + format!("Unable to parse domain from {}. Needed for SSL.", url), + ))?; + let connector = SslConnector::builder(SslMethod::tls()) + .map_err(|e| { + Error::new( + Kind::Internal, + format!("Failed to upgrade client to SSL: {}", e), + ) + })? + .build(); connector.connect(domain, stream).map_err(Error::from) } + #[inline] + #[cfg(feature = "nativetls")] + fn upgrade_ssl_client( + &mut self, + stream: TcpStream, + url: &url::Url, + ) -> Result> { + let domain = url.domain().ok_or(Error::new( + Kind::Protocol, + format!("Unable to parse domain from {}. Needed for SSL.", url), + ))?; + + let connector = TlsConnector::new().map_err(|e| { + Error::new( + Kind::Internal, + format!("Failed to upgrade client to SSL: {}", e), + ) + })?; + + connector.connect(domain, stream).map_err(Error::from) + } /// A method for wrapping a server TcpStream with Ssl Authentication machinery /// /// Override this method to customize how the connection is encrypted. By default /// this method is not implemented. #[inline] - #[cfg(feature="ssl")] - fn upgrade_ssl_server(&mut self, _: TcpStream) -> Result> - { + #[cfg(any(feature = "ssl", feature = "nativetls"))] + fn upgrade_ssl_server(&mut self, _: TcpStream) -> Result> { unimplemented!() } } impl Handler for F - where F: Fn(Message) -> Result<()> +where + F: Fn(Message) -> Result<()>, { fn on_message(&mut self, msg: Message) -> Result<()> { self(msg) @@ -311,19 +350,20 @@ impl Handler for F mod test { #![allow(unused_imports, unused_variables, dead_code)] use super::*; - use url; - use mio; - use handshake::{Request, Response, Handshake}; - use protocol::CloseCode; use frame; + use handshake::{Handshake, Request, Response}; use message; + use mio; + use protocol::CloseCode; use result::Result; + use url; #[derive(Debug, Eq, PartialEq)] struct M; impl Handler for M { fn on_message(&mut self, _: message::Message) -> Result<()> { - Ok(println!("test")) + println!("test"); + Ok(()) } fn on_frame(&mut self, f: frame::Frame) -> Result> { @@ -336,7 +376,6 @@ mod test { struct H; impl Handler for H { - fn on_open(&mut self, shake: Handshake) -> Result<()> { assert!(shake.request.key().is_ok()); assert!(shake.response.key().is_ok()); @@ -344,26 +383,29 @@ mod test { } fn on_message(&mut self, msg: message::Message) -> Result<()> { - Ok(assert_eq!(msg, message::Message::Text(String::from("testme")))) + Ok(assert_eq!( + msg, + message::Message::Text(String::from("testme")) + )) } fn on_close(&mut self, code: CloseCode, _: &str) { assert_eq!(code, CloseCode::Normal) } - } let mut h = H; let url = url::Url::parse("wss://127.0.0.1:3012").unwrap(); let req = Request::from_url(&url).unwrap(); let res = Response::from_request(&req).unwrap(); - h.on_open(Handshake{ + h.on_open(Handshake { request: req, response: res, peer_addr: None, local_addr: None, }).unwrap(); - h.on_message(message::Message::Text("testme".to_owned())).unwrap(); + h.on_message(message::Message::Text("testme".to_owned())) + .unwrap(); h.on_close(CloseCode::Normal, ""); } @@ -374,6 +416,8 @@ mod test { Ok(()) }; - close.on_message(message::Message::Binary(vec![1, 2, 3])).unwrap(); + close + .on_message(message::Message::Binary(vec![1, 2, 3])) + .unwrap(); } } diff --git a/third_party/rust/ws/src/handshake.rs b/third_party/rust/ws/src/handshake.rs index 808201721bd2..b7520bde56aa 100644 --- a/third_party/rust/ws/src/handshake.rs +++ b/third_party/rust/ws/src/handshake.rs @@ -1,14 +1,14 @@ use std::fmt; use std::io::Write; -use std::str::from_utf8; use std::net::SocketAddr; +use std::str::from_utf8; -use sha1; -use rand; -use url; use httparse; +use rand; +use sha1::{self, Digest}; +use url; -use result::{Result, Error, Kind}; +use result::{Error, Kind, Result}; static WS_GUID: &'static str = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; static BASE64: &'static [u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; @@ -22,10 +22,10 @@ fn generate_key() -> String { pub fn hash_key(key: &[u8]) -> String { let mut hasher = sha1::Sha1::new(); - hasher.update(key); - hasher.update(WS_GUID.as_bytes()); + hasher.input(key); + hasher.input(WS_GUID.as_bytes()); - encode_base64(&hasher.digest().bytes()) + encode_base64(&hasher.result()) } // This code is based on rustc_serialize base64 STANDARD @@ -35,28 +35,30 @@ fn encode_base64(data: &[u8]) -> String { let mut encoded = vec![b'='; (len + 2) / 3 * 4]; { - let mut in_iter = data[..len - mod_len].iter().map(|&c| c as u32); + let mut in_iter = data[..len - mod_len].iter().map(|&c| u32::from(c)); let mut out_iter = encoded.iter_mut(); let enc = |val| BASE64[val as usize]; let mut write = |val| *out_iter.next().unwrap() = val; - while let (Some(one), Some(two), Some(three)) = (in_iter.next(), in_iter.next(), in_iter.next()) { + while let (Some(one), Some(two), Some(three)) = + (in_iter.next(), in_iter.next(), in_iter.next()) + { let g24 = one << 16 | two << 8 | three; write(enc((g24 >> 18) & 63)); write(enc((g24 >> 12) & 63)); - write(enc((g24 >> 6 ) & 63)); + write(enc((g24 >> 6) & 63)); write(enc(g24 & 63)); } match mod_len { 1 => { - let pad = (data[len-1] as u32) << 16; + let pad = (u32::from(data[len - 1])) << 16; write(enc((pad >> 18) & 63)); write(enc((pad >> 12) & 63)); } 2 => { - let pad = (data[len-2] as u32) << 16 | (data[len-1] as u32) << 8; + let pad = (u32::from(data[len - 2])) << 16 | (u32::from(data[len - 1])) << 8; write(enc((pad >> 18) & 63)); write(enc((pad >> 12) & 63)); write(enc((pad >> 6) & 63)); @@ -83,7 +85,6 @@ pub struct Handshake { } impl Handshake { - /// Get the IP address of the remote connection. /// /// This is the preferred method of obtaining the client's IP address. @@ -98,7 +99,7 @@ impl Handshake { /// This method does not ensure that the address is a valid IP address. #[allow(dead_code)] pub fn remote_addr(&self) -> Result> { - Ok(try!(self.request.client_addr()).map(String::from).or_else(|| { + Ok(self.request.client_addr()?.map(String::from).or_else(|| { if let Some(addr) = self.peer_addr { Some(addr.ip().to_string()) } else { @@ -106,10 +107,8 @@ impl Handshake { } })) } - } - /// The handshake request. #[derive(Debug)] pub struct Request { @@ -119,7 +118,6 @@ pub struct Request { } impl Request { - /// Get the value of the first instance of an HTTP header. pub fn header(&self, header: &str) -> Option<&Vec> { self.headers @@ -154,7 +152,7 @@ impl Request { #[allow(dead_code)] pub fn origin(&self) -> Result> { if let Some(origin) = self.header("origin") { - Ok(Some(try!(from_utf8(origin)))) + Ok(Some(from_utf8(origin)?)) } else { Ok(None) } @@ -163,12 +161,12 @@ impl Request { /// Get the unhashed WebSocket key sent in the request. pub fn key(&self) -> Result<&Vec> { self.header("sec-websocket-key") - .ok_or(Error::new(Kind::Protocol, "Unable to parse WebSocket key.")) + .ok_or_else(|| Error::new(Kind::Protocol, "Unable to parse WebSocket key.")) } /// Get the hashed WebSocket key from this request. pub fn hashed_key(&self) -> Result { - Ok(hash_key(try!(self.key()))) + Ok(hash_key(self.key()?)) } /// Get the WebSocket protocol version from the request (should be 13). @@ -177,10 +175,19 @@ impl Request { if let Some(version) = self.header("sec-websocket-version") { from_utf8(version).map_err(Error::from) } else { - Err(Error::new(Kind::Protocol, "The Sec-WebSocket-Version header is missing.")) + Err(Error::new( + Kind::Protocol, + "The Sec-WebSocket-Version header is missing.", + )) } } + /// Get the request method. + #[inline] + pub fn method(&self) -> &str { + &self.method + } + /// Get the path of the request. #[allow(dead_code)] #[inline] @@ -192,7 +199,10 @@ impl Request { #[allow(dead_code)] pub fn protocols(&self) -> Result> { if let Some(protos) = self.header("sec-websocket-protocol") { - Ok(try!(from_utf8(protos)).split(',').map(|proto| proto.trim()).collect()) + Ok(from_utf8(protos)? + .split(',') + .map(|proto| proto.trim()) + .collect()) } else { Ok(Vec::new()) } @@ -205,9 +215,10 @@ impl Request { if let Some(protos) = self.header_mut("sec-websocket-protocol") { protos.push(b","[0]); protos.extend(protocol.as_bytes()); - return + return; } - self.headers_mut().push(("Sec-WebSocket-Protocol".into(), protocol.into())) + self.headers_mut() + .push(("Sec-WebSocket-Protocol".into(), protocol.into())) } /// Remove a possible protocol from this request. @@ -221,7 +232,8 @@ impl Request { .split(',') .filter(|proto| proto.trim() == protocol) .collect::>() - .join(",").into(); + .join(",") + .into(); } if new_protos.len() < protos.len() { *protos = new_protos @@ -233,7 +245,7 @@ impl Request { #[allow(dead_code)] pub fn extensions(&self) -> Result> { if let Some(exts) = self.header("sec-websocket-extensions") { - Ok(try!(from_utf8(exts)).split(',').map(|ext| ext.trim()).collect()) + Ok(from_utf8(exts)?.split(',').map(|ext| ext.trim()).collect()) } else { Ok(Vec::new()) } @@ -248,9 +260,10 @@ impl Request { if let Some(exts) = self.header_mut("sec-websocket-extensions") { exts.push(b","[0]); exts.extend(ext.as_bytes()); - return + return; } - self.headers_mut().push(("Sec-WebSocket-Extensions".into(), ext.into())) + self.headers_mut() + .push(("Sec-WebSocket-Extensions".into(), ext.into())) } /// Remove a possible extension from this request. @@ -265,7 +278,8 @@ impl Request { .split(',') .filter(|e| e.trim().starts_with(ext)) .collect::>() - .join(",").into(); + .join(",") + .into(); } if new_exts.len() < exts.len() { *exts = new_exts @@ -290,19 +304,19 @@ impl Request { #[allow(dead_code)] pub fn client_addr(&self) -> Result> { if let Some(x_forward) = self.header("x-forwarded-for") { - return Ok(try!(from_utf8(x_forward)).split(',').next()) + return Ok(from_utf8(x_forward)?.split(',').next()); } // We only care about the first forwarded header, so header is ok if let Some(forward) = self.header("forwarded") { - if let Some(_for) = try!(from_utf8(forward)) + if let Some(_for) = from_utf8(forward)? .split(';') .find(|f| f.trim().starts_with("for")) { if let Some(_for_eq) = _for.trim().split(',').next() { let mut it = _for_eq.split('='); it.next(); - return Ok(it.next()) + return Ok(it.next()); } } } @@ -314,12 +328,15 @@ impl Request { pub fn parse(buf: &[u8]) -> Result> { let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS]; let mut req = httparse::Request::new(&mut headers); - let parsed = try!(req.parse(buf)); + let parsed = req.parse(buf)?; if !parsed.is_partial() { Ok(Some(Request { path: req.path.unwrap().into(), method: req.method.unwrap().into(), - headers: req.headers.iter().map(|h| (h.name.into(), h.value.into())).collect(), + headers: req.headers + .iter() + .map(|h| (h.name.into(), h.value.into())) + .collect(), })) } else { Ok(None) @@ -328,33 +345,39 @@ impl Request { /// Construct a new WebSocket handshake HTTP request from a url. pub fn from_url(url: &url::Url) -> Result { - let query = if let Some(q) = url.query() { format!("?{}", q) } else { "".into() }; + let mut headers = vec![ + ("Connection".into(), "Upgrade".into()), + ( + "Host".into(), + format!( + "{}:{}", + url.host_str().ok_or_else(|| Error::new( + Kind::Internal, + "No host passed for WebSocket connection.", + ))?, + url.port_or_known_default().unwrap_or(80) + ).into(), + ), + ("Sec-WebSocket-Version".into(), "13".into()), + ("Sec-WebSocket-Key".into(), generate_key().into()), + ("Upgrade".into(), "websocket".into()), + ]; + + if url.password().is_some() || url.username() != "" { + let basic = encode_base64(format!("{}:{}", url.username(), url.password().unwrap_or("")).as_bytes()); + headers.push(("Authorization".into(), format!("Basic {}", basic).into())) + } + let req = Request { - path: format!( - "{}{}", - url.path(), - query), + path: format!("{}{}", url.path(), query), method: "GET".to_owned(), - headers: vec![ - ("Connection".into(), "Upgrade".into()), - ( - "Host".into(), - format!( - "{}:{}", - try!(url.host_str().ok_or( - Error::new(Kind::Internal, "No host passed for WebSocket connection."))), - url.port_or_known_default().unwrap_or(80)).into(), - ), - ("Sec-WebSocket-Version".into(), "13".into()), - ("Sec-WebSocket-Key".into(), generate_key().into()), - ("Upgrade".into(), "websocket".into()), - ], + headers: headers, }; debug!("Built request from URL:\n{}", req); @@ -364,34 +387,36 @@ impl Request { /// Write a request out to a buffer pub fn format(&self, w: &mut W) -> Result<()> - where W: Write, + where + W: Write, { - try!(write!(w, "{} {} HTTP/1.1\r\n", self.method, self.path)); - for &(ref key, ref val) in self.headers.iter() { - try!(write!(w, "{}: ", key)); - try!(w.write(val)); - try!(write!(w, "\r\n")); + write!(w, "{} {} HTTP/1.1\r\n", self.method, self.path)?; + for &(ref key, ref val) in &self.headers { + write!(w, "{}: ", key)?; + w.write_all(val)?; + write!(w, "\r\n")?; } - try!(write!(w, "\r\n")); + write!(w, "\r\n")?; Ok(()) } - } impl fmt::Display for Request { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut s = Vec::with_capacity(2048); - try!(self.format(&mut s).map_err(|err| { + self.format(&mut s).map_err(|err| { error!("{:?}", err); fmt::Error - })); - write!(f, "{}", try!(from_utf8(&s).map_err(|err| { - error!("Unable to format request as utf8: {:?}", err); - fmt::Error - }))) + })?; + write!( + f, + "{}", + from_utf8(&s).map_err(|err| { + error!("Unable to format request as utf8: {:?}", err); + fmt::Error + })? + ) } - } /// The handshake response. @@ -400,11 +425,31 @@ pub struct Response { status: u16, reason: String, headers: Vec<(String, Vec)>, + body: Vec, } impl Response { // TODO: resolve the overlap with Request + /// Construct a generic HTTP response with a body. + pub fn new(status: u16, reason: R, body: Vec) -> Response + where + R: Into, + { + Response { + status, + reason: reason.into(), + headers: vec![("Content-Length".into(), body.len().to_string().into())], + body, + } + } + + /// Get the response body. + #[inline] + pub fn body(&self) -> &[u8] { + &self.body + } + /// Get the value of the first instance of an HTTP header. fn header(&self, header: &str) -> Option<&Vec> { self.headers @@ -444,7 +489,7 @@ impl Response { /// Set the HTTP status code. #[allow(dead_code)] #[inline] - pub fn set_status(&mut self, status: u16) { + pub fn set_status(&mut self, status: u16) { self.status = status } @@ -455,26 +500,27 @@ impl Response { &self.reason } - /// Set the HTTP status reason. #[allow(dead_code)] #[inline] pub fn set_reason(&mut self, reason: R) - where R: Into + where + R: Into, { self.reason = reason.into() } /// Get the hashed WebSocket key. pub fn key(&self) -> Result<&Vec> { - self.header("sec-websocket-accept").ok_or(Error::new(Kind::Protocol, "Unable to parse WebSocket key.")) + self.header("sec-websocket-accept") + .ok_or_else(|| Error::new(Kind::Protocol, "Unable to parse WebSocket key.")) } /// Get the protocol that the server has decided to use. #[allow(dead_code)] pub fn protocol(&self) -> Result> { if let Some(proto) = self.header("sec-websocket-protocol") { - Ok(Some(try!(from_utf8(proto)))) + Ok(Some(from_utf8(proto)?)) } else { Ok(None) } @@ -485,9 +531,10 @@ impl Response { pub fn set_protocol(&mut self, protocol: &str) { if let Some(proto) = self.header_mut("sec-websocket-protocol") { *proto = protocol.into(); - return + return; } - self.headers_mut().push(("Sec-WebSocket-Protocol".into(), protocol.into())) + self.headers_mut() + .push(("Sec-WebSocket-Protocol".into(), protocol.into())) } /// Get the extensions that the server has decided to use. If these are unacceptable, it is @@ -495,7 +542,10 @@ impl Response { #[allow(dead_code)] pub fn extensions(&self) -> Result> { if let Some(exts) = self.header("sec-websocket-extensions") { - Ok(try!(from_utf8(exts)).split(',').map(|proto| proto.trim()).collect()) + Ok(from_utf8(exts)? + .split(',') + .map(|proto| proto.trim()) + .collect()) } else { Ok(Vec::new()) } @@ -508,9 +558,10 @@ impl Response { if let Some(exts) = self.header_mut("sec-websocket-extensions") { exts.push(b","[0]); exts.extend(ext.as_bytes()); - return + return; } - self.headers_mut().push(("Sec-WebSocket-Extensions".into(), ext.into())) + self.headers_mut() + .push(("Sec-WebSocket-Extensions".into(), ext.into())) } /// Remove an accepted extension from this response. @@ -525,7 +576,8 @@ impl Response { .split(',') .filter(|e| e.trim().starts_with(ext)) .collect::>() - .join(",").into(); + .join(",") + .into(); } if new_exts.len() < exts.len() { *exts = new_exts @@ -539,12 +591,16 @@ impl Response { let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS]; let mut res = httparse::Response::new(&mut headers); - let parsed = try!(res.parse(buf)); + let parsed = res.parse(buf)?; if !parsed.is_partial() { Ok(Some(Response { status: res.code.unwrap(), reason: res.reason.unwrap().into(), - headers: res.headers.iter().map(|h| (h.name.into(), h.value.into())).collect(), + headers: res.headers + .iter() + .map(|h| (h.name.into(), h.value.into())) + .collect(), + body: Vec::new(), })) } else { Ok(None) @@ -560,9 +616,10 @@ impl Response { reason: "Switching Protocols".into(), headers: vec![ ("Connection".into(), "Upgrade".into()), - ("Sec-WebSocket-Accept".into(), try!(req.hashed_key()).into()), + ("Sec-WebSocket-Accept".into(), req.hashed_key()?.into()), ("Upgrade".into(), "websocket".into()), ], + body: Vec::new(), }; debug!("Built response from request:\n{}", res); @@ -571,41 +628,45 @@ impl Response { /// Write a response out to a buffer pub fn format(&self, w: &mut W) -> Result<()> - where W: Write + where + W: Write, { - try!(write!(w, "HTTP/1.1 {} {}\r\n", self.status, self.reason)); - for &(ref key, ref val) in self.headers.iter() { - try!(write!(w, "{}: ", key)); - try!(w.write(val)); - try!(write!(w, "\r\n")); + write!(w, "HTTP/1.1 {} {}\r\n", self.status, self.reason)?; + for &(ref key, ref val) in &self.headers { + write!(w, "{}: ", key)?; + w.write_all(val)?; + write!(w, "\r\n")?; } - try!(write!(w, "\r\n")); + write!(w, "\r\n")?; + w.write_all(&self.body)?; Ok(()) } } impl fmt::Display for Response { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut s = Vec::with_capacity(2048); - try!(self.format(&mut s).map_err(|err| { + self.format(&mut s).map_err(|err| { error!("{:?}", err); fmt::Error - })); - write!(f, "{}", try!(from_utf8(&s).map_err(|err| { - error!("Unable to format response as utf8: {:?}", err); - fmt::Error - }))) + })?; + write!( + f, + "{}", + from_utf8(&s).map_err(|err| { + error!("Unable to format response as utf8: {:?}", err); + fmt::Error + })? + ) } - } mod test { #![allow(unused_imports, unused_variables, dead_code)] + use super::*; use std::io::Write; use std::net::SocketAddr; use std::str::FromStr; - use super::*; #[test] fn remote_addr() { @@ -613,10 +674,11 @@ mod test { write!( &mut buf, "GET / HTTP/1.1\r\n\ - Connection: Upgrade\r\n\ - Upgrade: websocket\r\n\ - Sec-WebSocket-Version: 13\r\n\ - Sec-WebSocket-Key: q16eN37NCfVwUChPvBdk4g==\r\n\r\n").unwrap(); + Connection: Upgrade\r\n\ + Upgrade: websocket\r\n\ + Sec-WebSocket-Version: 13\r\n\ + Sec-WebSocket-Key: q16eN37NCfVwUChPvBdk4g==\r\n\r\n" + ).unwrap(); let req = Request::parse(&buf).unwrap().unwrap(); let res = Response::from_request(&req).unwrap(); @@ -635,11 +697,12 @@ mod test { write!( &mut buf, "GET / HTTP/1.1\r\n\ - Connection: Upgrade\r\n\ - Upgrade: websocket\r\n\ - X-Forwarded-For: 192.168.1.1, 192.168.1.2, 192.168.1.3\r\n\ - Sec-WebSocket-Version: 13\r\n\ - Sec-WebSocket-Key: q16eN37NCfVwUChPvBdk4g==\r\n\r\n").unwrap(); + Connection: Upgrade\r\n\ + Upgrade: websocket\r\n\ + X-Forwarded-For: 192.168.1.1, 192.168.1.2, 192.168.1.3\r\n\ + Sec-WebSocket-Version: 13\r\n\ + Sec-WebSocket-Key: q16eN37NCfVwUChPvBdk4g==\r\n\r\n" + ).unwrap(); let req = Request::parse(&buf).unwrap().unwrap(); let res = Response::from_request(&req).unwrap(); @@ -662,7 +725,8 @@ mod test { Upgrade: websocket\r\n\ Forwarded: by=192.168.1.1; for=192.0.2.43, for=\"[2001:db8:cafe::17]\", for=unknown\r\n\ Sec-WebSocket-Version: 13\r\n\ - Sec-WebSocket-Key: q16eN37NCfVwUChPvBdk4g==\r\n\r\n").unwrap(); + Sec-WebSocket-Key: q16eN37NCfVwUChPvBdk4g==\r\n\r\n") + .unwrap(); let req = Request::parse(&buf).unwrap().unwrap(); let res = Response::from_request(&req).unwrap(); let shake = Handshake { diff --git a/third_party/rust/ws/src/io.rs b/third_party/rust/ws/src/io.rs index e52a84fde45c..7739cdc472f7 100644 --- a/third_party/rust/ws/src/io.rs +++ b/third_party/rust/ws/src/io.rs @@ -1,29 +1,26 @@ -use std::net::{SocketAddr, ToSocketAddrs}; use std::borrow::Borrow; +use std::io::{Error as IoError, ErrorKind}; +use std::net::{SocketAddr, ToSocketAddrs}; use std::time::Duration; use std::usize; -use std::io::{ErrorKind, Error as IoError}; use mio; -use mio::{ - Token, - Ready, - Poll, - PollOpt, -}; use mio::tcp::{TcpListener, TcpStream}; +use mio::{Poll, PollOpt, Ready, Token}; +use mio_extras; use url::Url; -#[cfg(feature="ssl")] -use openssl::ssl::Error as SslError; +#[cfg(feature = "native_tls")] +use native_tls::Error as SslError; -use communication::{Sender, Signal, Command}; -use result::{Result, Error, Kind}; +use super::Settings; +use communication::{Command, Sender, Signal}; use connection::Connection; use factory::Factory; -use util::Slab; -use super::Settings; +use slab::Slab; +use result::{Error, Kind, Result}; + const QUEUE: Token = Token(usize::MAX - 3); const TIMER: Token = Token(usize::MAX - 4); @@ -44,15 +41,19 @@ const CONNECTION_REFUSED: i32 = 111; const CONNECTION_REFUSED: i32 = 61; fn url_to_addrs(url: &Url) -> Result> { - let host = url.host_str(); - if host.is_none() || ( url.scheme() != "ws" && url.scheme() != "wss" ) { - return Err(Error::new(Kind::Internal, format!("Not a valid websocket url: {}", url))) + if host.is_none() || (url.scheme() != "ws" && url.scheme() != "wss") { + return Err(Error::new( + Kind::Internal, + format!("Not a valid websocket url: {}", url), + )); } let host = host.unwrap(); let port = url.port_or_known_default().unwrap_or(80); - let mut addrs = try!((&host[..], port).to_socket_addrs()).collect::>(); + let mut addrs = (&host[..], port) + .to_socket_addrs()? + .collect::>(); addrs.dedup(); Ok(addrs) } @@ -63,7 +64,6 @@ enum State { } impl State { - fn is_active(&self) -> bool { match *self { State::Active => true, @@ -79,7 +79,8 @@ pub struct Timeout { } pub struct Handler - where F: Factory +where + F: Factory, { listener: Option, connections: Slab>, @@ -88,17 +89,17 @@ pub struct Handler state: State, queue_tx: mio::channel::SyncSender, queue_rx: mio::channel::Receiver, - timer: mio::timer::Timer, - next_connection_id: u32 + timer: mio_extras::timer::Timer, + next_connection_id: u32, } - impl Handler - where F: Factory +where + F: Factory, { pub fn new(factory: F, settings: Settings) -> Handler { let (tx, rx) = mio::channel::sync_channel(settings.max_connections * settings.queue_size); - let timer = mio::timer::Builder::default() + let timer = mio_extras::timer::Builder::default() .tick_duration(Duration::from_millis(TIMER_TICK_MILLIS)) .num_slots(TIMER_WHEEL_SIZE) .capacity(TIMER_CAPACITY) @@ -106,29 +107,29 @@ impl Handler Handler { listener: None, connections: Slab::with_capacity(settings.max_connections), - factory: factory, - settings: settings, + factory, + settings, state: State::Inactive, queue_tx: tx, queue_rx: rx, - timer: timer, - next_connection_id: 0 + timer, + next_connection_id: 0, } } - pub fn sender(&self ) -> Sender { + pub fn sender(&self) -> Sender { Sender::new(ALL, self.queue_tx.clone(), 0) } pub fn listen(&mut self, poll: &mut Poll, addr: &SocketAddr) -> Result<&mut Handler> { - debug_assert!( self.listener.is_none(), - "Attempted to listen for connections from two addresses on the same websocket."); + "Attempted to listen for connections from two addresses on the same websocket." + ); - let tcp = try!(TcpListener::bind(addr)); + let tcp = TcpListener::bind(addr)?; // TODO: consider net2 in order to set reuse_addr - try!(poll.register(&tcp, ALL, Ready::readable(), PollOpt::level())); + poll.register(&tcp, ALL, Ready::readable(), PollOpt::level())?; self.listener = Some(tcp); Ok(self) } @@ -141,19 +142,33 @@ impl Handler } } - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] pub fn connect(&mut self, poll: &mut Poll, url: Url) -> Result<()> { let settings = self.settings; let (tok, addresses) = { - let (tok, entry, connection_id, handler) = if let Some(entry) = self.connections.vacant_entry() { - let tok = entry.index(); - let connection_id = self.next_connection_id; - self.next_connection_id = self.next_connection_id.wrapping_add(1); - (tok, entry, connection_id, self.factory.client_connected(Sender::new(tok, self.queue_tx.clone(), connection_id))) - } else { - return Err(Error::new(Kind::Capacity, "Unable to add another connection to the event loop.")); - }; + let (tok, entry, connection_id, handler) = + if self.connections.len() < settings.max_connections { + let entry = self.connections.vacant_entry(); + let tok = Token(entry.key()); + let connection_id = self.next_connection_id; + self.next_connection_id = self.next_connection_id.wrapping_add(1); + ( + tok, + entry, + connection_id, + self.factory.client_connected(Sender::new( + tok, + self.queue_tx.clone(), + connection_id, + )), + ) + } else { + return Err(Error::new( + Kind::Capacity, + "Unable to add another connection to the event loop.", + )); + }; let mut addresses = match url_to_addrs(&url) { Ok(addresses) => addresses, @@ -167,18 +182,18 @@ impl Handler if let Some(addr) = addresses.pop() { if let Ok(sock) = TcpStream::connect(&addr) { if settings.tcp_nodelay { - try!(sock.set_nodelay(true)) + sock.set_nodelay(true)? } addresses.push(addr); // Replace the first addr in case ssl fails and we fallback entry.insert(Connection::new(tok, sock, handler, settings, connection_id)); - break + break; } } else { self.factory.connection_lost(handler); - return Err( - Error::new( - Kind::Internal, - format!("Unable to obtain any socket address for {}", url))) + return Err(Error::new( + Kind::Internal, + format!("Unable to obtain any socket address for {}", url), + )); } } @@ -187,60 +202,95 @@ impl Handler let will_encrypt = url.scheme() == "wss"; - if let Err(error) = self.connections[tok].as_client(url, addresses) { - let handler = self.connections.remove(tok).unwrap().consume(); + if let Err(error) = self.connections[tok.into()].as_client(url, addresses) { + let handler = self.connections.remove(tok.into()).consume(); self.factory.connection_lost(handler); - return Err(error) + return Err(error); } if will_encrypt { - while let Err(ssl_error) = self.connections[tok].encrypt() { + while let Err(ssl_error) = self.connections[tok.into()].encrypt() { match ssl_error.kind { - Kind::Ssl(SslError::Stream(ref io_error)) => { - if let Some(errno) = io_error.raw_os_error() { - if errno == CONNECTION_REFUSED { - if let Err(reset_error) = self.connections[tok].reset() { - trace!("Encountered error while trying to reset connection: {:?}", reset_error); - } else { - continue + #[cfg(feature = "ssl")] + Kind::Ssl(ref inner_ssl_error) => { + if let Some(io_error) = inner_ssl_error.io_error() { + if let Some(errno) = io_error.raw_os_error() { + if errno == CONNECTION_REFUSED { + if let Err(reset_error) = self.connections[tok.into()].reset() { + trace!( + "Encountered error while trying to reset connection: {:?}", + reset_error + ); + } else { + continue; + } } } } } + #[cfg(feature = "nativetls")] + Kind::Ssl(_) => { + if let Err(reset_error) = self.connections[tok.into()].reset() { + trace!( + "Encountered error while trying to reset connection: {:?}", + reset_error + ); + } else { + continue; + } + } _ => (), } - self.connections[tok].error(ssl_error); + self.connections[tok.into()].error(ssl_error); // Allow socket to be registered anyway to await hangup - break + break; } } poll.register( - self.connections[tok].socket(), - self.connections[tok].token(), - self.connections[tok].events(), + self.connections[tok.into()].socket(), + self.connections[tok.into()].token(), + self.connections[tok.into()].events(), PollOpt::edge() | PollOpt::oneshot(), - ).map_err(Error::from).or_else(|err| { - error!("Encountered error while trying to build WebSocket connection: {}", err); - let handler = self.connections.remove(tok).unwrap().consume(); - self.factory.connection_lost(handler); - Err(err) - }) + ).map_err(Error::from) + .or_else(|err| { + error!( + "Encountered error while trying to build WebSocket connection: {}", + err + ); + let handler = self.connections.remove(tok.into()).consume(); + self.factory.connection_lost(handler); + Err(err) + }) } - #[cfg(not(feature="ssl"))] + #[cfg(not(any(feature = "ssl", feature = "nativetls")))] pub fn connect(&mut self, poll: &mut Poll, url: Url) -> Result<()> { let settings = self.settings; let (tok, addresses) = { - let (tok, entry, connection_id, handler) = if let Some(entry) = self.connections.vacant_entry() { - let tok = entry.index(); - let connection_id = self.next_connection_id; - self.next_connection_id = self.next_connection_id.wrapping_add(1); - (tok, entry, connection_id, self.factory.client_connected(Sender::new(tok, self.queue_tx.clone(), connection_id))) - } else { - return Err(Error::new(Kind::Capacity, "Unable to add another connection to the event loop.")); - }; + let (tok, entry, connection_id, handler) = + if self.connections.len() < settings.max_connections { + let entry = self.connections.vacant_entry(); + let tok = Token(entry.key()); + let connection_id = self.next_connection_id; + self.next_connection_id = self.next_connection_id.wrapping_add(1); + ( + tok, + entry, + connection_id, + self.factory.client_connected(Sender::new( + tok, + self.queue_tx.clone(), + connection_id, + )), + ) + } else { + return Err(Error::new( + Kind::Capacity, + "Unable to add another connection to the event loop.", + )); + }; let mut addresses = match url_to_addrs(&url) { Ok(addresses) => addresses, @@ -254,17 +304,17 @@ impl Handler if let Some(addr) = addresses.pop() { if let Ok(sock) = TcpStream::connect(&addr) { if settings.tcp_nodelay { - try!(sock.set_nodelay(true)) + sock.set_nodelay(true)? } entry.insert(Connection::new(tok, sock, handler, settings, connection_id)); - break + break; } } else { self.factory.connection_lost(handler); - return Err( - Error::new( - Kind::Internal, - format!("Unable to obtain any socket address for {}", url))) + return Err(Error::new( + Kind::Internal, + format!("Unable to obtain any socket address for {}", url), + )); } } @@ -272,133 +322,170 @@ impl Handler }; if url.scheme() == "wss" { - let error = Error::new(Kind::Protocol, "The ssl feature is not enabled. Please enable it to use wss urls."); - let handler = self.connections.remove(tok).unwrap().consume(); + let error = Error::new( + Kind::Protocol, + "The ssl feature is not enabled. Please enable it to use wss urls.", + ); + let handler = self.connections.remove(tok.into()).consume(); self.factory.connection_lost(handler); - return Err(error) + return Err(error); } - if let Err(error) = self.connections[tok].as_client(url, addresses) { - let handler = self.connections.remove(tok).unwrap().consume(); + if let Err(error) = self.connections[tok.into()].as_client(url, addresses) { + let handler = self.connections.remove(tok.into()).consume(); self.factory.connection_lost(handler); - return Err(error) + return Err(error); } poll.register( - self.connections[tok].socket(), - self.connections[tok].token(), - self.connections[tok].events(), + self.connections[tok.into()].socket(), + self.connections[tok.into()].token(), + self.connections[tok.into()].events(), PollOpt::edge() | PollOpt::oneshot(), - ).map_err(Error::from).or_else(|err| { - error!("Encountered error while trying to build WebSocket connection: {}", err); - let handler = self.connections.remove(tok).unwrap().consume(); - self.factory.connection_lost(handler); - Err(err) - }) + ).map_err(Error::from) + .or_else(|err| { + error!( + "Encountered error while trying to build WebSocket connection: {}", + err + ); + let handler = self.connections.remove(tok.into()).consume(); + self.factory.connection_lost(handler); + Err(err) + }) } - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] pub fn accept(&mut self, poll: &mut Poll, sock: TcpStream) -> Result<()> { let factory = &mut self.factory; let settings = self.settings; if settings.tcp_nodelay { - try!(sock.set_nodelay(true)) + sock.set_nodelay(true)? } let tok = { - if let Some(entry) = self.connections.vacant_entry() { - let tok = entry.index(); + if self.connections.len() < settings.max_connections { + let entry = self.connections.vacant_entry(); + let tok = Token(entry.key()); let connection_id = self.next_connection_id; self.next_connection_id = self.next_connection_id.wrapping_add(1); - let handler = factory.server_connected(Sender::new(tok, self.queue_tx.clone(), connection_id)); + let handler = factory.server_connected(Sender::new( + tok, + self.queue_tx.clone(), + connection_id, + )); entry.insert(Connection::new(tok, sock, handler, settings, connection_id)); tok } else { - return Err(Error::new(Kind::Capacity, "Unable to add another connection to the event loop.")); + return Err(Error::new( + Kind::Capacity, + "Unable to add another connection to the event loop.", + )); } }; - let conn = &mut self.connections[tok]; + let conn = &mut self.connections[tok.into()]; - try!(conn.as_server()); + conn.as_server()?; if settings.encrypt_server { - try!(conn.encrypt()) + conn.encrypt()? } - poll.register( conn.socket(), conn.token(), conn.events(), PollOpt::edge() | PollOpt::oneshot(), - ).map_err(Error::from).or_else(|err| { - error!("Encountered error while trying to build WebSocket connection: {}", err); - conn.error(err); - if settings.panic_on_new_connection { - panic!("Encountered error while trying to build WebSocket connection."); - } - Ok(()) - }) + ).map_err(Error::from) + .or_else(|err| { + error!( + "Encountered error while trying to build WebSocket connection: {}", + err + ); + conn.error(err); + if settings.panic_on_new_connection { + panic!("Encountered error while trying to build WebSocket connection."); + } + Ok(()) + }) } - #[cfg(not(feature="ssl"))] + #[cfg(not(any(feature = "ssl", feature = "nativetls")))] pub fn accept(&mut self, poll: &mut Poll, sock: TcpStream) -> Result<()> { let factory = &mut self.factory; let settings = self.settings; if settings.tcp_nodelay { - try!(sock.set_nodelay(true)) + sock.set_nodelay(true)? } let tok = { - if let Some(entry) = self.connections.vacant_entry() { - let tok = entry.index(); + if self.connections.len() < settings.max_connections { + let entry = self.connections.vacant_entry(); + let tok = Token(entry.key()); let connection_id = self.next_connection_id; self.next_connection_id = self.next_connection_id.wrapping_add(1); - let handler = factory.server_connected(Sender::new(tok, self.queue_tx.clone(), connection_id)); + let handler = factory.server_connected(Sender::new( + tok, + self.queue_tx.clone(), + connection_id, + )); entry.insert(Connection::new(tok, sock, handler, settings, connection_id)); tok } else { - return Err(Error::new(Kind::Capacity, "Unable to add another connection to the event loop.")); + return Err(Error::new( + Kind::Capacity, + "Unable to add another connection to the event loop.", + )); } }; - let conn = &mut self.connections[tok]; + let conn = &mut self.connections[tok.into()]; - try!(conn.as_server()); + conn.as_server()?; if settings.encrypt_server { - return Err(Error::new(Kind::Protocol, "The ssl feature is not enabled. Please enable it to use wss urls.")) + return Err(Error::new( + Kind::Protocol, + "The ssl feature is not enabled. Please enable it to use wss urls.", + )); } - poll.register( conn.socket(), conn.token(), conn.events(), PollOpt::edge() | PollOpt::oneshot(), - ).map_err(Error::from).or_else(|err| { - error!("Encountered error while trying to build WebSocket connection: {}", err); - conn.error(err); - if settings.panic_on_new_connection { - panic!("Encountered error while trying to build WebSocket connection."); - } - Ok(()) - }) + ).map_err(Error::from) + .or_else(|err| { + error!( + "Encountered error while trying to build WebSocket connection: {}", + err + ); + conn.error(err); + if settings.panic_on_new_connection { + panic!("Encountered error while trying to build WebSocket connection."); + } + Ok(()) + }) } pub fn run(&mut self, poll: &mut Poll) -> Result<()> { trace!("Running event loop"); - try!(poll.register(&self.queue_rx, QUEUE, Ready::readable(), PollOpt::edge() | PollOpt::oneshot())); - try!(poll.register(&self.timer, TIMER, Ready::readable(), PollOpt::edge())); + poll.register( + &self.queue_rx, + QUEUE, + Ready::readable(), + PollOpt::edge() | PollOpt::oneshot(), + )?; + poll.register(&self.timer, TIMER, Ready::readable(), PollOpt::edge())?; self.state = State::Active; let result = self.event_loop(poll); self.state = State::Inactive; result - .and(poll.deregister(&self.timer).map_err(|e| Error::from(e))) - .and(poll.deregister(&self.queue_rx).map_err(|e| Error::from(e))) + .and(poll.deregister(&self.timer).map_err(Error::from)) + .and(poll.deregister(&self.queue_rx).map_err(Error::from)) } #[inline] @@ -414,7 +501,7 @@ impl Handler error!("Websocket shutting down for interrupt."); self.state = State::Inactive; } else { - error!("Websocket received interupt."); + error!("Websocket received interrupt."); } 0 } else { @@ -436,18 +523,26 @@ impl Handler #[inline] fn schedule(&self, poll: &mut Poll, conn: &Conn) -> Result<()> { - trace!("Scheduling connection to {} as {:?}", conn.socket().peer_addr().map(|addr| addr.to_string()).unwrap_or("UNKNOWN".into()), conn.events()); - Ok(try!(poll.reregister( + trace!( + "Scheduling connection to {} as {:?}", + conn.socket() + .peer_addr() + .map(|addr| addr.to_string()) + .unwrap_or_else(|_| "UNKNOWN".into()), + conn.events() + ); + poll.reregister( conn.socket(), conn.token(), conn.events(), - PollOpt::edge() | PollOpt::oneshot() - ))) + PollOpt::edge() | PollOpt::oneshot(), + )?; + Ok(()) } fn shutdown(&mut self) { debug!("Received shutdown signal. WebSocket is attempting to shut down."); - for conn in self.connections.iter_mut() { + for (_, conn) in self.connections.iter_mut() { conn.shutdown(); } self.factory.on_shutdown(); @@ -463,23 +558,24 @@ impl Handler // established. It's possible that we may go inactive while in a connecting // state if the handshake fails. if !active { - if let Ok(addr) = self.connections[token].socket().peer_addr() { + if let Ok(addr) = self.connections[token.into()].socket().peer_addr() { debug!("WebSocket connection to {} disconnected.", addr); } else { trace!("WebSocket connection to token={:?} disconnected.", token); } - let handler = self.connections.remove(token).unwrap().consume(); + let handler = self.connections.remove(token.into()).consume(); self.factory.connection_lost(handler); } else { - self.schedule(poll, &self.connections[token]).or_else(|err| { - // This will be an io error, so disconnect will already be called - self.connections[token].error(Error::from(err)); - let handler = self.connections.remove(token).unwrap().consume(); - self.factory.connection_lost(handler); - Ok::<(), Error>(()) - }).unwrap() + self.schedule(poll, &self.connections[token.into()]) + .or_else(|err| { + // This will be an io error, so disconnect will already be called + self.connections[token.into()].error(err); + let handler = self.connections.remove(token.into()).consume(); + self.factory.connection_lost(handler); + Ok::<(), Error>(()) + }) + .unwrap() } - } #[inline] @@ -490,7 +586,7 @@ impl Handler #[inline] fn check_count(&mut self) { trace!("Active connections {:?}", self.connections.len()); - if self.connections.len() == 0 { + if self.connections.is_empty() { if !self.state.is_active() { debug!("Shutting down websocket server."); } else if self.is_client() { @@ -509,7 +605,8 @@ impl Handler } ALL => { if events.is_readable() { - match self.listener.as_ref() + match self.listener + .as_ref() .expect("No listener provided for server websocket connections") .accept() { @@ -522,49 +619,59 @@ impl Handler } } } - Err(err) => error!("Encountered an error {:?} while accepting tcp connection.", err), + Err(err) => error!( + "Encountered an error {:?} while accepting tcp connection.", + err + ), } } } - TIMER => { - while let Some(t) = self.timer.poll() { - self.handle_timeout(poll, t); - } - } + TIMER => while let Some(t) = self.timer.poll() { + self.handle_timeout(poll, t); + }, QUEUE => { for _ in 0..MESSAGES_PER_TICK { match self.queue_rx.try_recv() { Ok(cmd) => self.handle_queue(poll, cmd), - _ => break + _ => break, } } - let _ = poll.reregister(&self.queue_rx, QUEUE, Ready::readable(), PollOpt::edge() | PollOpt::oneshot()); + let _ = poll.reregister( + &self.queue_rx, + QUEUE, + Ready::readable(), + PollOpt::edge() | PollOpt::oneshot(), + ); } _ => { let active = { - let conn_events = self.connections[token].events(); + let conn_events = self.connections[token.into()].events(); if (events & conn_events).is_readable() { - if let Err(err) = self.connections[token].read() { + if let Err(err) = self.connections[token.into()].read() { trace!("Encountered error while reading: {}", err); if let Kind::Io(ref err) = err.kind { if let Some(errno) = err.raw_os_error() { if errno == CONNECTION_REFUSED { - match self.connections[token].reset() { + match self.connections[token.into()].reset() { Ok(_) => { poll.register( - self.connections[token].socket(), - self.connections[token].token(), - self.connections[token].events(), + self.connections[token.into()].socket(), + self.connections[token.into()].token(), + self.connections[token.into()].events(), PollOpt::edge() | PollOpt::oneshot(), ).or_else(|err| { - self.connections[token].error(Error::from(err)); - let handler = self.connections.remove(token).unwrap().consume(); - self.factory.connection_lost(handler); - Ok::<(), Error>(()) - }).unwrap(); - return - }, + self.connections[token.into()] + .error(Error::from(err)); + let handler = self.connections + .remove(token.into()) + .consume(); + self.factory.connection_lost(handler); + Ok::<(), Error>(()) + }) + .unwrap(); + return; + } Err(err) => { trace!("Encountered error while trying to reset connection: {:?}", err); } @@ -573,33 +680,37 @@ impl Handler } } // This will trigger disconnect if the connection is open - self.connections[token].error(err) + self.connections[token.into()].error(err) } } - let conn_events = self.connections[token].events(); + let conn_events = self.connections[token.into()].events(); if (events & conn_events).is_writable() { - if let Err(err) = self.connections[token].write() { + if let Err(err) = self.connections[token.into()].write() { trace!("Encountered error while writing: {}", err); if let Kind::Io(ref err) = err.kind { if let Some(errno) = err.raw_os_error() { if errno == CONNECTION_REFUSED { - match self.connections[token].reset() { + match self.connections[token.into()].reset() { Ok(_) => { poll.register( - self.connections[token].socket(), - self.connections[token].token(), - self.connections[token].events(), + self.connections[token.into()].socket(), + self.connections[token.into()].token(), + self.connections[token.into()].events(), PollOpt::edge() | PollOpt::oneshot(), ).or_else(|err| { - self.connections[token].error(Error::from(err)); - let handler = self.connections.remove(token).unwrap().consume(); - self.factory.connection_lost(handler); - Ok::<(), Error>(()) - }).unwrap(); - return - }, + self.connections[token.into()] + .error(Error::from(err)); + let handler = self.connections + .remove(token.into()) + .consume(); + self.factory.connection_lost(handler); + Ok::<(), Error>(()) + }) + .unwrap(); + return; + } Err(err) => { trace!("Encountered error while trying to reset connection: {:?}", err); } @@ -608,13 +719,13 @@ impl Handler } } // This will trigger disconnect if the connection is open - self.connections[token].error(err) + self.connections[token.into()].error(err) } } // connection events may have changed - self.connections[token].events().is_readable() || - self.connections[token].events().is_writable() + self.connections[token.into()].events().is_readable() + || self.connections[token.into()].events().is_writable() }; self.check_active(poll, active, token) @@ -633,7 +744,7 @@ impl Handler match cmd.into_signal() { Signal::Message(msg) => { trace!("Broadcasting message: {:?}", msg); - for conn in self.connections.iter_mut() { + for (_, conn) in self.connections.iter_mut() { if let Err(err) = conn.send_message(msg.clone()) { dead.push((conn.token(), err)) } @@ -641,7 +752,7 @@ impl Handler } Signal::Close(code, reason) => { trace!("Broadcasting close: {:?} - {}", code, reason); - for conn in self.connections.iter_mut() { + for (_, conn) in self.connections.iter_mut() { if let Err(err) = conn.send_close(code, reason.borrow()) { dead.push((conn.token(), err)) } @@ -649,7 +760,7 @@ impl Handler } Signal::Ping(data) => { trace!("Broadcasting ping"); - for conn in self.connections.iter_mut() { + for (_, conn) in self.connections.iter_mut() { if let Err(err) = conn.send_ping(data.clone()) { dead.push((conn.token(), err)) } @@ -657,7 +768,7 @@ impl Handler } Signal::Pong(data) => { trace!("Broadcasting pong"); - for conn in self.connections.iter_mut() { + for (_, conn) in self.connections.iter_mut() { if let Err(err) = conn.send_pong(data.clone()) { dead.push((conn.token(), err)) } @@ -670,53 +781,48 @@ impl Handler } error!("Unable to establish connection to {}: {:?}", url, err); } - return + return; } Signal::Shutdown => self.shutdown(), - Signal::Timeout { delay, token: event } => { - match self.timer.set_timeout(Duration::from_millis(delay), + Signal::Timeout { + delay, + token: event, + } => { + let timeout = self.timer.set_timeout( + Duration::from_millis(delay), Timeout { connection: ALL, - event: event, - }).map_err(Error::from) - { - Ok(timeout) => { - for conn in self.connections.iter_mut() { - if let Err(err) = conn.new_timeout(event, timeout.clone()) { - conn.error(err) - } - } - } - Err(err) => { - if self.settings.panic_on_timeout { - panic!("Unable to schedule timeout: {:?}", err); - } - error!("Unable to schedule timeout: {:?}", err); + event, + }, + ); + for (_, conn) in self.connections.iter_mut() { + if let Err(err) = conn.new_timeout(event, timeout.clone()) { + conn.error(err); } } - return + return; } Signal::Cancel(timeout) => { self.timer.cancel_timeout(&timeout); - return + return; } } - for conn in self.connections.iter() { + for (_, conn) in self.connections.iter() { if let Err(err) = self.schedule(poll, conn) { dead.push((conn.token(), err)) } } for (token, err) in dead { // note the same connection may be called twice - self.connections[token].error(err) + self.connections[token.into()].error(err) } } token => { let connection_id = cmd.connection_id(); match cmd.into_signal() { Signal::Message(msg) => { - if let Some(conn) = self.connections.get_mut(token) { + if let Some(conn) = self.connections.get_mut(token.into()) { if conn.connection_id() == connection_id { if let Err(err) = conn.send_message(msg) { conn.error(err) @@ -725,11 +831,13 @@ impl Handler trace!("Connection disconnected while a message was waiting in the queue.") } } else { - trace!("Connection disconnected while a message was waiting in the queue.") + trace!( + "Connection disconnected while a message was waiting in the queue." + ) } } Signal::Close(code, reason) => { - if let Some(conn) = self.connections.get_mut(token) { + if let Some(conn) = self.connections.get_mut(token.into()) { if conn.connection_id() == connection_id { if let Err(err) = conn.send_close(code, reason) { conn.error(err) @@ -742,7 +850,7 @@ impl Handler } } Signal::Ping(data) => { - if let Some(conn) = self.connections.get_mut(token) { + if let Some(conn) = self.connections.get_mut(token.into()) { if conn.connection_id() == connection_id { if let Err(err) = conn.send_ping(data) { conn.error(err) @@ -755,7 +863,7 @@ impl Handler } } Signal::Pong(data) => { - if let Some(conn) = self.connections.get_mut(token) { + if let Some(conn) = self.connections.get_mut(token.into()) { if conn.connection_id() == connection_id { if let Err(err) = conn.send_pong(data) { conn.error(err) @@ -769,7 +877,7 @@ impl Handler } Signal::Connect(url) => { if let Err(err) = self.connect(poll, url.clone()) { - if let Some(conn) = self.connections.get_mut(token) { + if let Some(conn) = self.connections.get_mut(token.into()) { conn.error(err) } else { if self.settings.panic_on_new_connection { @@ -778,54 +886,47 @@ impl Handler error!("Unable to establish connection to {}: {:?}", url, err); } } - return + return; } Signal::Shutdown => self.shutdown(), - Signal::Timeout { delay, token: event } => { - match self.timer.set_timeout(Duration::from_millis(delay), + Signal::Timeout { + delay, + token: event, + } => { + let timeout = self.timer.set_timeout( + Duration::from_millis(delay), Timeout { connection: token, - event: event, - }).map_err(Error::from) - { - Ok(timeout) => { - if let Some(conn) = self.connections.get_mut(token) { - if let Err(err) = conn.new_timeout(event, timeout) { - conn.error(err) - } - } else { - trace!("Connection disconnected while pong signal was waiting in the queue.") - } - } - Err(err) => { - if let Some(conn) = self.connections.get_mut(token) { - conn.error(err) - } else { - trace!("Connection disconnected while pong signal was waiting in the queue.") - } + event, + }, + ); + if let Some(conn) = self.connections.get_mut(token.into()) { + if let Err(err) = conn.new_timeout(event, timeout) { + conn.error(err) } + } else { + trace!("Connection disconnected while pong signal was waiting in the queue.") } - return + return; } Signal::Cancel(timeout) => { self.timer.cancel_timeout(&timeout); - return + return; } } - if let Some(_) = self.connections.get(token) { - if let Err(err) = self.schedule(poll, &self.connections[token]) { - self.connections[token].error(err) + if self.connections.get(token.into()).is_some() { + if let Err(err) = self.schedule(poll, &self.connections[token.into()]) { + self.connections[token.into()].error(err) } } } } } - fn handle_timeout(&mut self, poll: &mut Poll, Timeout { connection, event }: Timeout) { let active = { - if let Some(conn) = self.connections.get_mut(connection) { + if let Some(conn) = self.connections.get_mut(connection.into()) { if let Err(err) = conn.timeout_triggered(event) { conn.error(err) } @@ -833,7 +934,7 @@ impl Handler conn.events().is_readable() || conn.events().is_writable() } else { trace!("Connection disconnected while timeout was waiting."); - return + return; } }; self.check_active(poll, active, connection); @@ -846,9 +947,9 @@ mod test { use url::Url; - use result::{Error, Kind}; - use super::*; use super::url_to_addrs; + use super::*; + use result::{Error, Kind}; #[test] fn test_url_to_addrs() { @@ -864,16 +965,21 @@ mod test { match url_to_addrs(&bad_url) { Ok(_) => panic!("url_to_addrs accepts http urls."), - Err(Error { kind: Kind::Internal, details: _}) => (), // pass + Err(Error { + kind: Kind::Internal, + details: _, + }) => (), // pass err => panic!("{:?}", err), } match url_to_addrs(&no_resolve) { Ok(_) => panic!("url_to_addrs creates addresses for non-existent domains."), - Err(Error { kind: Kind::Io(_), details: _}) => (), // pass + Err(Error { + kind: Kind::Io(_), + details: _, + }) => (), // pass err => panic!("{:?}", err), } - } } diff --git a/third_party/rust/ws/src/lib.rs b/third_party/rust/ws/src/lib.rs index d2d36309b5e1..ea9f1a54e485 100644 --- a/third_party/rust/ws/src/lib.rs +++ b/third_party/rust/ws/src/lib.rs @@ -1,35 +1,37 @@ //! Lightweight, event-driven WebSockets for Rust. #![allow(deprecated)] -#![deny( - missing_copy_implementations, - trivial_casts, trivial_numeric_casts, - unstable_features, - unused_import_braces)] +#![deny(missing_copy_implementations, trivial_casts, trivial_numeric_casts, unstable_features, + unused_import_braces)] +extern crate byteorder; +extern crate bytes; extern crate httparse; extern crate mio; -extern crate sha1; +extern crate mio_extras; +#[cfg(feature = "ssl")] +extern crate openssl; +#[cfg(feature = "nativetls")] +extern crate native_tls; extern crate rand; -extern crate url; +extern crate sha1; extern crate slab; -extern crate bytes; -extern crate byteorder; -#[cfg(feature="ssl")] extern crate openssl; -#[macro_use] extern crate log; +extern crate url; +#[macro_use] +extern crate log; -mod result; +mod communication; mod connection; -mod handler; mod factory; mod frame; -mod message; +mod handler; mod handshake; -mod protocol; -mod communication; mod io; +mod message; +mod protocol; +mod result; mod stream; -#[cfg(feature="permessage-deflate")] +#[cfg(feature = "permessage-deflate")] pub mod deflate; pub mod util; @@ -37,18 +39,18 @@ pub mod util; pub use factory::Factory; pub use handler::Handler; -pub use result::{Result, Error}; -pub use result::Kind as ErrorKind; -pub use message::Message; pub use communication::Sender; pub use frame::Frame; -pub use protocol::{CloseCode, OpCode}; pub use handshake::{Handshake, Request, Response}; +pub use message::Message; +pub use protocol::{CloseCode, OpCode}; +pub use result::Kind as ErrorKind; +pub use result::{Error, Result}; -use std::fmt; -use std::default::Default; -use std::net::{SocketAddr, ToSocketAddrs}; use std::borrow::Borrow; +use std::default::Default; +use std::fmt; +use std::net::{SocketAddr, ToSocketAddrs}; use mio::Poll; @@ -72,13 +74,13 @@ use mio::Poll; /// ``` /// pub fn listen(addr: A, factory: F) -> Result<()> - where - A: ToSocketAddrs + fmt::Debug, - F: FnMut(Sender) -> H, - H: Handler, +where + A: ToSocketAddrs + fmt::Debug, + F: FnMut(Sender) -> H, + H: Handler, { - let ws = try!(WebSocket::new(factory)); - try!(ws.listen(addr)); + let ws = WebSocket::new(factory)?; + ws.listen(addr)?; Ok(()) } @@ -106,19 +108,20 @@ pub fn listen(addr: A, factory: F) -> Result<()> /// ``` /// pub fn connect(url: U, factory: F) -> Result<()> - where - U: Borrow, - F: FnMut(Sender) -> H, - H: Handler +where + U: Borrow, + F: FnMut(Sender) -> H, + H: Handler, { - let mut ws = try!(WebSocket::new(factory)); - let parsed = try!( - url::Url::parse(url.borrow()) - .map_err(|err| Error::new( - ErrorKind::Internal, - format!("Unable to parse {} as url due to {:?}", url.borrow(), err)))); - try!(ws.connect(parsed)); - try!(ws.run()); + let mut ws = WebSocket::new(factory)?; + let parsed = url::Url::parse(url.borrow()).map_err(|err| { + Error::new( + ErrorKind::Internal, + format!("Unable to parse {} as url due to {:?}", url.borrow(), err), + ) + })?; + ws.connect(parsed)?; + ws.run()?; Ok(()) } @@ -155,6 +158,9 @@ pub struct Settings { /// The maximum length of outgoing frames. Messages longer than this will be fragmented. /// Default: 65,535 pub fragment_size: usize, + /// The maximum length of acceptable incoming frames. Messages longer than this will be rejected. + /// Default: unlimited + pub max_fragment_size: usize, /// The size of the incoming buffer. A larger buffer uses more memory but will allow for fewer /// reallocations. /// Default: 2048 @@ -204,7 +210,7 @@ pub struct Settings { pub masking_strict: bool, /// The WebSocket protocol requires clients to verify the key returned by a server to ensure /// that the server and all intermediaries can perform the protocol. Verifying the key will - /// consume processing time and other resources with the benifit that we can fail the + /// consume processing time and other resources with the benefit that we can fail the /// connection early. The default in WS-RS is to accept any key from the server and instead /// fail late if a protocol error occurs. Change this setting to enable key verification. /// Default: false @@ -229,11 +235,10 @@ pub struct Settings { /// When enabled socket will try to send packet as fast as possible. /// /// Default: false - pub tcp_nodelay: bool + pub tcp_nodelay: bool, } impl Default for Settings { - fn default() -> Settings { Settings { max_connections: 100, @@ -243,6 +248,7 @@ impl Default for Settings { fragments_capacity: 10, fragments_grow: true, fragment_size: u16::max_value() as usize, + max_fragment_size: usize::max_value(), in_buffer_capacity: 2048, in_buffer_grow: true, out_buffer_capacity: 2048, @@ -259,22 +265,23 @@ impl Default for Settings { key_strict: false, method_strict: false, encrypt_server: false, - tcp_nodelay: false + tcp_nodelay: false, } } } - /// The WebSocket struct. A WebSocket can support multiple incoming and outgoing connections. pub struct WebSocket - where F: Factory +where + F: Factory, { poll: Poll, handler: io::Handler, } impl WebSocket - where F: Factory +where + F: Factory, { /// Create a new WebSocket using the given Factory to create handlers. pub fn new(factory: F) -> Result> { @@ -285,13 +292,14 @@ impl WebSocket /// If the `addr_spec` yields multiple addresses this will return after the /// first successful bind. `local_addr` can be called to determine which /// address it ended up binding to. - /// After the server is succesfully bound you should start it using `run`. + /// After the server is successfully bound you should start it using `run`. pub fn bind(mut self, addr_spec: A) -> Result> - where A: ToSocketAddrs + where + A: ToSocketAddrs, { let mut last_error = Error::new(ErrorKind::Internal, "No address given"); - for addr in try!(addr_spec.to_socket_addrs()) { + for addr in addr_spec.to_socket_addrs()? { if let Err(e) = self.handler.listen(&mut self.poll, &addr) { error!("Unable to listen on {}", addr); last_error = e; @@ -311,30 +319,31 @@ impl WebSocket /// /// This method will block until the event loop finishes running. pub fn listen(self, addr_spec: A) -> Result> - where A: ToSocketAddrs + where + A: ToSocketAddrs, { self.bind(addr_spec).and_then(|server| server.run()) } /// Queue an outgoing connection on this WebSocket. This method may be called multiple times, - /// but the actual connections will not be established until after `run` is called. + /// but the actual connections will not be established until `run` is called. pub fn connect(&mut self, url: url::Url) -> Result<&mut WebSocket> { let sender = self.handler.sender(); info!("Queuing connection to {}", url); - try!(sender.connect(url)); + sender.connect(url)?; Ok(self) } - /// Run the WebSocket. This will run the encapsulated event loop blocking until the WebSocket - /// is shutdown. + /// Run the WebSocket. This will run the encapsulated event loop blocking the calling thread until + /// the WebSocket is shutdown. pub fn run(mut self) -> Result> { - try!(self.handler.run(&mut self.poll)); + self.handler.run(&mut self.poll)?; Ok(self) } /// Get a Sender that can be used to send messages on all connections. /// Calling `send` on this Sender is equivalent to calling `broadcast`. - /// Calling `shutdown` on this Sender will shudown the WebSocket even if no connections have + /// Calling `shutdown` on this Sender will shutdown the WebSocket even if no connections have /// been established. #[inline] pub fn broadcaster(&self) -> Sender { @@ -350,7 +359,7 @@ impl WebSocket } /// Utility for constructing a WebSocket from various settings. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Default, Clone, Copy)] pub struct Builder { settings: Settings, } @@ -359,18 +368,17 @@ pub struct Builder { impl Builder { /// Create a new Builder with default settings. pub fn new() -> Builder { - Builder { - settings: Settings::default(), - } + Builder::default() } /// Build a WebSocket using this builder and a factory. /// It is possible to use the same builder to create multiple WebSockets. pub fn build(&self, factory: F) -> Result> - where F: Factory + where + F: Factory, { Ok(WebSocket { - poll: try!(Poll::new()), + poll: Poll::new()?, handler: io::Handler::new(factory, self.settings), }) } diff --git a/third_party/rust/ws/src/message.rs b/third_party/rust/ws/src/message.rs index 3e40289af71d..08509a5e1d73 100644 --- a/third_party/rust/ws/src/message.rs +++ b/third_party/rust/ws/src/message.rs @@ -1,7 +1,7 @@ -use std::fmt; use std::convert::{From, Into}; -use std::str::from_utf8; +use std::fmt; use std::result::Result as StdResult; +use std::str::from_utf8; use protocol::OpCode; use result::Result; @@ -18,17 +18,18 @@ pub enum Message { } impl Message { - /// Create a new text WebSocket message from a stringable. pub fn text(string: S) -> Message - where S: Into + where + S: Into, { Message::Text(string.into()) } /// Create a new binary WebSocket message by converting to Vec. pub fn binary(bin: B) -> Message - where B: Into> + where + B: Into>, { Message::Binary(bin.into()) } @@ -86,8 +87,7 @@ impl Message { pub fn into_text(self) -> Result { match self { Text(string) => Ok(string), - Binary(data) => Ok(try!( - String::from_utf8(data).map_err(|err| err.utf8_error()))), + Binary(data) => Ok(String::from_utf8(data).map_err(|err| err.utf8_error())?), } } @@ -96,34 +96,30 @@ impl Message { pub fn as_text(&self) -> Result<&str> { match *self { Text(ref string) => Ok(string), - Binary(ref data) => Ok(try!(from_utf8(data))), + Binary(ref data) => Ok(from_utf8(data)?), } } } impl From for Message { - fn from(string: String) -> Message { Message::text(string) } } impl<'s> From<&'s str> for Message { - fn from(string: &'s str) -> Message { Message::text(string) } } impl<'b> From<&'b [u8]> for Message { - fn from(data: &'b [u8]) -> Message { Message::binary(data) } } impl From> for Message { - fn from(data: Vec) -> Message { Message::binary(data) } @@ -139,7 +135,6 @@ impl fmt::Display for Message { } } - mod test { #![allow(unused_imports, unused_variables, dead_code)] use super::*; @@ -161,7 +156,6 @@ mod test { assert!(msg.into_text().is_err()); } - #[test] fn binary_convert_vec() { let bin = vec![6u8, 7, 8, 9, 10, 241]; diff --git a/third_party/rust/ws/src/protocol.rs b/third_party/rust/ws/src/protocol.rs index aa55a0a1bac3..d4c1f2e326f8 100644 --- a/third_party/rust/ws/src/protocol.rs +++ b/third_party/rust/ws/src/protocol.rs @@ -1,5 +1,5 @@ +use std::convert::{From, Into}; use std::fmt; -use std::convert::{Into, From}; use self::OpCode::*; /// Operation codes as part of rfc6455. @@ -22,7 +22,6 @@ pub enum OpCode { } impl OpCode { - /// Test whether the opcode indicates a control frame. pub fn is_control(&self) -> bool { match *self { @@ -30,52 +29,52 @@ impl OpCode { _ => true, } } - } impl fmt::Display for OpCode { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Continue => write!(f, "CONTINUE"), - Text => write!(f, "TEXT"), - Binary => write!(f, "BINARY"), - Close => write!(f, "CLOSE"), - Ping => write!(f, "PING"), - Pong => write!(f, "PONG"), - Bad => write!(f, "BAD"), + Continue => write!(f, "CONTINUE"), + Text => write!(f, "TEXT"), + Binary => write!(f, "BINARY"), + Close => write!(f, "CLOSE"), + Ping => write!(f, "PING"), + Pong => write!(f, "PONG"), + Bad => write!(f, "BAD"), } } } impl Into for OpCode { - fn into(self) -> u8 { match self { - Continue => 0, - Text => 1, - Binary => 2, - Close => 8, - Ping => 9, - Pong => 10, - Bad => { - debug_assert!(false, "Attempted to convert invalid opcode to u8. This is a bug."); - 8 // if this somehow happens, a close frame will help us tear down quickly + Continue => 0, + Text => 1, + Binary => 2, + Close => 8, + Ping => 9, + Pong => 10, + Bad => { + debug_assert!( + false, + "Attempted to convert invalid opcode to u8. This is a bug." + ); + 8 // if this somehow happens, a close frame will help us tear down quickly } } } } impl From for OpCode { - fn from(byte: u8) -> OpCode { match byte { - 0 => Continue, - 1 => Text, - 2 => Binary, - 8 => Close, - 9 => Ping, - 10 => Pong, - _ => Bad + 0 => Continue, + 1 => Text, + 2 => Binary, + 8 => Close, + 9 => Ping, + 10 => Pong, + _ => Bad, } } } @@ -151,31 +150,29 @@ pub enum CloseCode { } impl Into for CloseCode { - fn into(self) -> u16 { match self { - Normal => 1000, - Away => 1001, - Protocol => 1002, - Unsupported => 1003, - Status => 1005, - Abnormal => 1006, - Invalid => 1007, - Policy => 1008, - Size => 1009, - Extension => 1010, - Error => 1011, - Restart => 1012, - Again => 1013, - Tls => 1015, - Empty => 0, - Other(code) => code, + Normal => 1000, + Away => 1001, + Protocol => 1002, + Unsupported => 1003, + Status => 1005, + Abnormal => 1006, + Invalid => 1007, + Policy => 1008, + Size => 1009, + Extension => 1010, + Error => 1011, + Restart => 1012, + Again => 1013, + Tls => 1015, + Empty => 0, + Other(code) => code, } } } impl From for CloseCode { - fn from(code: u16) -> CloseCode { match code { 1000 => Normal, @@ -192,13 +189,12 @@ impl From for CloseCode { 1012 => Restart, 1013 => Again, 1015 => Tls, - 0 => Empty, + 0 => Empty, _ => Other(code), } } } - mod test { #![allow(unused_imports, unused_variables, dead_code)] use super::*; diff --git a/third_party/rust/ws/src/result.rs b/third_party/rust/ws/src/result.rs index 226e73266fe8..eaec5151bb40 100644 --- a/third_party/rust/ws/src/result.rs +++ b/third_party/rust/ws/src/result.rs @@ -1,16 +1,18 @@ +use std::borrow::Cow; +use std::convert::{From, Into}; +use std::error::Error as StdError; use std::fmt; use std::io; -use std::borrow::Cow; -use std::str::Utf8Error; use std::result::Result as StdResult; -use std::error::Error as StdError; -use std::convert::{From, Into}; +use std::str::Utf8Error; use httparse; use mio; -#[cfg(feature="ssl")] +#[cfg(feature = "ssl")] use openssl::ssl::{Error as SslError, HandshakeError as SslHandshakeError}; -#[cfg(feature="ssl")] +#[cfg(feature = "nativetls")] +use native_tls::{Error as SslError, HandshakeError as SslHandshakeError}; +#[cfg(any(feature = "ssl", feature = "nativetls"))] type HandshakeError = SslHandshakeError; use communication::Command; @@ -21,7 +23,8 @@ pub type Result = StdResult; #[derive(Debug)] pub enum Kind { /// Indicates an internal application error. - /// The WebSocket will automatically attempt to send an Error (1011) close code. + /// If panic_on_internal is true, which is the default, then the application will panic. + /// Otherwise the WebSocket will automatically attempt to send an Error (1011) close code. Internal, /// Indicates a state where some size limit has been exceeded, such as an inability to accept /// any more new connections. @@ -30,7 +33,7 @@ pub enum Kind { Capacity, /// Indicates a violation of the WebSocket protocol. /// The WebSocket will automatically attempt to send a Protocol (1002) close code, or if - /// this error occurs during a handshake, an HTTP 400 reponse will be generated. + /// this error occurs during a handshake, an HTTP 400 response will be generated. Protocol, /// Indicates that the WebSocket received data that should be utf8 encoded but was not. /// The WebSocket will automatically attempt to send a Invalid Frame Payload Data (1007) close @@ -49,13 +52,11 @@ pub enum Kind { /// If encountered, retuning from a handler method and waiting for the EventLoop to consume /// the queue may relieve the situation. Queue(mio::channel::SendError), - /// Indicates a failure to schedule a timeout on the EventLoop. - Timer(mio::timer::TimerError), /// Indicates a failure to perform SSL encryption. - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] Ssl(SslError), /// Indicates a failure to perform SSL encryption. - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] SslHandshake(HandshakeError), /// A custom error kind for use by applications. This error kind involves extra overhead /// because it will allocate the memory on the heap. The WebSocket ignores such errors by @@ -63,19 +64,19 @@ pub enum Kind { Custom(Box), } -/// A struct indicating the kind of error that has occured and any precise details of that error. +/// A struct indicating the kind of error that has occurred and any precise details of that error. pub struct Error { pub kind: Kind, pub details: Cow<'static, str>, } impl Error { - pub fn new(kind: Kind, details: I) -> Error - where I: Into> + where + I: Into>, { Error { - kind: kind, + kind, details: details.into(), } } @@ -99,7 +100,6 @@ impl fmt::Debug for Error { } impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if self.details.len() > 0 { write!(f, "{}: {}", self.description(), self.details) @@ -110,34 +110,32 @@ impl fmt::Display for Error { } impl StdError for Error { - fn description(&self) -> &str { match self.kind { - Kind::Internal => "Internal Application Error", - Kind::Capacity => "WebSocket at Capacity", - Kind::Protocol => "WebSocket Protocol Error", - Kind::Encoding(ref err) => err.description(), - Kind::Io(ref err) => err.description(), - Kind::Http(_) => "Unable to parse HTTP", - #[cfg(feature="ssl")] - Kind::Ssl(ref err) => err.description(), - #[cfg(feature="ssl")] + Kind::Internal => "Internal Application Error", + Kind::Capacity => "WebSocket at Capacity", + Kind::Protocol => "WebSocket Protocol Error", + Kind::Encoding(ref err) => err.description(), + Kind::Io(ref err) => err.description(), + Kind::Http(_) => "Unable to parse HTTP", + #[cfg(any(feature = "ssl", feature = "nativetls"))] + Kind::Ssl(ref err) => err.description(), + #[cfg(any(feature = "ssl", feature = "nativetls"))] Kind::SslHandshake(ref err) => err.description(), - Kind::Queue(_) => "Unable to send signal on event loop", - Kind::Timer(_) => "Unable to schedule timeout on event loop", - Kind::Custom(ref err) => err.description(), + Kind::Queue(_) => "Unable to send signal on event loop", + Kind::Custom(ref err) => err.description(), } } fn cause(&self) -> Option<&StdError> { match self.kind { Kind::Encoding(ref err) => Some(err), - Kind::Io(ref err) => Some(err), - #[cfg(feature="ssl")] - Kind::Ssl(ref err) => Some(err), - #[cfg(feature="ssl")] - Kind::SslHandshake(ref err) => err.cause(), - Kind::Custom(ref err) => Some(err.as_ref()), + Kind::Io(ref err) => Some(err), + #[cfg(any(feature = "ssl", feature = "nativetls"))] + Kind::Ssl(ref err) => Some(err), + #[cfg(any(feature = "ssl", feature = "nativetls"))] + Kind::SslHandshake(ref err) => err.cause(), + Kind::Custom(ref err) => Some(err.as_ref()), _ => None, } } @@ -150,7 +148,6 @@ impl From for Error { } impl From for Error { - fn from(err: httparse::Error) -> Error { let details = match err { httparse::Error::HeaderName => "Invalid byte in header name.", @@ -158,34 +155,23 @@ impl From for Error { httparse::Error::NewLine => "Invalid byte in new line.", httparse::Error::Status => "Invalid byte in Response status.", httparse::Error::Token => "Invalid byte where token is required.", - httparse::Error::TooManyHeaders => "Parsed more headers than provided buffer can contain.", + httparse::Error::TooManyHeaders => { + "Parsed more headers than provided buffer can contain." + } httparse::Error::Version => "Invalid byte in HTTP version.", }; Error::new(Kind::Http(err), details) } - } impl From> for Error { - fn from(err: mio::channel::SendError) -> Error { match err { mio::channel::SendError::Io(err) => Error::from(err), - _ => Error::new(Kind::Queue(err), "") + _ => Error::new(Kind::Queue(err), ""), } } - -} - -impl From for Error { - - fn from(err: mio::timer::TimerError) -> Error { - match err { - _ => Error::new(Kind::Timer(err), "") - } - } - } impl From for Error { @@ -194,14 +180,14 @@ impl From for Error { } } -#[cfg(feature="ssl")] +#[cfg(any(feature = "ssl", feature = "nativetls"))] impl From for Error { fn from(err: SslError) -> Error { Error::new(Kind::Ssl(err), "") } } -#[cfg(feature="ssl")] +#[cfg(any(feature = "ssl", feature = "nativetls"))] impl From for Error { fn from(err: HandshakeError) -> Error { Error::new(Kind::SslHandshake(err), "") @@ -209,7 +195,8 @@ impl From for Error { } impl From> for Error - where B: StdError + Send + Sync + 'static +where + B: StdError + Send + Sync + 'static, { fn from(err: Box) -> Error { Error::new(Kind::Custom(err), "") diff --git a/third_party/rust/ws/src/stream.rs b/third_party/rust/ws/src/stream.rs index 888ffb9a9969..3b8d9c441bf4 100644 --- a/third_party/rust/ws/src/stream.rs +++ b/third_party/rust/ws/src/stream.rs @@ -1,17 +1,19 @@ use std::io; use std::io::ErrorKind::WouldBlock; -use std::net::SocketAddr; -#[cfg(feature="ssl")] +#[cfg(any(feature = "ssl", feature = "nativetls"))] use std::mem::replace; +use std::net::SocketAddr; -use mio::tcp::TcpStream; -#[cfg(feature="ssl")] -use openssl::ssl::{SslStream, MidHandshakeSslStream, HandshakeError}; -#[cfg(feature="ssl")] -use openssl::ssl::Error as SslError; use bytes::{Buf, BufMut}; +use mio::tcp::TcpStream; +#[cfg(feature = "nativetls")] +use native_tls::{ + HandshakeError, MidHandshakeTlsStream as MidHandshakeSslStream, TlsStream as SslStream, +}; +#[cfg(feature = "ssl")] +use openssl::ssl::{ErrorCode as SslErrorCode, HandshakeError, MidHandshakeSslStream, SslStream}; -use result::{Result, Error, Kind}; +use result::{Error, Kind, Result}; fn map_non_block(res: io::Result) -> io::Result> { match res { @@ -28,7 +30,8 @@ fn map_non_block(res: io::Result) -> io::Result> { pub trait TryReadBuf: io::Read { fn try_read_buf(&mut self, buf: &mut B) -> io::Result> - where Self : Sized + where + Self: Sized, { // Reads the length of the slice supplied by buf.mut_bytes into the buffer // This is not guaranteed to consume an entire datagram or segment. @@ -38,7 +41,9 @@ pub trait TryReadBuf: io::Read { let res = map_non_block(self.read(unsafe { buf.bytes_mut() })); if let Ok(Some(cnt)) = res { - unsafe { buf.advance_mut(cnt); } + unsafe { + buf.advance_mut(cnt); + } } res @@ -47,7 +52,8 @@ pub trait TryReadBuf: io::Read { pub trait TryWriteBuf: io::Write { fn try_write_buf(&mut self, buf: &mut B) -> io::Result> - where Self : Sized + where + Self: Sized, { let res = map_non_block(self.write(buf.bytes())); @@ -65,27 +71,29 @@ impl TryWriteBuf for T {} use self::Stream::*; pub enum Stream { Tcp(TcpStream), - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] Tls(TlsStream), } impl Stream { - pub fn tcp(stream: TcpStream) -> Stream { Tcp(stream) } - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] pub fn tls(stream: MidHandshakeSslStream) -> Stream { - Tls(TlsStream::Handshake {sock: stream, negotiating: false }) + Tls(TlsStream::Handshake { + sock: stream, + negotiating: false, + }) } - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] pub fn tls_live(stream: SslStream) -> Stream { Tls(TlsStream::Live(stream)) } - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] pub fn is_tls(&self) -> bool { match *self { Tcp(_) => false, @@ -96,7 +104,7 @@ impl Stream { pub fn evented(&self) -> &TcpStream { match *self { Tcp(ref sock) => sock, - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] Tls(ref inner) => inner.evented(), } } @@ -104,15 +112,18 @@ impl Stream { pub fn is_negotiating(&self) -> bool { match *self { Tcp(_) => false, - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] Tls(ref inner) => inner.is_negotiating(), } } pub fn clear_negotiating(&mut self) -> Result<()> { match *self { - Tcp(_) => Err(Error::new(Kind::Internal, "Attempted to clear negotiating flag on non ssl connection.")), - #[cfg(feature="ssl")] + Tcp(_) => Err(Error::new( + Kind::Internal, + "Attempted to clear negotiating flag on non ssl connection.", + )), + #[cfg(any(feature = "ssl", feature = "nativetls"))] Tls(ref mut inner) => inner.clear_negotiating(), } } @@ -120,7 +131,7 @@ impl Stream { pub fn peer_addr(&self) -> io::Result { match *self { Tcp(ref sock) => sock.peer_addr(), - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] Tls(ref inner) => inner.peer_addr(), } } @@ -128,56 +139,74 @@ impl Stream { pub fn local_addr(&self) -> io::Result { match *self { Tcp(ref sock) => sock.local_addr(), - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] Tls(ref inner) => inner.local_addr(), } } } impl io::Read for Stream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { match *self { Tcp(ref mut sock) => sock.read(buf), - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] Tls(TlsStream::Live(ref mut sock)) => sock.read(buf), - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] Tls(ref mut tls_stream) => { trace!("Attempting to read ssl handshake."); match replace(tls_stream, TlsStream::Upgrading) { TlsStream::Live(_) | TlsStream::Upgrading => unreachable!(), - TlsStream::Handshake {sock, mut negotiating } => { - match sock.handshake() { - Ok(mut sock) => { - trace!("Completed SSL Handshake"); - let res = sock.read(buf); - *tls_stream = TlsStream::Live(sock); - res - } - Err(HandshakeError::SetupFailure(err)) => - Err(io::Error::new(io::ErrorKind::Other, err)), - Err(HandshakeError::Failure(mid)) | - Err(HandshakeError::Interrupted(mid)) => { - let err = match *mid.error() { - SslError::WantWrite(_) => { - negotiating = true; - Err(io::Error::new( - io::ErrorKind::WouldBlock, - "SSL wants writing")) - }, - SslError::WantRead(_) => Err(io::Error::new( - io::ErrorKind::WouldBlock, - "SSL wants reading")), - SslError::Stream(ref e) => - Err(From::from(e.kind())), - ref err => - Err(io::Error::new(io::ErrorKind::Other, format!("{}", err))), - }; - *tls_stream = TlsStream::Handshake { sock: mid, negotiating: negotiating }; - err - } + TlsStream::Handshake { + sock, + mut negotiating, + } => match sock.handshake() { + Ok(mut sock) => { + trace!("Completed SSL Handshake"); + let res = sock.read(buf); + *tls_stream = TlsStream::Live(sock); + res } - } + #[cfg(feature = "ssl")] + Err(HandshakeError::SetupFailure(err)) => { + Err(io::Error::new(io::ErrorKind::Other, err)) + } + #[cfg(feature = "ssl")] + Err(HandshakeError::Failure(mid)) + | Err(HandshakeError::WouldBlock(mid)) => { + if mid.error().code() == SslErrorCode::WANT_READ { + negotiating = true; + } + let err = if let Some(io_error) = mid.error().io_error() { + Err(io::Error::new( + io_error.kind(), + format!("{:?}", io_error.get_ref()), + )) + } else { + Err(io::Error::new( + io::ErrorKind::Other, + format!("{}", mid.error()), + )) + }; + *tls_stream = TlsStream::Handshake { + sock: mid, + negotiating, + }; + err + } + #[cfg(feature = "nativetls")] + Err(HandshakeError::WouldBlock(mid)) => { + negotiating = true; + *tls_stream = TlsStream::Handshake { + sock: mid, + negotiating: negotiating, + }; + Err(io::Error::new(io::ErrorKind::WouldBlock, "SSL would block")) + } + #[cfg(feature = "nativetls")] + Err(HandshakeError::Failure(err)) => { + Err(io::Error::new(io::ErrorKind::Other, format!("{}", err))) + } + }, } } } @@ -185,52 +214,69 @@ impl io::Read for Stream { } impl io::Write for Stream { - fn write(&mut self, buf: &[u8]) -> io::Result { match *self { Tcp(ref mut sock) => sock.write(buf), - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] Tls(TlsStream::Live(ref mut sock)) => sock.write(buf), - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] Tls(ref mut tls_stream) => { trace!("Attempting to write ssl handshake."); match replace(tls_stream, TlsStream::Upgrading) { TlsStream::Live(_) | TlsStream::Upgrading => unreachable!(), - TlsStream::Handshake {sock, mut negotiating } => { - - negotiating = false; - - match sock.handshake() { - Ok(mut sock) => { - trace!("Completed SSL Handshake"); - let res = sock.write(buf); - *tls_stream = TlsStream::Live(sock); - res - } - Err(HandshakeError::SetupFailure(err)) => - Err(io::Error::new(io::ErrorKind::Other, err)), - Err(HandshakeError::Failure(mid)) | - Err(HandshakeError::Interrupted(mid)) => { - let err = match *mid.error() { - SslError::WantRead(_) => { - negotiating = true; - Err(io::Error::new( - io::ErrorKind::WouldBlock, - "SSL wants reading")) - }, - SslError::WantWrite(_)=> Err(io::Error::new( - io::ErrorKind::WouldBlock, - "SSL wants writing")), - SslError::Stream(ref e) => - Err(From::from(e.kind())), - ref err => - Err(io::Error::new(io::ErrorKind::Other, format!("{}", err))), - }; - *tls_stream = TlsStream::Handshake { sock: mid, negotiating: negotiating }; - err - } + TlsStream::Handshake { + sock, + mut negotiating, + } => match sock.handshake() { + Ok(mut sock) => { + trace!("Completed SSL Handshake"); + let res = sock.write(buf); + *tls_stream = TlsStream::Live(sock); + res } - } + #[cfg(feature = "ssl")] + Err(HandshakeError::SetupFailure(err)) => { + Err(io::Error::new(io::ErrorKind::Other, err)) + } + #[cfg(feature = "ssl")] + Err(HandshakeError::Failure(mid)) + | Err(HandshakeError::WouldBlock(mid)) => { + if mid.error().code() == SslErrorCode::WANT_READ { + negotiating = true; + } else { + negotiating = false; + } + let err = if let Some(io_error) = mid.error().io_error() { + Err(io::Error::new( + io_error.kind(), + format!("{:?}", io_error.get_ref()), + )) + } else { + Err(io::Error::new( + io::ErrorKind::Other, + format!("{}", mid.error()), + )) + }; + *tls_stream = TlsStream::Handshake { + sock: mid, + negotiating, + }; + err + } + #[cfg(feature = "nativetls")] + Err(HandshakeError::WouldBlock(mid)) => { + negotiating = true; + *tls_stream = TlsStream::Handshake { + sock: mid, + negotiating: negotiating, + }; + Err(io::Error::new(io::ErrorKind::WouldBlock, "SSL would block")) + } + #[cfg(feature = "nativetls")] + Err(HandshakeError::Failure(err)) => { + Err(io::Error::new(io::ErrorKind::Other, format!("{}", err))) + } + }, } } } @@ -239,17 +285,17 @@ impl io::Write for Stream { fn flush(&mut self) -> io::Result<()> { match *self { Tcp(ref mut sock) => sock.flush(), - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] Tls(TlsStream::Live(ref mut sock)) => sock.flush(), - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] Tls(TlsStream::Handshake { ref mut sock, .. }) => sock.get_mut().flush(), - #[cfg(feature="ssl")] + #[cfg(any(feature = "ssl", feature = "nativetls"))] Tls(TlsStream::Upgrading) => panic!("Tried to access actively upgrading TlsStream"), } } } -#[cfg(feature="ssl")] +#[cfg(any(feature = "ssl", feature = "nativetls"))] pub enum TlsStream { Live(SslStream), Handshake { @@ -259,9 +305,8 @@ pub enum TlsStream { Upgrading, } -#[cfg(feature="ssl")] +#[cfg(any(feature = "ssl", feature = "nativetls"))] impl TlsStream { - pub fn evented(&self) -> &TcpStream { match *self { TlsStream::Live(ref sock) => sock.get_ref(), @@ -273,17 +318,24 @@ impl TlsStream { pub fn is_negotiating(&self) -> bool { match *self { TlsStream::Live(_) => false, - TlsStream::Handshake { sock: _, negotiating } => negotiating, + TlsStream::Handshake { + sock: _, + negotiating, + } => negotiating, TlsStream::Upgrading => panic!("Tried to access actively upgrading TlsStream"), } - } pub fn clear_negotiating(&mut self) -> Result<()> { match *self { - TlsStream::Live(_) => Err( - Error::new(Kind::Internal, "Attempted to clear negotiating flag on live ssl connection.")), - TlsStream::Handshake { sock: _, ref mut negotiating } => Ok(*negotiating = false), + TlsStream::Live(_) => Err(Error::new( + Kind::Internal, + "Attempted to clear negotiating flag on live ssl connection.", + )), + TlsStream::Handshake { + sock: _, + ref mut negotiating, + } => Ok(*negotiating = false), TlsStream::Upgrading => panic!("Tried to access actively upgrading TlsStream"), } } diff --git a/third_party/rust/ws/src/util.rs b/third_party/rust/ws/src/util.rs index fc9bfe7f2a38..fc66394a745a 100644 --- a/third_party/rust/ws/src/util.rs +++ b/third_party/rust/ws/src/util.rs @@ -1,12 +1,9 @@ //! The util module rexports some tools from mio in order to facilitate handling timeouts. -use slab; /// Used to identify some timed-out event. pub use mio::Token; /// A handle to a specific timeout. -pub use mio::timer::Timeout; -/// A Slab allocator for associating tokens to data. -pub type Slab = slab::Slab; -#[cfg(feature="ssl")] +pub use mio_extras::timer::Timeout; +#[cfg(any(feature = "ssl", feature = "nativetls"))] /// TcpStream underlying the WebSocket pub use mio::tcp::TcpStream; diff --git a/third_party/rust/ws/tests/deflate.rs b/third_party/rust/ws/tests/deflate.rs index 95454c4667b2..dfbfaddbf26c 100644 --- a/third_party/rust/ws/tests/deflate.rs +++ b/third_party/rust/ws/tests/deflate.rs @@ -1,20 +1,18 @@ -#![cfg(feature="permessage-deflate")] -extern crate ws; -extern crate url; +#![cfg(feature = "permessage-deflate")] extern crate env_logger; +extern crate url; +extern crate ws; -use ws::{WebSocket, Sender, Message, Builder, Settings}; use ws::deflate::DeflateHandler; +use ws::{Builder, Message, Sender, Settings, WebSocket}; #[test] fn round_trip() { - const MESSAGE: &'static str = "this is the message that will be sent as a message"; let mut name = "Client"; let mut ws = WebSocket::new(|output: Sender| { - if name == "Client" { output.send(MESSAGE).unwrap(); } @@ -38,40 +36,39 @@ fn round_trip() { ws.connect(url).unwrap(); ws.listen("127.0.0.1:3012").unwrap(); - } #[test] fn fragment() { - - env_logger::init().unwrap(); + env_logger::init(); const MESSAGE: &'static str = "Hello"; let mut name = "Client"; - let mut ws = Builder::new().with_settings(Settings { - fragment_size: 4, - ..Default::default() - }).build(|output: Sender| { - - if name == "Client" { - output.send(MESSAGE).unwrap(); - } - - let handler = move |msg: Message| { - if name == "Server" { - output.send(msg) - } else { - assert!(msg.as_text().unwrap() == MESSAGE); - output.shutdown() + let mut ws = Builder::new() + .with_settings(Settings { + fragment_size: 4, + ..Default::default() + }) + .build(|output: Sender| { + if name == "Client" { + output.send(MESSAGE).unwrap(); } - }; - name = "Server"; + let handler = move |msg: Message| { + if name == "Server" { + output.send(msg) + } else { + assert!(msg.as_text().unwrap() == MESSAGE); + output.shutdown() + } + }; - DeflateHandler::new(handler) + name = "Server"; - }).unwrap(); + DeflateHandler::new(handler) + }) + .unwrap(); let url = url::Url::parse("ws://127.0.0.1:3024").unwrap(); diff --git a/third_party/rust/ws/tests/shutdown.rs b/third_party/rust/ws/tests/shutdown.rs index e3f09a0707e5..1c1234572631 100644 --- a/third_party/rust/ws/tests/shutdown.rs +++ b/third_party/rust/ws/tests/shutdown.rs @@ -1,18 +1,20 @@ extern crate ws; +use std::sync::mpsc::channel; use std::thread; use std::time::Duration; -use std::sync::mpsc::channel; #[test] fn shutdown_before_connections() { let (tx, rx) = channel(); let mut connections = 0; - let socket = ws::Builder::new().build(move |_| { - tx.send(1).unwrap(); - |_| Ok(()) - }).unwrap(); + let socket = ws::Builder::new() + .build(move |_| { + tx.send(1).unwrap(); + |_| Ok(()) + }) + .unwrap(); let handle = socket.broadcaster(); @@ -26,7 +28,7 @@ fn shutdown_before_connections() { assert!(res.is_err()); match res { Ok(n) => connections += n, - Err(_) => { + Err(_) => { if connections < 1 { handle.shutdown().unwrap(); break; @@ -36,5 +38,4 @@ fn shutdown_before_connections() { } assert!(t.join().is_ok()); - } diff --git a/toolkit/content/license.html b/toolkit/content/license.html index 9c8ef6f7d706..565a73e8290f 100644 --- a/toolkit/content/license.html +++ b/toolkit/content/license.html @@ -75,7 +75,6 @@
  • Babylon License
  • bincode License
  • -
  • BSD-3-Clause License
  • bspatch License
  • byteorder License
  • Cairo Component Licenses
  • @@ -2893,46 +2892,6 @@ SOFTWARE. -
    - -

    BSD-3-Clause License

    - -

    This license applies to files in the following directories: -

      -
    • third_party/rust/sha1
    • -
    - See the individual LICENSE files for copyright owners.

    - -
    -Redistribution and use in source and binary forms, with or without
    -modification, are permitted provided that the following conditions are
    -met:
    -
    -    * Redistributions of source code must retain the above copyright
    -      notice, this list of conditions and the following disclaimer.
    -
    -    * Redistributions in binary form must reproduce the above
    -      copyright notice, this list of conditions and the following
    -      disclaimer in the documentation and/or other materials provided
    -      with the distribution.
    -
    -    * The names of the contributors may not be used to endorse or
    -      promote products derived from this software without specific
    -      prior written permission.
    -
    -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    -
    -

    bspatch License

  • Babel License