Upgrade rust/crates/rand to 0.8.0

Test: make
Change-Id: I7c56d8b0d48f1ef95b1355e33d33c90fcaf55fc9
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 93fa283..37219d9 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
 {
   "git": {
-    "sha1": "074cb6a997f91db653f8a53c755ddc07495ab429"
+    "sha1": "98a1aaf28e7bc272c12796d96401c177bf2205e4"
   }
 }
diff --git a/.github/ISSUE_TEMPLATE/compile-issue.md b/.github/ISSUE_TEMPLATE/compile-issue.md
deleted file mode 100644
index 8a8354b..0000000
--- a/.github/ISSUE_TEMPLATE/compile-issue.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-name: Compile issue
-about: Report / ask about a compilation issue
-title: ''
-labels: ''
-assignees: ''
-
----
-
-# Common issues
-
-**Problem**: `rand_hc::Hc128Rng: rand_core::SeedableRng` (or other RNG)
-
-**Quick solution**: `cargo update`
-
-**Details**: This happens when multiple versions of the `rand_core` crate are in use. Check your `Cargo.lock` file for all versions of `rand_core`. Note that some versions (0.2.2 and 0.3.1) are compatibility shims and are not a problem by themselves.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index 90c57c8..0000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-title: ''
-labels: ''
-assignees: ''
-
----
-
-## Background
-
-**What is your motivation?**
-
-**What type of application is this?** (E.g. cryptography, game, numerical simulation)
-
-## Feature request
-
-<details here>
diff --git a/.github/ISSUE_TEMPLATE/other.md b/.github/ISSUE_TEMPLATE/other.md
deleted file mode 100644
index a3e76ca..0000000
--- a/.github/ISSUE_TEMPLATE/other.md
+++ /dev/null
@@ -1,10 +0,0 @@
----
-name: Other
-about: empty template
-title: ''
-labels: ''
-assignees: ''
-
----
-
-
diff --git a/Android.bp b/Android.bp
index 5b2b7e0..f489cd6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -10,12 +10,13 @@
         "alloc",
         "default",
         "getrandom",
-        "getrandom_package",
         "libc",
+        "rand_chacha",
+        "rand_hc",
         "std",
+        "std_rng",
     ],
     rustlibs: [
-        "libgetrandom",
         "liblibc",
         "librand_chacha",
         "librand_core",
@@ -24,8 +25,8 @@
 
 // dependent_library ["feature_list"]
 //   cfg-if-0.1.10
-//   getrandom-0.1.15 "std"
-//   libc-0.2.77
-//   ppv-lite86-0.2.9 "simd,std"
-//   rand_chacha-0.2.2 "std"
-//   rand_core-0.5.1 "alloc,getrandom,std"
+//   getrandom-0.2.0 "std"
+//   libc-0.2.81
+//   ppv-lite86-0.2.10 "simd,std"
+//   rand_chacha-0.3.0 "std"
+//   rand_core-0.6.0 "alloc,getrandom,std"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b519d48..c4815bb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,62 @@
 
 You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.html) useful.
 
+## [0.8.0] - 2020-12-18
+### Platform support
+- The minimum supported Rust version is now 1.36 (#1011)
+- `getrandom` updated to v0.2 (#1041)
+- Remove `wasm-bindgen` and `stdweb` feature flags. For details of WASM support,
+  see the [getrandom documentation](https://docs.rs/getrandom/latest). (#948)
+- `ReadRng::next_u32` and `next_u64` now use little-Endian conversion instead
+  of native-Endian, affecting results on Big-Endian platforms (#1061)
+- The `nightly` feature no longer implies the `simd_support` feature (#1048)
+- Fix `simd_support` feature to work on current nightlies (#1056)
+
+### Rngs
+- `ThreadRng` is no longer `Copy` to enable safe usage within thread-local destructors (#1035)
+- `gen_range(a, b)` was replaced with `gen_range(a..b)`. `gen_range(a..=b)` is
+  also supported. Note that `a` and `b` can no longer be references or SIMD types. (#744, #1003)
+- Replace `AsByteSliceMut` with `Fill` and add support for `[bool], [char], [f32], [f64]` (#940)
+- Restrict `rand::rngs::adapter` to `std` (#1027; see also #928)
+- `StdRng`: add new `std_rng` feature flag (enabled by default, but might need
+  to be used if disabling default crate features) (#948)
+- `StdRng`: Switch from ChaCha20 to ChaCha12 for better performance (#1028)
+- `SmallRng`: Replace PCG algorithm with xoshiro{128,256}++ (#1038)
+
+### Sequences
+- Add `IteratorRandom::choose_stable` as an alternative to `choose` which does
+  not depend on size hints (#1057)
+- Improve accuracy and performance of `IteratorRandom::choose` (#1059)
+- Implement `IntoIterator` for `IndexVec`, replacing the `into_iter` method (#1007)
+- Add value stability tests for `seq` module (#933)
+
+### Misc
+- Support `PartialEq` and `Eq` for `StdRng`, `SmallRng` and `StepRng` (#979)
+- Added a `serde1` feature and added Serialize/Deserialize to `UniformInt` and `WeightedIndex` (#974)
+- Drop some unsafe code (#962, #963, #1011)
+- Reduce packaged crate size (#983)
+- Migrate to GitHub Actions from Travis+AppVeyor (#1073)
+
+### Distributions
+- `Alphanumeric` samples bytes instead of chars (#935)
+- `Uniform` now supports `char`, enabling `rng.gen_range('A'..='Z')` (#1068)
+- Add `UniformSampler::sample_single_inclusive` (#1003)
+
+#### Weighted sampling
+- Implement weighted sampling without replacement (#976, #1013)
+- `rand::distributions::alias_method::WeightedIndex` was moved to `rand_distr::WeightedAliasIndex`.
+  The simpler alternative `rand::distribution::WeightedIndex` remains. (#945)
+- Improve treatment of rounding errors in `WeightedIndex::update_weights` (#956)
+- `WeightedIndex`: return error on NaN instead of panic (#1005)
+
+### Documentation
+- Document types supported by `random` (#994)
+- Document notes on password generation (#995)
+- Note that `SmallRng` may not be the best choice for performance and in some
+  other cases (#1038)
+- Use `doc(cfg)` to annotate feature-gated items (#1019)
+- Adjust README (#1065)
+
 ## [0.7.3] - 2020-01-10
 ### Fixes
 - The `Bernoulli` distribution constructors now reports an error on NaN and on
@@ -40,7 +96,7 @@
 - Fix or squelch issues from Clippy lints (#840)
 
 ### Additions
-- Add a `no_std` target to CI to continously evaluate `no_std` status (#844)
+- Add a `no_std` target to CI to continuously evaluate `no_std` status (#844)
 - `WeightedIndex`: allow adjusting a sub-set of weights (#866)
 
 ## [0.7.0] - 2019-06-28
@@ -400,7 +456,7 @@
 
 ## [0.3.14] - 2016-02-13
 ### Fixed
-- Inline definitions from winapi/advapi32, wich decreases build times
+- Inline definitions from winapi/advapi32, which decreases build times
 
 
 ## [0.3.13] - 2016-01-09
diff --git a/Cargo.lock b/Cargo.lock
index a03987b..be7d3a4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,388 +1,184 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
 [[package]]
-name = "base-x"
-version = "0.2.5"
+name = "bincode"
+version = "1.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "bumpalo"
-version = "2.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "c2-chacha"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d"
 dependencies = [
- "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder",
+ "serde",
 ]
 
 [[package]]
+name = "byteorder"
+version = "1.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
+
+[[package]]
 name = "cfg-if"
-version = "0.1.9"
+version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "discard"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
 
 [[package]]
 name = "getrandom"
-version = "0.1.12"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4"
 dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
- "stdweb 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if",
+ "libc",
+ "wasi",
 ]
 
 [[package]]
-name = "itoa"
-version = "0.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "lazy_static"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
 name = "libc"
-version = "0.2.62"
+version = "0.2.76"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3"
+
+[[package]]
+name = "libm"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
 
 [[package]]
 name = "log"
-version = "0.4.8"
+version = "0.4.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
 dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if",
 ]
 
 [[package]]
-name = "packed_simd"
-version = "0.3.3"
+name = "packed_simd_2"
+version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3278e0492f961fd4ae70909f56b2723a7e8d01a228427294e19cdfdebda89a17"
 dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if",
+ "libm",
 ]
 
 [[package]]
 name = "ppv-lite86"
-version = "0.2.5"
+version = "0.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
 
 [[package]]
 name = "proc-macro2"
-version = "0.4.30"
+version = "1.0.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12"
 dependencies = [
- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid",
 ]
 
 [[package]]
 name = "quote"
-version = "0.6.13"
+version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
 dependencies = [
- "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2",
 ]
 
 [[package]]
 name = "rand"
-version = "0.7.3"
+version = "0.8.0"
 dependencies = [
- "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "packed_simd 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bincode",
+ "libc",
+ "log",
+ "packed_simd_2",
+ "rand_chacha",
+ "rand_core",
+ "rand_hc",
+ "rand_pcg",
+ "serde",
 ]
 
 [[package]]
 name = "rand_chacha"
-version = "0.2.1"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
 dependencies = [
- "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ppv-lite86",
+ "rand_core",
 ]
 
 [[package]]
 name = "rand_core"
-version = "0.5.1"
+version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8b34ba8cfb21243bd8df91854c830ff0d785fff2e82ebd4434c2644cb9ada18"
 dependencies = [
- "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "getrandom",
 ]
 
 [[package]]
 name = "rand_hc"
-version = "0.2.0"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
 dependencies = [
- "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core",
 ]
 
 [[package]]
 name = "rand_pcg"
-version = "0.2.1"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7de198537002b913568a3847e53535ace266f93526caf5c360ec41d72c5787f0"
 dependencies = [
- "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core",
 ]
 
 [[package]]
-name = "rustc_version"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "ryu"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "semver"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "semver-parser"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
 name = "serde"
-version = "1.0.100"
+version = "1.0.115"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5"
+dependencies = [
+ "serde_derive",
+]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.100"
+version = "1.0.115"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48"
 dependencies = [
- "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "serde_json"
-version = "1.0.40"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "sha1"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "stdweb"
-version = "0.4.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "stdweb-derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "stdweb-internal-macros 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "stdweb-internal-runtime 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "stdweb-derive"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "stdweb-internal-macros"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "base-x 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "stdweb-internal-runtime"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "syn"
-version = "0.15.44"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2",
+ "quote",
+ "syn",
 ]
 
 [[package]]
 name = "syn"
-version = "1.0.5"
+version = "1.0.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "891d8d6567fe7c7f8835a3a98af4208f3846fba258c1bc3c31d6e506239f11f9"
 dependencies = [
- "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
 ]
 
 [[package]]
 name = "unicode-xid"
-version = "0.1.0"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "unicode-xid"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
 
 [[package]]
 name = "wasi"
-version = "0.7.0"
+version = "0.9.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "wasm-bindgen"
-version = "0.2.50"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasm-bindgen-macro 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "wasm-bindgen-backend"
-version = "0.2.50"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasm-bindgen-shared 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "wasm-bindgen-macro"
-version = "0.2.50"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasm-bindgen-macro-support 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "wasm-bindgen-macro-support"
-version = "0.2.50"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasm-bindgen-backend 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasm-bindgen-shared 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "wasm-bindgen-shared"
-version = "0.2.50"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[metadata]
-"checksum base-x 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "76f4eae81729e69bb1819a26c6caac956cc429238388091f98cb6cd858f16443"
-"checksum bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad807f2fc2bf185eeb98ff3a901bd46dc5ad58163d0fa4577ba0d25674d71708"
-"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101"
-"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
-"checksum discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
-"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571"
-"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
-"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
-"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
-"checksum packed_simd 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a85ea9fc0d4ac0deb6fe7911d38786b32fc11119afd9e9d38b84ff691ce64220"
-"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b"
-"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
-"checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8"
-"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
-"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
-"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
-"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
-"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
-"checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
-"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
-"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
-"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
-"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-"checksum serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)" = "f4473e8506b213730ff2061073b48fa51dcc66349219e2e7c5608f0296a1d95a"
-"checksum serde_derive 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)" = "11e410fde43e157d789fc290d26bc940778ad0fdd47836426fbac36573710dbb"
-"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704"
-"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
-"checksum stdweb 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)" = "a68c0ce28cf7400ed022e18da3c4591e14e1df02c70e93573cc59921b3923aeb"
-"checksum stdweb-derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e21ebd9179de08f2300a65454268a17ea3de204627458588c84319c4def3930"
-"checksum stdweb-internal-macros 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e68f7d08b76979a43e93fe043b66d2626e35d41d68b0b85519202c6dd8ac59fa"
-"checksum stdweb-internal-runtime 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d52317523542cc0af5b7e31017ad0f7d1e78da50455e38d5657cd17754f617da"
-"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
-"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
-"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
-"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
-"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d"
-"checksum wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "dcddca308b16cd93c2b67b126c688e5467e4ef2e28200dc7dfe4ae284f2faefc"
-"checksum wasm-bindgen-backend 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "f805d9328b5fc7e5c6399960fd1889271b9b58ae17bdb2417472156cc9fafdd0"
-"checksum wasm-bindgen-macro 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "3ff88201a482abfc63921621f6cb18eb1efd74f136b05e5841e7f8ca434539e9"
-"checksum wasm-bindgen-macro-support 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "6a433d89ecdb9f77d46fcf00c8cf9f3467b7de9954d8710c175f61e2e245bb0e"
-"checksum wasm-bindgen-shared 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "d41fc1bc3570cdf8d108c15e014045fd45a95bb5eb36605f96a90461fc34027d"
+checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
diff --git a/Cargo.toml b/Cargo.toml
index 78a29b0..e44e775 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,13 +13,13 @@
 [package]
 edition = "2018"
 name = "rand"
-version = "0.7.3"
+version = "0.8.0"
 authors = ["The Rand Project Developers", "The Rust Project Developers"]
-exclude = ["/utils/*", "/.travis.yml", "/appveyor.yml", ".gitignore"]
+include = ["src/", "LICENSE-*", "README.md", "CHANGELOG.md", "COPYRIGHT"]
 autobenches = true
 description = "Random number generators and other randomness functionality.\n"
-homepage = "https://crates.io/crates/rand"
-documentation = "https://rust-random.github.io/rand/"
+homepage = "https://rust-random.github.io/book"
+documentation = "https://docs.rs/rand"
 readme = "README.md"
 keywords = ["random", "rng"]
 categories = ["algorithms", "no-std"]
@@ -27,54 +27,51 @@
 repository = "https://github.com/rust-random/rand"
 [package.metadata.docs.rs]
 all-features = true
-[dependencies.getrandom_package]
-version = "0.1.1"
-optional = true
-package = "getrandom"
-
+rustdoc-args = ["--cfg", "doc_cfg"]
 [dependencies.log]
 version = "0.4.4"
 optional = true
 
 [dependencies.packed_simd]
-version = "0.3"
+version = "0.3.4"
 features = ["into_bits"]
 optional = true
+package = "packed_simd_2"
 
 [dependencies.rand_core]
-version = "0.5.1"
+version = "0.6.0"
 
-[dependencies.rand_pcg]
-version = "0.2"
+[dependencies.serde]
+version = "1.0.103"
+features = ["derive"]
 optional = true
+[dev-dependencies.bincode]
+version = "1.2.1"
+
 [dev-dependencies.rand_hc]
-version = "0.2"
+version = "0.3.0"
 
 [dev-dependencies.rand_pcg]
-version = "0.2"
+version = "0.3.0"
 
 [features]
 alloc = ["rand_core/alloc"]
-default = ["std"]
-getrandom = ["getrandom_package", "rand_core/getrandom"]
-nightly = ["simd_support"]
-serde1 = []
+default = ["std", "std_rng"]
+getrandom = ["rand_core/getrandom"]
+nightly = []
+serde1 = ["serde"]
 simd_support = ["packed_simd"]
-small_rng = ["rand_pcg"]
+small_rng = []
 std = ["rand_core/std", "rand_chacha/std", "alloc", "getrandom", "libc"]
-stdweb = ["getrandom_package/stdweb"]
-wasm-bindgen = ["getrandom_package/wasm-bindgen"]
+std_rng = ["rand_chacha", "rand_hc"]
 [target."cfg(not(target_os = \"emscripten\"))".dependencies.rand_chacha]
-version = "0.2.1"
+version = "0.3.0"
+optional = true
 default-features = false
 [target."cfg(target_os = \"emscripten\")".dependencies.rand_hc]
-version = "0.2"
+version = "0.3.0"
+optional = true
 [target."cfg(unix)".dependencies.libc]
 version = "0.2.22"
 optional = true
 default-features = false
-[badges.appveyor]
-repository = "rust-random/rand"
-
-[badges.travis-ci]
-repository = "rust-random/rand"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index ac64187..aee917c 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,44 +1,45 @@
 [package]
 name = "rand"
-version = "0.7.3"
+version = "0.8.0"
 authors = ["The Rand Project Developers", "The Rust Project Developers"]
 license = "MIT OR Apache-2.0"
 readme = "README.md"
 repository = "https://github.com/rust-random/rand"
-documentation = "https://rust-random.github.io/rand/"
-homepage = "https://crates.io/crates/rand"
+documentation = "https://docs.rs/rand"
+homepage = "https://rust-random.github.io/book"
 description = """
 Random number generators and other randomness functionality.
 """
 keywords = ["random", "rng"]
 categories = ["algorithms", "no-std"]
-exclude = ["/utils/*", "/.travis.yml", "/appveyor.yml", ".gitignore"]
 autobenches = true
 edition = "2018"
-
-[badges]
-travis-ci = { repository = "rust-random/rand" }
-appveyor = { repository = "rust-random/rand" }
+include = ["src/", "LICENSE-*", "README.md", "CHANGELOG.md", "COPYRIGHT"]
 
 [features]
 # Meta-features:
-default = ["std"] # without "std" rand uses libcore
-nightly = ["simd_support"] # enables all features requiring nightly rust
-serde1 = [] # does nothing, deprecated
+default = ["std", "std_rng"]
+nightly = [] # enables performance optimizations requiring nightly rust
+serde1 = ["serde"]
 
-# Optional dependencies:
+# Option (enabled by default): without "std" rand uses libcore; this option
+# enables functionality expected to be available on a standard platform.
 std = ["rand_core/std", "rand_chacha/std", "alloc", "getrandom", "libc"]
-alloc = ["rand_core/alloc"]  # enables Vec and Box support (without std)
-# re-export optional WASM dependencies to avoid breakage:
-# Warning: wasm-bindgen and stdweb features will be removed in rand 0.8;
-# recommended to activate via the getrandom crate instead.
-wasm-bindgen = ["getrandom_package/wasm-bindgen"]
-stdweb = ["getrandom_package/stdweb"]
-getrandom = ["getrandom_package", "rand_core/getrandom"]
 
-# Configuration:
-simd_support = ["packed_simd"] # enables SIMD support
-small_rng = ["rand_pcg"]    # enables SmallRng
+# Option: "alloc" enables support for Vec and Box when not using "std"
+alloc = ["rand_core/alloc"]
+
+# Option: use getrandom package for seeding
+getrandom = ["rand_core/getrandom"]
+
+# Option (requires nightly): experimental SIMD support
+simd_support = ["packed_simd"]
+
+# Option (enabled by default): enable StdRng
+std_rng = ["rand_chacha", "rand_hc"]
+
+# Option: enable SmallRng
+small_rng = []
 
 [workspace]
 members = [
@@ -47,22 +48,17 @@
     "rand_chacha",
     "rand_hc",
     "rand_pcg",
-    "tests/wasm_bindgen",
 ]
 
 [dependencies]
-rand_core = { path = "rand_core", version = "0.5.1" }
-rand_pcg = { path = "rand_pcg", version = "0.2", optional = true }
-# Do not depend on 'getrandom_package' directly; use the 'getrandom' feature!
-# This is a dependency because: we forward wasm feature flags
-# This is renamed because: we need getrandom to depend on rand_core/getrandom
-getrandom_package = { version = "0.1.1", package = "getrandom", optional = true }
+rand_core = { path = "rand_core", version = "0.6.0" }
 log = { version = "0.4.4", optional = true }
+serde = { version = "1.0.103", features = ["derive"], optional = true }
 
 [dependencies.packed_simd]
 # NOTE: so far no version works reliably due to dependence on unstable features
-version = "0.3"
-# git = "https://github.com/rust-lang-nursery/packed_simd"
+package = "packed_simd_2"
+version = "0.3.4"
 optional = true
 features = ["into_bits"]
 
@@ -73,14 +69,19 @@
 # Emscripten does not support 128-bit integers, which are used by ChaCha code.
 # We work around this by using a different RNG.
 [target.'cfg(not(target_os = "emscripten"))'.dependencies]
-rand_chacha = { path = "rand_chacha", version = "0.2.1", default-features = false }
+rand_chacha = { path = "rand_chacha", version = "0.3.0", default-features = false, optional = true }
 [target.'cfg(target_os = "emscripten")'.dependencies]
-rand_hc = { path = "rand_hc", version = "0.2" }
+rand_hc = { path = "rand_hc", version = "0.3.0", optional = true }
 
 [dev-dependencies]
-rand_pcg = { path = "rand_pcg", version = "0.2" }
+rand_pcg = { path = "rand_pcg", version = "0.3.0" }
 # Only for benches:
-rand_hc = { path = "rand_hc", version = "0.2" }
+rand_hc = { path = "rand_hc", version = "0.3.0" }
+# Only to test serde1
+bincode = "1.2.1"
 
 [package.metadata.docs.rs]
+# To build locally:
+# RUSTDOCFLAGS="--cfg doc_cfg" cargo +nightly doc --all-features --no-deps --open
 all-features = true
+rustdoc-args = ["--cfg", "doc_cfg"]
diff --git a/METADATA b/METADATA
index 39d161d..af9a0a8 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/rand/rand-0.7.3.crate"
+    value: "https://static.crates.io/crates/rand/rand-0.8.0.crate"
   }
-  version: "0.7.3"
+  version: "0.8.0"
   license_type: NOTICE
   last_upgrade_date {
     year: 2020
-    month: 6
-    day: 18
+    month: 12
+    day: 22
   }
 }
diff --git a/README.md b/README.md
index c4bd676..aaf6df1 100644
--- a/README.md
+++ b/README.md
@@ -1,26 +1,47 @@
 # Rand
 
-[![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)
+[![Test Status](https://github.com/rust-random/rand/workflows/Tests/badge.svg?event=push)](https://github.com/rust-random/rand/actions)
 [![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://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand)
 [![API](https://docs.rs/rand/badge.svg)](https://docs.rs/rand)
-[![Minimum rustc version](https://img.shields.io/badge/rustc-1.32+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
+[![Minimum rustc version](https://img.shields.io/badge/rustc-1.36+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
 
-A Rust library for random number generation.
+A Rust library for random number generation, featuring:
 
-Rand provides utilities to generate random numbers, to convert them to useful
-types and distributions, and some randomness-related algorithms.
+-   Easy random value generation and usage via the [`Rng`](https://docs.rs/rand/*/rand/trait.Rng.html),
+    [`SliceRandom`](https://docs.rs/rand/*/rand/seq/trait.SliceRandom.html) and
+    [`IteratorRandom`](https://docs.rs/rand/*/rand/seq/trait.IteratorRandom.html) traits
+-   Secure seeding via the [`getrandom` crate](https://crates.io/crates/getrandom)
+    and fast, convenient generation via [`thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html)
+-   A modular design built over [`rand_core`](https://crates.io/crates/rand_core)
+    ([see the book](https://rust-random.github.io/book/crates.html))
+-   Fast implementations of the best-in-class [cryptographic](https://rust-random.github.io/book/guide-rngs.html#cryptographically-secure-pseudo-random-number-generators-csprngs) and
+    [non-cryptographic](https://rust-random.github.io/book/guide-rngs.html#basic-pseudo-random-number-generators-prngs) generators
+-   A flexible [`distributions`](https://docs.rs/rand/*/rand/distributions/index.html) module
+-   Samplers for a large number of random number distributions via our own
+    [`rand_distr`](https://docs.rs/rand_distr) and via
+    the [`statrs`](https://docs.rs/statrs/0.13.0/statrs/)
+-   [Portably reproducible output](https://rust-random.github.io/book/portability.html)
+-   `#[no_std]` compatibility (partial)
+-   *Many* performance optimisations
 
-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`.
+It's also worth pointing out what `rand` *is not*:
+
+-   Small. Most low-level crates are small, but the higher-level `rand` and
+    `rand_distr` each contain a lot of functionality.
+-   Simple (implementation). We have a strong focus on correctness, speed and flexibility, but
+    not simplicity. If you prefer a small-and-simple library, there are
+    alternatives including [fastrand](https://crates.io/crates/fastrand)
+    and [oorandom](https://crates.io/crates/oorandom).
+-   Slow. We take performance seriously, with considerations also for set-up
+    time of new distributions, commonly-used parameters, and parameters of the
+    current sampler.
 
 Documentation:
+
 -   [The Rust Rand Book](https://rust-random.github.io/book)
--   [API reference (master)](https://rust-random.github.io/rand)
+-   [API reference (master branch)](https://rust-random.github.io/rand)
 -   [API reference (docs.rs)](https://docs.rs/rand)
 
 
@@ -30,7 +51,7 @@
 
 ```toml
 [dependencies]
-rand = "0.7"
+rand = "0.8.0"
 ```
 
 To get started using Rand, see [The Book](https://rust-random.github.io/book).
@@ -38,6 +59,27 @@
 
 ## Versions
 
+Rand is *mature* (suitable for general usage, with infrequent breaking releases
+which minimise breakage) but not yet at 1.0. We maintain compatibility with
+pinned versions of the Rust compiler (see below).
+
+Current Rand versions are:
+
+-   Version 0.7 was released in June 2019, moving most non-uniform distributions
+    to an external crate, moving `from_entropy` to `SeedableRng`, and many small
+    changes and fixes.
+-   Version 0.8 was released in December 2020 with many small changes.
+
+A detailed [changelog](CHANGELOG.md) is available for releases.
+
+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).
+
+Rand has not yet reached 1.0 implying some breaking changes may arrive in the
+future ([SemVer](https://semver.org/) allows each 0.x.0 release to include
+breaking changes), but is considered *mature*: breaking changes are minimised
+and breaking releases are infrequent.
+
 Rand libs have inter-dependencies and make use of the
 [semver trick](https://github.com/dtolnay/semver-trick/) in order to make traits
 compatible across crate versions. (This is especially important for `RngCore`
@@ -47,26 +89,6 @@
 `rand_core_0_3_0::SeedableRng` are distinct, incompatible traits, which can
 cause build errors. Usually, running `cargo update` is enough to fix any issues.
 
-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.7 was released in June 2019, moving most non-uniform distributions
-    to an external crate, moving `from_entropy` to `SeedableRng`, and many small
-    changes and fixes.
--   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.
-
-A detailed [changelog](CHANGELOG.md) is available.
-
-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).
-
 ### Yanked versions
 
 Some versions of Rand crates have been yanked ("unreleased"). Where this occurs,
@@ -75,14 +97,14 @@
 
 ### Rust version requirements
 
-Since version 0.7, Rand requires **Rustc version 1.32 or greater**.
-Rand 0.5 requires Rustc 1.22 or greater while versions
-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.
+Since version 0.8, Rand requires **Rustc version 1.36 or greater**.
+Rand 0.7 requires Rustc 1.32 or greater while versions 0.5 require Rustc 1.22 or
+greater, and 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.
 
-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
+Continuous Integration (CI) will always test the minimum supported Rustc version
+(the MSRV). The current policy is that this can be updated in any
 Rand release if required, but the change must be noted in the changelog.
 
 ## Crate Features
@@ -90,26 +112,26 @@
 Rand is built with these features enabled by default:
 
 -   `std` enables functionality dependent on the `std` lib
--   `alloc` (implied by `std`) enables functionality requiring an allocator (when using this feature in `no_std`, Rand requires Rustc version 1.36 or greater)
+-   `alloc` (implied by `std`) enables functionality requiring an allocator
 -   `getrandom` (implied by `std`) is an optional dependency providing the code
     behind `rngs::OsRng`
+-   `std_rng` enables inclusion of `StdRng`, `thread_rng` and `random`
+    (the latter two *also* require that `std` be enabled)
 
 Optionally, the following dependencies can be enabled:
 
--   `log` enables logging via the `log` crate
--   `stdweb` implies `getrandom/stdweb` to enable
-    `getrandom` support on `wasm32-unknown-unknown`
-    (will be removed in rand 0.8; activate via `getrandom` crate instead)
--   `wasm-bindgen` implies `getrandom/wasm-bindgen` to enable
-    `getrandom` support on `wasm32-unknown-unknown`
-    (will be removed in rand 0.8; activate via `getrandom` crate instead)
+-   `log` enables logging via the `log` crate` crate
 
 Additionally, these features configure Rand:
 
 -   `small_rng` enables inclusion of the `SmallRng` PRNG
--   `nightly` enables all experimental features
+-   `nightly` enables some optimizations requiring nightly Rust
 -   `simd_support` (experimental) enables sampling of SIMD values
-    (uniformly random SIMD integers and floats)
+    (uniformly random SIMD integers and floats), requiring nightly Rust
+
+Note that nightly features are not stable and therefore not all library and
+compiler versions will be compatible. This is especially true of Rand's
+experimental `simd_support` feature.
 
 Rand supports limited functionality in `no_std` mode (enabled via
 `default-features = false`). In this case, `OsRng` and `from_entropy` are
diff --git a/SECURITY.md b/SECURITY.md
deleted file mode 100644
index daedb78..0000000
--- a/SECURITY.md
+++ /dev/null
@@ -1,69 +0,0 @@
-# Security Policy
-
-## No guarantees
-
-Support is provided on a best-effort bases only.
-No binding guarantees can be provided.
-
-## Security premises
-
-Rand provides the trait `rand_core::CryptoRng` aka `rand::CryptoRng` as a marker
-trait. Generators implementating `RngCore` *and* `CryptoRng`, and given the
-additional constraints that:
-
--   Instances of seedable RNGs (those implementing `SeedableRng`) are
-    constructed with cryptographically secure seed values
--   The state (memory) of the RNG and its seed value are not be exposed
-
-are expected to provide the following:
-
--   An attacker can gain no advantage over chance (50% for each bit) in
-    predicting the RNG output, even with full knowledge of all prior outputs.
-
-For some RNGs, notably `OsRng`, `ThreadRng` and those wrapped by `ReseedingRng`,
-we provide limited mitigations against side-channel attacks:
-
--   After a process fork on Unix, there is an upper-bound on the number of bits
-    output by the RNG before the processes diverge, after which outputs from
-    each process's RNG are uncorrelated
--   After the state (memory) of an RNG is leaked, there is an upper-bound on the
-    number of bits of output by the RNG before prediction of output by an
-    observer again becomes computationally-infeasible
-
-Additionally, derivations from such an RNG (including the `Rng` trait,
-implementations of the `Distribution` trait, and `seq` algorithms) should not
-introduce signficant bias other than that expected from the operation in
-question (e.g. bias from a weighted distribution).
-
-## Supported Versions
-
-We will attempt to uphold these premises in the following crate versions,
-provided that only the latest patch version is used, and with potential
-exceptions for theoretical issues without a known exploit:
-
-| Crate | Versions | Exceptions |
-| ----- | -------- | ---------- |
-| `rand` | 0.7 |  |
-| `rand` | 0.5, 0.6 | Jitter |
-| `rand` | 0.4 | Jitter, ISAAC |
-| `rand_core` | 0.2 - 0.5 | |
-| `rand_chacha` | 0.1 - 0.2 | |
-| `rand_hc` | 0.1 - 0.2 | |
-
-Explanation of exceptions:
-
--   Jitter: `JitterRng` is used as an entropy source when the primary source
-    fails; this source may not be secure against side-channel attacks, see #699.
--   ISAAC: the [ISAAC](https://burtleburtle.net/bob/rand/isaacafa.html) RNG used
-    to implement `thread_rng` is difficult to analyse and thus cannot provide
-    strong assertions of security.
-
-## Known issues
-
-In `rand` version 0.3 (0.3.18 and later), if `OsRng` fails, `thread_rng` is
-seeded from the system time in an insecure manner.
-
-## Reporting a Vulnerability
-
-To report a vulnerability, [open a new issue](https://github.com/rust-random/rand/issues/new).
-Once the issue is resolved, the vulnerability should be [reported to RustSec](https://github.com/RustSec/advisory-db/blob/master/CONTRIBUTING.md).
diff --git a/benches/generators.rs b/benches/generators.rs
deleted file mode 100644
index 3e26408..0000000
--- a/benches/generators.rs
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, 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;
-
-const RAND_BENCH_N: u64 = 1000;
-const BYTES_LEN: usize = 1024;
-
-use std::mem::size_of;
-use test::{black_box, Bencher};
-
-use rand::prelude::*;
-use rand::rngs::adapter::ReseedingRng;
-use rand::rngs::{mock::StepRng, OsRng};
-use rand_chacha::{ChaCha12Rng, ChaCha20Core, ChaCha20Rng, ChaCha8Rng};
-use rand_hc::Hc128Rng;
-use rand_pcg::{Pcg32, Pcg64, Pcg64Mcg};
-
-macro_rules! gen_bytes {
-    ($fnn:ident, $gen:expr) => {
-        #[bench]
-        fn $fnn(b: &mut Bencher) {
-            let mut rng = $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;
-        }
-    };
-}
-
-gen_bytes!(gen_bytes_step, StepRng::new(0, 1));
-gen_bytes!(gen_bytes_pcg32, Pcg32::from_entropy());
-gen_bytes!(gen_bytes_pcg64, Pcg64::from_entropy());
-gen_bytes!(gen_bytes_pcg64mcg, Pcg64Mcg::from_entropy());
-gen_bytes!(gen_bytes_chacha8, ChaCha8Rng::from_entropy());
-gen_bytes!(gen_bytes_chacha12, ChaCha12Rng::from_entropy());
-gen_bytes!(gen_bytes_chacha20, ChaCha20Rng::from_entropy());
-gen_bytes!(gen_bytes_hc128, Hc128Rng::from_entropy());
-gen_bytes!(gen_bytes_std, StdRng::from_entropy());
-#[cfg(feature = "small_rng")]
-gen_bytes!(gen_bytes_small, SmallRng::from_entropy());
-gen_bytes!(gen_bytes_os, OsRng);
-
-macro_rules! gen_uint {
-    ($fnn:ident, $ty:ty, $gen:expr) => {
-        #[bench]
-        fn $fnn(b: &mut Bencher) {
-            let mut rng = $gen;
-            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;
-        }
-    };
-}
-
-gen_uint!(gen_u32_step, u32, StepRng::new(0, 1));
-gen_uint!(gen_u32_pcg32, u32, Pcg32::from_entropy());
-gen_uint!(gen_u32_pcg64, u32, Pcg64::from_entropy());
-gen_uint!(gen_u32_pcg64mcg, u32, Pcg64Mcg::from_entropy());
-gen_uint!(gen_u32_chacha8, u32, ChaCha8Rng::from_entropy());
-gen_uint!(gen_u32_chacha12, u32, ChaCha12Rng::from_entropy());
-gen_uint!(gen_u32_chacha20, u32, ChaCha20Rng::from_entropy());
-gen_uint!(gen_u32_hc128, u32, Hc128Rng::from_entropy());
-gen_uint!(gen_u32_std, u32, StdRng::from_entropy());
-#[cfg(feature = "small_rng")]
-gen_uint!(gen_u32_small, u32, SmallRng::from_entropy());
-gen_uint!(gen_u32_os, u32, OsRng);
-
-gen_uint!(gen_u64_step, u64, StepRng::new(0, 1));
-gen_uint!(gen_u64_pcg32, u64, Pcg32::from_entropy());
-gen_uint!(gen_u64_pcg64, u64, Pcg64::from_entropy());
-gen_uint!(gen_u64_pcg64mcg, u64, Pcg64Mcg::from_entropy());
-gen_uint!(gen_u64_chacha8, u64, ChaCha8Rng::from_entropy());
-gen_uint!(gen_u64_chacha12, u64, ChaCha12Rng::from_entropy());
-gen_uint!(gen_u64_chacha20, u64, ChaCha20Rng::from_entropy());
-gen_uint!(gen_u64_hc128, u64, Hc128Rng::from_entropy());
-gen_uint!(gen_u64_std, u64, StdRng::from_entropy());
-#[cfg(feature = "small_rng")]
-gen_uint!(gen_u64_small, u64, SmallRng::from_entropy());
-gen_uint!(gen_u64_os, u64, OsRng);
-
-macro_rules! init_gen {
-    ($fnn:ident, $gen:ident) => {
-        #[bench]
-        fn $fnn(b: &mut Bencher) {
-            let mut rng = Pcg32::from_entropy();
-            b.iter(|| {
-                let r2 = $gen::from_rng(&mut rng).unwrap();
-                r2
-            });
-        }
-    };
-}
-
-init_gen!(init_pcg32, Pcg32);
-init_gen!(init_pcg64, Pcg64);
-init_gen!(init_pcg64mcg, Pcg64Mcg);
-init_gen!(init_hc128, Hc128Rng);
-init_gen!(init_chacha, ChaCha20Rng);
-
-const RESEEDING_BYTES_LEN: usize = 1024 * 1024;
-const RESEEDING_BENCH_N: u64 = 16;
-
-macro_rules! reseeding_bytes {
-    ($fnn:ident, $thresh:expr) => {
-        #[bench]
-        fn $fnn(b: &mut Bencher) {
-            let mut rng = ReseedingRng::new(ChaCha20Core::from_entropy(), $thresh * 1024, OsRng);
-            let mut buf = [0u8; RESEEDING_BYTES_LEN];
-            b.iter(|| {
-                for _ in 0..RESEEDING_BENCH_N {
-                    rng.fill_bytes(&mut buf);
-                    black_box(&buf);
-                }
-            });
-            b.bytes = RESEEDING_BYTES_LEN as u64 * RESEEDING_BENCH_N;
-        }
-    };
-}
-
-reseeding_bytes!(reseeding_chacha20_4k, 4);
-reseeding_bytes!(reseeding_chacha20_16k, 16);
-reseeding_bytes!(reseeding_chacha20_32k, 32);
-reseeding_bytes!(reseeding_chacha20_64k, 64);
-reseeding_bytes!(reseeding_chacha20_256k, 256);
-reseeding_bytes!(reseeding_chacha20_1M, 1024);
-
-
-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/benches/misc.rs b/benches/misc.rs
deleted file mode 100644
index e46137f..0000000
--- a/benches/misc.rs
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(test)]
-
-extern crate test;
-
-const RAND_BENCH_N: u64 = 1000;
-
-use test::Bencher;
-
-use rand::distributions::{Bernoulli, Distribution, Standard};
-use rand::prelude::*;
-use rand_pcg::{Pcg32, Pcg64Mcg};
-
-#[bench]
-fn misc_gen_bool_const(b: &mut Bencher) {
-    let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap();
-    b.iter(|| {
-        let mut accum = true;
-        for _ in 0..crate::RAND_BENCH_N {
-            accum ^= rng.gen_bool(0.18);
-        }
-        accum
-    })
-}
-
-#[bench]
-fn misc_gen_bool_var(b: &mut Bencher) {
-    let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap();
-    b.iter(|| {
-        let mut accum = true;
-        let mut p = 0.18;
-        for _ in 0..crate::RAND_BENCH_N {
-            accum ^= rng.gen_bool(p);
-            p += 0.0001;
-        }
-        accum
-    })
-}
-
-#[bench]
-fn misc_gen_ratio_const(b: &mut Bencher) {
-    let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap();
-    b.iter(|| {
-        let mut accum = true;
-        for _ in 0..crate::RAND_BENCH_N {
-            accum ^= rng.gen_ratio(2, 3);
-        }
-        accum
-    })
-}
-
-#[bench]
-fn misc_gen_ratio_var(b: &mut Bencher) {
-    let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap();
-    b.iter(|| {
-        let mut accum = true;
-        for i in 2..(crate::RAND_BENCH_N as u32 + 2) {
-            accum ^= rng.gen_ratio(i, i + 1);
-        }
-        accum
-    })
-}
-
-#[bench]
-fn misc_bernoulli_const(b: &mut Bencher) {
-    let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap();
-    b.iter(|| {
-        let d = rand::distributions::Bernoulli::new(0.18).unwrap();
-        let mut accum = true;
-        for _ in 0..crate::RAND_BENCH_N {
-            accum ^= rng.sample(d);
-        }
-        accum
-    })
-}
-
-#[bench]
-fn misc_bernoulli_var(b: &mut Bencher) {
-    let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap();
-    b.iter(|| {
-        let mut accum = true;
-        let mut p = 0.18;
-        for _ in 0..crate::RAND_BENCH_N {
-            let d = Bernoulli::new(p).unwrap();
-            accum ^= rng.sample(d);
-            p += 0.0001;
-        }
-        accum
-    })
-}
-
-#[bench]
-fn gen_1k_iter_repeat(b: &mut Bencher) {
-    use std::iter;
-    let mut rng = Pcg64Mcg::from_rng(&mut thread_rng()).unwrap();
-    b.iter(|| {
-        let v: Vec<u64> = iter::repeat(()).map(|()| rng.gen()).take(128).collect();
-        v
-    });
-    b.bytes = 1024;
-}
-
-#[bench]
-fn gen_1k_sample_iter(b: &mut Bencher) {
-    let mut rng = Pcg64Mcg::from_rng(&mut thread_rng()).unwrap();
-    b.iter(|| {
-        let v: Vec<u64> = Standard.sample_iter(&mut rng).take(128).collect();
-        v
-    });
-    b.bytes = 1024;
-}
-
-#[bench]
-fn gen_1k_gen_array(b: &mut Bencher) {
-    let mut rng = Pcg64Mcg::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 = Pcg64Mcg::from_rng(&mut thread_rng()).unwrap();
-    let mut buf = [0u64; 128];
-    b.iter(|| {
-        rng.fill(&mut buf[..]);
-        buf
-    });
-    b.bytes = 1024;
-}
diff --git a/benches/seq.rs b/benches/seq.rs
deleted file mode 100644
index 7da2ff8..0000000
--- a/benches/seq.rs
+++ /dev/null
@@ -1,179 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, 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;
-
-use test::Bencher;
-
-use rand::prelude::*;
-use rand::seq::*;
-use std::mem::size_of;
-
-// We force use of 32-bit RNG since seq code is optimised for use with 32-bit
-// generators on all platforms.
-use rand_pcg::Pcg32 as SmallRng;
-
-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::<usize>() as u64 * crate::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::<usize>() as u64 * crate::RAND_BENCH_N;
-}
-
-#[derive(Clone)]
-struct UnhintedIterator<I: Iterator + Clone> {
-    iter: I,
-}
-impl<I: Iterator + Clone> Iterator for UnhintedIterator<I> {
-    type Item = I::Item;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        self.iter.next()
-    }
-}
-
-#[derive(Clone)]
-struct WindowHintedIterator<I: ExactSizeIterator + Iterator + Clone> {
-    iter: I,
-    window_size: usize,
-}
-impl<I: ExactSizeIterator + Iterator + Clone> Iterator for WindowHintedIterator<I> {
-    type Item = I::Item;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        self.iter.next()
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        (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/benches/weighted.rs b/benches/weighted.rs
deleted file mode 100644
index 6872290..0000000
--- a/benches/weighted.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2019 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(test)]
-
-extern crate test;
-
-use rand::distributions::WeightedIndex;
-use rand::Rng;
-use test::Bencher;
-
-#[bench]
-fn weighted_index_creation(b: &mut Bencher) {
-    let mut rng = rand::thread_rng();
-    let weights = [1u32, 2, 4, 0, 5, 1, 7, 1, 2, 3, 4, 5, 6, 7];
-    b.iter(|| {
-        let distr = WeightedIndex::new(weights.to_vec()).unwrap();
-        rng.sample(distr)
-    })
-}
-
-#[bench]
-fn weighted_index_modification(b: &mut Bencher) {
-    let mut rng = rand::thread_rng();
-    let weights = [1u32, 2, 3, 0, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7];
-    let mut distr = WeightedIndex::new(weights.to_vec()).unwrap();
-    b.iter(|| {
-        distr.update_weights(&[(2, &4), (5, &1)]).unwrap();
-        rng.sample(&distr)
-    })
-}
diff --git a/examples/monte-carlo.rs b/examples/monte-carlo.rs
deleted file mode 100644
index 70560d0..0000000
--- a/examples/monte-carlo.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2013-2018 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, 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")]
-
-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/examples/monty-hall.rs b/examples/monty-hall.rs
deleted file mode 100644
index 30e2f44..0000000
--- a/examples/monty-hall.rs
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2013-2018 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, 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")]
-
-use rand::distributions::{Distribution, Uniform};
-use rand::Rng;
-
-struct SimulationResult {
-    win: bool,
-    switch: bool,
-}
-
-// Run a single simulation of the Monty Hall problem.
-fn simulate<R: Rng>(random_door: &Uniform<u32>, 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<R: Rng>(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<u32> {
-    (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/rustfmt.toml b/rustfmt.toml
deleted file mode 100644
index 6a2d9d4..0000000
--- a/rustfmt.toml
+++ /dev/null
@@ -1,32 +0,0 @@
-# This rustfmt file is added for configuration, but in practice much of our
-# code is hand-formatted, frequently with more readable results.
-
-# Comments:
-normalize_comments = true
-wrap_comments = false
-comment_width = 90      # small excess is okay but prefer 80
-
-# Arguments:
-use_small_heuristics = "Default"
-# TODO: single line functions only where short, please?
-# https://github.com/rust-lang/rustfmt/issues/3358
-fn_single_line = false
-fn_args_layout = "Compressed"
-overflow_delimited_expr = true
-where_single_line = true
-
-# enum_discrim_align_threshold = 20
-# struct_field_align_threshold = 20
-
-# Compatibility:
-edition = "2018"        # we require compatibility back to 1.32.0
-
-# Misc:
-inline_attribute_width = 80
-blank_lines_upper_bound = 2
-reorder_impl_items = true
-# report_todo = "Unnumbered"
-# report_fixme = "Unnumbered"
-
-# Ignored files:
-ignore = []
diff --git a/src/distributions/bernoulli.rs b/src/distributions/bernoulli.rs
index a1fa86e..b968ca0 100644
--- a/src/distributions/bernoulli.rs
+++ b/src/distributions/bernoulli.rs
@@ -12,6 +12,8 @@
 use crate::Rng;
 use core::{fmt, u64};
 
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
 /// The Bernoulli distribution.
 ///
 /// This is a special case of the Binomial distribution where `n = 1`.
@@ -32,6 +34,7 @@
 /// so only probabilities that are multiples of 2<sup>-64</sup> can be
 /// represented.
 #[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub struct Bernoulli {
     /// Probability of success, relative to the maximal integer.
     p_int: u64,
@@ -144,6 +147,15 @@
     use crate::Rng;
 
     #[test]
+    #[cfg(feature="serde1")]
+    fn test_serializing_deserializing_bernoulli() {
+        let coin_flip = Bernoulli::new(0.5).unwrap();
+        let de_coin_flip : Bernoulli = bincode::deserialize(&bincode::serialize(&coin_flip).unwrap()).unwrap();
+
+        assert_eq!(coin_flip.p_int, de_coin_flip.p_int);
+    }
+
+    #[test]
     fn test_trivial() {
         let mut r = crate::test::rng(1);
         let always_false = Bernoulli::new(0.0).unwrap();
diff --git a/src/distributions/binomial.rs b/src/distributions/binomial.rs
deleted file mode 100644
index c096e4a..0000000
--- a/src/distributions/binomial.rs
+++ /dev/null
@@ -1,321 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2016-2017 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The binomial distribution.
-#![allow(deprecated)]
-#![allow(clippy::all)]
-
-use crate::distributions::{Distribution, Uniform};
-use crate::Rng;
-
-/// 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`.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[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 }
-    }
-}
-
-/// Convert a `f64` to an `i64`, panicing on overflow.
-// In the future (Rust 1.34), this might be replaced with `TryFrom`.
-fn f64_to_i64(x: f64) -> i64 {
-    assert!(x < (::std::i64::MAX as f64));
-    x as i64
-}
-
-impl Distribution<u64> for Binomial {
-    fn sample<R: Rng + ?Sized>(&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;
-        }
-
-        // The 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 };
-
-        let result;
-        let q = 1. - p;
-
-        // For small n * min(p, 1 - p), the BINV algorithm based on the inverse
-        // transformation of the binomial distribution is efficient. Otherwise,
-        // the BTPE algorithm is used.
-        //
-        // Voratas Kachitvichyanukul and Bruce W. Schmeiser. 1988. Binomial
-        // random variate generation. Commun. ACM 31, 2 (February 1988),
-        // 216-222. http://dx.doi.org/10.1145/42372.42381
-
-        // Threshold for prefering the BINV algorithm. The paper suggests 10,
-        // Ranlib uses 30, and GSL uses 14.
-        const BINV_THRESHOLD: f64 = 10.;
-
-        if (self.n as f64) * p < BINV_THRESHOLD && self.n <= (::std::i32::MAX as u64) {
-            // Use the BINV algorithm.
-            let s = p / q;
-            let a = ((self.n + 1) as f64) * s;
-            let mut r = q.powi(self.n as i32);
-            let mut u: f64 = rng.gen();
-            let mut x = 0;
-            while u > r as f64 {
-                u -= r;
-                x += 1;
-                r *= a / (x as f64) - s;
-            }
-            result = x;
-        } else {
-            // Use the BTPE algorithm.
-
-            // Threshold for using the squeeze algorithm. This can be freely
-            // chosen based on performance. Ranlib and GSL use 20.
-            const SQUEEZE_THRESHOLD: i64 = 20;
-
-            // Step 0: Calculate constants as functions of `n` and `p`.
-            let n = self.n as f64;
-            let np = n * p;
-            let npq = np * q;
-            let f_m = np + p;
-            let m = f64_to_i64(f_m);
-            // radius of triangle region, since height=1 also area of region
-            let p1 = (2.195 * npq.sqrt() - 4.6 * q).floor() + 0.5;
-            // tip of triangle
-            let x_m = (m as f64) + 0.5;
-            // left edge of triangle
-            let x_l = x_m - p1;
-            // right edge of triangle
-            let x_r = x_m + p1;
-            let c = 0.134 + 20.5 / (15.3 + (m as f64));
-            // p1 + area of parallelogram region
-            let p2 = p1 * (1. + 2. * c);
-
-            fn lambda(a: f64) -> f64 {
-                a * (1. + 0.5 * a)
-            }
-
-            let lambda_l = lambda((f_m - x_l) / (f_m - x_l * p));
-            let lambda_r = lambda((x_r - f_m) / (x_r * q));
-            // p1 + area of left tail
-            let p3 = p2 + c / lambda_l;
-            // p1 + area of right tail
-            let p4 = p3 + c / lambda_r;
-
-            // return value
-            let mut y: i64;
-
-            let gen_u = Uniform::new(0., p4);
-            let gen_v = Uniform::new(0., 1.);
-
-            loop {
-                // Step 1: Generate `u` for selecting the region. If region 1 is
-                // selected, generate a triangularly distributed variate.
-                let u = gen_u.sample(rng);
-                let mut v = gen_v.sample(rng);
-                if !(u > p1) {
-                    y = f64_to_i64(x_m - p1 * v + u);
-                    break;
-                }
-
-                if !(u > p2) {
-                    // Step 2: Region 2, parallelograms. Check if region 2 is
-                    // used. If so, generate `y`.
-                    let x = x_l + (u - p1) / c;
-                    v = v * c + 1.0 - (x - x_m).abs() / p1;
-                    if v > 1. {
-                        continue;
-                    } else {
-                        y = f64_to_i64(x);
-                    }
-                } else if !(u > p3) {
-                    // Step 3: Region 3, left exponential tail.
-                    y = f64_to_i64(x_l + v.ln() / lambda_l);
-                    if y < 0 {
-                        continue;
-                    } else {
-                        v *= (u - p2) * lambda_l;
-                    }
-                } else {
-                    // Step 4: Region 4, right exponential tail.
-                    y = f64_to_i64(x_r - v.ln() / lambda_r);
-                    if y > 0 && (y as u64) > self.n {
-                        continue;
-                    } else {
-                        v *= (u - p3) * lambda_r;
-                    }
-                }
-
-                // Step 5: Acceptance/rejection comparison.
-
-                // Step 5.0: Test for appropriate method of evaluating f(y).
-                let k = (y - m).abs();
-                if !(k > SQUEEZE_THRESHOLD && (k as f64) < 0.5 * npq - 1.) {
-                    // Step 5.1: Evaluate f(y) via the recursive relationship. Start the
-                    // search from the mode.
-                    let s = p / q;
-                    let a = s * (n + 1.);
-                    let mut f = 1.0;
-                    if m < y {
-                        let mut i = m;
-                        loop {
-                            i += 1;
-                            f *= a / (i as f64) - s;
-                            if i == y {
-                                break;
-                            }
-                        }
-                    } else if m > y {
-                        let mut i = y;
-                        loop {
-                            i += 1;
-                            f /= a / (i as f64) - s;
-                            if i == m {
-                                break;
-                            }
-                        }
-                    }
-                    if v > f {
-                        continue;
-                    } else {
-                        break;
-                    }
-                }
-
-                // Step 5.2: Squeezing. Check the value of ln(v) againts upper and
-                // lower bound of ln(f(y)).
-                let k = k as f64;
-                let rho = (k / npq) * ((k * (k / 3. + 0.625) + 1. / 6.) / npq + 0.5);
-                let t = -0.5 * k * k / npq;
-                let alpha = v.ln();
-                if alpha < t - rho {
-                    break;
-                }
-                if alpha > t + rho {
-                    continue;
-                }
-
-                // Step 5.3: Final acceptance/rejection test.
-                let x1 = (y + 1) as f64;
-                let f1 = (m + 1) as f64;
-                let z = (f64_to_i64(n) + 1 - m) as f64;
-                let w = (f64_to_i64(n) - y + 1) as f64;
-
-                fn stirling(a: f64) -> f64 {
-                    let a2 = a * a;
-                    (13860. - (462. - (132. - (99. - 140. / a2) / a2) / a2) / a2) / a / 166320.
-                }
-
-                if alpha
-                        > x_m * (f1 / x1).ln()
-                        + (n - (m as f64) + 0.5) * (z / w).ln()
-                        + ((y - m) as f64) * (w * p / (x1 * q)).ln()
-                        // We use the signs from the GSL implementation, which are
-                        // different than the ones in the reference. According to
-                        // the GSL authors, the new signs were verified to be
-                        // correct by one of the original designers of the
-                        // algorithm.
-                        + stirling(f1)
-                        + stirling(z)
-                        - stirling(x1)
-                        - stirling(w)
-                {
-                    continue;
-                }
-
-                break;
-            }
-            assert!(y >= 0);
-            result = y as u64;
-        }
-
-        // Invert the result for p < 0.5.
-        if p != self.p {
-            self.n - result
-        } else {
-            result
-        }
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use super::Binomial;
-    use crate::distributions::Distribution;
-    use crate::Rng;
-
-    fn test_binomial_mean_and_variance<R: Rng>(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::<f64>() / results.len() as f64;
-        assert!(
-            (mean as f64 - expected_mean).abs() < expected_mean / 50.0,
-            "mean: {}, expected_mean: {}",
-            mean,
-            expected_mean
-        );
-
-        let variance =
-            results.iter().map(|x| (x - mean) * (x - mean)).sum::<f64>() / results.len() as f64;
-        assert!(
-            (variance - expected_variance).abs() < expected_variance / 10.0,
-            "variance: {}, expected_variance: {}",
-            variance,
-            expected_variance
-        );
-    }
-
-    #[test]
-    #[cfg_attr(miri, ignore)] // Miri is too slow
-    fn test_binomial() {
-        let mut rng = crate::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 = crate::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/src/distributions/cauchy.rs b/src/distributions/cauchy.rs
deleted file mode 100644
index dc54c98..0000000
--- a/src/distributions/cauchy.rs
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2016-2017 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The Cauchy distribution.
-#![allow(deprecated)]
-#![allow(clippy::all)]
-
-use crate::distributions::Distribution;
-use crate::Rng;
-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))`
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[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<f64> for Cauchy {
-    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
-        // sample from [0, 1)
-        let x = rng.gen::<f64>();
-        // 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 super::Cauchy;
-    use crate::distributions::Distribution;
-
-    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_averages() {
-        // NOTE: given that the variance and mean are undefined,
-        // this test does not have any rigorous statistical meaning.
-        let cauchy = Cauchy::new(10.0, 5.0);
-        let mut rng = crate::test::rng(123);
-        let mut numbers: [f64; 1000] = [0.0; 1000];
-        let mut sum = 0.0;
-        for i in 0..1000 {
-            numbers[i] = cauchy.sample(&mut rng);
-            sum += numbers[i];
-        }
-        let median = median(&mut numbers);
-        println!("Cauchy median: {}", median);
-        assert!((median - 10.0).abs() < 0.4); // not 100% certain, but probable enough
-        let mean = sum / 1000.0;
-        println!("Cauchy mean: {}", mean);
-        // for a Cauchy distribution the mean should not converge
-        assert!((mean - 10.0).abs() > 0.4); // 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/src/distributions/dirichlet.rs b/src/distributions/dirichlet.rs
deleted file mode 100644
index a75678a..0000000
--- a/src/distributions/dirichlet.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2013 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The dirichlet distribution.
-#![allow(deprecated)]
-#![allow(clippy::all)]
-
-use crate::distributions::gamma::Gamma;
-use crate::distributions::Distribution;
-use crate::Rng;
-
-/// 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.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Debug)]
-pub struct Dirichlet {
-    /// Concentration parameters (alpha)
-    alpha: Vec<f64>,
-}
-
-impl Dirichlet {
-    /// Construct a new `Dirichlet` with the given alpha parameter `alpha`.
-    ///
-    /// # Panics
-    /// - if `alpha.len() < 2`
-    #[inline]
-    pub fn new<V: Into<Vec<f64>>>(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<Vec<f64>> for Dirichlet {
-    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Vec<f64> {
-        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 crate::distributions::Distribution;
-
-    #[test]
-    fn test_dirichlet() {
-        let d = Dirichlet::new(vec![1.0, 2.0, 3.0]);
-        let mut rng = crate::test::rng(221);
-        let samples = d.sample(&mut rng);
-        let _: Vec<f64> = 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 = crate::test::rng(221);
-        let samples = d.sample(&mut rng);
-        let _: Vec<f64> = 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/src/distributions/exponential.rs b/src/distributions/exponential.rs
deleted file mode 100644
index 5fdf7aa..0000000
--- a/src/distributions/exponential.rs
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2013 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The exponential distribution.
-#![allow(deprecated)]
-
-use crate::distributions::utils::ziggurat;
-use crate::distributions::{ziggurat_tables, Distribution};
-use crate::Rng;
-
-/// 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::<f64>().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.
-///
-/// [^1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
-///       Generate Normal Random Samples*](
-///       https://www.doornik.com/research/ziggurat.pdf).
-///       Nuffield College, Oxford
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Copy, Debug)]
-pub struct Exp1;
-
-// This could be done via `-rng.gen::<f64>().ln()` but that is slower.
-impl Distribution<f64> for Exp1 {
-    #[inline]
-    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
-        #[inline]
-        fn pdf(x: f64) -> f64 {
-            (-x).exp()
-        }
-        #[inline]
-        fn zero_case<R: Rng + ?Sized>(rng: &mut R, _u: f64) -> f64 {
-            ziggurat_tables::ZIG_EXP_R - rng.gen::<f64>().ln()
-        }
-
-        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`.
-///
-/// Note that [`Exp1`](crate::distributions::Exp1) is an optimised implementation for `lambda = 1`.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[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 Distribution<f64> for Exp {
-    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
-        let n: f64 = rng.sample(Exp1);
-        n * self.lambda_inverse
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use super::Exp;
-    use crate::distributions::Distribution;
-
-    #[test]
-    fn test_exp() {
-        let exp = Exp::new(10.0);
-        let mut rng = crate::test::rng(221);
-        for _ in 0..1000 {
-            assert!(exp.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/src/distributions/float.rs b/src/distributions/float.rs
index 0a45f39..733a403 100644
--- a/src/distributions/float.rs
+++ b/src/distributions/float.rs
@@ -14,6 +14,9 @@
 use core::mem;
 #[cfg(feature = "simd_support")] use packed_simd::*;
 
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
+
 /// A distribution to sample floating point numbers uniformly in the half-open
 /// interval `(0, 1]`, i.e. including 1 but not 0.
 ///
@@ -39,6 +42,7 @@
 /// [`Open01`]: crate::distributions::Open01
 /// [`Uniform`]: crate::distributions::uniform::Uniform
 #[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub struct OpenClosed01;
 
 /// A distribution to sample floating point numbers uniformly in the open
@@ -65,6 +69,7 @@
 /// [`OpenClosed01`]: crate::distributions::OpenClosed01
 /// [`Uniform`]: crate::distributions::uniform::Uniform
 #[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub struct Open01;
 
 
diff --git a/src/distributions/gamma.rs b/src/distributions/gamma.rs
deleted file mode 100644
index f19738d..0000000
--- a/src/distributions/gamma.rs
+++ /dev/null
@@ -1,373 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2013 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The Gamma and derived distributions.
-#![allow(deprecated)]
-
-use self::ChiSquaredRepr::*;
-use self::GammaRepr::*;
-
-use crate::distributions::normal::StandardNormal;
-use crate::distributions::{Distribution, Exp, Open01};
-use crate::Rng;
-
-/// 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 that paper for
-/// `shape < 1`.
-///
-/// [^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)
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[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 }
-    }
-}
-
-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,
-            c: 1. / (9. * d).sqrt(),
-            d,
-        }
-    }
-}
-
-impl Distribution<f64> for Gamma {
-    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
-        match self.repr {
-            Small(ref g) => g.sample(rng),
-            One(ref g) => g.sample(rng),
-            Large(ref g) => g.sample(rng),
-        }
-    }
-}
-impl Distribution<f64> for GammaSmallShape {
-    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
-        let u: f64 = rng.sample(Open01);
-
-        self.large_shape.sample(rng) * u.powf(self.inv_shape)
-    }
-}
-impl Distribution<f64> for GammaLargeShape {
-    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
-        loop {
-            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 u: f64 = rng.sample(Open01);
-
-            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)`.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[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 }
-    }
-}
-impl Distribution<f64> for ChiSquared {
-    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
-        match self.repr {
-            DoFExactlyOne => {
-                // k == 1 => N(0,1)^2
-                let norm = rng.sample(StandardNormal);
-                norm * norm
-            }
-            DoFAnythingElse(ref g) => g.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)`.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[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 Distribution<f64> for FisherF {
-    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
-        self.numer.sample(rng) / self.denom.sample(rng) * self.dof_ratio
-    }
-}
-
-/// The Student t distribution, `t(nu)`, where `nu` is the degrees of
-/// freedom.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[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 Distribution<f64> for StudentT {
-    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
-        let norm = rng.sample(StandardNormal);
-        norm * (self.dof / self.chi.sample(rng)).sqrt()
-    }
-}
-
-/// The Beta distribution with shape parameters `alpha` and `beta`.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[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<f64> for Beta {
-    fn sample<R: Rng + ?Sized>(&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 super::{Beta, ChiSquared, FisherF, StudentT};
-    use crate::distributions::Distribution;
-
-    const N: u32 = 100;
-
-    #[test]
-    fn test_chi_squared_one() {
-        let chi = ChiSquared::new(1.0);
-        let mut rng = crate::test::rng(201);
-        for _ in 0..N {
-            chi.sample(&mut rng);
-        }
-    }
-    #[test]
-    fn test_chi_squared_small() {
-        let chi = ChiSquared::new(0.5);
-        let mut rng = crate::test::rng(202);
-        for _ in 0..N {
-            chi.sample(&mut rng);
-        }
-    }
-    #[test]
-    fn test_chi_squared_large() {
-        let chi = ChiSquared::new(30.0);
-        let mut rng = crate::test::rng(203);
-        for _ in 0..N {
-            chi.sample(&mut rng);
-        }
-    }
-    #[test]
-    #[should_panic]
-    fn test_chi_squared_invalid_dof() {
-        ChiSquared::new(-1.0);
-    }
-
-    #[test]
-    fn test_f() {
-        let f = FisherF::new(2.0, 32.0);
-        let mut rng = crate::test::rng(204);
-        for _ in 0..N {
-            f.sample(&mut rng);
-        }
-    }
-
-    #[test]
-    fn test_t() {
-        let t = StudentT::new(11.0);
-        let mut rng = crate::test::rng(205);
-        for _ in 0..N {
-            t.sample(&mut rng);
-        }
-    }
-
-    #[test]
-    fn test_beta() {
-        let beta = Beta::new(1.0, 2.0);
-        let mut rng = crate::test::rng(201);
-        for _ in 0..N {
-            beta.sample(&mut rng);
-        }
-    }
-
-    #[test]
-    #[should_panic]
-    fn test_beta_invalid_dof() {
-        Beta::new(0., 0.);
-    }
-}
diff --git a/src/distributions/integer.rs b/src/distributions/integer.rs
index f2db1f1..8a2ce4c 100644
--- a/src/distributions/integer.rs
+++ b/src/distributions/integer.rs
@@ -10,9 +10,10 @@
 
 use crate::distributions::{Distribution, Standard};
 use crate::Rng;
-#[cfg(all(target_arch = "x86", feature = "nightly"))] use core::arch::x86::*;
-#[cfg(all(target_arch = "x86_64", feature = "nightly"))]
-use core::arch::x86_64::*;
+#[cfg(all(target_arch = "x86", feature = "simd_support"))]
+use core::arch::x86::{__m128i, __m256i};
+#[cfg(all(target_arch = "x86_64", feature = "simd_support"))]
+use core::arch::x86_64::{__m128i, __m256i};
 #[cfg(not(target_os = "emscripten"))] use core::num::NonZeroU128;
 use core::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
 #[cfg(feature = "simd_support")] use packed_simd::*;
@@ -155,10 +156,9 @@
 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),);
+simd_impl!((__m128i, u8x16), (__m256i, u8x32),);
 
 #[cfg(test)]
 mod tests {
diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs
index 4e1b1a6..652f52a 100644
--- a/src/distributions/mod.rs
+++ b/src/distributions/mod.rs
@@ -11,11 +11,11 @@
 //!
 //! 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, e.g. [`Rng::gen`], [`Rng::gen_range`] and
-//! of course [`Rng::sample`].
+//! functionality of the [`Rng`] trait, e.g. [`Rng::gen`] and of course
+//! [`Rng::sample`].
 //!
 //! Abstractly, a [probability distribution] describes the probability of
-//! occurance of each value in its sample space.
+//! occurrence of each value in its sample space.
 //!
 //! More concretely, an implementation of `Distribution<T>` for type `X` is an
 //! algorithm for choosing values from the sample space (a subset of `T`)
@@ -54,16 +54,16 @@
 //! 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
+//! Values may be sampled from this distribution using [`Rng::sample(Range)`] or
 //! by creating a distribution object with [`Uniform::new`],
 //! [`Uniform::new_inclusive`] or `From<Range>`. 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`].
+//! `Uniform` object than to call [`Rng::sample(Range)`].
 //!
 //! User types `T` may also implement `Distribution<T>` 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`].
+//! documentation in the [`uniform`] module). Doing so enables generation of
+//! values of type `T` with  [`Rng::sample(Range)`].
 //!
 //! ## Open and half-open ranges
 //!
@@ -79,7 +79,7 @@
 //! the [`Bernoulli`] distribution (this is used by [`Rng::gen_bool`]).
 //!
 //! For weighted sampling from a sequence of discrete values, use the
-//! [`weighted`] module.
+//! [`WeightedIndex`] distribution.
 //!
 //! This crate no longer includes other non-uniform distributions; instead
 //! it is recommended that you use either [`rand_distr`] or [`statrs`].
@@ -100,62 +100,21 @@
 pub use self::float::{Open01, OpenClosed01};
 pub use self::other::Alphanumeric;
 #[doc(inline)] pub use self::uniform::Uniform;
-#[cfg(feature = "alloc")]
-pub use self::weighted::{WeightedError, WeightedIndex};
 
-// The following are all deprecated after being moved to rand_distr
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::binomial::Binomial;
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::cauchy::Cauchy;
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::dirichlet::Dirichlet;
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::exponential::{Exp, Exp1};
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::gamma::{Beta, ChiSquared, FisherF, Gamma, StudentT};
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::normal::{LogNormal, Normal, StandardNormal};
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::pareto::Pareto;
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::poisson::Poisson;
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::triangular::Triangular;
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::unit_circle::UnitCircle;
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::unit_sphere::UnitSphereSurface;
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::weibull::Weibull;
+#[cfg(feature = "alloc")]
+pub use self::weighted_index::{WeightedError, WeightedIndex};
 
 mod bernoulli;
-#[cfg(feature = "std")] mod binomial;
-#[cfg(feature = "std")] mod cauchy;
-#[cfg(feature = "std")] mod dirichlet;
-#[cfg(feature = "std")] mod exponential;
-#[cfg(feature = "std")] mod gamma;
-#[cfg(feature = "std")] mod normal;
-#[cfg(feature = "std")] mod pareto;
-#[cfg(feature = "std")] mod poisson;
-#[cfg(feature = "std")] mod triangular;
 pub mod uniform;
-#[cfg(feature = "std")] mod unit_circle;
-#[cfg(feature = "std")] mod unit_sphere;
-#[cfg(feature = "std")] mod weibull;
-#[cfg(feature = "alloc")] pub mod weighted;
+
+#[deprecated(since = "0.8.0", note = "use rand::distributions::{WeightedIndex, WeightedError} instead")]
+#[cfg(feature = "alloc")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
+pub mod weighted;
+#[cfg(feature = "alloc")] mod weighted_index;
+
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
 
 mod float;
 #[doc(hidden)]
@@ -165,7 +124,6 @@
 mod integer;
 mod other;
 mod utils;
-#[cfg(feature = "std")] mod ziggurat_tables;
 
 /// Types (distributions) that can be used to create a random instance of `T`.
 ///
@@ -204,17 +162,21 @@
     /// use rand::thread_rng;
     /// use rand::distributions::{Distribution, Alphanumeric, Uniform, Standard};
     ///
-    /// let rng = thread_rng();
+    /// let mut rng = thread_rng();
     ///
     /// // Vec of 16 x f32:
-    /// let v: Vec<f32> = Standard.sample_iter(rng).take(16).collect();
+    /// let v: Vec<f32> = Standard.sample_iter(&mut rng).take(16).collect();
     ///
     /// // String:
-    /// let s: String = Alphanumeric.sample_iter(rng).take(7).collect();
+    /// let s: String = Alphanumeric
+    ///     .sample_iter(&mut rng)
+    ///     .take(7)
+    ///     .map(char::from)
+    ///     .collect();
     ///
     /// // Dice-rolling:
     /// let die_range = Uniform::new_inclusive(1, 6);
-    /// let mut roll_die = die_range.sample_iter(rng);
+    /// let mut roll_die = die_range.sample_iter(&mut rng);
     /// while roll_die.next().unwrap() != 6 {
     ///     println!("Not a 6; rolling again!");
     /// }
@@ -359,18 +321,18 @@
 /// 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).
+/// samples from `(0, 1]` and `Rng::gen_range(0..1)` which also samples from
+/// `[0, 1)`. Note that `Open01` uses 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)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub struct Standard;
 
 
-#[cfg(all(test, feature = "std"))]
+#[cfg(test)]
 mod tests {
     use super::{Distribution, Uniform};
     use crate::Rng;
@@ -380,8 +342,12 @@
         use crate::distributions::Open01;
         let mut rng = crate::test::rng(210);
         let distr = Open01;
-        let results: Vec<f32> = distr.sample_iter(&mut rng).take(100).collect();
-        println!("{:?}", results);
+        let mut iter = Distribution::<f32>::sample_iter(distr, &mut rng);
+        let mut sum: f32 = 0.;
+        for _ in 0..100 {
+            sum += iter.next().unwrap();
+        }
+        assert!(0. < sum && sum < 100.);
     }
 
     #[test]
diff --git a/src/distributions/normal.rs b/src/distributions/normal.rs
deleted file mode 100644
index ec62fa9..0000000
--- a/src/distributions/normal.rs
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2013 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The normal and derived distributions.
-#![allow(deprecated)]
-
-use crate::distributions::utils::ziggurat;
-use crate::distributions::{ziggurat_tables, Distribution, Open01};
-use crate::Rng;
-
-/// 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.
-///
-/// [^1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
-///       Generate Normal Random Samples*](
-///       https://www.doornik.com/research/ziggurat.pdf).
-///       Nuffield College, Oxford
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Copy, Debug)]
-pub struct StandardNormal;
-
-impl Distribution<f64> for StandardNormal {
-    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
-        #[inline]
-        fn pdf(x: f64) -> f64 {
-            (-x * x / 2.0).exp()
-        }
-        #[inline]
-        fn zero_case<R: Rng + ?Sized>(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 x_: f64 = rng.sample(Open01);
-                let y_: f64 = rng.sample(Open01);
-
-                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
-            }
-        }
-
-        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.
-///
-/// Note that [`StandardNormal`] is an optimised implementation for mean 0, and
-/// standard deviation 1.
-///
-/// [`StandardNormal`]: crate::distributions::StandardNormal
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[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, std_dev }
-    }
-}
-impl Distribution<f64> for Normal {
-    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
-        let n = rng.sample(StandardNormal);
-        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.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[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 Distribution<f64> for LogNormal {
-    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
-        self.norm.sample(rng).exp()
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::{LogNormal, Normal};
-    use crate::distributions::Distribution;
-
-    #[test]
-    fn test_normal() {
-        let norm = Normal::new(10.0, 10.0);
-        let mut rng = crate::test::rng(210);
-        for _ in 0..1000 {
-            norm.sample(&mut rng);
-        }
-    }
-    #[test]
-    #[should_panic]
-    fn test_normal_invalid_sd() {
-        Normal::new(10.0, -1.0);
-    }
-
-
-    #[test]
-    fn test_log_normal() {
-        let lnorm = LogNormal::new(10.0, 10.0);
-        let mut rng = crate::test::rng(211);
-        for _ in 0..1000 {
-            lnorm.sample(&mut rng);
-        }
-    }
-    #[test]
-    #[should_panic]
-    fn test_log_normal_invalid_sd() {
-        LogNormal::new(10.0, -1.0);
-    }
-}
diff --git a/src/distributions/other.rs b/src/distributions/other.rs
index c95060e..f62fe59 100644
--- a/src/distributions/other.rs
+++ b/src/distributions/other.rs
@@ -14,9 +14,12 @@
 use crate::distributions::{Distribution, Standard, Uniform};
 use crate::Rng;
 
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
+
 // ----- Sampling distributions -----
 
-/// Sample a `char`, uniformly distributed over ASCII letters and numbers:
+/// Sample a `u8`, uniformly distributed over ASCII letters and numbers:
 /// a-z, A-Z and 0-9.
 ///
 /// # Example
@@ -29,11 +32,30 @@
 /// let mut rng = thread_rng();
 /// let chars: String = iter::repeat(())
 ///         .map(|()| rng.sample(Alphanumeric))
+///         .map(char::from)
 ///         .take(7)
 ///         .collect();
 /// println!("Random chars: {}", chars);
 /// ```
+///
+/// # Passwords
+///
+/// Users sometimes ask whether it is safe to use a string of random characters
+/// as a password. In principle, all RNGs in Rand implementing `CryptoRng` are
+/// suitable as a source of randomness for generating passwords (if they are
+/// properly seeded), but it is more conservative to only use randomness
+/// directly from the operating system via the `getrandom` crate, or the
+/// corresponding bindings of a crypto library.
+///
+/// When generating passwords or keys, it is important to consider the threat
+/// model and in some cases the memorability of the password. This is out of
+/// scope of the Rand project, and therefore we defer to the following
+/// references:
+///
+/// - [Wikipedia article on Password Strength](https://en.wikipedia.org/wiki/Password_strength)
+/// - [Diceware for generating memorable passwords](https://en.wikipedia.org/wiki/Diceware)
 #[derive(Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub struct Alphanumeric;
 
 
@@ -60,8 +82,8 @@
     }
 }
 
-impl Distribution<char> for Alphanumeric {
-    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
+impl Distribution<u8> for Alphanumeric {
+    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u8 {
         const RANGE: u32 = 26 + 26 + 10;
         const GEN_ASCII_STR_CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                 abcdefghijklmnopqrstuvwxyz\
@@ -73,7 +95,7 @@
         loop {
             let var = rng.next_u32() >> (32 - 6);
             if var < RANGE {
-                return GEN_ASCII_STR_CHARSET[var as usize] as char;
+                return GEN_ASCII_STR_CHARSET[var as usize];
             }
         }
     }
@@ -184,7 +206,7 @@
 mod tests {
     use super::*;
     use crate::RngCore;
-    #[cfg(all(not(feature = "std"), feature = "alloc"))] use alloc::string::String;
+    #[cfg(feature = "alloc")] use alloc::string::String;
 
     #[test]
     fn test_misc() {
@@ -217,7 +239,7 @@
         // take the rejection sampling path.
         let mut incorrect = false;
         for _ in 0..100 {
-            let c = rng.sample(Alphanumeric);
+            let c: char = rng.sample(Alphanumeric).into();
             incorrect |= !((c >= '0' && c <= '9') ||
                            (c >= 'A' && c <= 'Z') ||
                            (c >= 'a' && c <= 'z') );
@@ -245,7 +267,7 @@
             '\u{ed692}',
             '\u{35888}',
         ]);
-        test_samples(&Alphanumeric, 'a', &['h', 'm', 'e', '3', 'M']);
+        test_samples(&Alphanumeric, 0, &[104, 109, 101, 51, 77]);
         test_samples(&Standard, false, &[true, true, false, true, false]);
         test_samples(&Standard, None as Option<bool>, &[
             Some(true),
diff --git a/src/distributions/pareto.rs b/src/distributions/pareto.rs
deleted file mode 100644
index ac5473b..0000000
--- a/src/distributions/pareto.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The Pareto distribution.
-#![allow(deprecated)]
-
-use crate::distributions::{Distribution, OpenClosed01};
-use crate::Rng;
-
-/// Samples floating-point numbers according to the Pareto distribution
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[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 x<sub>m</sub> 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<f64> for Pareto {
-    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
-        let u: f64 = rng.sample(OpenClosed01);
-        self.scale * u.powf(self.inv_neg_shape)
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::Pareto;
-    use crate::distributions::Distribution;
-
-    #[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 = crate::test::rng(1);
-        for _ in 0..1000 {
-            let r = d.sample(&mut rng);
-            assert!(r >= scale);
-        }
-    }
-}
diff --git a/src/distributions/poisson.rs b/src/distributions/poisson.rs
deleted file mode 100644
index ce94d75..0000000
--- a/src/distributions/poisson.rs
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2016-2017 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The Poisson distribution.
-#![allow(deprecated)]
-
-use crate::distributions::utils::log_gamma;
-use crate::distributions::{Cauchy, Distribution};
-use crate::Rng;
-
-/// The Poisson distribution `Poisson(lambda)`.
-///
-/// This distribution has a density function:
-/// `f(k) = lambda^k * exp(-lambda) / k!` for `k >= 0`.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[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<u64> for Poisson {
-    fn sample<R: Rng + ?Sized>(&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::<f64>();
-                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::<f64>() <= check {
-                    break;
-                }
-            }
-            int_result
-        }
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use super::Poisson;
-    use crate::distributions::Distribution;
-
-    #[test]
-    #[cfg_attr(miri, ignore)] // Miri is too slow
-    fn test_poisson_10() {
-        let poisson = Poisson::new(10.0);
-        let mut rng = crate::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 = crate::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/src/distributions/triangular.rs b/src/distributions/triangular.rs
deleted file mode 100644
index 37be198..0000000
--- a/src/distributions/triangular.rs
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The triangular distribution.
-#![allow(deprecated)]
-
-use crate::distributions::{Distribution, Standard};
-use crate::Rng;
-
-/// The triangular distribution.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[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<f64> for Triangular {
-    #[inline]
-    fn sample<R: Rng + ?Sized>(&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 super::Triangular;
-    use crate::distributions::Distribution;
-
-    #[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 = crate::test::rng(1);
-        for _ in 0..1000 {
-            norm.sample(&mut rng);
-        }
-    }
-}
diff --git a/src/distributions/uniform.rs b/src/distributions/uniform.rs
index 8584152..bbd9694 100644
--- a/src/distributions/uniform.rs
+++ b/src/distributions/uniform.rs
@@ -1,4 +1,4 @@
-// Copyright 2018 Developers of the Rand project.
+// Copyright 2018-2020 Developers of the Rand project.
 // Copyright 2017 The Rust Project Developers.
 //
 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
@@ -34,7 +34,7 @@
 //! let side = Uniform::new(-10.0, 10.0);
 //!
 //! // sample between 1 and 10 points
-//! for _ in 0..rng.gen_range(1, 11) {
+//! for _ in 0..rng.gen_range(1..=10) {
 //!     // 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);
@@ -105,24 +105,28 @@
 
 #[cfg(not(feature = "std"))] use core::time::Duration;
 #[cfg(feature = "std")] use std::time::Duration;
+use core::ops::{Range, RangeInclusive};
 
 use crate::distributions::float::IntoFloat;
 use crate::distributions::utils::{BoolAsSIMD, FloatAsSIMD, FloatSIMDUtils, WideningMultiply};
 use crate::distributions::Distribution;
-use crate::Rng;
+use crate::{Rng, RngCore};
 
 #[cfg(not(feature = "std"))]
 #[allow(unused_imports)] // rustc doesn't detect that this is actually used
 use crate::distributions::utils::Float;
 
-
 #[cfg(feature = "simd_support")] use packed_simd::*;
 
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
+
 /// 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.
+/// work up front to make sampling of multiple values faster. If only one sample
+/// from the range is required, [`Rng::gen_range`] can be more efficient.
 ///
 /// When sampling from a constant range, many calculations can happen at
 /// compile-time and all methods should be fast; for floating-point ranges and
@@ -137,7 +141,7 @@
 /// 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
+/// `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
@@ -145,20 +149,29 @@
 /// ```
 /// 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);
+/// 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);
+/// ```
+///
+/// For a single sample, [`Rng::gen_range`] may be prefered:
+///
+/// ```
+/// use rand::Rng;
+///
+/// let mut rng = rand::thread_rng();
+/// println!("{}", rng.gen_range(0..10));
 /// ```
 ///
 /// [`new`]: Uniform::new
 /// [`new_inclusive`]: Uniform::new_inclusive
+/// [`Rng::gen_range`]: Rng::gen_range
 #[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub struct Uniform<X: SampleUniform>(X::Sampler);
 
 impl<X: SampleUniform> Uniform<X> {
@@ -265,20 +278,38 @@
         let uniform: Self = UniformSampler::new(low, high);
         uniform.sample(rng)
     }
+
+    /// Sample a single value uniformly from a range with inclusive lower bound
+    /// and inclusive upper bound `[low, high]`.
+    ///
+    /// By default this is implemented using
+    /// `UniformSampler::new_inclusive(low, high).sample(rng)`. However, for
+    /// some types more optimal implementations for single usage may be provided
+    /// via this method.
+    /// Results may not be identical.
+    fn sample_single_inclusive<R: Rng + ?Sized, B1, B2>(low: B1, high: B2, rng: &mut R)
+        -> Self::X
+        where B1: SampleBorrow<Self::X> + Sized,
+              B2: SampleBorrow<Self::X> + Sized
+    {
+        let uniform: Self = UniformSampler::new_inclusive(low, high);
+        uniform.sample(rng)
+    }
 }
 
-impl<X: SampleUniform> From<::core::ops::Range<X>> for Uniform<X> {
+impl<X: SampleUniform> From<Range<X>> for Uniform<X> {
     fn from(r: ::core::ops::Range<X>) -> Uniform<X> {
         Uniform::new(r.start, r.end)
     }
 }
 
-impl<X: SampleUniform> From<::core::ops::RangeInclusive<X>> for Uniform<X> {
+impl<X: SampleUniform> From<RangeInclusive<X>> for Uniform<X> {
     fn from(r: ::core::ops::RangeInclusive<X>) -> Uniform<X> {
         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.
@@ -307,6 +338,43 @@
     }
 }
 
+/// Range that supports generating a single sample efficiently.
+///
+/// Any type implementing this trait can be used to specify the sampled range
+/// for `Rng::gen_range`.
+pub trait SampleRange<T> {
+    /// Generate a sample from the given range.
+    fn sample_single<R: RngCore + ?Sized>(self, rng: &mut R) -> T;
+
+    /// Check whether the range is empty.
+    fn is_empty(&self) -> bool;
+}
+
+impl<T: SampleUniform + PartialOrd> SampleRange<T> for Range<T> {
+    #[inline]
+    fn sample_single<R: RngCore + ?Sized>(self, rng: &mut R) -> T {
+        T::Sampler::sample_single(self.start, self.end, rng)
+    }
+
+    #[inline]
+    fn is_empty(&self) -> bool {
+        !(self.start < self.end)
+    }
+}
+
+impl<T: SampleUniform + PartialOrd> SampleRange<T> for RangeInclusive<T> {
+    #[inline]
+    fn sample_single<R: RngCore + ?Sized>(self, rng: &mut R) -> T {
+        T::Sampler::sample_single_inclusive(self.start(), self.end(), rng)
+    }
+
+    #[inline]
+    fn is_empty(&self) -> bool {
+        !(self.start() <= self.end())
+    }
+}
+
+
 ////////////////////////////////////////////////////////////////////////////////
 
 // What follows are all back-ends.
@@ -347,6 +415,7 @@
 /// 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)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub struct UniformInt<X> {
     low: X,
     range: X,
@@ -404,13 +473,14 @@
                 };
 
                 UniformInt {
-                    low: low,
+                    low,
                     // These are really $unsigned values, but store as $ty:
                     range: range as $ty,
                     z: ints_to_reject as $unsigned as $ty,
                 }
             }
 
+            #[inline]
             fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
                 let range = self.range as $unsigned as $u_large;
                 if range > 0 {
@@ -429,6 +499,7 @@
                 }
             }
 
+            #[inline]
             fn sample_single<R: Rng + ?Sized, B1, B2>(low_b: B1, high_b: B2, rng: &mut R) -> Self::X
             where
                 B1: SampleBorrow<Self::X> + Sized,
@@ -437,7 +508,19 @@
                 let low = *low_b.borrow();
                 let high = *high_b.borrow();
                 assert!(low < high, "UniformSampler::sample_single: low >= high");
-                let range = high.wrapping_sub(low) as $unsigned as $u_large;
+                Self::sample_single_inclusive(low, high - 1, rng)
+            }
+
+            #[inline]
+            fn sample_single_inclusive<R: Rng + ?Sized, B1, B2>(low_b: B1, high_b: B2, rng: &mut R) -> Self::X
+            where
+                B1: SampleBorrow<Self::X> + Sized,
+                B2: SampleBorrow<Self::X> + Sized,
+            {
+                let low = *low_b.borrow();
+                let high = *high_b.borrow();
+                assert!(low <= high, "UniformSampler::sample_single_inclusive: low > high");
+                let range = high.wrapping_sub(low).wrapping_add(1) 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
@@ -478,7 +561,7 @@
 #[cfg(not(target_os = "emscripten"))]
 uniform_int_impl! { u128, u128, u128 }
 
-#[cfg(all(feature = "simd_support", feature = "nightly"))]
+#[cfg(feature = "simd_support")]
 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
@@ -535,7 +618,7 @@
                 let zone = unsigned_max - ints_to_reject;
 
                 UniformInt {
-                    low: low,
+                    low,
                     // These are really $unsigned values, but store as $ty:
                     range: range.cast(),
                     z: zone.cast(),
@@ -585,7 +668,7 @@
     };
 }
 
-#[cfg(all(feature = "simd_support", feature = "nightly"))]
+#[cfg(feature = "simd_support")]
 uniform_simd_int_impl! {
     (u64x2, i64x2),
     (u64x4, i64x4),
@@ -593,7 +676,7 @@
     u64
 }
 
-#[cfg(all(feature = "simd_support", feature = "nightly"))]
+#[cfg(feature = "simd_support")]
 uniform_simd_int_impl! {
     (u32x2, i32x2),
     (u32x4, i32x4),
@@ -602,7 +685,7 @@
     u32
 }
 
-#[cfg(all(feature = "simd_support", feature = "nightly"))]
+#[cfg(feature = "simd_support")]
 uniform_simd_int_impl! {
     (u16x2, i16x2),
     (u16x4, i16x4),
@@ -612,7 +695,7 @@
     u16
 }
 
-#[cfg(all(feature = "simd_support", feature = "nightly"))]
+#[cfg(feature = "simd_support")]
 uniform_simd_int_impl! {
     (u8x2, i8x2),
     (u8x4, i8x4),
@@ -623,6 +706,78 @@
     u8
 }
 
+impl SampleUniform for char {
+    type Sampler = UniformChar;
+}
+
+/// The back-end implementing [`UniformSampler`] for `char`.
+///
+/// Unless you are implementing [`UniformSampler`] for your own type, this type
+/// should not be used directly, use [`Uniform`] instead.
+///
+/// This differs from integer range sampling since the range `0xD800..=0xDFFF`
+/// are used for surrogate pairs in UCS and UTF-16, and consequently are not
+/// valid Unicode code points. We must therefore avoid sampling values in this
+/// range.
+#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
+pub struct UniformChar {
+    sampler: UniformInt<u32>,
+}
+
+/// UTF-16 surrogate range start
+const CHAR_SURROGATE_START: u32 = 0xD800;
+/// UTF-16 surrogate range size
+const CHAR_SURROGATE_LEN: u32 = 0xE000 - CHAR_SURROGATE_START;
+
+/// Convert `char` to compressed `u32`
+fn char_to_comp_u32(c: char) -> u32 {
+    match c as u32 {
+        c if c >= CHAR_SURROGATE_START => c - CHAR_SURROGATE_LEN,
+        c => c,
+    }
+}
+
+impl UniformSampler for UniformChar {
+    type X = char;
+
+    #[inline] // if the range is constant, this helps LLVM to do the
+              // calculations at compile-time.
+    fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
+    where
+        B1: SampleBorrow<Self::X> + Sized,
+        B2: SampleBorrow<Self::X> + Sized,
+    {
+        let low = char_to_comp_u32(*low_b.borrow());
+        let high = char_to_comp_u32(*high_b.borrow());
+        let sampler = UniformInt::<u32>::new(low, high);
+        UniformChar { sampler }
+    }
+
+    #[inline] // if the range is constant, this helps LLVM to do the
+              // calculations at compile-time.
+    fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
+    where
+        B1: SampleBorrow<Self::X> + Sized,
+        B2: SampleBorrow<Self::X> + Sized,
+    {
+        let low = char_to_comp_u32(*low_b.borrow());
+        let high = char_to_comp_u32(*high_b.borrow());
+        let sampler = UniformInt::<u32>::new_inclusive(low, high);
+        UniformChar { sampler }
+    }
+
+    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
+        let mut x = self.sampler.sample(rng);
+        if x >= CHAR_SURROGATE_START {
+            x += CHAR_SURROGATE_LEN;
+        }
+        // SAFETY: x must not be in surrogate range or greater than char::MAX.
+        // This relies on range constructors which accept char arguments.
+        // Validity of input char values is assumed.
+        unsafe { core::char::from_u32_unchecked(x) }
+    }
+}
 
 /// The back-end implementing [`UniformSampler`] for floating-point types.
 ///
@@ -644,6 +799,7 @@
 /// [`new_inclusive`]: UniformSampler::new_inclusive
 /// [`Standard`]: crate::distributions::Standard
 #[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub struct UniformFloat<X> {
     low: X,
     scale: X,
@@ -837,12 +993,14 @@
 /// Unless you are implementing [`UniformSampler`] for your own types, this type
 /// should not be used directly, use [`Uniform`] instead.
 #[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub struct UniformDuration {
     mode: UniformDurationMode,
     offset: u32,
 }
 
 #[derive(Debug, Copy, Clone)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 enum UniformDurationMode {
     Small {
         secs: u64,
@@ -947,7 +1105,7 @@
                 max_nanos,
                 secs,
             } => {
-                // constant folding means this is at least as fast as `gen_range`
+                // constant folding means this is at least as fast as `Rng::sample(Range)`
                 let nano_range = Uniform::new(0, 1_000_000_000);
                 loop {
                     let s = secs.sample(rng);
@@ -967,6 +1125,56 @@
     use super::*;
     use crate::rngs::mock::StepRng;
 
+    #[test]
+    #[cfg(feature = "serde1")]
+    fn test_serialization_uniform_duration() {
+        let distr = UniformDuration::new(std::time::Duration::from_secs(10), std::time::Duration::from_secs(60));
+        let de_distr: UniformDuration = bincode::deserialize(&bincode::serialize(&distr).unwrap()).unwrap();
+        assert_eq!(
+            distr.offset, de_distr.offset
+        );
+        match (distr.mode, de_distr.mode) {
+            (UniformDurationMode::Small {secs: a_secs, nanos: a_nanos}, UniformDurationMode::Small {secs, nanos}) => {
+                assert_eq!(a_secs, secs);
+
+                assert_eq!(a_nanos.0.low, nanos.0.low);
+                assert_eq!(a_nanos.0.range, nanos.0.range);
+                assert_eq!(a_nanos.0.z, nanos.0.z);
+            }
+            (UniformDurationMode::Medium {nanos: a_nanos} , UniformDurationMode::Medium {nanos}) => {
+                assert_eq!(a_nanos.0.low, nanos.0.low);
+                assert_eq!(a_nanos.0.range, nanos.0.range);
+                assert_eq!(a_nanos.0.z, nanos.0.z);
+            }
+            (UniformDurationMode::Large {max_secs:a_max_secs, max_nanos:a_max_nanos, secs:a_secs}, UniformDurationMode::Large {max_secs, max_nanos, secs} ) => {
+                assert_eq!(a_max_secs, max_secs);
+                assert_eq!(a_max_nanos, max_nanos);
+
+                assert_eq!(a_secs.0.low, secs.0.low);
+                assert_eq!(a_secs.0.range, secs.0.range);
+                assert_eq!(a_secs.0.z, secs.0.z);
+            }
+            _ => panic!("`UniformDurationMode` was not serialized/deserialized correctly")
+        }
+    }
+    
+    #[test]
+    #[cfg(feature = "serde1")]
+    fn test_uniform_serialization() {
+        let unit_box: Uniform<i32>  = Uniform::new(-1, 1);
+        let de_unit_box: Uniform<i32> = bincode::deserialize(&bincode::serialize(&unit_box).unwrap()).unwrap();
+
+        assert_eq!(unit_box.0.low, de_unit_box.0.low);
+        assert_eq!(unit_box.0.range, de_unit_box.0.range);
+        assert_eq!(unit_box.0.z, de_unit_box.0.z);
+
+        let unit_box: Uniform<f32> = Uniform::new(-1., 1.);
+        let de_unit_box: Uniform<f32> = bincode::deserialize(&bincode::serialize(&unit_box).unwrap()).unwrap();
+
+        assert_eq!(unit_box.0.low, de_unit_box.0.low);
+        assert_eq!(unit_box.0.scale, de_unit_box.0.scale);
+    }
+
     #[should_panic]
     #[test]
     fn test_uniform_bad_limits_equal_int() {
@@ -1024,7 +1232,7 @@
                     }
 
                     for _ in 0..1000 {
-                        let v: $ty = rng.gen_range(low, high);
+                        let v = <$ty as SampleUniform>::Sampler::sample_single(low, high, &mut rng);
                         assert!($le(low, v) && $lt(v, high));
                     }
                 }
@@ -1058,7 +1266,7 @@
         #[cfg(not(target_os = "emscripten"))]
         t!(i128, u128);
 
-        #[cfg(all(feature = "simd_support", feature = "nightly"))]
+        #[cfg(feature = "simd_support")]
         {
             t!(u8x2, u8x4, u8x8, u8x16, u8x32, u8x64 => u8);
             t!(i8x2, i8x4, i8x8, i8x16, i8x32, i8x64 => i8);
@@ -1073,6 +1281,27 @@
 
     #[test]
     #[cfg_attr(miri, ignore)] // Miri is too slow
+    fn test_char() {
+        let mut rng = crate::test::rng(891);
+        let mut max = core::char::from_u32(0).unwrap();
+        for _ in 0..100 {
+            let c = rng.gen_range('A'..='Z');
+            assert!('A' <= c && c <= 'Z');
+            max = max.max(c);
+        }
+        assert_eq!(max, 'Z');
+        let d = Uniform::new(
+            core::char::from_u32(0xD7F0).unwrap(),
+            core::char::from_u32(0xE010).unwrap(),
+        );
+        for _ in 0..100 {
+            let c = d.sample(&mut rng);
+            assert!((c as u32) < 0xD800 || (c as u32) > 0xDFFF);
+        }
+    }
+
+    #[test]
+    #[cfg_attr(miri, ignore)] // Miri is too slow
     fn test_floats() {
         let mut rng = crate::test::rng(252);
         let mut zero_rng = StepRng::new(0, 0);
@@ -1106,7 +1335,8 @@
                             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);
+                            let v = <$ty as SampleUniform>::Sampler
+                                ::sample_single(low, high, &mut rng).extract(lane);
                             assert!(low_scalar <= v && v < high_scalar);
                         }
 
@@ -1117,7 +1347,9 @@
 
                         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_eq!(<$ty as SampleUniform>::Sampler
+                            ::sample_single(low, high, &mut zero_rng)
+                            .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);
 
@@ -1130,7 +1362,9 @@
                                 (-1i64 << $bits_shifted) as u64,
                             );
                             assert!(
-                                lowering_max_rng.gen_range(low, high).extract(lane) < high_scalar
+                                <$ty as SampleUniform>::Sampler
+                                    ::sample_single(low, high, &mut lowering_max_rng)
+                                    .extract(lane) < high_scalar
                             );
                         }
                     }
@@ -1178,7 +1412,7 @@
         use std::panic::catch_unwind;
         fn range<T: SampleUniform>(low: T, high: T) {
             let mut rng = crate::test::rng(253);
-            rng.gen_range(low, high);
+            T::Sampler::sample_single(low, high, &mut rng);
         }
 
         macro_rules! t {
diff --git a/src/distributions/unit_circle.rs b/src/distributions/unit_circle.rs
deleted file mode 100644
index 37885d8..0000000
--- a/src/distributions/unit_circle.rs
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![allow(deprecated)]
-#![allow(clippy::all)]
-
-use crate::distributions::{Distribution, Uniform};
-use crate::Rng;
-
-/// Samples uniformly from the edge of the unit circle in two dimensions.
-///
-/// Implemented via a method by von Neumann[^1].
-///
-/// [^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.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[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<R: Rng + ?Sized>(&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 super::UnitCircle;
-    use crate::distributions::Distribution;
-
-    /// 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 = crate::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 = crate::test::rng(2);
-        let expected = [
-            [-0.9965658683520504, -0.08280380447614634],
-            [-0.9790853270389644, -0.20345004884984505],
-            [-0.8449189758898707, 0.5348943112253227],
-        ];
-        let samples = [
-            UnitCircle.sample(&mut rng),
-            UnitCircle.sample(&mut rng),
-            UnitCircle.sample(&mut rng),
-        ];
-        assert_eq!(samples, expected);
-    }
-}
diff --git a/src/distributions/unit_sphere.rs b/src/distributions/unit_sphere.rs
deleted file mode 100644
index 5b8c8ad..0000000
--- a/src/distributions/unit_sphere.rs
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![allow(deprecated)]
-#![allow(clippy::all)]
-
-use crate::distributions::{Distribution, Uniform};
-use crate::Rng;
-
-/// Samples uniformly from the surface of the unit sphere in three dimensions.
-///
-/// Implemented via a method by Marsaglia[^1].
-///
-/// [^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.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[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<R: Rng + ?Sized>(&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 super::UnitSphereSurface;
-    use crate::distributions::Distribution;
-
-    /// 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 = crate::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 = crate::test::rng(2);
-        let expected = [
-            [0.03247542860231647, -0.7830477442152738, 0.6211131755296027],
-            [-0.09978440840914075, 0.9706650829833128, -0.21875184231323952],
-            [0.2735582468624679, 0.9435374242279655, -0.1868234852870203],
-        ];
-        let samples = [
-            UnitSphereSurface.sample(&mut rng),
-            UnitSphereSurface.sample(&mut rng),
-            UnitSphereSurface.sample(&mut rng),
-        ];
-        assert_eq!(samples, expected);
-    }
-}
diff --git a/src/distributions/utils.rs b/src/distributions/utils.rs
index 2d36b02..e3bceb8 100644
--- a/src/distributions/utils.rs
+++ b/src/distributions/utils.rs
@@ -8,12 +8,10 @@
 
 //! Math helper functions
 
-#[cfg(feature = "std")] use crate::distributions::ziggurat_tables;
-#[cfg(feature = "std")] use crate::Rng;
 #[cfg(feature = "simd_support")] use packed_simd::*;
 
 
-pub trait WideningMultiply<RHS = Self> {
+pub(crate) trait WideningMultiply<RHS = Self> {
     type Output;
 
     fn wmul(self, x: RHS) -> Self::Output;
@@ -145,7 +143,7 @@
 #[cfg(target_pointer_width = "64")]
 wmul_impl_usize! { u64 }
 
-#[cfg(all(feature = "simd_support", feature = "nightly"))]
+#[cfg(feature = "simd_support")]
 mod simd_wmul {
     use super::*;
     #[cfg(target_arch = "x86")] use core::arch::x86::*;
@@ -161,9 +159,8 @@
     }
 
     wmul_impl! { (u16x2, u32x2),, 16 }
-    #[cfg(not(target_feature = "sse2"))]
     wmul_impl! { (u16x4, u32x4),, 16 }
-    #[cfg(not(target_feature = "sse4.2"))]
+    #[cfg(not(target_feature = "sse2"))]
     wmul_impl! { (u16x8, u32x8),, 16 }
     #[cfg(not(target_feature = "avx2"))]
     wmul_impl! { (u16x16, u32x16),, 16 }
@@ -189,8 +186,6 @@
     }
 
     #[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 }
@@ -210,9 +205,6 @@
     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 {
@@ -435,113 +427,3 @@
 #[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<R: Rng + ?Sized, P, Z>(
-    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 crate::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::<f64>() < pdf(x) {
-            return x;
-        }
-    }
-}
diff --git a/src/distributions/weibull.rs b/src/distributions/weibull.rs
deleted file mode 100644
index ffbc93b..0000000
--- a/src/distributions/weibull.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The Weibull distribution.
-#![allow(deprecated)]
-
-use crate::distributions::{Distribution, OpenClosed01};
-use crate::Rng;
-
-/// Samples floating-point numbers according to the Weibull distribution
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[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<f64> for Weibull {
-    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
-        let x: f64 = rng.sample(OpenClosed01);
-        self.scale * (-x.ln()).powf(self.inv_shape)
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::Weibull;
-    use crate::distributions::Distribution;
-
-    #[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 = crate::test::rng(1);
-        for _ in 0..1000 {
-            let r = d.sample(&mut rng);
-            assert!(r >= 0.);
-        }
-    }
-}
diff --git a/src/distributions/weighted.rs b/src/distributions/weighted.rs
new file mode 100644
index 0000000..6dd9273
--- /dev/null
+++ b/src/distributions/weighted.rs
@@ -0,0 +1,48 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Weighted index sampling
+//!
+//! This module is deprecated. Use [`crate::distributions::WeightedIndex`] and
+//! [`crate::distributions::WeightedError`] instead.
+
+pub use super::{WeightedIndex, WeightedError};
+
+#[allow(missing_docs)]
+#[deprecated(since = "0.8.0", note = "moved to rand_distr crate")]
+pub mod alias_method {
+    // This module exists to provide a deprecation warning which minimises
+    // compile errors, but still fails to compile if ever used.
+    use core::marker::PhantomData;
+    use alloc::vec::Vec;
+    use super::WeightedError;
+
+    #[derive(Debug)]
+    pub struct WeightedIndex<W: Weight> {
+        _phantom: PhantomData<W>,
+    }
+    impl<W: Weight> WeightedIndex<W> {
+        pub fn new(_weights: Vec<W>) -> Result<Self, WeightedError> {
+            Err(WeightedError::NoItem)
+        }
+    }
+
+    pub trait Weight {}
+    macro_rules! impl_weight {
+        () => {};
+        ($T:ident, $($more:ident,)*) => {
+            impl Weight for $T {}
+            impl_weight!($($more,)*);
+        };
+    }
+    impl_weight!(f64, f32,);
+    impl_weight!(u8, u16, u32, u64, usize,);
+    impl_weight!(i8, i16, i32, i64, isize,);
+    #[cfg(not(target_os = "emscripten"))]
+    impl_weight!(u128, i128,);
+}
diff --git a/src/distributions/weighted/alias_method.rs b/src/distributions/weighted/alias_method.rs
deleted file mode 100644
index 7d42a35..0000000
--- a/src/distributions/weighted/alias_method.rs
+++ /dev/null
@@ -1,517 +0,0 @@
-//! This module contains an implementation of alias method for sampling random
-//! indices with probabilities proportional to a collection of weights.
-
-use super::WeightedError;
-#[cfg(not(feature = "std"))] use crate::alloc::vec;
-#[cfg(not(feature = "std"))] use crate::alloc::vec::Vec;
-use crate::distributions::uniform::SampleUniform;
-use crate::distributions::Distribution;
-use crate::distributions::Uniform;
-use crate::Rng;
-use core::fmt;
-use core::iter::Sum;
-use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
-
-/// A distribution using weighted sampling to pick a discretely selected item.
-///
-/// Sampling a [`WeightedIndex<W>`] distribution returns the index of a randomly
-/// selected element from the vector used to create the [`WeightedIndex<W>`].
-/// The chance of a given element being picked is proportional to the value of
-/// the element. The weights can have any type `W` for which a implementation of
-/// [`Weight`] exists.
-///
-/// # Performance
-///
-/// Given that `n` is the number of items in the vector used to create an
-/// [`WeightedIndex<W>`], [`WeightedIndex<W>`] will require `O(n)` amount of
-/// memory. More specifically it takes up some constant amount of memory plus
-/// the vector used to create it and a [`Vec<u32>`] with capacity `n`.
-///
-/// Time complexity for the creation of a [`WeightedIndex<W>`] is `O(n)`.
-/// Sampling is `O(1)`, it makes a call to [`Uniform<u32>::sample`] and a call
-/// to [`Uniform<W>::sample`].
-///
-/// # Example
-///
-/// ```
-/// use rand::distributions::weighted::alias_method::WeightedIndex;
-/// use rand::prelude::*;
-///
-/// let choices = vec!['a', 'b', 'c'];
-/// let weights = vec![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).collect()).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);
-/// }
-/// ```
-///
-/// [`WeightedIndex<W>`]: crate::distributions::weighted::alias_method::WeightedIndex
-/// [`Weight`]: crate::distributions::weighted::alias_method::Weight
-/// [`Vec<u32>`]: Vec
-/// [`Uniform<u32>::sample`]: Distribution::sample
-/// [`Uniform<W>::sample`]: Distribution::sample
-pub struct WeightedIndex<W: Weight> {
-    aliases: Vec<u32>,
-    no_alias_odds: Vec<W>,
-    uniform_index: Uniform<u32>,
-    uniform_within_weight_sum: Uniform<W>,
-}
-
-impl<W: Weight> WeightedIndex<W> {
-    /// Creates a new [`WeightedIndex`].
-    ///
-    /// Returns an error if:
-    /// - The vector is empty.
-    /// - The vector is longer than `u32::MAX`.
-    /// - For any weight `w`: `w < 0` or `w > max` where `max = W::MAX /
-    ///   weights.len()`.
-    /// - The sum of weights is zero.
-    pub fn new(weights: Vec<W>) -> Result<Self, WeightedError> {
-        let n = weights.len();
-        if n == 0 {
-            return Err(WeightedError::NoItem);
-        } else if n > ::core::u32::MAX as usize {
-            return Err(WeightedError::TooMany);
-        }
-        let n = n as u32;
-
-        let max_weight_size = W::try_from_u32_lossy(n)
-            .map(|n| W::MAX / n)
-            .unwrap_or(W::ZERO);
-        if !weights
-            .iter()
-            .all(|&w| W::ZERO <= w && w <= max_weight_size)
-        {
-            return Err(WeightedError::InvalidWeight);
-        }
-
-        // The sum of weights will represent 100% of no alias odds.
-        let weight_sum = Weight::sum(weights.as_slice());
-        // Prevent floating point overflow due to rounding errors.
-        let weight_sum = if weight_sum > W::MAX {
-            W::MAX
-        } else {
-            weight_sum
-        };
-        if weight_sum == W::ZERO {
-            return Err(WeightedError::AllWeightsZero);
-        }
-
-        // `weight_sum` would have been zero if `try_from_lossy` causes an error here.
-        let n_converted = W::try_from_u32_lossy(n).unwrap();
-
-        let mut no_alias_odds = weights;
-        for odds in no_alias_odds.iter_mut() {
-            *odds *= n_converted;
-            // Prevent floating point overflow due to rounding errors.
-            *odds = if *odds > W::MAX { W::MAX } else { *odds };
-        }
-
-        /// This struct is designed to contain three data structures at once,
-        /// sharing the same memory. More precisely it contains two linked lists
-        /// and an alias map, which will be the output of this method. To keep
-        /// the three data structures from getting in each other's way, it must
-        /// be ensured that a single index is only ever in one of them at the
-        /// same time.
-        struct Aliases {
-            aliases: Vec<u32>,
-            smalls_head: u32,
-            bigs_head: u32,
-        }
-
-        impl Aliases {
-            fn new(size: u32) -> Self {
-                Aliases {
-                    aliases: vec![0; size as usize],
-                    smalls_head: ::core::u32::MAX,
-                    bigs_head: ::core::u32::MAX,
-                }
-            }
-
-            fn push_small(&mut self, idx: u32) {
-                self.aliases[idx as usize] = self.smalls_head;
-                self.smalls_head = idx;
-            }
-
-            fn push_big(&mut self, idx: u32) {
-                self.aliases[idx as usize] = self.bigs_head;
-                self.bigs_head = idx;
-            }
-
-            fn pop_small(&mut self) -> u32 {
-                let popped = self.smalls_head;
-                self.smalls_head = self.aliases[popped as usize];
-                popped
-            }
-
-            fn pop_big(&mut self) -> u32 {
-                let popped = self.bigs_head;
-                self.bigs_head = self.aliases[popped as usize];
-                popped
-            }
-
-            fn smalls_is_empty(&self) -> bool {
-                self.smalls_head == ::core::u32::MAX
-            }
-
-            fn bigs_is_empty(&self) -> bool {
-                self.bigs_head == ::core::u32::MAX
-            }
-
-            fn set_alias(&mut self, idx: u32, alias: u32) {
-                self.aliases[idx as usize] = alias;
-            }
-        }
-
-        let mut aliases = Aliases::new(n);
-
-        // Split indices into those with small weights and those with big weights.
-        for (index, &odds) in no_alias_odds.iter().enumerate() {
-            if odds < weight_sum {
-                aliases.push_small(index as u32);
-            } else {
-                aliases.push_big(index as u32);
-            }
-        }
-
-        // Build the alias map by finding an alias with big weight for each index with
-        // small weight.
-        while !aliases.smalls_is_empty() && !aliases.bigs_is_empty() {
-            let s = aliases.pop_small();
-            let b = aliases.pop_big();
-
-            aliases.set_alias(s, b);
-            no_alias_odds[b as usize] =
-                no_alias_odds[b as usize] - weight_sum + no_alias_odds[s as usize];
-
-            if no_alias_odds[b as usize] < weight_sum {
-                aliases.push_small(b);
-            } else {
-                aliases.push_big(b);
-            }
-        }
-
-        // The remaining indices should have no alias odds of about 100%. This is due to
-        // numeric accuracy. Otherwise they would be exactly 100%.
-        while !aliases.smalls_is_empty() {
-            no_alias_odds[aliases.pop_small() as usize] = weight_sum;
-        }
-        while !aliases.bigs_is_empty() {
-            no_alias_odds[aliases.pop_big() as usize] = weight_sum;
-        }
-
-        // Prepare distributions for sampling. Creating them beforehand improves
-        // sampling performance.
-        let uniform_index = Uniform::new(0, n);
-        let uniform_within_weight_sum = Uniform::new(W::ZERO, weight_sum);
-
-        Ok(Self {
-            aliases: aliases.aliases,
-            no_alias_odds,
-            uniform_index,
-            uniform_within_weight_sum,
-        })
-    }
-}
-
-impl<W: Weight> Distribution<usize> for WeightedIndex<W> {
-    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
-        let candidate = rng.sample(self.uniform_index);
-        if rng.sample(&self.uniform_within_weight_sum) < self.no_alias_odds[candidate as usize] {
-            candidate as usize
-        } else {
-            self.aliases[candidate as usize] as usize
-        }
-    }
-}
-
-impl<W: Weight> fmt::Debug for WeightedIndex<W>
-where
-    W: fmt::Debug,
-    Uniform<W>: fmt::Debug,
-{
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.debug_struct("WeightedIndex")
-            .field("aliases", &self.aliases)
-            .field("no_alias_odds", &self.no_alias_odds)
-            .field("uniform_index", &self.uniform_index)
-            .field("uniform_within_weight_sum", &self.uniform_within_weight_sum)
-            .finish()
-    }
-}
-
-impl<W: Weight> Clone for WeightedIndex<W>
-where Uniform<W>: Clone
-{
-    fn clone(&self) -> Self {
-        Self {
-            aliases: self.aliases.clone(),
-            no_alias_odds: self.no_alias_odds.clone(),
-            uniform_index: self.uniform_index.clone(),
-            uniform_within_weight_sum: self.uniform_within_weight_sum.clone(),
-        }
-    }
-}
-
-/// Trait that must be implemented for weights, that are used with
-/// [`WeightedIndex`]. Currently no guarantees on the correctness of
-/// [`WeightedIndex`] are given for custom implementations of this trait.
-pub trait Weight:
-    Sized
-    + Copy
-    + SampleUniform
-    + PartialOrd
-    + Add<Output = Self>
-    + AddAssign
-    + Sub<Output = Self>
-    + SubAssign
-    + Mul<Output = Self>
-    + MulAssign
-    + Div<Output = Self>
-    + DivAssign
-    + Sum
-{
-    /// Maximum number representable by `Self`.
-    const MAX: Self;
-
-    /// Element of `Self` equivalent to 0.
-    const ZERO: Self;
-
-    /// Produce an instance of `Self` from a `u32` value, or return `None` if
-    /// out of range. Loss of precision (where `Self` is a floating point type)
-    /// is acceptable.
-    fn try_from_u32_lossy(n: u32) -> Option<Self>;
-
-    /// Sums all values in slice `values`.
-    fn sum(values: &[Self]) -> Self {
-        values.iter().map(|x| *x).sum()
-    }
-}
-
-macro_rules! impl_weight_for_float {
-    ($T: ident) => {
-        impl Weight for $T {
-            const MAX: Self = ::core::$T::MAX;
-            const ZERO: Self = 0.0;
-
-            fn try_from_u32_lossy(n: u32) -> Option<Self> {
-                Some(n as $T)
-            }
-
-            fn sum(values: &[Self]) -> Self {
-                pairwise_sum(values)
-            }
-        }
-    };
-}
-
-/// In comparison to naive accumulation, the pairwise sum algorithm reduces
-/// rounding errors when there are many floating point values.
-fn pairwise_sum<T: Weight>(values: &[T]) -> T {
-    if values.len() <= 32 {
-        values.iter().map(|x| *x).sum()
-    } else {
-        let mid = values.len() / 2;
-        let (a, b) = values.split_at(mid);
-        pairwise_sum(a) + pairwise_sum(b)
-    }
-}
-
-macro_rules! impl_weight_for_int {
-    ($T: ident) => {
-        impl Weight for $T {
-            const MAX: Self = ::core::$T::MAX;
-            const ZERO: Self = 0;
-
-            fn try_from_u32_lossy(n: u32) -> Option<Self> {
-                let n_converted = n as Self;
-                if n_converted >= Self::ZERO && n_converted as u32 == n {
-                    Some(n_converted)
-                } else {
-                    None
-                }
-            }
-        }
-    };
-}
-
-impl_weight_for_float!(f64);
-impl_weight_for_float!(f32);
-impl_weight_for_int!(usize);
-#[cfg(not(target_os = "emscripten"))]
-impl_weight_for_int!(u128);
-impl_weight_for_int!(u64);
-impl_weight_for_int!(u32);
-impl_weight_for_int!(u16);
-impl_weight_for_int!(u8);
-impl_weight_for_int!(isize);
-#[cfg(not(target_os = "emscripten"))]
-impl_weight_for_int!(i128);
-impl_weight_for_int!(i64);
-impl_weight_for_int!(i32);
-impl_weight_for_int!(i16);
-impl_weight_for_int!(i8);
-
-#[cfg(test)]
-mod test {
-    use super::*;
-
-    #[test]
-    #[cfg_attr(miri, ignore)] // Miri is too slow
-    fn test_weighted_index_f32() {
-        test_weighted_index(f32::into);
-
-        // Floating point special cases
-        assert_eq!(
-            WeightedIndex::new(vec![::core::f32::INFINITY]).unwrap_err(),
-            WeightedError::InvalidWeight
-        );
-        assert_eq!(
-            WeightedIndex::new(vec![-0_f32]).unwrap_err(),
-            WeightedError::AllWeightsZero
-        );
-        assert_eq!(
-            WeightedIndex::new(vec![-1_f32]).unwrap_err(),
-            WeightedError::InvalidWeight
-        );
-        assert_eq!(
-            WeightedIndex::new(vec![-::core::f32::INFINITY]).unwrap_err(),
-            WeightedError::InvalidWeight
-        );
-        assert_eq!(
-            WeightedIndex::new(vec![::core::f32::NAN]).unwrap_err(),
-            WeightedError::InvalidWeight
-        );
-    }
-
-    #[cfg(not(target_os = "emscripten"))]
-    #[test]
-    #[cfg_attr(miri, ignore)] // Miri is too slow
-    fn test_weighted_index_u128() {
-        test_weighted_index(|x: u128| x as f64);
-    }
-
-    #[cfg(all(rustc_1_26, not(target_os = "emscripten")))]
-    #[test]
-    #[cfg_attr(miri, ignore)] // Miri is too slow
-    fn test_weighted_index_i128() {
-        test_weighted_index(|x: i128| x as f64);
-
-        // Signed integer special cases
-        assert_eq!(
-            WeightedIndex::new(vec![-1_i128]).unwrap_err(),
-            WeightedError::InvalidWeight
-        );
-        assert_eq!(
-            WeightedIndex::new(vec![::core::i128::MIN]).unwrap_err(),
-            WeightedError::InvalidWeight
-        );
-    }
-
-    #[test]
-    #[cfg_attr(miri, ignore)] // Miri is too slow
-    fn test_weighted_index_u8() {
-        test_weighted_index(u8::into);
-    }
-
-    #[test]
-    #[cfg_attr(miri, ignore)] // Miri is too slow
-    fn test_weighted_index_i8() {
-        test_weighted_index(i8::into);
-
-        // Signed integer special cases
-        assert_eq!(
-            WeightedIndex::new(vec![-1_i8]).unwrap_err(),
-            WeightedError::InvalidWeight
-        );
-        assert_eq!(
-            WeightedIndex::new(vec![::core::i8::MIN]).unwrap_err(),
-            WeightedError::InvalidWeight
-        );
-    }
-
-    fn test_weighted_index<W: Weight, F: Fn(W) -> f64>(w_to_f64: F)
-    where WeightedIndex<W>: fmt::Debug {
-        const NUM_WEIGHTS: u32 = 10;
-        const ZERO_WEIGHT_INDEX: u32 = 3;
-        const NUM_SAMPLES: u32 = 15000;
-        let mut rng = crate::test::rng(0x9c9fa0b0580a7031);
-
-        let weights = {
-            let mut weights = Vec::with_capacity(NUM_WEIGHTS as usize);
-            let random_weight_distribution = crate::distributions::Uniform::new_inclusive(
-                W::ZERO,
-                W::MAX / W::try_from_u32_lossy(NUM_WEIGHTS).unwrap(),
-            );
-            for _ in 0..NUM_WEIGHTS {
-                weights.push(rng.sample(&random_weight_distribution));
-            }
-            weights[ZERO_WEIGHT_INDEX as usize] = W::ZERO;
-            weights
-        };
-        let weight_sum = weights.iter().map(|w| *w).sum::<W>();
-        let expected_counts = weights
-            .iter()
-            .map(|&w| w_to_f64(w) / w_to_f64(weight_sum) * NUM_SAMPLES as f64)
-            .collect::<Vec<f64>>();
-        let weight_distribution = WeightedIndex::new(weights).unwrap();
-
-        let mut counts = vec![0; NUM_WEIGHTS as usize];
-        for _ in 0..NUM_SAMPLES {
-            counts[rng.sample(&weight_distribution)] += 1;
-        }
-
-        assert_eq!(counts[ZERO_WEIGHT_INDEX as usize], 0);
-        for (count, expected_count) in counts.into_iter().zip(expected_counts) {
-            let difference = (count as f64 - expected_count).abs();
-            let max_allowed_difference = NUM_SAMPLES as f64 / NUM_WEIGHTS as f64 * 0.1;
-            assert!(difference <= max_allowed_difference);
-        }
-
-        assert_eq!(
-            WeightedIndex::<W>::new(vec![]).unwrap_err(),
-            WeightedError::NoItem
-        );
-        assert_eq!(
-            WeightedIndex::new(vec![W::ZERO]).unwrap_err(),
-            WeightedError::AllWeightsZero
-        );
-        assert_eq!(
-            WeightedIndex::new(vec![W::MAX, W::MAX]).unwrap_err(),
-            WeightedError::InvalidWeight
-        );
-    }
-
-    #[test]
-    fn value_stability() {
-        fn test_samples<W: Weight>(weights: Vec<W>, buf: &mut [usize], expected: &[usize]) {
-            assert_eq!(buf.len(), expected.len());
-            let distr = WeightedIndex::new(weights).unwrap();
-            let mut rng = crate::test::rng(0x9c9fa0b0580a7031);
-            for r in buf.iter_mut() {
-                *r = rng.sample(&distr);
-            }
-            assert_eq!(buf, expected);
-        }
-
-        let mut buf = [0; 10];
-        test_samples(vec![1i32, 1, 1, 1, 1, 1, 1, 1, 1], &mut buf, &[
-            6, 5, 7, 5, 8, 7, 6, 2, 3, 7,
-        ]);
-        test_samples(vec![0.7f32, 0.1, 0.1, 0.1], &mut buf, &[
-            2, 0, 0, 0, 0, 0, 0, 0, 1, 3,
-        ]);
-        test_samples(vec![1.0f64, 0.999, 0.998, 0.997], &mut buf, &[
-            2, 1, 2, 3, 2, 1, 3, 2, 1, 1,
-        ]);
-    }
-}
diff --git a/src/distributions/weighted/mod.rs b/src/distributions/weighted_index.rs
similarity index 84%
rename from src/distributions/weighted/mod.rs
rename to src/distributions/weighted_index.rs
index 357e3a9..07ba53e 100644
--- a/src/distributions/weighted/mod.rs
+++ b/src/distributions/weighted_index.rs
@@ -7,16 +7,6 @@
 // except according to those terms.
 
 //! Weighted index sampling
-//!
-//! This module provides two implementations for sampling indices:
-//!
-//! *   [`WeightedIndex`] allows `O(log N)` sampling
-//! *   [`alias_method::WeightedIndex`] allows `O(1)` sampling, but with
-//!      much greater set-up cost
-//!      
-//! [`alias_method::WeightedIndex`]: alias_method/struct.WeightedIndex.html
-
-pub mod alias_method;
 
 use crate::distributions::uniform::{SampleBorrow, SampleUniform, UniformSampler};
 use crate::distributions::Distribution;
@@ -25,10 +15,12 @@
 use core::fmt;
 
 // Note that this whole module is only imported if feature="alloc" is enabled.
-#[cfg(not(feature = "std"))] use crate::alloc::vec::Vec;
+use alloc::vec::Vec;
 
-/// A distribution using weighted sampling to pick a discretely selected
-/// item.
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
+
+/// A distribution using weighted sampling of discrete items
 ///
 /// Sampling a `WeightedIndex` distribution returns the index of a randomly
 /// selected element from the iterator used when the `WeightedIndex` was
@@ -38,6 +30,11 @@
 ///
 /// # Performance
 ///
+/// Time complexity of sampling from `WeightedIndex` is `O(log N)` where
+/// `N` is the number of weights. As an alternative,
+/// [`rand_distr::weighted_alias`](https://docs.rs/rand_distr/*/rand_distr/weighted_alias/index.html)
+/// supports `O(1)` sampling, but with much higher initialisation cost.
+///
 /// A `WeightedIndex<X>` contains a `Vec<X>` and a [`Uniform<X>`] and so its
 /// size is the sum of the size of those objects, possibly plus some alignment.
 ///
@@ -46,15 +43,12 @@
 /// `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<X>`] doesn't allocate any memory.
-///
-/// Time complexity of sampling from `WeightedIndex` is `O(log N)` where
-/// `N` is the number of weights.
+/// types, [`Uniform<X>`] doesn't allocate any memory.
 ///
 /// Sampling from `WeightedIndex` will result in a single call to
 /// `Uniform<X>::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<X>::sample`.
+/// exact number depends on the implementation of `Uniform<X>::sample`.
 ///
 /// # Example
 ///
@@ -79,9 +73,11 @@
 /// }
 /// ```
 ///
-/// [`Uniform<X>`]: crate::distributions::uniform::Uniform
+/// [`Uniform<X>`]: crate::distributions::Uniform
 /// [`RngCore`]: crate::RngCore
 #[derive(Debug, Clone)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
 pub struct WeightedIndex<X: SampleUniform + PartialOrd> {
     cumulative_weights: Vec<X>,
     total_weight: X,
@@ -107,13 +103,15 @@
         let mut total_weight: X = iter.next().ok_or(WeightedError::NoItem)?.borrow().clone();
 
         let zero = <X as Default>::default();
-        if total_weight < zero {
+        if !(total_weight >= zero) {
             return Err(WeightedError::InvalidWeight);
         }
 
         let mut weights = Vec::<X>::with_capacity(iter.size_hint().0);
         for w in iter {
-            if *w.borrow() < zero {
+            // Note that `!(w >= x)` is not equivalent to `w < x` for partially
+            // ordered types due to NaNs which are equal to nothing.
+            if !(w.borrow() >= &zero) {
                 return Err(WeightedError::InvalidWeight);
             }
             weights.push(total_weight.clone());
@@ -163,10 +161,10 @@
                     return Err(WeightedError::InvalidWeight);
                 }
             }
-            if *w < zero {
+            if !(*w >= zero) {
                 return Err(WeightedError::InvalidWeight);
             }
-            if i >= self.cumulative_weights.len() + 1 {
+            if i > self.cumulative_weights.len() {
                 return Err(WeightedError::TooMany);
             }
 
@@ -183,7 +181,7 @@
             total_weight += w;
             prev_i = Some(i);
         }
-        if total_weight == zero {
+        if total_weight <= zero {
             return Err(WeightedError::AllWeightsZero);
         }
 
@@ -245,6 +243,47 @@
 mod test {
     use super::*;
 
+    #[cfg(feature = "serde1")]
+    #[test]
+    fn test_weightedindex_serde1() {
+        let weighted_index = WeightedIndex::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).unwrap();
+
+        let ser_weighted_index = bincode::serialize(&weighted_index).unwrap();
+        let de_weighted_index: WeightedIndex<i32> =
+            bincode::deserialize(&ser_weighted_index).unwrap();
+
+        assert_eq!(
+            de_weighted_index.cumulative_weights,
+            weighted_index.cumulative_weights
+        );
+        assert_eq!(de_weighted_index.total_weight, weighted_index.total_weight);
+    }
+
+    #[test]
+    fn test_accepting_nan(){
+        assert_eq!(
+            WeightedIndex::new(&[core::f32::NAN, 0.5]).unwrap_err(),
+            WeightedError::InvalidWeight,
+        );
+        assert_eq!(
+            WeightedIndex::new(&[core::f32::NAN]).unwrap_err(),
+            WeightedError::InvalidWeight,
+        );
+        assert_eq!(
+            WeightedIndex::new(&[0.5, core::f32::NAN]).unwrap_err(),
+            WeightedError::InvalidWeight,
+        );
+
+        assert_eq!(
+            WeightedIndex::new(&[0.5, 7.0])
+                .unwrap()
+                .update_weights(&[(0, &core::f32::NAN)])
+                .unwrap_err(),
+            WeightedError::InvalidWeight,
+        )
+    }
+
+
     #[test]
     #[cfg_attr(miri, ignore)] // Miri is too slow
     fn test_weightedindex() {
@@ -382,13 +421,14 @@
 }
 
 /// Error type returned from `WeightedIndex::new`.
+#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub enum WeightedError {
     /// The provided weight collection contains no items.
     NoItem,
 
-    /// A weight is either less than zero, greater than the supported maximum or
-    /// otherwise invalid.
+    /// A weight is either less than zero, greater than the supported maximum,
+    /// NaN, or otherwise invalid.
     InvalidWeight,
 
     /// All items in the provided weight collection are zero.
diff --git a/src/distributions/ziggurat_tables.rs b/src/distributions/ziggurat_tables.rs
deleted file mode 100644
index f830a60..0000000
--- a/src/distributions/ziggurat_tables.rs
+++ /dev/null
@@ -1,283 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2013 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, 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;
-#[rustfmt::skip]
-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];
-#[rustfmt::skip]
-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;
-#[rustfmt::skip]
-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];
-#[rustfmt::skip]
-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/src/lib.rs b/src/lib.rs
index d42a79f..8bf7a9d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -37,7 +37,7 @@
 //!
 //! # The Book
 //!
-//! For the user guide and futher documentation, please read
+//! For the user guide and further documentation, please read
 //! [The Rust Rand Book](https://rust-random.github.io/book).
 
 #![doc(
@@ -48,15 +48,17 @@
 #![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 = "simd_support", feature = "nightly"), feature(stdsimd))]
+#![no_std]
+#![cfg_attr(feature = "simd_support", feature(stdsimd))]
+#![cfg_attr(feature = "nightly", feature(slice_partition_at_index))]
+#![cfg_attr(doc_cfg, feature(doc_cfg))]
 #![allow(
-    clippy::excessive_precision,
-    clippy::unreadable_literal,
-    clippy::float_cmp
+    clippy::float_cmp,
+    clippy::neg_cmp_op_on_partial_ord,
 )]
 
-#[cfg(all(feature = "alloc", not(feature = "std")))] extern crate alloc;
+#[cfg(feature = "std")] extern crate std;
+#[cfg(feature = "alloc")] extern crate alloc;
 
 #[allow(unused)]
 macro_rules! trace { ($($x:tt)*) => (
@@ -92,418 +94,20 @@
 // Re-exports from rand_core
 pub use rand_core::{CryptoRng, Error, RngCore, SeedableRng};
 
-// Public exports
-#[cfg(feature = "std")] pub use crate::rngs::thread::thread_rng;
-
 // Public modules
 pub mod distributions;
 pub mod prelude;
+mod rng;
 pub mod rngs;
 pub mod seq;
 
+// Public exports
+#[cfg(all(feature = "std", feature = "std_rng"))]
+pub use crate::rngs::thread::thread_rng;
+pub use rng::{Fill, Rng};
 
-use crate::distributions::uniform::{SampleBorrow, SampleUniform, UniformSampler};
+#[cfg(all(feature = "std", feature = "std_rng"))]
 use crate::distributions::{Distribution, Standard};
-use core::num::Wrapping;
-use core::{mem, slice};
-
-/// An automatically-implemented extension trait on [`RngCore`] providing high-level
-/// generic methods for sampling values and other convenience methods.
-///
-/// This is the primary trait to use when generating random values.
-///
-/// # Generic usage
-///
-/// The basic pattern is `fn foo<R: Rng + ?Sized>(rng: &mut R)`. Some
-/// things are worth noting here:
-///
-/// - Since `Rng: RngCore` and every `RngCore` implements `Rng`, it makes no
-///   difference whether we use `R: Rng` or `R: RngCore`.
-/// - The `+ ?Sized` un-bounding allows functions to be called directly on
-///   type-erased references; i.e. `foo(r)` where `r: &mut RngCore`. Without
-///   this it would be necessary to write `foo(&mut r)`.
-///
-/// An alternative pattern is possible: `fn foo<R: Rng>(rng: R)`. This has some
-/// trade-offs. It allows the argument to be consumed directly without a `&mut`
-/// (which is how `from_rng(thread_rng())` works); also it still works directly
-/// 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.
-///
-/// Example:
-///
-/// ```
-/// # use rand::thread_rng;
-/// use rand::Rng;
-///
-/// fn foo<R: Rng + ?Sized>(rng: &mut R) -> f32 {
-///     rng.gen()
-/// }
-///
-/// # let v = foo(&mut thread_rng());
-/// ```
-pub trait Rng: RngCore {
-    /// Return a random value supporting the [`Standard`] distribution.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use rand::{thread_rng, Rng};
-    ///
-    /// let mut rng = thread_rng();
-    /// let x: u32 = rng.gen();
-    /// println!("{}", x);
-    /// println!("{:?}", rng.gen::<(f64, bool)>());
-    /// ```
-    ///
-    /// # Arrays and tuples
-    ///
-    /// The `rng.gen()` method is able to generate arrays (up to 32 elements)
-    /// and tuples (up to 12 elements), so long as all element types can be
-    /// generated.
-    ///
-    /// For arrays of integers, especially for those with small element types
-    /// (< 64 bit), it will likely be faster to instead use [`Rng::fill`].
-    ///
-    /// ```
-    /// use rand::{thread_rng, Rng};
-    ///
-    /// let mut rng = thread_rng();
-    /// let tuple: (u8, i32, char) = rng.gen(); // arbitrary tuple support
-    ///
-    /// let arr1: [f32; 32] = rng.gen();        // array construction
-    /// let mut arr2 = [0u8; 128];
-    /// rng.fill(&mut arr2);                    // array fill
-    /// ```
-    ///
-    /// [`Standard`]: distributions::Standard
-    #[inline]
-    fn gen<T>(&mut self) -> T
-    where Standard: Distribution<T> {
-        Standard.sample(self)
-    }
-
-    /// Generate a random value in the range [`low`, `high`), i.e. inclusive of
-    /// `low` and exclusive of `high`.
-    ///
-    /// 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
-    ///
-    /// Panics if `low >= high`.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// 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);
-    /// ```
-    ///
-    /// [`Uniform`]: distributions::uniform::Uniform
-    fn gen_range<T: SampleUniform, B1, B2>(&mut self, low: B1, high: B2) -> T
-    where
-        B1: SampleBorrow<T> + Sized,
-        B2: SampleBorrow<T> + Sized,
-    {
-        T::Sampler::sample_single(low, high, self)
-    }
-
-    /// 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::<u16, _>(Uniform::new(10, 15));
-    /// ```
-    fn sample<T, D: Distribution<T>>(&mut self, distr: D) -> T {
-        distr.sample(self)
-    }
-
-    /// Create an iterator that generates values using the given distribution.
-    ///
-    /// Note that this function takes its arguments by value. This works since
-    /// `(&mut R): Rng where R: Rng` and
-    /// `(&D): Distribution where D: Distribution`,
-    /// however borrowing is not automatic hence `rng.sample_iter(...)` may
-    /// need to be replaced with `(&mut rng).sample_iter(...)`.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use rand::{thread_rng, Rng};
-    /// use rand::distributions::{Alphanumeric, Uniform, Standard};
-    ///
-    /// let rng = thread_rng();
-    ///
-    /// // Vec of 16 x f32:
-    /// let v: Vec<f32> = rng.sample_iter(Standard).take(16).collect();
-    ///
-    /// // String:
-    /// let s: String = rng.sample_iter(Alphanumeric).take(7).collect();
-    ///
-    /// // Combined values
-    /// println!("{:?}", rng.sample_iter(Standard).take(5)
-    ///                              .collect::<Vec<(f64, bool)>>());
-    ///
-    /// // 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<T, D>(self, distr: D) -> distributions::DistIter<D, Self, T>
-    where
-        D: Distribution<T>,
-        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<T: AsByteSliceMut + ?Sized>(&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 is identical to [`fill`] except that it uses [`try_fill_bytes`]
-    /// internally and forwards RNG errors.
-    ///
-    /// # 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<T: AsByteSliceMut + ?Sized>(&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_bool(1.0 / 3.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).unwrap();
-        self.sample(d)
-    }
-
-    /// 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
-    ///
-    /// ```
-    /// use rand::{thread_rng, Rng};
-    ///
-    /// let mut rng = thread_rng();
-    /// println!("{}", rng.gen_ratio(2, 3));
-    /// ```
-    ///
-    /// [`Bernoulli`]: distributions::bernoulli::Bernoulli
-    #[inline]
-    fn gen_ratio(&mut self, numerator: u32, denominator: u32) -> bool {
-        let d = distributions::Bernoulli::from_ratio(numerator, denominator).unwrap();
-        self.sample(d)
-    }
-}
-
-impl<R: RngCore + ?Sized> Rng for R {}
-
-/// 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];
-
-    /// Call `to_le` on each element (i.e. byte-swap on Big Endian platforms).
-    fn to_le(&mut self);
-}
-
-impl AsByteSliceMut for [u8] {
-    fn as_byte_slice_mut(&mut self) -> &mut [u8] {
-        self
-    }
-
-    fn to_le(&mut self) {}
-}
-
-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(self.as_mut_ptr()
-                            as *mut u8,
-                            self.len() * mem::size_of::<$t>()
-                        )
-                    }
-                }
-            }
-
-            fn to_le(&mut self) {
-                for x in self {
-                    *x = x.to_le();
-                }
-            }
-        }
-
-        impl AsByteSliceMut for [Wrapping<$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(self.as_mut_ptr()
-                            as *mut u8,
-                            self.len() * mem::size_of::<$t>()
-                        )
-                    }
-                }
-            }
-
-            fn to_le(&mut self) {
-                for x in self {
-                    *x = Wrapping(x.0.to_le());
-                }
-            }
-        }
-    };
-    ($t:ty, $($tt:ty,)*) => {
-        impl_as_byte_slice!($t);
-        // TODO: this could replace above impl once Rust #32463 is fixed
-        // impl_as_byte_slice!(Wrapping<$t>);
-        impl_as_byte_slice!($($tt,)*);
-    }
-}
-
-impl_as_byte_slice!(u16, u32, u64, usize,);
-#[cfg(not(target_os = "emscripten"))]
-impl_as_byte_slice!(u128);
-impl_as_byte_slice!(i8, i16, i32, i64, isize,);
-#[cfg(not(target_os = "emscripten"))]
-impl_as_byte_slice!(i128);
-
-macro_rules! impl_as_byte_slice_arrays {
-    ($n:expr,) => {};
-    ($n:expr, $N:ident) => {
-        impl<T> AsByteSliceMut for [T; $n] where [T]: AsByteSliceMut {
-            fn as_byte_slice_mut(&mut self) -> &mut [u8] {
-                self[..].as_byte_slice_mut()
-            }
-
-            fn to_le(&mut self) {
-                self[..].to_le()
-            }
-        }
-    };
-    ($n:expr, $N:ident, $($NN:ident,)*) => {
-        impl_as_byte_slice_arrays!($n, $N);
-        impl_as_byte_slice_arrays!($n - 1, $($NN,)*);
-    };
-    (!div $n:expr,) => {};
-    (!div $n:expr, $N:ident, $($NN:ident,)*) => {
-        impl_as_byte_slice_arrays!($n, $N);
-        impl_as_byte_slice_arrays!(!div $n / 2, $($NN,)*);
-    };
-}
-#[rustfmt::skip]
-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,);
 
 /// Generates a random value using the thread-local random number generator.
 ///
@@ -511,6 +115,33 @@
 /// documentation of the entropy source and [`Standard`] for documentation of
 /// distributions and type-specific generation.
 ///
+/// # Provided implementations
+///
+/// The following types have provided implementations that
+/// 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<T>`), besides the type identical to their
+///   normal integer variants.
+///
+/// Also supported is the generation of the following
+/// compound types where all component types are supported:
+///
+/// *   Tuples (up to 12 elements): each element is generated sequentially.
+/// *   Arrays (up to 32 elements): each element is generated sequentially;
+///     see also [`Rng::fill`] which supports arbitrary array length for integer
+///     types and tends to be faster for `u32` and smaller types.
+/// *   `Option<T>` first generates a `bool`, and if true generates and returns
+///     `Some(value)` where `value: T`, otherwise returning `None`.
+///
 /// # Examples
 ///
 /// ```
@@ -547,7 +178,8 @@
 /// ```
 ///
 /// [`Standard`]: distributions::Standard
-#[cfg(feature = "std")]
+#[cfg(all(feature = "std", feature = "std_rng"))]
+#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", feature = "std_rng"))))]
 #[inline]
 pub fn random<T>() -> T
 where Standard: Distribution<T> {
@@ -557,8 +189,6 @@
 #[cfg(test)]
 mod test {
     use super::*;
-    use crate::rngs::mock::StepRng;
-    #[cfg(all(not(feature = "std"), feature = "alloc"))] use alloc::boxed::Box;
 
     /// Construct a deterministic RNG with the given seed
     pub fn rng(seed: u64) -> impl RngCore {
@@ -569,126 +199,7 @@
     }
 
     #[test]
-    fn test_fill_bytes_default() {
-        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 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() {
-                if byte == 0 {
-                    panic!("byte {} of {} is zero", i, n)
-                }
-            }
-        }
-    }
-
-    #[test]
-    fn test_fill() {
-        let x = 9041086907909331047; // a random u64
-        let mut rng = StepRng::new(x, 0);
-
-        // Convert to byte sequence and back to u64; byte-swap twice if BE.
-        let mut array = [0u64; 2];
-        rng.fill(&mut array[..]);
-        assert_eq!(array, [x, x]);
-        assert_eq!(rng.next_u64(), x);
-
-        // Convert to bytes then u32 in LE order
-        let mut array = [0u32; 2];
-        rng.fill(&mut array[..]);
-        assert_eq!(array, [x as u32, (x >> 32) as u32]);
-        assert_eq!(rng.next_u32(), x as u32);
-
-        // Check equivalence using wrapped arrays
-        let mut warray = [Wrapping(0u32); 2];
-        rng.fill(&mut warray[..]);
-        assert_eq!(array[0], warray[0].0);
-        assert_eq!(array[1], warray[1].0);
-    }
-
-    #[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(-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 = rng(102);
-        r.gen_range(5, -2);
-    }
-
-    #[test]
-    #[should_panic]
-    fn test_gen_range_panic_usize() {
-        let mut r = rng(103);
-        r.gen_range(5, 2);
-    }
-
-    #[test]
-    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() {
-        use crate::distributions::{Distribution, Standard};
-        let mut rng = rng(109);
-        let mut r = &mut rng as &mut dyn RngCore;
-        r.next_u32();
-        r.gen::<i32>();
-        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 crate::distributions::{Distribution, Standard};
-        let rng = rng(110);
-        let mut r = Box::new(rng) as Box<dyn RngCore>;
-        r.next_u32();
-        r.gen::<i32>();
-        assert_eq!(r.gen_range(0, 1), 0);
-        let _c: u8 = Standard.sample(&mut r);
-    }
-
-    #[test]
-    #[cfg(feature = "std")]
+    #[cfg(all(feature = "std", feature = "std_rng"))]
     fn test_random() {
         // not sure how to test this aside from just getting some values
         let _n: usize = random();
@@ -701,23 +212,4 @@
             (f32, (f64, (f64,))),
         ) = random();
     }
-
-    #[test]
-    #[cfg_attr(miri, ignore)] // Miri is too slow
-    fn test_gen_ratio_average() {
-        const NUM: u32 = 3;
-        const DENOM: u32 = 10;
-        const N: u32 = 100_000;
-
-        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/src/prelude.rs b/src/prelude.rs
index 98ae3bb..51c457e 100644
--- a/src/prelude.rs
+++ b/src/prelude.rs
@@ -22,12 +22,13 @@
 #[cfg(feature = "small_rng")]
 #[doc(no_inline)]
 pub use crate::rngs::SmallRng;
+#[cfg(feature = "std_rng")]
 #[doc(no_inline)] pub use crate::rngs::StdRng;
 #[doc(no_inline)]
-#[cfg(feature = "std")]
+#[cfg(all(feature = "std", feature = "std_rng"))]
 pub use crate::rngs::ThreadRng;
 #[doc(no_inline)] pub use crate::seq::{IteratorRandom, SliceRandom};
 #[doc(no_inline)]
-#[cfg(feature = "std")]
+#[cfg(all(feature = "std", feature = "std_rng"))]
 pub use crate::{random, thread_rng};
 #[doc(no_inline)] pub use crate::{CryptoRng, Rng, RngCore, SeedableRng};
diff --git a/src/rng.rs b/src/rng.rs
new file mode 100644
index 0000000..bb977a5
--- /dev/null
+++ b/src/rng.rs
@@ -0,0 +1,585 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2013-2017 The Rust Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! [`Rng`] trait
+
+use rand_core::{Error, RngCore};
+use crate::distributions::uniform::{SampleRange, SampleUniform};
+use crate::distributions::{self, Distribution, Standard};
+use core::num::Wrapping;
+use core::{mem, slice};
+
+/// An automatically-implemented extension trait on [`RngCore`] providing high-level
+/// generic methods for sampling values and other convenience methods.
+///
+/// This is the primary trait to use when generating random values.
+///
+/// # Generic usage
+///
+/// The basic pattern is `fn foo<R: Rng + ?Sized>(rng: &mut R)`. Some
+/// things are worth noting here:
+///
+/// - Since `Rng: RngCore` and every `RngCore` implements `Rng`, it makes no
+///   difference whether we use `R: Rng` or `R: RngCore`.
+/// - The `+ ?Sized` un-bounding allows functions to be called directly on
+///   type-erased references; i.e. `foo(r)` where `r: &mut RngCore`. Without
+///   this it would be necessary to write `foo(&mut r)`.
+///
+/// An alternative pattern is possible: `fn foo<R: Rng>(rng: R)`. This has some
+/// trade-offs. It allows the argument to be consumed directly without a `&mut`
+/// (which is how `from_rng(thread_rng())` works); also it still works directly
+/// 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.
+///
+/// Example:
+///
+/// ```
+/// # use rand::thread_rng;
+/// use rand::Rng;
+///
+/// fn foo<R: Rng + ?Sized>(rng: &mut R) -> f32 {
+///     rng.gen()
+/// }
+///
+/// # let v = foo(&mut thread_rng());
+/// ```
+pub trait Rng: RngCore {
+    /// Return a random value supporting the [`Standard`] distribution.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use rand::{thread_rng, Rng};
+    ///
+    /// let mut rng = thread_rng();
+    /// let x: u32 = rng.gen();
+    /// println!("{}", x);
+    /// println!("{:?}", rng.gen::<(f64, bool)>());
+    /// ```
+    ///
+    /// # Arrays and tuples
+    ///
+    /// The `rng.gen()` method is able to generate arrays (up to 32 elements)
+    /// and tuples (up to 12 elements), so long as all element types can be
+    /// generated.
+    ///
+    /// For arrays of integers, especially for those with small element types
+    /// (< 64 bit), it will likely be faster to instead use [`Rng::fill`].
+    ///
+    /// ```
+    /// use rand::{thread_rng, Rng};
+    ///
+    /// let mut rng = thread_rng();
+    /// let tuple: (u8, i32, char) = rng.gen(); // arbitrary tuple support
+    ///
+    /// let arr1: [f32; 32] = rng.gen();        // array construction
+    /// let mut arr2 = [0u8; 128];
+    /// rng.fill(&mut arr2);                    // array fill
+    /// ```
+    ///
+    /// [`Standard`]: distributions::Standard
+    #[inline]
+    fn gen<T>(&mut self) -> T
+    where Standard: Distribution<T> {
+        Standard.sample(self)
+    }
+
+    /// Generate a random value in the given range.
+    ///
+    /// 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.
+    ///
+    /// Only `gen_range(low..high)` and `gen_range(low..=high)` are supported.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the range is empty.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use rand::{thread_rng, Rng};
+    ///
+    /// let mut rng = thread_rng();
+    ///
+    /// // Exclusive range
+    /// let n: u32 = rng.gen_range(0..10);
+    /// println!("{}", n);
+    /// let m: f64 = rng.gen_range(-40.0..1.3e5);
+    /// println!("{}", m);
+    ///
+    /// // Inclusive range
+    /// let n: u32 = rng.gen_range(0..=10);
+    /// println!("{}", n);
+    /// ```
+    ///
+    /// [`Uniform`]: distributions::uniform::Uniform
+    fn gen_range<T, R>(&mut self, range: R) -> T
+    where
+        T: SampleUniform,
+        R: SampleRange<T>
+    {
+        assert!(!range.is_empty(), "cannot sample empty range");
+        range.sample_single(self)
+    }
+
+    /// 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::<u16, _>(Uniform::new(10, 15));
+    /// ```
+    fn sample<T, D: Distribution<T>>(&mut self, distr: D) -> T {
+        distr.sample(self)
+    }
+
+    /// Create an iterator that generates values using the given distribution.
+    ///
+    /// Note that this function takes its arguments by value. This works since
+    /// `(&mut R): Rng where R: Rng` and
+    /// `(&D): Distribution where D: Distribution`,
+    /// however borrowing is not automatic hence `rng.sample_iter(...)` may
+    /// need to be replaced with `(&mut rng).sample_iter(...)`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use rand::{thread_rng, Rng};
+    /// use rand::distributions::{Alphanumeric, Uniform, Standard};
+    ///
+    /// let mut rng = thread_rng();
+    ///
+    /// // Vec of 16 x f32:
+    /// let v: Vec<f32> = (&mut rng).sample_iter(Standard).take(16).collect();
+    ///
+    /// // String:
+    /// let s: String = (&mut rng).sample_iter(Alphanumeric)
+    ///     .take(7)
+    ///     .map(char::from)
+    ///     .collect();
+    ///
+    /// // Combined values
+    /// println!("{:?}", (&mut rng).sample_iter(Standard).take(5)
+    ///                              .collect::<Vec<(f64, bool)>>());
+    ///
+    /// // Dice-rolling:
+    /// let die_range = Uniform::new_inclusive(1, 6);
+    /// let mut roll_die = (&mut rng).sample_iter(die_range);
+    /// while roll_die.next().unwrap() != 6 {
+    ///     println!("Not a 6; rolling again!");
+    /// }
+    /// ```
+    fn sample_iter<T, D>(self, distr: D) -> distributions::DistIter<D, Self, T>
+    where
+        D: Distribution<T>,
+        Self: Sized,
+    {
+        distr.sample_iter(self)
+    }
+
+    /// Fill any type implementing [`Fill`] with random data
+    ///
+    /// The distribution is expected to be uniform with portable results, but
+    /// this cannot be guaranteed for third-party implementations.
+    ///
+    /// This is identical to [`try_fill`] except that it panics on error.
+    ///
+    /// # 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<T: Fill + ?Sized>(&mut self, dest: &mut T) {
+        dest.try_fill(self).unwrap_or_else(|_| panic!("Rng::fill failed"))
+    }
+
+    /// Fill any type implementing [`Fill`] with random data
+    ///
+    /// The distribution is expected to be uniform with portable results, but
+    /// this cannot be guaranteed for third-party implementations.
+    ///
+    /// This is identical to [`fill`] except that it forwards errors.
+    ///
+    /// # 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<T: Fill + ?Sized>(&mut self, dest: &mut T) -> Result<(), Error> {
+        dest.try_fill(self)
+    }
+
+    /// 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_bool(1.0 / 3.0));
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// If `p < 0` or `p > 1`.
+    ///
+    /// [`Bernoulli`]: distributions::Bernoulli
+    #[inline]
+    fn gen_bool(&mut self, p: f64) -> bool {
+        let d = distributions::Bernoulli::new(p).unwrap();
+        self.sample(d)
+    }
+
+    /// 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
+    ///
+    /// ```
+    /// use rand::{thread_rng, Rng};
+    ///
+    /// let mut rng = thread_rng();
+    /// println!("{}", rng.gen_ratio(2, 3));
+    /// ```
+    ///
+    /// [`Bernoulli`]: distributions::Bernoulli
+    #[inline]
+    fn gen_ratio(&mut self, numerator: u32, denominator: u32) -> bool {
+        let d = distributions::Bernoulli::from_ratio(numerator, denominator).unwrap();
+        self.sample(d)
+    }
+}
+
+impl<R: RngCore + ?Sized> Rng for R {}
+
+/// Types which may be filled with random data
+///
+/// This trait allows arrays to be efficiently filled with random data.
+///
+/// Implementations are expected to be portable across machines unless
+/// clearly documented otherwise (see the
+/// [Chapter on Portability](https://rust-random.github.io/book/portability.html)).
+pub trait Fill {
+    /// Fill self with random data
+    fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error>;
+}
+
+macro_rules! impl_fill_each {
+    () => {};
+    ($t:ty) => {
+        impl Fill for [$t] {
+            fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
+                for elt in self.iter_mut() {
+                    *elt = rng.gen();
+                }
+                Ok(())
+            }
+        }
+    };
+    ($t:ty, $($tt:ty,)*) => {
+        impl_fill_each!($t);
+        impl_fill_each!($($tt,)*);
+    };
+}
+
+impl_fill_each!(bool, char, f32, f64,);
+
+impl Fill for [u8] {
+    fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
+        rng.try_fill_bytes(self)
+    }
+}
+
+macro_rules! impl_fill {
+    () => {};
+    ($t:ty) => {
+        impl Fill for [$t] {
+            #[inline(never)] // in micro benchmarks, this improves performance
+            fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
+                if self.len() > 0 {
+                    rng.try_fill_bytes(unsafe {
+                        slice::from_raw_parts_mut(self.as_mut_ptr()
+                            as *mut u8,
+                            self.len() * mem::size_of::<$t>()
+                        )
+                    })?;
+                    for x in self {
+                        *x = x.to_le();
+                    }
+                }
+                Ok(())
+            }
+        }
+
+        impl Fill for [Wrapping<$t>] {
+            #[inline(never)]
+            fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
+                if self.len() > 0 {
+                    rng.try_fill_bytes(unsafe {
+                        slice::from_raw_parts_mut(self.as_mut_ptr()
+                            as *mut u8,
+                            self.len() * mem::size_of::<$t>()
+                        )
+                    })?;
+                    for x in self {
+                    *x = Wrapping(x.0.to_le());
+                    }
+                }
+                Ok(())
+            }
+        }
+    };
+    ($t:ty, $($tt:ty,)*) => {
+        impl_fill!($t);
+        // TODO: this could replace above impl once Rust #32463 is fixed
+        // impl_fill!(Wrapping<$t>);
+        impl_fill!($($tt,)*);
+    }
+}
+
+impl_fill!(u16, u32, u64, usize,);
+#[cfg(not(target_os = "emscripten"))]
+impl_fill!(u128);
+impl_fill!(i8, i16, i32, i64, isize,);
+#[cfg(not(target_os = "emscripten"))]
+impl_fill!(i128);
+
+macro_rules! impl_fill_arrays {
+    ($n:expr,) => {};
+    ($n:expr, $N:ident) => {
+        impl<T> Fill for [T; $n] where [T]: Fill {
+            fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
+                self[..].try_fill(rng)
+            }
+        }
+    };
+    ($n:expr, $N:ident, $($NN:ident,)*) => {
+        impl_fill_arrays!($n, $N);
+        impl_fill_arrays!($n - 1, $($NN,)*);
+    };
+    (!div $n:expr,) => {};
+    (!div $n:expr, $N:ident, $($NN:ident,)*) => {
+        impl_fill_arrays!($n, $N);
+        impl_fill_arrays!(!div $n / 2, $($NN,)*);
+    };
+}
+#[rustfmt::skip]
+impl_fill_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_fill_arrays!(!div 4096, N,N,N,N,N,N,N,);
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use crate::test::rng;
+    use crate::rngs::mock::StepRng;
+    #[cfg(feature = "alloc")] use alloc::boxed::Box;
+
+    #[test]
+    fn test_fill_bytes_default() {
+        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 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() {
+                if byte == 0 {
+                    panic!("byte {} of {} is zero", i, n)
+                }
+            }
+        }
+    }
+
+    #[test]
+    fn test_fill() {
+        let x = 9041086907909331047; // a random u64
+        let mut rng = StepRng::new(x, 0);
+
+        // Convert to byte sequence and back to u64; byte-swap twice if BE.
+        let mut array = [0u64; 2];
+        rng.fill(&mut array[..]);
+        assert_eq!(array, [x, x]);
+        assert_eq!(rng.next_u64(), x);
+
+        // Convert to bytes then u32 in LE order
+        let mut array = [0u32; 2];
+        rng.fill(&mut array[..]);
+        assert_eq!(array, [x as u32, (x >> 32) as u32]);
+        assert_eq!(rng.next_u32(), x as u32);
+
+        // Check equivalence using wrapped arrays
+        let mut warray = [Wrapping(0u32); 2];
+        rng.fill(&mut warray[..]);
+        assert_eq!(array[0], warray[0].0);
+        assert_eq!(array[1], warray[1].0);
+
+        // Check equivalence for generated floats
+        let mut array = [0f32; 2];
+        rng.fill(&mut array);
+        let gen: [f32; 2] = rng.gen();
+        assert_eq!(array, gen);
+    }
+
+    #[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_int() {
+        let mut r = rng(101);
+        for _ in 0..1000 {
+            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: u16 = r.gen_range(10..99);
+            assert!(a >= 10u16 && a < 99u16);
+            let a = r.gen_range(-100i32..2000);
+            assert!(a >= -100i32 && a < 2000i32);
+            let a: u32 = r.gen_range(12..=24);
+            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]
+    fn test_gen_range_float() {
+        let mut r = rng(101);
+        for _ in 0..1000 {
+            let a = r.gen_range(-4.5..1.7);
+            assert!(a >= -4.5 && a < 1.7);
+            let a = r.gen_range(-1.1..=-0.3);
+            assert!(a >= -1.1 && a <= -0.3);
+
+            assert_eq!(r.gen_range(0.0f32..=0.0), 0.);
+            assert_eq!(r.gen_range(-11.0..=-11.0), -11.);
+            assert_eq!(r.gen_range(3_000_000.0..=3_000_000.0), 3_000_000.);
+        }
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_gen_range_panic_int() {
+        let mut r = rng(102);
+        r.gen_range(5..-2);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_gen_range_panic_usize() {
+        let mut r = rng(103);
+        r.gen_range(5..2);
+    }
+
+    #[test]
+    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() {
+        use crate::distributions::{Distribution, Standard};
+        let mut rng = rng(109);
+        let mut r = &mut rng as &mut dyn RngCore;
+        r.next_u32();
+        r.gen::<i32>();
+        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 crate::distributions::{Distribution, Standard};
+        let rng = rng(110);
+        let mut r = Box::new(rng) as Box<dyn RngCore>;
+        r.next_u32();
+        r.gen::<i32>();
+        assert_eq!(r.gen_range(0..1), 0);
+        let _c: u8 = Standard.sample(&mut r);
+    }
+
+    #[test]
+    #[cfg_attr(miri, ignore)] // Miri is too slow
+    fn test_gen_ratio_average() {
+        const NUM: u32 = 3;
+        const DENOM: u32 = 10;
+        const N: u32 = 100_000;
+
+        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/src/rngs/adapter/mod.rs b/src/rngs/adapter/mod.rs
index 45e56af..22b7158 100644
--- a/src/rngs/adapter/mod.rs
+++ b/src/rngs/adapter/mod.rs
@@ -8,8 +8,8 @@
 
 //! Wrappers / adapters forming RNGs
 
-#[cfg(feature = "std")] mod read;
+mod read;
 mod reseeding;
 
-#[cfg(feature = "std")] pub use self::read::{ReadError, ReadRng};
+pub use self::read::{ReadError, ReadRng};
 pub use self::reseeding::ReseedingRng;
diff --git a/src/rngs/adapter/read.rs b/src/rngs/adapter/read.rs
index 9a4b55d..63b0dd0 100644
--- a/src/rngs/adapter/read.rs
+++ b/src/rngs/adapter/read.rs
@@ -103,6 +103,8 @@
 
 #[cfg(test)]
 mod test {
+    use std::println;
+
     use super::ReadRng;
     use crate::RngCore;
 
@@ -110,24 +112,24 @@
     fn test_reader_rng_u64() {
         // transmute from the target to avoid endianness concerns.
         #[rustfmt::skip]
-        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 v = [0u8, 0, 0, 0, 0, 0, 0, 1,
+                 0,   4, 0, 0, 3, 0, 0, 2,
+                 5,   0, 0, 0, 0, 0, 0, 0];
         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());
+        assert_eq!(rng.next_u64(), 1 << 56);
+        assert_eq!(rng.next_u64(), (2 << 56) + (3 << 32) + (4 << 8));
+        assert_eq!(rng.next_u64(), 5);
     }
 
     #[test]
     fn test_reader_rng_u32() {
-        let v = vec![0u8, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3];
+        let v = [0u8, 0, 0, 1, 0, 0, 2, 0, 3, 0, 0, 0];
         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());
+        assert_eq!(rng.next_u32(), 1 << 24);
+        assert_eq!(rng.next_u32(), 2 << 16);
+        assert_eq!(rng.next_u32(), 3);
     }
 
     #[test]
diff --git a/src/rngs/adapter/reseeding.rs b/src/rngs/adapter/reseeding.rs
index 5460e34..1977cb3 100644
--- a/src/rngs/adapter/reseeding.rs
+++ b/src/rngs/adapter/reseeding.rs
@@ -279,7 +279,7 @@
 }
 
 
-#[cfg(all(unix, feature = "std", not(target_os = "emscripten")))]
+#[cfg(all(unix, not(target_os = "emscripten")))]
 mod fork {
     use core::sync::atomic::{AtomicUsize, Ordering};
     use std::sync::Once;
@@ -316,7 +316,7 @@
     }
 }
 
-#[cfg(not(all(unix, feature = "std", not(target_os = "emscripten"))))]
+#[cfg(not(all(unix, not(target_os = "emscripten"))))]
 mod fork {
     pub fn get_fork_counter() -> usize {
         0
@@ -325,6 +325,7 @@
 }
 
 
+#[cfg(feature = "std_rng")]
 #[cfg(test)]
 mod test {
     use super::ReseedingRng;
diff --git a/src/rngs/entropy.rs b/src/rngs/entropy.rs
deleted file mode 100644
index 9ad0d71..0000000
--- a/src/rngs/entropy.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Entropy generator, or wrapper around external generators
-
-#![allow(deprecated)] // whole module is deprecated
-
-use crate::rngs::OsRng;
-use rand_core::{CryptoRng, Error, RngCore};
-
-/// An interface returning random data from external source(s), provided
-/// specifically for securely seeding algorithmic generators (PRNGs).
-///
-/// This is deprecated. It is suggested you use [`rngs::OsRng`] instead.
-///
-/// [`rngs::OsRng`]: crate::rngs::OsRng
-#[derive(Debug)]
-#[deprecated(since = "0.7.0", note = "use rngs::OsRng instead")]
-pub struct EntropyRng {
-    source: OsRng,
-}
-
-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: OsRng }
-    }
-}
-
-impl Default for EntropyRng {
-    fn default() -> Self {
-        EntropyRng::new()
-    }
-}
-
-impl RngCore for EntropyRng {
-    fn next_u32(&mut self) -> u32 {
-        self.source.next_u32()
-    }
-
-    fn next_u64(&mut self) -> u64 {
-        self.source.next_u64()
-    }
-
-    fn fill_bytes(&mut self, dest: &mut [u8]) {
-        self.source.fill_bytes(dest)
-    }
-
-    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
-        self.source.try_fill_bytes(dest)
-    }
-}
-
-impl CryptoRng for EntropyRng {}
-
-
-#[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/src/rngs/mock.rs b/src/rngs/mock.rs
index 9a47264..a1745a4 100644
--- a/src/rngs/mock.rs
+++ b/src/rngs/mock.rs
@@ -10,6 +10,9 @@
 
 use rand_core::{impls, Error, RngCore};
 
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
+
 /// A simple implementation of `RngCore` for testing purposes.
 ///
 /// This generates an arithmetic sequence (i.e. adds a constant each step)
@@ -24,7 +27,8 @@
 /// let sample: [u64; 3] = my_rng.gen();
 /// assert_eq!(sample, [2, 3, 4]);
 /// ```
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub struct StepRng {
     v: u64,
     a: u64,
@@ -65,3 +69,19 @@
         Ok(())
     }
 }
+
+#[cfg(test)]
+mod tests {
+    #[test]
+    #[cfg(feature = "serde1")]
+    fn test_serialization_step_rng() {
+        use super::StepRng;
+
+        let some_rng = StepRng::new(42, 7);
+        let de_some_rng: StepRng =
+            bincode::deserialize(&bincode::serialize(&some_rng).unwrap()).unwrap();
+        assert_eq!(some_rng.v, de_some_rng.v);
+        assert_eq!(some_rng.a, de_some_rng.a);
+
+    }
+}
diff --git a/src/rngs/mod.rs b/src/rngs/mod.rs
index 1112196..ac3c2c5 100644
--- a/src/rngs/mod.rs
+++ b/src/rngs/mod.rs
@@ -58,7 +58,7 @@
 //!     is local, it is typically much faster than [`OsRng`]. It should be
 //!     secure, though the paranoid may prefer [`OsRng`].
 //! -   [`StdRng`] is a CSPRNG chosen for good performance and trust of security
-//!     (based on reviews, maturity and usage). The current algorithm is ChaCha20,
+//!     (based on reviews, maturity and usage). The current algorithm is ChaCha12,
 //!     which is well established and rigorously analysed.
 //!     [`StdRng`] provides the algorithm used by [`ThreadRng`] but without
 //!     periodic reseeding.
@@ -96,21 +96,24 @@
 //! [`rand_xoshiro`]: https://crates.io/crates/rand_xoshiro
 //! [`rng` tag]: https://crates.io/keywords/rng
 
-pub mod adapter;
+#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
+#[cfg(feature = "std")] 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.
-#[cfg(feature = "small_rng")] mod small;
-mod std;
-#[cfg(feature = "std")] pub(crate) mod thread;
 
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::entropy::EntropyRng;
+#[cfg(all(feature = "small_rng", target_pointer_width = "64"))]
+mod xoshiro256plusplus;
+#[cfg(all(feature = "small_rng", not(target_pointer_width = "64")))]
+mod xoshiro128plusplus;
+#[cfg(feature = "small_rng")] mod small;
+
+#[cfg(feature = "std_rng")] mod std;
+#[cfg(all(feature = "std", feature = "std_rng"))] pub(crate) mod thread;
 
 #[cfg(feature = "small_rng")] pub use self::small::SmallRng;
-pub use self::std::StdRng;
-#[cfg(feature = "std")] pub use self::thread::ThreadRng;
+#[cfg(feature = "std_rng")] pub use self::std::StdRng;
+#[cfg(all(feature = "std", feature = "std_rng"))] pub use self::thread::ThreadRng;
 
+#[cfg_attr(doc_cfg, doc(cfg(feature = "getrandom")))]
 #[cfg(feature = "getrandom")] pub use rand_core::OsRng;
diff --git a/src/rngs/small.rs b/src/rngs/small.rs
index d676898..fb0e0d1 100644
--- a/src/rngs/small.rs
+++ b/src/rngs/small.rs
@@ -10,33 +10,36 @@
 
 use rand_core::{Error, RngCore, SeedableRng};
 
-#[cfg(all(not(target_os = "emscripten"), target_pointer_width = "64"))]
-type Rng = rand_pcg::Pcg64Mcg;
-#[cfg(not(all(not(target_os = "emscripten"), target_pointer_width = "64")))]
-type Rng = rand_pcg::Pcg32;
+#[cfg(target_pointer_width = "64")]
+type Rng = super::xoshiro256plusplus::Xoshiro256PlusPlus;
+#[cfg(not(target_pointer_width = "64"))]
+type Rng = super::xoshiro128plusplus::Xoshiro128PlusPlus;
 
 /// A small-state, fast non-crypto PRNG
 ///
 /// `SmallRng` may be a good choice when a PRNG with small state, cheap
 /// initialization, good statistical quality and good performance are required.
-/// It is **not** a good choice when security against prediction or
-/// reproducibility are important.
-///
-/// This PRNG is **feature-gated**: to use, you must enable the crate feature
-/// `small_rng`.
+/// Note that depending on the application, [`StdRng`] may be faster on many
+/// modern platforms while providing higher-quality randomness. Furthermore,
+/// `SmallRng` is **not** a good choice when:
+/// - Security against prediction is important. Use [`StdRng`] instead.
+/// - Seeds with many zeros are provided. In such cases, it takes `SmallRng`
+///   about 10 samples to produce 0 and 1 bits with equal probability. Either
+///   provide seeds with an approximately equal number of 0 and 1 (for example
+///   by using [`SeedableRng::from_entropy`] or [`SeedableRng::seed_from_u64`]),
+///   or use [`StdRng`] instead.
 ///
 /// The algorithm is deterministic but should not be considered reproducible
 /// due to dependence on platform and possible replacement in future
 /// library versions. For a reproducible generator, use a named PRNG from an
-/// external crate, e.g. [rand_pcg] or [rand_chacha].
+/// external crate, e.g. [rand_xoshiro] or [rand_chacha].
 /// Refer also to [The Book](https://rust-random.github.io/book/guide-rngs.html).
 ///
-/// 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 [`StdRng`].
-/// The current algorithm is [`Pcg64Mcg`](rand_pcg::Pcg64Mcg) on 64-bit
-/// platforms and [`Pcg32`](rand_pcg::Pcg32) on 32-bit platforms. Both are
-/// implemented by the [rand_pcg] crate.
+/// 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 [`StdRng`]. The current algorithm is
+/// `Xoshiro256PlusPlus` on 64-bit platforms and `Xoshiro128PlusPlus` on 32-bit
+/// platforms. Both are also implemented by the [rand_xoshiro] crate.
 ///
 /// # Examples
 ///
@@ -72,8 +75,9 @@
 /// [`StdRng`]: crate::rngs::StdRng
 /// [`thread_rng`]: crate::thread_rng
 /// [rand_chacha]: https://crates.io/crates/rand_chacha
-/// [rand_pcg]: https://crates.io/crates/rand_pcg
-#[derive(Clone, Debug)]
+/// [rand_xoshiro]: https://crates.io/crates/rand_xoshiro
+#[cfg_attr(doc_cfg, doc(cfg(feature = "small_rng")))]
+#[derive(Clone, Debug, PartialEq, Eq)]
 pub struct SmallRng(Rng);
 
 impl RngCore for SmallRng {
diff --git a/src/rngs/std.rs b/src/rngs/std.rs
index 8b07081..80f8433 100644
--- a/src/rngs/std.rs
+++ b/src/rngs/std.rs
@@ -11,20 +11,20 @@
 use crate::{CryptoRng, Error, RngCore, SeedableRng};
 
 #[cfg(all(any(test, feature = "std"), not(target_os = "emscripten")))]
-pub(crate) use rand_chacha::ChaCha20Core as Core;
+pub(crate) use rand_chacha::ChaCha12Core as Core;
 #[cfg(all(any(test, feature = "std"), target_os = "emscripten"))]
 pub(crate) use rand_hc::Hc128Core as Core;
 
-#[cfg(not(target_os = "emscripten"))] use rand_chacha::ChaCha20Rng as Rng;
+#[cfg(not(target_os = "emscripten"))] use rand_chacha::ChaCha12Rng as Rng;
 #[cfg(target_os = "emscripten")] use rand_hc::Hc128Rng as Rng;
 
 /// 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 is the ChaCha block cipher with 20 rounds.
-/// This may change as new evidence of cipher security and performance
-/// becomes available.
+/// The current algorithm used is the ChaCha block cipher with 12 rounds. Please
+/// see this relevant [rand issue] for the discussion. This may change as new 
+/// evidence of cipher security and performance becomes available.
 ///
 /// The algorithm is deterministic but should not be considered reproducible
 /// due to dependence on configuration and possible replacement in future
@@ -32,7 +32,9 @@
 /// the [rand_chacha] crate directly.
 ///
 /// [rand_chacha]: https://crates.io/crates/rand_chacha
-#[derive(Clone, Debug)]
+/// [rand issue]: https://github.com/rust-random/rand/issues/932
+#[cfg_attr(doc_cfg, doc(cfg(feature = "std_rng")))]
+#[derive(Clone, Debug, PartialEq, Eq)]
 pub struct StdRng(Rng);
 
 impl RngCore for StdRng {
@@ -87,9 +89,6 @@
         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];
 
-        #[cfg(any(feature = "stdrng_strong", not(feature = "stdrng_fast")))]
-        let target = [3950704604716924505, 5573172343717151650];
-        #[cfg(all(not(feature = "stdrng_strong"), feature = "stdrng_fast"))]
         let target = [10719222850664546238, 14064965282130556830];
 
         let mut rng0 = StdRng::from_seed(seed);
diff --git a/src/rngs/thread.rs b/src/rngs/thread.rs
index 91ed4c3..552851f 100644
--- a/src/rngs/thread.rs
+++ b/src/rngs/thread.rs
@@ -8,8 +8,9 @@
 
 //! Thread-local random number generator
 
-use std::cell::UnsafeCell;
-use std::ptr::NonNull;
+use core::cell::UnsafeCell;
+use std::rc::Rc;
+use std::thread_local;
 
 use super::std::Core;
 use crate::rngs::adapter::ReseedingRng;
@@ -36,37 +37,42 @@
 // of 32 kB and less. We choose 64 kB to avoid significant overhead.
 const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64;
 
-/// The type returned by [`thread_rng`], essentially just a reference to the
-/// PRNG in thread-local memory.
+/// A reference to the thread-local generator
 ///
-/// `ThreadRng` uses the same PRNG as [`StdRng`] for security and performance.
-/// As hinted by the name, the generator is thread-local. `ThreadRng` is a
-/// handle to this generator and thus supports `Copy`, but not `Send` or `Sync`.
+/// An instance can be obtained via [`thread_rng`] or via `ThreadRng::default()`.
+/// This handle is safe to use everywhere (including thread-local destructors)
+/// but cannot be passed between threads (is not `Send` or `Sync`).
+///
+/// `ThreadRng` uses the same PRNG as [`StdRng`] for security and performance
+/// and is automatically seeded from [`OsRng`].
 ///
 /// Unlike `StdRng`, `ThreadRng` uses the  [`ReseedingRng`] wrapper to reseed
-/// the PRNG from fresh entropy every 64 kiB of random data.
-/// [`OsRng`] is used to provide seed data.
-///
+/// the PRNG from fresh entropy every 64 kiB of random data as well as after a
+/// fork on Unix (though not quite immediately; see documentation of
+/// [`ReseedingRng`]).
 /// Note that the reseeding is done as an extra precaution against side-channel
 /// attacks and mis-use (e.g. if somehow weak entropy were supplied initially).
 /// The PRNG algorithms used are assumed to be secure.
 ///
 /// [`ReseedingRng`]: crate::rngs::adapter::ReseedingRng
 /// [`StdRng`]: crate::rngs::StdRng
-#[derive(Copy, Clone, Debug)]
+#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", feature = "std_rng"))))]
+#[derive(Clone, Debug)]
 pub struct ThreadRng {
-    // inner raw pointer implies type is neither Send nor Sync
-    rng: NonNull<ReseedingRng<Core, OsRng>>,
+    // Rc is explictly !Send and !Sync
+    rng: Rc<UnsafeCell<ReseedingRng<Core, OsRng>>>,
 }
 
 thread_local!(
-    static THREAD_RNG_KEY: UnsafeCell<ReseedingRng<Core, OsRng>> = {
+    // We require Rc<..> to avoid premature freeing when thread_rng is used
+    // within thread-local destructors. See #968.
+    static THREAD_RNG_KEY: Rc<UnsafeCell<ReseedingRng<Core, OsRng>>> = {
         let r = Core::from_rng(OsRng).unwrap_or_else(|err|
                 panic!("could not initialize thread_rng: {}", err));
         let rng = ReseedingRng::new(r,
                                     THREAD_RNG_RESEED_THRESHOLD,
                                     OsRng);
-        UnsafeCell::new(rng)
+        Rc::new(UnsafeCell::new(rng))
     }
 );
 
@@ -77,10 +83,10 @@
 /// `ThreadRng::default()` equivalent.
 ///
 /// For more information see [`ThreadRng`].
+#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", feature = "std_rng"))))]
 pub fn thread_rng() -> ThreadRng {
-    let raw = THREAD_RNG_KEY.with(|t| t.get());
-    let nn = NonNull::new(raw).unwrap();
-    ThreadRng { rng: nn }
+    let rng = THREAD_RNG_KEY.with(|t| t.clone());
+    ThreadRng { rng }
 }
 
 impl Default for ThreadRng {
@@ -92,20 +98,32 @@
 impl RngCore for ThreadRng {
     #[inline(always)]
     fn next_u32(&mut self) -> u32 {
-        unsafe { self.rng.as_mut().next_u32() }
+        // SAFETY: We must make sure to stop using `rng` before anyone else
+        // creates another mutable reference
+        let rng = unsafe { &mut *self.rng.get() };
+        rng.next_u32()
     }
 
     #[inline(always)]
     fn next_u64(&mut self) -> u64 {
-        unsafe { self.rng.as_mut().next_u64() }
+        // SAFETY: We must make sure to stop using `rng` before anyone else
+        // creates another mutable reference
+        let rng = unsafe { &mut *self.rng.get() };
+        rng.next_u64()
     }
 
     fn fill_bytes(&mut self, dest: &mut [u8]) {
-        unsafe { self.rng.as_mut().fill_bytes(dest) }
+        // SAFETY: We must make sure to stop using `rng` before anyone else
+        // creates another mutable reference
+        let rng = unsafe { &mut *self.rng.get() };
+        rng.fill_bytes(dest)
     }
 
     fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
-        unsafe { self.rng.as_mut().try_fill_bytes(dest) }
+        // SAFETY: We must make sure to stop using `rng` before anyone else
+        // creates another mutable reference
+        let rng = unsafe { &mut *self.rng.get() };
+        rng.try_fill_bytes(dest)
     }
 }
 
@@ -119,6 +137,6 @@
         use crate::Rng;
         let mut r = crate::thread_rng();
         r.gen::<i32>();
-        assert_eq!(r.gen_range(0, 1), 0);
+        assert_eq!(r.gen_range(0..1), 0);
     }
 }
diff --git a/src/rngs/xoshiro128plusplus.rs b/src/rngs/xoshiro128plusplus.rs
new file mode 100644
index 0000000..ece98fa
--- /dev/null
+++ b/src/rngs/xoshiro128plusplus.rs
@@ -0,0 +1,118 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[cfg(feature="serde1")] use serde::{Serialize, Deserialize};
+use rand_core::impls::{next_u64_via_u32, fill_bytes_via_next};
+use rand_core::le::read_u32_into;
+use rand_core::{SeedableRng, RngCore, Error};
+
+/// A xoshiro128++ random number generator.
+///
+/// The xoshiro128++ algorithm is not suitable for cryptographic purposes, but
+/// is very fast and has excellent statistical properties.
+///
+/// The algorithm used here is translated from [the `xoshiro128plusplus.c`
+/// reference source code](http://xoshiro.di.unimi.it/xoshiro128plusplus.c) by
+/// David Blackman and Sebastiano Vigna.
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
+pub struct Xoshiro128PlusPlus {
+    s: [u32; 4],
+}
+
+impl SeedableRng for Xoshiro128PlusPlus {
+    type Seed = [u8; 16];
+
+    /// Create a new `Xoshiro128PlusPlus`.  If `seed` is entirely 0, it will be
+    /// mapped to a different seed.
+    #[inline]
+    fn from_seed(seed: [u8; 16]) -> Xoshiro128PlusPlus {
+        if seed.iter().all(|&x| x == 0) {
+            return Self::seed_from_u64(0);
+        }
+        let mut state = [0; 4];
+        read_u32_into(&seed, &mut state);
+        Xoshiro128PlusPlus { s: state }
+    }
+
+    /// Create a new `Xoshiro128PlusPlus` from a `u64` seed.
+    ///
+    /// This uses the SplitMix64 generator internally.
+    fn seed_from_u64(mut state: u64) -> Self {
+        const PHI: u64 = 0x9e3779b97f4a7c15;
+        let mut seed = Self::Seed::default();
+        for chunk in seed.as_mut().chunks_mut(8) {
+            state = state.wrapping_add(PHI);
+            let mut z = state;
+            z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
+            z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
+            z = z ^ (z >> 31);
+            chunk.copy_from_slice(&z.to_le_bytes());
+        }
+        Self::from_seed(seed)
+    }
+}
+
+impl RngCore for Xoshiro128PlusPlus {
+    #[inline]
+    fn next_u32(&mut self) -> u32 {
+        let result_starstar = self.s[0]
+            .wrapping_add(self.s[3])
+            .rotate_left(7)
+            .wrapping_add(self.s[0]);
+
+        let t = self.s[1] << 9;
+
+        self.s[2] ^= self.s[0];
+        self.s[3] ^= self.s[1];
+        self.s[1] ^= self.s[2];
+        self.s[0] ^= self.s[3];
+
+        self.s[2] ^= t;
+
+        self.s[3] = self.s[3].rotate_left(11);
+
+        result_starstar
+    }
+
+    #[inline]
+    fn next_u64(&mut self) -> u64 {
+        next_u64_via_u32(self)
+    }
+
+    #[inline]
+    fn fill_bytes(&mut self, dest: &mut [u8]) {
+        fill_bytes_via_next(self, dest);
+    }
+
+    #[inline]
+    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+        self.fill_bytes(dest);
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn reference() {
+        let mut rng = Xoshiro128PlusPlus::from_seed(
+            [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0]);
+        // These values were produced with the reference implementation:
+        // http://xoshiro.di.unimi.it/xoshiro128plusplus.c
+        let expected = [
+            641, 1573767, 3222811527, 3517856514, 836907274, 4247214768,
+            3867114732, 1355841295, 495546011, 621204420,
+        ];
+        for &e in &expected {
+            assert_eq!(rng.next_u32(), e);
+        }
+    }
+}
diff --git a/src/rngs/xoshiro256plusplus.rs b/src/rngs/xoshiro256plusplus.rs
new file mode 100644
index 0000000..cd373c3
--- /dev/null
+++ b/src/rngs/xoshiro256plusplus.rs
@@ -0,0 +1,122 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[cfg(feature="serde1")] use serde::{Serialize, Deserialize};
+use rand_core::impls::fill_bytes_via_next;
+use rand_core::le::read_u64_into;
+use rand_core::{SeedableRng, RngCore, Error};
+
+/// A xoshiro256** random number generator.
+///
+/// The xoshiro256** algorithm is not suitable for cryptographic purposes, but
+/// is very fast and has excellent statistical properties.
+///
+/// The algorithm used here is translated from [the `xoshiro256plusplus.c`
+/// reference source code](http://xoshiro.di.unimi.it/xoshiro256plusplus.c) by
+/// David Blackman and Sebastiano Vigna.
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
+pub struct Xoshiro256PlusPlus {
+    s: [u64; 4],
+}
+
+impl SeedableRng for Xoshiro256PlusPlus {
+    type Seed = [u8; 32];
+
+    /// Create a new `Xoshiro256PlusPlus`.  If `seed` is entirely 0, it will be
+    /// mapped to a different seed.
+    #[inline]
+    fn from_seed(seed: [u8; 32]) -> Xoshiro256PlusPlus {
+        if seed.iter().all(|&x| x == 0) {
+            return Self::seed_from_u64(0);
+        }
+        let mut state = [0; 4];
+        read_u64_into(&seed, &mut state);
+        Xoshiro256PlusPlus { s: state }
+    }
+
+    /// Create a new `Xoshiro256PlusPlus` from a `u64` seed.
+    ///
+    /// This uses the SplitMix64 generator internally.
+    fn seed_from_u64(mut state: u64) -> Self {
+        const PHI: u64 = 0x9e3779b97f4a7c15;
+        let mut seed = Self::Seed::default();
+        for chunk in seed.as_mut().chunks_mut(8) {
+            state = state.wrapping_add(PHI);
+            let mut z = state;
+            z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
+            z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
+            z = z ^ (z >> 31);
+            chunk.copy_from_slice(&z.to_le_bytes());
+        }
+        Self::from_seed(seed)
+    }
+}
+
+impl RngCore for Xoshiro256PlusPlus {
+    #[inline]
+    fn next_u32(&mut self) -> u32 {
+        // The lowest bits have some linear dependencies, so we use the
+        // upper bits instead.
+        (self.next_u64() >> 32) as u32
+    }
+
+    #[inline]
+    fn next_u64(&mut self) -> u64 {
+        let result_plusplus = self.s[0]
+            .wrapping_add(self.s[3])
+            .rotate_left(23)
+            .wrapping_add(self.s[0]);
+
+        let t = self.s[1] << 17;
+
+        self.s[2] ^= self.s[0];
+        self.s[3] ^= self.s[1];
+        self.s[1] ^= self.s[2];
+        self.s[0] ^= self.s[3];
+
+        self.s[2] ^= t;
+
+        self.s[3] = self.s[3].rotate_left(45);
+
+        result_plusplus
+    }
+
+    #[inline]
+    fn fill_bytes(&mut self, dest: &mut [u8]) {
+        fill_bytes_via_next(self, dest);
+    }
+
+    #[inline]
+    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+        self.fill_bytes(dest);
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn reference() {
+        let mut rng = Xoshiro256PlusPlus::from_seed(
+            [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
+             3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0]);
+        // These values were produced with the reference implementation:
+        // http://xoshiro.di.unimi.it/xoshiro256plusplus.c
+        let expected = [
+            41943041, 58720359, 3588806011781223, 3591011842654386,
+            9228616714210784205, 9973669472204895162, 14011001112246962877,
+            12406186145184390807, 15849039046786891736, 10450023813501588000,
+        ];
+        for &e in &expected {
+            assert_eq!(rng.next_u64(), e);
+        }
+    }
+}
diff --git a/src/seq/index.rs b/src/seq/index.rs
index 551d409..c09e580 100644
--- a/src/seq/index.rs
+++ b/src/seq/index.rs
@@ -10,22 +10,24 @@
 
 #[cfg(feature = "alloc")] use core::slice;
 
-#[cfg(all(feature = "alloc", not(feature = "std")))]
-use crate::alloc::vec::{self, Vec};
-#[cfg(feature = "std")] use std::vec;
+#[cfg(feature = "alloc")] use alloc::vec::{self, Vec};
 // BTreeMap is not as fast in tests, but better than nothing.
 #[cfg(all(feature = "alloc", not(feature = "std")))]
-use crate::alloc::collections::BTreeSet;
+use alloc::collections::BTreeSet;
 #[cfg(feature = "std")] use std::collections::HashSet;
 
 #[cfg(feature = "alloc")]
-use crate::distributions::{uniform::SampleUniform, Distribution, Uniform};
+use crate::distributions::{uniform::SampleUniform, Distribution, Uniform, WeightedError};
 use crate::Rng;
 
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
+
 /// A vector of indices.
 ///
 /// Multiple internal representations are possible.
 #[derive(Clone, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub enum IndexVec {
     #[doc(hidden)]
     U32(Vec<u32>),
@@ -81,10 +83,15 @@
             IndexVec::USize(ref v) => IndexVecIter::USize(v.iter()),
         }
     }
+}
+
+impl IntoIterator for IndexVec {
+    type Item = usize;
+    type IntoIter = IndexVecIntoIter;
 
     /// Convert into an iterator over the indices as a sequence of `usize` values
     #[inline]
-    pub fn into_iter(self) -> IndexVecIntoIter {
+    fn into_iter(self) -> IndexVecIntoIter {
         match self {
             IndexVec::U32(v) => IndexVecIntoIter::U32(v.into_iter()),
             IndexVec::USize(v) => IndexVecIntoIter::USize(v.into_iter()),
@@ -249,6 +256,154 @@
     }
 }
 
+/// Randomly sample exactly `amount` distinct indices from `0..length`, and
+/// return them in an arbitrary order (there is no guarantee of shuffling or
+/// ordering). The weights are to be provided by the input function `weights`,
+/// which will be called once for each index.
+///
+/// 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.
+///
+/// This implementation uses `O(length + amount)` space and `O(length)` time
+/// if the "nightly" feature is enabled, or `O(length)` space and
+/// `O(length + amount * log length)` time otherwise.
+///
+/// Panics if `amount > length`.
+pub fn sample_weighted<R, F, X>(
+    rng: &mut R, length: usize, weight: F, amount: usize,
+) -> Result<IndexVec, WeightedError>
+where
+    R: Rng + ?Sized,
+    F: Fn(usize) -> X,
+    X: Into<f64>,
+{
+    if length > (core::u32::MAX as usize) {
+        sample_efraimidis_spirakis(rng, length, weight, amount)
+    } else {
+        assert!(amount <= core::u32::MAX as usize);
+        let amount = amount as u32;
+        let length = length as u32;
+        sample_efraimidis_spirakis(rng, length, weight, amount)
+    }
+}
+
+
+/// Randomly sample exactly `amount` distinct indices from `0..length`, and
+/// return them in an arbitrary order (there is no guarantee of shuffling or
+/// ordering). The weights are to be provided by the input function `weights`,
+/// which will be called once for each index.
+///
+/// This implementation uses the algorithm described by Efraimidis and Spirakis
+/// in this paper: https://doi.org/10.1016/j.ipl.2005.11.003
+/// It uses `O(length + amount)` space and `O(length)` time if the
+/// "nightly" feature is enabled, or `O(length)` space and `O(length
+/// + amount * log length)` time otherwise.
+///
+/// Panics if `amount > length`.
+fn sample_efraimidis_spirakis<R, F, X, N>(
+    rng: &mut R, length: N, weight: F, amount: N,
+) -> Result<IndexVec, WeightedError>
+where
+    R: Rng + ?Sized,
+    F: Fn(usize) -> X,
+    X: Into<f64>,
+    N: UInt,
+    IndexVec: From<Vec<N>>,
+{
+    if amount == N::zero() {
+        return Ok(IndexVec::U32(Vec::new()));
+    }
+
+    if amount > length {
+        panic!("`amount` of samples must be less than or equal to `length`");
+    }
+
+    struct Element<N> {
+        index: N,
+        key: f64,
+    }
+    impl<N> PartialOrd for Element<N> {
+        fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+            self.key.partial_cmp(&other.key)
+        }
+    }
+    impl<N> Ord for Element<N> {
+        fn cmp(&self, other: &Self) -> core::cmp::Ordering {
+             // partial_cmp will always produce a value,
+             // because we check that the weights are not nan
+            self.partial_cmp(other).unwrap()
+        }
+    }
+    impl<N> PartialEq for Element<N> {
+        fn eq(&self, other: &Self) -> bool {
+            self.key == other.key
+        }
+    }
+    impl<N> Eq for Element<N> {}
+
+    #[cfg(feature = "nightly")]
+    {
+        let mut candidates = Vec::with_capacity(length.as_usize());
+        let mut index = N::zero();
+        while index < length {
+            let weight = weight(index.as_usize()).into();
+            if !(weight >= 0.) {
+                return Err(WeightedError::InvalidWeight);
+            }
+
+            let key = rng.gen::<f64>().powf(1.0 / weight);
+            candidates.push(Element { index, key });
+
+            index += N::one();
+        }
+
+        // Partially sort the array to find the `amount` elements with the greatest
+        // keys. Do this by using `select_nth_unstable` to put the elements with
+        // the *smallest* keys at the beginning of the list in `O(n)` time, which
+        // provides equivalent information about the elements with the *greatest* keys.
+        let (_, mid, greater)
+            = candidates.select_nth_unstable(length.as_usize() - amount.as_usize());
+
+        let mut result: Vec<N> = Vec::with_capacity(amount.as_usize());
+        result.push(mid.index);
+        for element in greater {
+            result.push(element.index);
+        }
+        Ok(IndexVec::from(result))
+    }
+
+    #[cfg(not(feature = "nightly"))]
+    {
+        #[cfg(all(feature = "alloc", not(feature = "std")))]
+        use crate::alloc::collections::BinaryHeap;
+        #[cfg(feature = "std")]
+        use std::collections::BinaryHeap;
+
+        // Partially sort the array such that the `amount` elements with the largest
+        // keys are first using a binary max heap.
+        let mut candidates = BinaryHeap::with_capacity(length.as_usize());
+        let mut index = N::zero();
+        while index < length {
+            let weight = weight(index.as_usize()).into();
+            if !(weight >= 0.) {
+                return Err(WeightedError::InvalidWeight);
+            }
+
+            let key = rng.gen::<f64>().powf(1.0 / weight);
+            candidates.push(Element { index, key });
+
+            index += N::one();
+        }
+
+        let mut result: Vec<N> = Vec::with_capacity(amount.as_usize());
+        while result.len() < amount.as_usize() {
+            result.push(candidates.pop().unwrap().index);
+        }
+        Ok(IndexVec::from(result))
+    }
+}
+
 /// Randomly sample exactly `amount` indices from `0..length`, using Floyd's
 /// combination algorithm.
 ///
@@ -265,7 +420,7 @@
     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);
+        let t = rng.gen_range(0..=j);
         if floyd_shuffle {
             if let Some(pos) = indices.iter().position(|&x| x == t) {
                 indices.insert(pos, j);
@@ -281,7 +436,7 @@
         // 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);
+            indices.swap(i as usize, rng.gen_range(0..=i) as usize);
         }
     }
     IndexVec::from(indices)
@@ -305,7 +460,7 @@
     let mut indices: Vec<u32> = Vec::with_capacity(length as usize);
     indices.extend(0..length);
     for i in 0..amount {
-        let j: u32 = rng.gen_range(i, length);
+        let j: u32 = rng.gen_range(i..length);
         indices.swap(i as usize, j as usize);
     }
     indices.truncate(amount as usize);
@@ -313,8 +468,10 @@
     IndexVec::from(indices)
 }
 
-trait UInt: Copy + PartialOrd + Ord + PartialEq + Eq + SampleUniform + core::hash::Hash {
+trait UInt: Copy + PartialOrd + Ord + PartialEq + Eq + SampleUniform
+    + core::hash::Hash + core::ops::AddAssign {
     fn zero() -> Self;
+    fn one() -> Self;
     fn as_usize(self) -> usize;
 }
 impl UInt for u32 {
@@ -324,6 +481,11 @@
     }
 
     #[inline]
+    fn one() -> Self {
+        1
+    }
+
+    #[inline]
     fn as_usize(self) -> usize {
         self as usize
     }
@@ -335,6 +497,11 @@
     }
 
     #[inline]
+    fn one() -> Self {
+        1
+    }
+
+    #[inline]
     fn as_usize(self) -> usize {
         self
     }
@@ -376,8 +543,24 @@
 #[cfg(test)]
 mod test {
     use super::*;
-    #[cfg(all(feature = "alloc", not(feature = "std")))] use crate::alloc::vec;
-    #[cfg(feature = "std")] use std::vec;
+
+    #[test]
+    #[cfg(feature = "serde1")]
+    fn test_serialization_index_vec() {
+        let some_index_vec = IndexVec::from(vec![254_usize, 234, 2, 1]);
+        let de_some_index_vec: IndexVec = bincode::deserialize(&bincode::serialize(&some_index_vec).unwrap()).unwrap();
+        match (some_index_vec, de_some_index_vec) {
+            (IndexVec::U32(a), IndexVec::U32(b)) => {
+                assert_eq!(a, b);
+            },
+            (IndexVec::USize(a), IndexVec::USize(b)) => {
+                assert_eq!(a, b);
+            },
+            _ => {panic!("failed to seralize/deserialize `IndexVec`")}
+        }
+    }
+
+    #[cfg(feature = "alloc")] use alloc::vec;
 
     #[test]
     fn test_sample_boundaries() {
@@ -435,4 +618,58 @@
         assert!(v1.iter().all(|e| e < length));
         assert_eq!(v1, v2);
     }
+
+    #[test]
+    fn test_sample_weighted() {
+        let seed_rng = crate::test::rng;
+        for &(amount, len) in &[(0, 10), (5, 10), (10, 10)] {
+            let v = sample_weighted(&mut seed_rng(423), len, |i| i as f64, amount).unwrap();
+            match v {
+                IndexVec::U32(mut indices) => {
+                    assert_eq!(indices.len(), amount);
+                    indices.sort();
+                    indices.dedup();
+                    assert_eq!(indices.len(), amount);
+                    for &i in &indices {
+                        assert!((i as usize) < len);
+                    }
+                },
+                IndexVec::USize(_) => panic!("expected `IndexVec::U32`"),
+            }
+        }
+    }
+
+    #[test]
+    fn value_stability_sample() {
+        let do_test = |length, amount, values: &[u32]| {
+            let mut buf = [0u32; 8];
+            let mut rng = crate::test::rng(410);
+
+            let res = sample(&mut rng, length, amount);
+            let len = res.len().min(buf.len());
+            for (x, y) in res.into_iter().zip(buf.iter_mut()) {
+                *y = x as u32;
+            }
+            assert_eq!(
+                &buf[0..len],
+                values,
+                "failed sampling {}, {}",
+                length,
+                amount
+            );
+        };
+
+        do_test(10, 6, &[8, 0, 3, 5, 9, 6]); // floyd
+        do_test(25, 10, &[18, 15, 14, 9, 0, 13, 5, 24]); // floyd
+        do_test(300, 8, &[30, 283, 150, 1, 73, 13, 285, 35]); // floyd
+        do_test(300, 80, &[31, 289, 248, 154, 5, 78, 19, 286]); // inplace
+        do_test(300, 180, &[31, 289, 248, 154, 5, 78, 19, 286]); // inplace
+
+        do_test(1000_000, 8, &[
+            103717, 963485, 826422, 509101, 736394, 807035, 5327, 632573,
+        ]); // floyd
+        do_test(1000_000, 180, &[
+            103718, 963490, 826426, 509103, 736396, 807036, 5327, 632573,
+        ]); // rejection
+    }
 }
diff --git a/src/seq/mod.rs b/src/seq/mod.rs
index dabf329..9e6ffaf 100644
--- a/src/seq/mod.rs
+++ b/src/seq/mod.rs
@@ -17,19 +17,21 @@
 //!
 //! Also see:
 //!
-//! *   [`crate::distributions::weighted`] module which provides
-//!     implementations of weighted index sampling.
+//! *   [`crate::distributions::WeightedIndex`] distribution which provides
+//!     weighted index sampling.
 //!
 //! In order to make results reproducible across 32-64 bit architectures, all
 //! `usize` indices are sampled as a `u32` where possible (also providing a
 //! small performance boost in some cases).
 
 
-#[cfg(feature = "alloc")] pub mod index;
+#[cfg(feature = "alloc")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
+pub mod index;
 
 #[cfg(feature = "alloc")] use core::ops::Index;
 
-#[cfg(all(feature = "alloc", not(feature = "std")))] use crate::alloc::vec::Vec;
+#[cfg(feature = "alloc")] use alloc::vec::Vec;
 
 #[cfg(feature = "alloc")]
 use crate::distributions::uniform::{SampleBorrow, SampleUniform};
@@ -44,13 +46,11 @@
 /// ```
 /// use rand::seq::SliceRandom;
 ///
-/// fn main() {
-///     let mut rng = rand::thread_rng();
-///     let mut bytes = "Hello, random!".to_string().into_bytes();
-///     bytes.shuffle(&mut rng);
-///     let str = String::from_utf8(bytes).unwrap();
-///     println!("{}", str);
-/// }
+/// let mut rng = rand::thread_rng();
+/// let mut bytes = "Hello, random!".to_string().into_bytes();
+/// bytes.shuffle(&mut rng);
+/// let str = String::from_utf8(bytes).unwrap();
+/// println!("{}", str);
 /// ```
 /// Example output (non-deterministic):
 /// ```none
@@ -111,6 +111,7 @@
     /// }
     /// ```
     #[cfg(feature = "alloc")]
+    #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
     fn choose_multiple<R>(&self, rng: &mut R, amount: usize) -> SliceChooseIter<Self, Self::Item>
     where R: Rng + ?Sized;
 
@@ -138,6 +139,7 @@
     /// [`choose_weighted_mut`]: SliceRandom::choose_weighted_mut
     /// [`distributions::weighted`]: crate::distributions::weighted
     #[cfg(feature = "alloc")]
+    #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
     fn choose_weighted<R, F, B, X>(
         &self, rng: &mut R, weight: F,
     ) -> Result<&Self::Item, WeightedError>
@@ -165,6 +167,7 @@
     /// [`choose_weighted`]: SliceRandom::choose_weighted
     /// [`distributions::weighted`]: crate::distributions::weighted
     #[cfg(feature = "alloc")]
+    #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
     fn choose_weighted_mut<R, F, B, X>(
         &mut self, rng: &mut R, weight: F,
     ) -> Result<&mut Self::Item, WeightedError>
@@ -178,6 +181,46 @@
             + Clone
             + Default;
 
+    /// Similar to [`choose_multiple`], but where the likelihood of each element's
+    /// inclusion in the output may be specified. The elements are returned in an
+    /// arbitrary, unspecified order.
+    ///
+    /// The specified function `weight` maps each item `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)`.
+    ///
+    /// If all of the weights are equal, even if they are all zero, each element has
+    /// an equal likelihood of being selected.
+    ///
+    /// The complexity of this method depends on the feature `partition_at_index`.
+    /// If the feature is enabled, then for slices of length `n`, the complexity
+    /// is `O(n)` space and `O(n)` time. Otherwise, the complexity is `O(n)` space and
+    /// `O(n * log amount)` time.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use rand::prelude::*;
+    ///
+    /// let choices = [('a', 2), ('b', 1), ('c', 1)];
+    /// let mut rng = thread_rng();
+    /// // First Draw * Second Draw = total odds
+    /// // -----------------------
+    /// // (50% * 50%) + (25% * 67%) = 41.7% chance that the output is `['a', 'b']` in some order.
+    /// // (50% * 50%) + (25% * 67%) = 41.7% chance that the output is `['a', 'c']` in some order.
+    /// // (25% * 33%) + (25% * 33%) = 16.6% chance that the output is `['b', 'c']` in some order.
+    /// println!("{:?}", choices.choose_multiple_weighted(&mut rng, 2, |item| item.1).unwrap().collect::<Vec<_>>());
+    /// ```
+    /// [`choose_multiple`]: SliceRandom::choose_multiple
+    #[cfg(feature = "alloc")]
+    fn choose_multiple_weighted<R, F, X>(
+        &self, rng: &mut R, amount: usize, weight: F,
+    ) -> Result<SliceChooseIter<Self, Self::Item>, WeightedError>
+    where
+        R: Rng + ?Sized,
+        F: Fn(&Self::Item) -> X,
+        X: Into<f64>;
+
     /// Shuffle a mutable slice in place.
     ///
     /// For slices of length `n`, complexity is `O(n)`.
@@ -222,18 +265,17 @@
 
 /// Extension trait on iterators, providing random sampling methods.
 ///
-/// This trait is implemented on all sized iterators, providing methods for
+/// This trait is implemented on all iterators `I` where `I: Iterator + Sized`
+/// and provides methods for
 /// choosing one or more elements. You must `use` this trait:
 ///
 /// ```
 /// use rand::seq::IteratorRandom;
 ///
-/// fn main() {
-///     let mut rng = rand::thread_rng();
-///     
-///     let faces = "😀😎😐😕😠😢";
-///     println!("I am {}!", faces.chars().choose(&mut rng).unwrap());
-/// }
+/// let mut rng = rand::thread_rng();
+///
+/// let faces = "😀😎😐😕😠😢";
+/// println!("I am {}!", faces.chars().choose(&mut rng).unwrap());
 /// ```
 /// Example output (non-deterministic):
 /// ```none
@@ -250,14 +292,20 @@
     /// available, complexity is `O(n)` where `n` is the iterator length.
     /// Partial hints (where `lower > 0`) also improve performance.
     ///
-    /// For slices, prefer [`SliceRandom::choose`] which guarantees `O(1)`
-    /// performance.
+    /// Note that the output values and the number of RNG samples used
+    /// depends on size hints. In particular, `Iterator` combinators that don't
+    /// change the values yielded but change the size hints may result in
+    /// `choose` returning different elements. If you want consistent results
+    /// and RNG usage consider using [`IteratorRandom::choose_stable`].
     fn choose<R>(mut self, rng: &mut R) -> Option<Self::Item>
     where R: Rng + ?Sized {
         let (mut lower, mut upper) = self.size_hint();
         let mut consumed = 0;
         let mut result = None;
 
+        // Handling for this condition outside the loop allows the optimizer to eliminate the loop
+        // when the Iterator is an ExactSizeIterator. This has a large performance impact on e.g.
+        // seq_iter_choose_from_1000.
         if upper == Some(lower) {
             return if lower == 0 {
                 None
@@ -289,8 +337,7 @@
                     return result;
                 }
                 consumed += 1;
-                let denom = consumed as f64; // accurate to 2^53 elements
-                if rng.gen_bool(1.0 / denom) {
+                if gen_index(rng, consumed) == 0 {
                     result = elem;
                 }
             }
@@ -301,6 +348,64 @@
         }
     }
 
+    /// Choose one element at random from the iterator.
+    ///
+    /// Returns `None` if and only if the iterator is empty.
+    ///
+    /// This method is very similar to [`choose`] except that the result
+    /// only depends on the length of the iterator and the values produced by
+    /// `rng`. Notably for any iterator of a given length this will make the
+    /// same requests to `rng` and if the same sequence of values are produced
+    /// the same index will be selected from `self`. This may be useful if you
+    /// need consistent results no matter what type of iterator you are working
+    /// with. If you do not need this stability prefer [`choose`].
+    ///
+    /// Note that this method still uses [`Iterator::size_hint`] to skip
+    /// constructing elements where possible, however the selection and `rng`
+    /// calls are the same in the face of this optimization. If you want to
+    /// force every element to be created regardless call `.inspect(|e| ())`.
+    ///
+    /// [`choose`]: IteratorRandom::choose
+    fn choose_stable<R>(mut self, rng: &mut R) -> Option<Self::Item>
+    where R: Rng + ?Sized {
+        let mut consumed = 0;
+        let mut result = None;
+
+        loop {
+            // Currently the only way to skip elements is `nth()`. So we need to
+            // store what index to access next here.
+            // This should be replaced by `advance_by()` once it is stable:
+            // https://github.com/rust-lang/rust/issues/77404
+            let mut next = 0;
+
+            let (lower, _) = self.size_hint();
+            if lower >= 2 {
+                let highest_selected = (0..lower)
+                    .filter(|ix| gen_index(rng, consumed+ix+1) == 0)
+                    .last();
+
+                consumed += lower;
+                next = lower;
+
+                if let Some(ix) = highest_selected {
+                    result = self.nth(ix);
+                    next -= ix + 1;
+                    debug_assert!(result.is_some(), "iterator shorter than size_hint().0");
+                }
+            }
+
+            let elem = self.nth(next);
+            if elem.is_none() {
+                return result
+            }
+
+            if gen_index(rng, consumed+1) == 0 {
+                result = elem;
+            }
+            consumed += 1;
+        }
+    }
+
     /// Collects values at random from the iterator into a supplied buffer
     /// until that buffer is filled.
     ///
@@ -353,6 +458,7 @@
     /// Complexity is `O(n)` where `n` is the length of the iterator.
     /// For slices, prefer [`SliceRandom::choose_multiple`].
     #[cfg(feature = "alloc")]
+    #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
     fn choose_multiple<R>(mut self, rng: &mut R, amount: usize) -> Vec<Self::Item>
     where R: Rng + ?Sized {
         let mut reservoir = Vec::with_capacity(amount);
@@ -450,6 +556,29 @@
         Ok(&mut self[distr.sample(rng)])
     }
 
+    #[cfg(feature = "alloc")]
+    fn choose_multiple_weighted<R, F, X>(
+        &self, rng: &mut R, amount: usize, weight: F,
+    ) -> Result<SliceChooseIter<Self, Self::Item>, WeightedError>
+    where
+        R: Rng + ?Sized,
+        F: Fn(&Self::Item) -> X,
+        X: Into<f64>,
+    {
+        let amount = ::core::cmp::min(amount, self.len());
+        Ok(SliceChooseIter {
+            slice: self,
+            _phantom: Default::default(),
+            indices: index::sample_weighted(
+                rng,
+                self.len(),
+                |idx| weight(&self[idx]).into(),
+                amount,
+            )?
+            .into_iter(),
+        })
+    }
+
     fn shuffle<R>(&mut self, rng: &mut R)
     where R: Rng + ?Sized {
         for i in (1..self.len()).rev() {
@@ -487,6 +616,7 @@
 /// This struct is created by
 /// [`SliceRandom::choose_multiple`](trait.SliceRandom.html#tymethod.choose_multiple).
 #[cfg(feature = "alloc")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
 #[derive(Debug)]
 pub struct SliceChooseIter<'a, S: ?Sized + 'a, T: 'a> {
     slice: &'a S,
@@ -524,9 +654,9 @@
 #[inline]
 fn gen_index<R: Rng + ?Sized>(rng: &mut R, ubound: usize) -> usize {
     if ubound <= (core::u32::MAX as usize) {
-        rng.gen_range(0, ubound as u32) as usize
+        rng.gen_range(0..ubound as u32) as usize
     } else {
-        rng.gen_range(0, ubound)
+        rng.gen_range(0..ubound)
     }
 }
 
@@ -567,6 +697,40 @@
         assert_eq!(v.choose_mut(&mut r), None);
     }
 
+    #[test]
+    fn value_stability_slice() {
+        let mut r = crate::test::rng(413);
+        let chars = [
+            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+        ];
+        let mut nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+
+        assert_eq!(chars.choose(&mut r), Some(&'l'));
+        assert_eq!(nums.choose_mut(&mut r), Some(&mut 10));
+
+        #[cfg(feature = "alloc")]
+        assert_eq!(
+            &chars
+                .choose_multiple(&mut r, 8)
+                .cloned()
+                .collect::<Vec<char>>(),
+            &['d', 'm', 'b', 'n', 'c', 'k', 'h', 'e']
+        );
+
+        #[cfg(feature = "alloc")]
+        assert_eq!(chars.choose_weighted(&mut r, |_| 1), Ok(&'f'));
+        #[cfg(feature = "alloc")]
+        assert_eq!(nums.choose_weighted_mut(&mut r, |_| 1), Ok(&mut 5));
+
+        let mut r = crate::test::rng(414);
+        nums.shuffle(&mut r);
+        assert_eq!(nums, [9, 5, 3, 10, 7, 12, 8, 11, 6, 4, 0, 2, 1]);
+        nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+        let res = nums.partial_shuffle(&mut r, 6);
+        assert_eq!(res.0, &mut [7, 4, 8, 6, 9, 3]);
+        assert_eq!(res.1, &mut [0, 1, 2, 12, 11, 5, 10]);
+    }
+
     #[derive(Clone)]
     struct UnhintedIterator<I: Iterator + Clone> {
         iter: I,
@@ -691,6 +855,103 @@
 
     #[test]
     #[cfg_attr(miri, ignore)] // Miri is too slow
+    fn test_iterator_choose_stable() {
+        let r = &mut crate::test::rng(109);
+        fn test_iter<R: Rng + ?Sized, Iter: Iterator<Item = usize> + Clone>(r: &mut R, iter: Iter) {
+            let mut chosen = [0i32; 9];
+            for _ in 0..1000 {
+                let picked = iter.clone().choose_stable(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::<Vec<_>>().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]
+    #[cfg_attr(miri, ignore)] // Miri is too slow
+    fn test_iterator_choose_stable_stability() {
+        fn test_iter(iter: impl Iterator<Item = usize> + Clone) -> [i32; 9] {
+            let r = &mut crate::test::rng(109);
+            let mut chosen = [0i32; 9];
+            for _ in 0..1000 {
+                let picked = iter.clone().choose_stable(r).unwrap();
+                chosen[picked] += 1;
+            }
+            chosen
+        }
+
+        let reference = test_iter(0..9);
+        assert_eq!(test_iter([0, 1, 2, 3, 4, 5, 6, 7, 8].iter().cloned()), reference);
+
+        #[cfg(feature = "alloc")]
+        assert_eq!(test_iter((0..9).collect::<Vec<_>>().into_iter()), reference);
+        assert_eq!(test_iter(UnhintedIterator { iter: 0..9 }), reference);
+        assert_eq!(test_iter(ChunkHintedIterator {
+            iter: 0..9,
+            chunk_size: 4,
+            chunk_remaining: 4,
+            hint_total_size: false,
+        }), reference);
+        assert_eq!(test_iter(ChunkHintedIterator {
+            iter: 0..9,
+            chunk_size: 4,
+            chunk_remaining: 4,
+            hint_total_size: true,
+        }), reference);
+        assert_eq!(test_iter(WindowHintedIterator {
+            iter: 0..9,
+            window_size: 2,
+            hint_total_size: false,
+        }), reference);
+        assert_eq!(test_iter(WindowHintedIterator {
+            iter: 0..9,
+            window_size: 2,
+            hint_total_size: true,
+        }), reference);
+    }
+
+    #[test]
+    #[cfg_attr(miri, ignore)] // Miri is too slow
     fn test_shuffle() {
         let mut r = crate::test::rng(108);
         let empty: &mut [isize] = &mut [];
@@ -847,4 +1108,248 @@
             Err(WeightedError::InvalidWeight)
         );
     }
+
+    #[test]
+    fn value_stability_choose() {
+        fn choose<I: Iterator<Item = u32>>(iter: I) -> Option<u32> {
+            let mut rng = crate::test::rng(411);
+            iter.choose(&mut rng)
+        }
+
+        assert_eq!(choose([].iter().cloned()), None);
+        assert_eq!(choose(0..100), Some(33));
+        assert_eq!(choose(UnhintedIterator { iter: 0..100 }), Some(40));
+        assert_eq!(
+            choose(ChunkHintedIterator {
+                iter: 0..100,
+                chunk_size: 32,
+                chunk_remaining: 32,
+                hint_total_size: false,
+            }),
+            Some(39)
+        );
+        assert_eq!(
+            choose(ChunkHintedIterator {
+                iter: 0..100,
+                chunk_size: 32,
+                chunk_remaining: 32,
+                hint_total_size: true,
+            }),
+            Some(39)
+        );
+        assert_eq!(
+            choose(WindowHintedIterator {
+                iter: 0..100,
+                window_size: 32,
+                hint_total_size: false,
+            }),
+            Some(90)
+        );
+        assert_eq!(
+            choose(WindowHintedIterator {
+                iter: 0..100,
+                window_size: 32,
+                hint_total_size: true,
+            }),
+            Some(90)
+        );
+    }
+
+    #[test]
+    fn value_stability_choose_stable() {
+        fn choose<I: Iterator<Item = u32>>(iter: I) -> Option<u32> {
+            let mut rng = crate::test::rng(411);
+            iter.choose_stable(&mut rng)
+        }
+
+        assert_eq!(choose([].iter().cloned()), None);
+        assert_eq!(choose(0..100), Some(40));
+        assert_eq!(choose(UnhintedIterator { iter: 0..100 }), Some(40));
+        assert_eq!(
+            choose(ChunkHintedIterator {
+                iter: 0..100,
+                chunk_size: 32,
+                chunk_remaining: 32,
+                hint_total_size: false,
+            }),
+            Some(40)
+        );
+        assert_eq!(
+            choose(ChunkHintedIterator {
+                iter: 0..100,
+                chunk_size: 32,
+                chunk_remaining: 32,
+                hint_total_size: true,
+            }),
+            Some(40)
+        );
+        assert_eq!(
+            choose(WindowHintedIterator {
+                iter: 0..100,
+                window_size: 32,
+                hint_total_size: false,
+            }),
+            Some(40)
+        );
+        assert_eq!(
+            choose(WindowHintedIterator {
+                iter: 0..100,
+                window_size: 32,
+                hint_total_size: true,
+            }),
+            Some(40)
+        );
+    }
+
+    #[test]
+    fn value_stability_choose_multiple() {
+        fn do_test<I: Iterator<Item = u32>>(iter: I, v: &[u32]) {
+            let mut rng = crate::test::rng(412);
+            let mut buf = [0u32; 8];
+            assert_eq!(iter.choose_multiple_fill(&mut rng, &mut buf), v.len());
+            assert_eq!(&buf[0..v.len()], v);
+        }
+
+        do_test(0..4, &[0, 1, 2, 3]);
+        do_test(0..8, &[0, 1, 2, 3, 4, 5, 6, 7]);
+        do_test(0..100, &[58, 78, 80, 92, 43, 8, 96, 7]);
+
+        #[cfg(feature = "alloc")]
+        {
+            fn do_test<I: Iterator<Item = u32>>(iter: I, v: &[u32]) {
+                let mut rng = crate::test::rng(412);
+                assert_eq!(iter.choose_multiple(&mut rng, v.len()), v);
+            }
+
+            do_test(0..4, &[0, 1, 2, 3]);
+            do_test(0..8, &[0, 1, 2, 3, 4, 5, 6, 7]);
+            do_test(0..100, &[58, 78, 80, 92, 43, 8, 96, 7]);
+        }
+    }
+
+    #[test]
+    #[cfg(feature = "alloc")]
+    fn test_multiple_weighted_edge_cases() {
+        use super::*;
+
+        let mut rng = crate::test::rng(413);
+
+        // Case 1: One of the weights is 0
+        let choices = [('a', 2), ('b', 1), ('c', 0)];
+        for _ in 0..100 {
+            let result = choices
+                .choose_multiple_weighted(&mut rng, 2, |item| item.1)
+                .unwrap()
+                .collect::<Vec<_>>();
+
+            assert_eq!(result.len(), 2);
+            assert!(!result.iter().any(|val| val.0 == 'c'));
+        }
+
+        // Case 2: All of the weights are 0
+        let choices = [('a', 0), ('b', 0), ('c', 0)];
+        let result = choices
+            .choose_multiple_weighted(&mut rng, 2, |item| item.1)
+            .unwrap()
+            .collect::<Vec<_>>();
+        assert_eq!(result.len(), 2);
+
+        // Case 3: Negative weights
+        let choices = [('a', -1), ('b', 1), ('c', 1)];
+        assert_eq!(
+            choices
+                .choose_multiple_weighted(&mut rng, 2, |item| item.1)
+                .unwrap_err(),
+            WeightedError::InvalidWeight
+        );
+
+        // Case 4: Empty list
+        let choices = [];
+        let result = choices
+            .choose_multiple_weighted(&mut rng, 0, |_: &()| 0)
+            .unwrap()
+            .collect::<Vec<_>>();
+        assert_eq!(result.len(), 0);
+
+        // Case 5: NaN weights
+        let choices = [('a', core::f64::NAN), ('b', 1.0), ('c', 1.0)];
+        assert_eq!(
+            choices
+                .choose_multiple_weighted(&mut rng, 2, |item| item.1)
+                .unwrap_err(),
+            WeightedError::InvalidWeight
+        );
+
+        // Case 6: +infinity weights
+        let choices = [('a', core::f64::INFINITY), ('b', 1.0), ('c', 1.0)];
+        for _ in 0..100 {
+            let result = choices
+                .choose_multiple_weighted(&mut rng, 2, |item| item.1)
+                .unwrap()
+                .collect::<Vec<_>>();
+            assert_eq!(result.len(), 2);
+            assert!(result.iter().any(|val| val.0 == 'a'));
+        }
+
+        // Case 7: -infinity weights
+        let choices = [('a', core::f64::NEG_INFINITY), ('b', 1.0), ('c', 1.0)];
+        assert_eq!(
+            choices
+                .choose_multiple_weighted(&mut rng, 2, |item| item.1)
+                .unwrap_err(),
+            WeightedError::InvalidWeight
+        );
+
+        // Case 8: -0 weights
+        let choices = [('a', -0.0), ('b', 1.0), ('c', 1.0)];
+        assert!(choices
+            .choose_multiple_weighted(&mut rng, 2, |item| item.1)
+            .is_ok());
+    }
+
+    #[test]
+    #[cfg(feature = "alloc")]
+    fn test_multiple_weighted_distributions() {
+        use super::*;
+
+        // The theoretical probabilities of the different outcomes are:
+        // AB: 0.5  * 0.5  = 0.250
+        // AC: 0.5  * 0.5  = 0.250
+        // BA: 0.25 * 0.67 = 0.167
+        // BC: 0.25 * 0.33 = 0.082
+        // CA: 0.25 * 0.67 = 0.167
+        // CB: 0.25 * 0.33 = 0.082
+        let choices = [('a', 2), ('b', 1), ('c', 1)];
+        let mut rng = crate::test::rng(414);
+
+        let mut results = [0i32; 3];
+        let expected_results = [4167, 4167, 1666];
+        for _ in 0..10000 {
+            let result = choices
+                .choose_multiple_weighted(&mut rng, 2, |item| item.1)
+                .unwrap()
+                .collect::<Vec<_>>();
+
+            assert_eq!(result.len(), 2);
+
+            match (result[0].0, result[1].0) {
+                ('a', 'b') | ('b', 'a') => {
+                    results[0] += 1;
+                }
+                ('a', 'c') | ('c', 'a') => {
+                    results[1] += 1;
+                }
+                ('b', 'c') | ('c', 'b') => {
+                    results[2] += 1;
+                }
+                (_, _) => panic!("unexpected result"),
+            }
+        }
+
+        let mut diffs = results
+            .iter()
+            .zip(&expected_results)
+            .map(|(a, b)| (a - b).abs());
+        assert!(!diffs.any(|deviation| deviation > 100));
+    }
 }