diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9667aebfa13..1a098453c0e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,7 @@ You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.
 - Enable feature `small_rng` by default (#1455)
 - Allow `UniformFloat::new` samples and `UniformFloat::sample_single` to yield `high` (#1462)
 - Fix portability of `rand::distributions::Slice` (#1469)
+- Rename `rand::distributions` to `rand::distr` (#1470)
 
 ## [0.9.0-alpha.1] - 2024-03-18
 - Add the `Slice::num_choices` method to the Slice distribution (#1402)
diff --git a/README.md b/README.md
index 9fa7a2f8528..18f22a89eb8 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ A Rust library for random number generation, featuring:
     ([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
+-   A flexible [`distributions`](https://docs.rs/rand/*/rand/distr/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/)
diff --git a/benches/Cargo.toml b/benches/Cargo.toml
index b3068c2f758..083512d0bc6 100644
--- a/benches/Cargo.toml
+++ b/benches/Cargo.toml
@@ -15,8 +15,8 @@ criterion = "0.5"
 criterion-cycles-per-byte = "0.6"
 
 [[bench]]
-name = "distributions"
-path = "src/distributions.rs"
+name = "distr"
+path = "src/distr.rs"
 harness = false
 
 [[bench]]
diff --git a/benches/benches/base_distributions.rs b/benches/benches/base_distributions.rs
index c60ce47aeab..17202a30350 100644
--- a/benches/benches/base_distributions.rs
+++ b/benches/benches/base_distributions.rs
@@ -16,8 +16,8 @@ extern crate test;
 
 const RAND_BENCH_N: u64 = 1000;
 
-use rand::distributions::{Alphanumeric, Open01, OpenClosed01, Standard, Uniform};
-use rand::distributions::uniform::{UniformInt, UniformSampler};
+use rand::distr::{Alphanumeric, Open01, OpenClosed01, Standard, Uniform};
+use rand::distr::uniform::{UniformInt, UniformSampler};
 use core::mem::size_of;
 use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8};
 use core::time::Duration;
@@ -253,7 +253,7 @@ gen_range_float!(gen_range_f32, f32, -20000.0f32, 100000.0);
 gen_range_float!(gen_range_f64, f64, 123.456f64, 7890.12);
 
 
-// In src/distributions/uniform.rs, we say:
+// In src/distr/uniform.rs, we say:
 // Implementation of [`uniform_single`] is optional, and is only useful when
 // the implementation can be faster than `Self::new(low, high).sample(rng)`.
 
diff --git a/benches/benches/misc.rs b/benches/benches/misc.rs
index 50dfc0ea8a7..8a3b4767ef2 100644
--- a/benches/benches/misc.rs
+++ b/benches/benches/misc.rs
@@ -14,7 +14,7 @@ const RAND_BENCH_N: u64 = 1000;
 
 use test::Bencher;
 
-use rand::distributions::{Bernoulli, Distribution, Standard};
+use rand::distr::{Bernoulli, Distribution, Standard};
 use rand::prelude::*;
 use rand_pcg::{Pcg32, Pcg64Mcg};
 
diff --git a/benches/benches/weighted.rs b/benches/benches/weighted.rs
index 68722908a9e..da437ab5b0b 100644
--- a/benches/benches/weighted.rs
+++ b/benches/benches/weighted.rs
@@ -10,7 +10,7 @@
 
 extern crate test;
 
-use rand::distributions::WeightedIndex;
+use rand::distr::WeightedIndex;
 use rand::Rng;
 use test::Bencher;
 
diff --git a/benches/src/distributions.rs b/benches/src/distr.rs
similarity index 100%
rename from benches/src/distributions.rs
rename to benches/src/distr.rs
diff --git a/benches/src/uniform.rs b/benches/src/uniform.rs
index 948d1315889..78eb066eac7 100644
--- a/benches/src/uniform.rs
+++ b/benches/src/uniform.rs
@@ -10,7 +10,7 @@
 
 use core::time::Duration;
 use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
-use rand::distributions::uniform::{SampleRange, Uniform};
+use rand::distr::uniform::{SampleRange, Uniform};
 use rand::prelude::*;
 use rand_chacha::ChaCha8Rng;
 use rand_pcg::{Pcg32, Pcg64};
diff --git a/benches/src/uniform_float.rs b/benches/src/uniform_float.rs
index 91c0eff4b7b..f33a2b729d3 100644
--- a/benches/src/uniform_float.rs
+++ b/benches/src/uniform_float.rs
@@ -14,7 +14,7 @@
 
 use core::time::Duration;
 use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
-use rand::distributions::uniform::{SampleUniform, Uniform, UniformSampler};
+use rand::distr::uniform::{SampleUniform, Uniform, UniformSampler};
 use rand::prelude::*;
 use rand_chacha::ChaCha8Rng;
 use rand_pcg::{Pcg32, Pcg64};
diff --git a/examples/monte-carlo.rs b/examples/monte-carlo.rs
index 21ab109ce05..0f50a4aeb0d 100644
--- a/examples/monte-carlo.rs
+++ b/examples/monte-carlo.rs
@@ -23,7 +23,7 @@
 //! We can use the above fact to estimate the value of π: pick many points in
 //! the square at random, calculate the fraction that fall within the circle,
 //! and multiply this fraction by 4.
-use rand::distributions::{Distribution, Uniform};
+use rand::distr::{Distribution, Uniform};
 
 fn main() {
     let range = Uniform::new(-1.0f64, 1.0).unwrap();
diff --git a/examples/monty-hall.rs b/examples/monty-hall.rs
index aaff41cad33..a6fcd04e802 100644
--- a/examples/monty-hall.rs
+++ b/examples/monty-hall.rs
@@ -26,7 +26,7 @@
 //!
 //! [Monty Hall Problem]: https://en.wikipedia.org/wiki/Monty_Hall_problem
 
-use rand::distributions::{Distribution, Uniform};
+use rand::distr::{Distribution, Uniform};
 use rand::Rng;
 
 struct SimulationResult {
diff --git a/examples/rayon-monte-carlo.rs b/examples/rayon-monte-carlo.rs
index 839a1593a1b..31d8e681067 100644
--- a/examples/rayon-monte-carlo.rs
+++ b/examples/rayon-monte-carlo.rs
@@ -38,7 +38,7 @@
 //! over BATCH_SIZE trials. Manually batching also turns out to be faster
 //! for the nondeterministic version of this program as well.
 
-use rand::distributions::{Distribution, Uniform};
+use rand::distr::{Distribution, Uniform};
 use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
 use rayon::prelude::*;
 
diff --git a/rand_distr/README.md b/rand_distr/README.md
index 16a44bc85c9..0c8b20b95ef 100644
--- a/rand_distr/README.md
+++ b/rand_distr/README.md
@@ -8,7 +8,7 @@
 
 Implements a full suite of random number distribution sampling routines.
 
-This crate is a superset of the [rand::distributions] module, including support
+This crate is a superset of the [rand::distr] module, including support
 for sampling from Beta, Binomial, Cauchy, ChiSquared, Dirichlet, Exponential,
 FisherF, Gamma, Geometric, Hypergeometric, InverseGaussian, LogNormal, Normal,
 Pareto, PERT, Poisson, StudentT, Triangular and Weibull distributions.  Sampling
@@ -46,7 +46,7 @@ can be enabled. (Note that any other crate depending on `num-traits` with the
 
 
 [statrs]: https://github.com/boxtown/statrs
-[rand::distributions]: https://rust-random.github.io/rand/rand/distributions/index.html
+[rand::distr]: https://rust-random.github.io/rand/rand/distr/index.html
 
 ## License
 
diff --git a/rand_distr/src/hypergeometric.rs b/rand_distr/src/hypergeometric.rs
index 4e4f4306353..683db15314d 100644
--- a/rand_distr/src/hypergeometric.rs
+++ b/rand_distr/src/hypergeometric.rs
@@ -4,7 +4,7 @@ use crate::Distribution;
 use core::fmt;
 #[allow(unused_imports)]
 use num_traits::Float;
-use rand::distributions::uniform::Uniform;
+use rand::distr::uniform::Uniform;
 use rand::Rng;
 
 #[derive(Clone, Copy, Debug, PartialEq)]
diff --git a/rand_distr/src/lib.rs b/rand_distr/src/lib.rs
index f6f3ad54cfa..90a534ff8cb 100644
--- a/rand_distr/src/lib.rs
+++ b/rand_distr/src/lib.rs
@@ -27,8 +27,8 @@
 //!
 //! ## Re-exports
 //!
-//! This crate is a super-set of the [`rand::distributions`] module. See the
-//! [`rand::distributions`] module documentation for an overview of the core
+//! This crate is a super-set of the [`rand::distr`] module. See the
+//! [`rand::distr`] module documentation for an overview of the core
 //! [`Distribution`] trait and implementations.
 //!
 //! The following are re-exported:
@@ -93,7 +93,7 @@ extern crate std;
 #[allow(unused)]
 use rand::Rng;
 
-pub use rand::distributions::{
+pub use rand::distr::{
     uniform, Alphanumeric, Bernoulli, BernoulliError, DistIter, Distribution, Open01, OpenClosed01,
     Standard, Uniform,
 };
@@ -129,7 +129,7 @@ pub use self::weibull::{Error as WeibullError, Weibull};
 pub use self::zeta::{Error as ZetaError, Zeta};
 pub use self::zipf::{Error as ZipfError, Zipf};
 #[cfg(feature = "alloc")]
-pub use rand::distributions::{WeightError, WeightedIndex};
+pub use rand::distr::{WeightError, WeightedIndex};
 pub use student_t::StudentT;
 #[cfg(feature = "alloc")]
 pub use weighted_alias::WeightedAliasIndex;
diff --git a/rand_distr/src/utils.rs b/rand_distr/src/utils.rs
index fb49ab85762..5879a152670 100644
--- a/rand_distr/src/utils.rs
+++ b/rand_distr/src/utils.rs
@@ -10,7 +10,7 @@
 
 use crate::ziggurat_tables;
 use num_traits::Float;
-use rand::distributions::hidden_export::IntoFloat;
+use rand::distr::hidden_export::IntoFloat;
 use rand::Rng;
 
 /// Calculates ln(gamma(x)) (natural logarithm of the gamma
diff --git a/rand_distr/src/weighted_tree.rs b/rand_distr/src/weighted_tree.rs
index f3463bcd960..28edab700d4 100644
--- a/rand_distr/src/weighted_tree.rs
+++ b/rand_distr/src/weighted_tree.rs
@@ -14,8 +14,8 @@ use core::ops::SubAssign;
 use super::WeightError;
 use crate::Distribution;
 use alloc::vec::Vec;
-use rand::distributions::uniform::{SampleBorrow, SampleUniform};
-use rand::distributions::Weight;
+use rand::distr::uniform::{SampleBorrow, SampleUniform};
+use rand::distr::Weight;
 use rand::Rng;
 #[cfg(feature = "serde1")]
 use serde::{Deserialize, Serialize};
@@ -30,7 +30,7 @@ use serde::{Deserialize, Serialize};
 ///
 /// # Key differences
 ///
-/// The main distinction between [`WeightedTreeIndex<W>`] and [`rand::distributions::WeightedIndex<W>`]
+/// The main distinction between [`WeightedTreeIndex<W>`] and [`rand::distr::WeightedIndex<W>`]
 /// lies in the internal representation of weights. In [`WeightedTreeIndex<W>`],
 /// weights are structured as a tree, which is optimized for frequent updates of the weights.
 ///
diff --git a/rand_distr/src/zeta.rs b/rand_distr/src/zeta.rs
index da146883f0a..922458436f5 100644
--- a/rand_distr/src/zeta.rs
+++ b/rand_distr/src/zeta.rs
@@ -11,7 +11,7 @@
 use crate::{Distribution, Standard};
 use core::fmt;
 use num_traits::Float;
-use rand::{distributions::OpenClosed01, Rng};
+use rand::{distr::OpenClosed01, Rng};
 
 /// The [Zeta distribution](https://en.wikipedia.org/wiki/Zeta_distribution) `Zeta(s)`.
 ///
diff --git a/src/distributions/bernoulli.rs b/src/distr/bernoulli.rs
similarity index 98%
rename from src/distributions/bernoulli.rs
rename to src/distr/bernoulli.rs
index e49b415fea9..5a56d079a83 100644
--- a/src/distributions/bernoulli.rs
+++ b/src/distr/bernoulli.rs
@@ -8,7 +8,7 @@
 
 //! The Bernoulli distribution `Bernoulli(p)`.
 
-use crate::distributions::Distribution;
+use crate::distr::Distribution;
 use crate::Rng;
 use core::fmt;
 
@@ -31,7 +31,7 @@ use serde::{Deserialize, Serialize};
 /// # Example
 ///
 /// ```rust
-/// use rand::distributions::{Bernoulli, Distribution};
+/// use rand::distr::{Bernoulli, Distribution};
 ///
 /// let d = Bernoulli::new(0.3).unwrap();
 /// let v = d.sample(&mut rand::thread_rng());
@@ -153,7 +153,7 @@ impl Distribution<bool> for Bernoulli {
 #[cfg(test)]
 mod test {
     use super::Bernoulli;
-    use crate::distributions::Distribution;
+    use crate::distr::Distribution;
     use crate::Rng;
 
     #[test]
diff --git a/src/distributions/distribution.rs b/src/distr/distribution.rs
similarity index 96%
rename from src/distributions/distribution.rs
rename to src/distr/distribution.rs
index d545eeea457..8a59e11e13c 100644
--- a/src/distributions/distribution.rs
+++ b/src/distr/distribution.rs
@@ -49,7 +49,7 @@ pub trait Distribution<T> {
     ///
     /// ```
     /// use rand::thread_rng;
-    /// use rand::distributions::{Distribution, Alphanumeric, Uniform, Standard};
+    /// use rand::distr::{Distribution, Alphanumeric, Uniform, Standard};
     ///
     /// let mut rng = thread_rng();
     ///
@@ -89,7 +89,7 @@ pub trait Distribution<T> {
     ///
     /// ```
     /// use rand::thread_rng;
-    /// use rand::distributions::{Distribution, Uniform};
+    /// use rand::distr::{Distribution, Uniform};
     ///
     /// let mut rng = thread_rng();
     ///
@@ -201,12 +201,12 @@ pub trait DistString {
 
 #[cfg(test)]
 mod tests {
-    use crate::distributions::{Distribution, Uniform};
+    use crate::distr::{Distribution, Uniform};
     use crate::Rng;
 
     #[test]
     fn test_distributions_iter() {
-        use crate::distributions::Open01;
+        use crate::distr::Open01;
         let mut rng = crate::test::rng(210);
         let distr = Open01;
         let mut iter = Distribution::<f32>::sample_iter(distr, &mut rng);
@@ -248,7 +248,7 @@ mod tests {
     #[test]
     #[cfg(feature = "alloc")]
     fn test_dist_string() {
-        use crate::distributions::{Alphanumeric, DistString, Standard};
+        use crate::distr::{Alphanumeric, DistString, Standard};
         use core::str;
         let mut rng = crate::test::rng(213);
 
diff --git a/src/distributions/float.rs b/src/distr/float.rs
similarity index 96%
rename from src/distributions/float.rs
rename to src/distr/float.rs
index 427385e50a2..67e6d4b250d 100644
--- a/src/distributions/float.rs
+++ b/src/distr/float.rs
@@ -8,8 +8,8 @@
 
 //! Basic floating-point number distributions
 
-use crate::distributions::utils::{FloatAsSIMD, FloatSIMDUtils, IntAsSIMD};
-use crate::distributions::{Distribution, Standard};
+use crate::distr::utils::{FloatAsSIMD, FloatSIMDUtils, IntAsSIMD};
+use crate::distr::{Distribution, Standard};
 use crate::Rng;
 use core::mem;
 #[cfg(feature = "simd_support")]
@@ -33,15 +33,15 @@ use serde::{Deserialize, Serialize};
 /// # Example
 /// ```
 /// use rand::{thread_rng, Rng};
-/// use rand::distributions::OpenClosed01;
+/// use rand::distr::OpenClosed01;
 ///
 /// let val: f32 = thread_rng().sample(OpenClosed01);
 /// println!("f32 from (0, 1): {}", val);
 /// ```
 ///
-/// [`Standard`]: crate::distributions::Standard
-/// [`Open01`]: crate::distributions::Open01
-/// [`Uniform`]: crate::distributions::uniform::Uniform
+/// [`Standard`]: crate::distr::Standard
+/// [`Open01`]: crate::distr::Open01
+/// [`Uniform`]: crate::distr::uniform::Uniform
 #[derive(Clone, Copy, Debug)]
 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub struct OpenClosed01;
@@ -60,15 +60,15 @@ pub struct OpenClosed01;
 /// # Example
 /// ```
 /// use rand::{thread_rng, Rng};
-/// use rand::distributions::Open01;
+/// use rand::distr::Open01;
 ///
 /// let val: f32 = thread_rng().sample(Open01);
 /// println!("f32 from (0, 1): {}", val);
 /// ```
 ///
-/// [`Standard`]: crate::distributions::Standard
-/// [`OpenClosed01`]: crate::distributions::OpenClosed01
-/// [`Uniform`]: crate::distributions::uniform::Uniform
+/// [`Standard`]: crate::distr::Standard
+/// [`OpenClosed01`]: crate::distr::OpenClosed01
+/// [`Uniform`]: crate::distr::uniform::Uniform
 #[derive(Clone, Copy, Debug)]
 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub struct Open01;
diff --git a/src/distributions/integer.rs b/src/distr/integer.rs
similarity index 99%
rename from src/distributions/integer.rs
rename to src/distr/integer.rs
index 66258dcbd5c..49546a39417 100644
--- a/src/distributions/integer.rs
+++ b/src/distr/integer.rs
@@ -8,7 +8,7 @@
 
 //! The implementations of the `Standard` distribution for integer types.
 
-use crate::distributions::{Distribution, Standard};
+use crate::distr::{Distribution, Standard};
 use crate::Rng;
 #[cfg(all(target_arch = "x86", feature = "simd_support"))]
 use core::arch::x86::__m512i;
diff --git a/src/distributions/mod.rs b/src/distr/mod.rs
similarity index 99%
rename from src/distributions/mod.rs
rename to src/distr/mod.rs
index b31ebe14f18..8b5c0054271 100644
--- a/src/distributions/mod.rs
+++ b/src/distr/mod.rs
@@ -172,7 +172,7 @@ use crate::Rng;
 /// ```
 /// # #![allow(dead_code)]
 /// use rand::Rng;
-/// use rand::distributions::{Distribution, Standard};
+/// use rand::distr::{Distribution, Standard};
 ///
 /// struct MyF32 {
 ///     x: f32,
@@ -188,7 +188,7 @@ use crate::Rng;
 /// ## Example usage
 /// ```
 /// use rand::prelude::*;
-/// use rand::distributions::Standard;
+/// use rand::distr::Standard;
 ///
 /// let val: f32 = StdRng::from_os_rng().sample(Standard);
 /// println!("f32 from [0, 1): {}", val);
diff --git a/src/distributions/other.rs b/src/distr/other.rs
similarity index 98%
rename from src/distributions/other.rs
rename to src/distr/other.rs
index 5b05854ac24..3ce24e00a01 100644
--- a/src/distributions/other.rs
+++ b/src/distr/other.rs
@@ -14,8 +14,8 @@ use core::char;
 use core::num::Wrapping;
 
 #[cfg(feature = "alloc")]
-use crate::distributions::DistString;
-use crate::distributions::{Distribution, Standard, Uniform};
+use crate::distr::DistString;
+use crate::distr::{Distribution, Standard, Uniform};
 use crate::Rng;
 
 use core::mem::{self, MaybeUninit};
@@ -35,7 +35,7 @@ use serde::{Deserialize, Serialize};
 ///
 /// ```
 /// use rand::{Rng, thread_rng};
-/// use rand::distributions::Alphanumeric;
+/// use rand::distr::Alphanumeric;
 ///
 /// let mut rng = thread_rng();
 /// let chars: String = (0..7).map(|_| rng.sample(Alphanumeric) as char).collect();
@@ -45,7 +45,7 @@ use serde::{Deserialize, Serialize};
 /// The [`DistString`] trait provides an easier method of generating
 /// a random `String`, and offers more efficient allocation:
 /// ```
-/// use rand::distributions::{Alphanumeric, DistString};
+/// use rand::distr::{Alphanumeric, DistString};
 /// let string = Alphanumeric.sample_string(&mut rand::thread_rng(), 16);
 /// println!("Random string: {}", string);
 /// ```
diff --git a/src/distributions/slice.rs b/src/distr/slice.rs
similarity index 97%
rename from src/distributions/slice.rs
rename to src/distr/slice.rs
index 8b8f9662595..4677b4e89e4 100644
--- a/src/distributions/slice.rs
+++ b/src/distr/slice.rs
@@ -8,7 +8,7 @@
 
 use core::num::NonZeroUsize;
 
-use crate::distributions::{Distribution, Uniform};
+use crate::distr::{Distribution, Uniform};
 use crate::Rng;
 #[cfg(feature = "alloc")]
 use alloc::string::String;
@@ -63,7 +63,7 @@ impl UniformUsize {
 ///
 /// ```
 /// use rand::Rng;
-/// use rand::distributions::Slice;
+/// use rand::distr::Slice;
 ///
 /// let vowels = ['a', 'e', 'i', 'o', 'u'];
 /// let vowels_dist = Slice::new(&vowels).unwrap();
@@ -146,10 +146,7 @@ pub struct EmptySlice;
 
 impl core::fmt::Display for EmptySlice {
     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
-        write!(
-            f,
-            "Tried to create a `distributions::Slice` with an empty slice"
-        )
+        write!(f, "Tried to create a `distr::Slice` with an empty slice")
     }
 }
 
diff --git a/src/distr/uniform.rs b/src/distr/uniform.rs
new file mode 100644
index 00000000000..fa245c3aaf8
--- /dev/null
+++ b/src/distr/uniform.rs
@@ -0,0 +1,581 @@
+// 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
+// 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.
+
+//! A distribution uniformly sampling numbers within a given range.
+//!
+//! [`Uniform`] is the standard distribution to sample uniformly from a range;
+//! e.g. `Uniform::new_inclusive(1, 6).unwrap()` can sample integers from 1 to 6, like a
+//! standard die. [`Rng::gen_range`] supports any type supported by [`Uniform`].
+//!
+//! This distribution is provided with support for several primitive types
+//! (all integer and floating-point types) as well as [`std::time::Duration`],
+//! and supports extension to user-defined types via a type-specific *back-end*
+//! implementation.
+//!
+//! The types [`UniformInt`], [`UniformFloat`] and [`UniformDuration`] are the
+//! back-ends supporting sampling from primitive integer and floating-point
+//! ranges as well as from [`std::time::Duration`]; these types do not normally
+//! need to be used directly (unless implementing a derived back-end).
+//!
+//! # Example usage
+//!
+//! ```
+//! use rand::{Rng, thread_rng};
+//! use rand::distr::Uniform;
+//!
+//! let mut rng = thread_rng();
+//! let side = Uniform::new(-10.0, 10.0).unwrap();
+//!
+//! // sample between 1 and 10 points
+//! 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);
+//! }
+//! ```
+//!
+//! # Extending `Uniform` to support a custom type
+//!
+//! To extend [`Uniform`] to support your own types, write a back-end which
+//! implements the [`UniformSampler`] trait, then implement the [`SampleUniform`]
+//! helper trait to "register" your back-end. See the `MyF32` example below.
+//!
+//! At a minimum, the back-end needs to store any parameters needed for sampling
+//! (e.g. the target range) and implement `new`, `new_inclusive` and `sample`.
+//! Those methods should include an assertion to check the range is valid (i.e.
+//! `low < high`). The example below merely wraps another back-end.
+//!
+//! The `new`, `new_inclusive`, `sample_single` and `sample_single_inclusive`
+//! functions use arguments of
+//! type `SampleBorrow<X>` to support passing in values by reference or
+//! by value. In the implementation of these functions, you can choose to
+//! simply use the reference returned by [`SampleBorrow::borrow`], or you can choose
+//! to copy or clone the value, whatever is appropriate for your type.
+//!
+//! ```
+//! use rand::prelude::*;
+//! use rand::distr::uniform::{Uniform, SampleUniform,
+//!         UniformSampler, UniformFloat, SampleBorrow, Error};
+//!
+//! struct MyF32(f32);
+//!
+//! #[derive(Clone, Copy, Debug)]
+//! struct UniformMyF32(UniformFloat<f32>);
+//!
+//! impl UniformSampler for UniformMyF32 {
+//!     type X = MyF32;
+//!
+//!     fn new<B1, B2>(low: B1, high: B2) -> Result<Self, Error>
+//!         where B1: SampleBorrow<Self::X> + Sized,
+//!               B2: SampleBorrow<Self::X> + Sized
+//!     {
+//!         UniformFloat::<f32>::new(low.borrow().0, high.borrow().0).map(UniformMyF32)
+//!     }
+//!     fn new_inclusive<B1, B2>(low: B1, high: B2) -> Result<Self, Error>
+//!         where B1: SampleBorrow<Self::X> + Sized,
+//!               B2: SampleBorrow<Self::X> + Sized
+//!     {
+//!         UniformFloat::<f32>::new_inclusive(low.borrow().0, high.borrow().0).map(UniformMyF32)
+//!     }
+//!     fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
+//!         MyF32(self.0.sample(rng))
+//!     }
+//! }
+//!
+//! impl SampleUniform for MyF32 {
+//!     type Sampler = UniformMyF32;
+//! }
+//!
+//! let (low, high) = (MyF32(17.0f32), MyF32(22.0f32));
+//! let uniform = Uniform::new(low, high).unwrap();
+//! let x = uniform.sample(&mut thread_rng());
+//! ```
+//!
+//! [`SampleUniform`]: crate::distr::uniform::SampleUniform
+//! [`UniformSampler`]: crate::distr::uniform::UniformSampler
+//! [`UniformInt`]: crate::distr::uniform::UniformInt
+//! [`UniformFloat`]: crate::distr::uniform::UniformFloat
+//! [`UniformDuration`]: crate::distr::uniform::UniformDuration
+//! [`SampleBorrow::borrow`]: crate::distr::uniform::SampleBorrow::borrow
+
+#[path = "uniform_float.rs"]
+mod float;
+#[doc(inline)]
+pub use float::UniformFloat;
+
+#[path = "uniform_int.rs"]
+mod int;
+#[doc(inline)]
+pub use int::UniformInt;
+
+#[path = "uniform_other.rs"]
+mod other;
+#[doc(inline)]
+pub use other::{UniformChar, UniformDuration};
+
+use core::fmt;
+use core::ops::{Range, RangeInclusive};
+
+use crate::distr::Distribution;
+use crate::{Rng, RngCore};
+
+/// Error type returned from [`Uniform::new`] and `new_inclusive`.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum Error {
+    /// `low > high`, or equal in case of exclusive range.
+    EmptyRange,
+    /// Input or range `high - low` is non-finite. Not relevant to integer types.
+    NonFinite,
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str(match self {
+            Error::EmptyRange => "low > high (or equal if exclusive) in uniform distribution",
+            Error::NonFinite => "Non-finite range in uniform distribution",
+        })
+    }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for Error {}
+
+#[cfg(feature = "serde1")]
+use serde::{Deserialize, Serialize};
+
+/// 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. 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
+/// the full range of integer types, this should have comparable performance to
+/// the `Standard` distribution.
+///
+/// Steps are taken to avoid bias, which might be present in naive
+/// implementations; for example `rng.gen::<u8>() % 170` samples from the range
+/// `[0, 169]` but is twice as likely to select numbers less than 85 than other
+/// values. Further, the implementations here give more weight to the high-bits
+/// generated by the RNG than the low bits, since with some RNGs the low-bits
+/// are of lower quality than the high bits.
+///
+/// Implementations must sample in `[low, high)` range for
+/// `Uniform::new(low, high)`, i.e., excluding `high`. In particular, care must
+/// be taken to ensure that rounding never results values `< low` or `>= high`.
+///
+/// # Example
+///
+/// ```
+/// use rand::distr::{Distribution, Uniform};
+///
+/// let between = Uniform::try_from(10..10000).unwrap();
+/// 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 preferred:
+///
+/// ```
+/// 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, PartialEq, Eq)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "serde1", serde(bound(serialize = "X::Sampler: Serialize")))]
+#[cfg_attr(
+    feature = "serde1",
+    serde(bound(deserialize = "X::Sampler: Deserialize<'de>"))
+)]
+pub struct Uniform<X: SampleUniform>(X::Sampler);
+
+impl<X: SampleUniform> Uniform<X> {
+    /// Create a new `Uniform` instance, which samples uniformly from the half
+    /// open range `[low, high)` (excluding `high`).
+    ///
+    /// For discrete types (e.g. integers), samples will always be strictly less
+    /// than `high`. For (approximations of) continuous types (e.g. `f32`, `f64`),
+    /// samples may equal `high` due to loss of precision but may not be
+    /// greater than `high`.
+    ///
+    /// Fails if `low >= high`, or if `low`, `high` or the range `high - low` is
+    /// non-finite. In release mode, only the range is checked.
+    pub fn new<B1, B2>(low: B1, high: B2) -> Result<Uniform<X>, Error>
+    where
+        B1: SampleBorrow<X> + Sized,
+        B2: SampleBorrow<X> + Sized,
+    {
+        X::Sampler::new(low, high).map(Uniform)
+    }
+
+    /// Create a new `Uniform` instance, which samples uniformly from the closed
+    /// range `[low, high]` (inclusive).
+    ///
+    /// Fails if `low > high`, or if `low`, `high` or the range `high - low` is
+    /// non-finite. In release mode, only the range is checked.
+    pub fn new_inclusive<B1, B2>(low: B1, high: B2) -> Result<Uniform<X>, Error>
+    where
+        B1: SampleBorrow<X> + Sized,
+        B2: SampleBorrow<X> + Sized,
+    {
+        X::Sampler::new_inclusive(low, high).map(Uniform)
+    }
+}
+
+impl<X: SampleUniform> Distribution<X> for Uniform<X> {
+    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> X {
+        self.0.sample(rng)
+    }
+}
+
+/// Helper trait for creating objects using the correct implementation of
+/// [`UniformSampler`] for the sampling type.
+///
+/// See the [module documentation] on how to implement [`Uniform`] range
+/// sampling for a custom type.
+///
+/// [module documentation]: crate::distr::uniform
+pub trait SampleUniform: Sized {
+    /// The `UniformSampler` implementation supporting type `X`.
+    type Sampler: UniformSampler<X = Self>;
+}
+
+/// Helper trait handling actual uniform sampling.
+///
+/// See the [module documentation] on how to implement [`Uniform`] range
+/// sampling for a custom type.
+///
+/// Implementation of [`sample_single`] is optional, and is only useful when
+/// the implementation can be faster than `Self::new(low, high).sample(rng)`.
+///
+/// [module documentation]: crate::distr::uniform
+/// [`sample_single`]: UniformSampler::sample_single
+pub trait UniformSampler: Sized {
+    /// The type sampled by this implementation.
+    type X;
+
+    /// Construct self, with inclusive lower bound and exclusive upper bound `[low, high)`.
+    ///
+    /// For discrete types (e.g. integers), samples will always be strictly less
+    /// than `high`. For (approximations of) continuous types (e.g. `f32`, `f64`),
+    /// samples may equal `high` due to loss of precision but may not be
+    /// greater than `high`.
+    ///
+    /// Usually users should not call this directly but prefer to use
+    /// [`Uniform::new`].
+    fn new<B1, B2>(low: B1, high: B2) -> Result<Self, Error>
+    where
+        B1: SampleBorrow<Self::X> + Sized,
+        B2: SampleBorrow<Self::X> + Sized;
+
+    /// Construct self, with inclusive bounds `[low, high]`.
+    ///
+    /// Usually users should not call this directly but prefer to use
+    /// [`Uniform::new_inclusive`].
+    fn new_inclusive<B1, B2>(low: B1, high: B2) -> Result<Self, Error>
+    where
+        B1: SampleBorrow<Self::X> + Sized,
+        B2: SampleBorrow<Self::X> + Sized;
+
+    /// Sample a value.
+    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X;
+
+    /// Sample a single value uniformly from a range with inclusive lower bound
+    /// and exclusive upper bound `[low, high)`.
+    ///
+    /// For discrete types (e.g. integers), samples will always be strictly less
+    /// than `high`. For (approximations of) continuous types (e.g. `f32`, `f64`),
+    /// samples may equal `high` due to loss of precision but may not be
+    /// greater than `high`.
+    ///
+    /// By default this is implemented using
+    /// `UniformSampler::new(low, high).sample(rng)`. However, for some types
+    /// more optimal implementations for single usage may be provided via this
+    /// method (which is the case for integers and floats).
+    /// Results may not be identical.
+    ///
+    /// Note that to use this method in a generic context, the type needs to be
+    /// retrieved via `SampleUniform::Sampler` as follows:
+    /// ```
+    /// use rand::{thread_rng, distr::uniform::{SampleUniform, UniformSampler}};
+    /// # #[allow(unused)]
+    /// fn sample_from_range<T: SampleUniform>(lb: T, ub: T) -> T {
+    ///     let mut rng = thread_rng();
+    ///     <T as SampleUniform>::Sampler::sample_single(lb, ub, &mut rng).unwrap()
+    /// }
+    /// ```
+    fn sample_single<R: Rng + ?Sized, B1, B2>(
+        low: B1,
+        high: B2,
+        rng: &mut R,
+    ) -> Result<Self::X, Error>
+    where
+        B1: SampleBorrow<Self::X> + Sized,
+        B2: SampleBorrow<Self::X> + Sized,
+    {
+        let uniform: Self = UniformSampler::new(low, high)?;
+        Ok(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,
+    ) -> Result<Self::X, Error>
+    where
+        B1: SampleBorrow<Self::X> + Sized,
+        B2: SampleBorrow<Self::X> + Sized,
+    {
+        let uniform: Self = UniformSampler::new_inclusive(low, high)?;
+        Ok(uniform.sample(rng))
+    }
+}
+
+impl<X: SampleUniform> TryFrom<Range<X>> for Uniform<X> {
+    type Error = Error;
+
+    fn try_from(r: Range<X>) -> Result<Uniform<X>, Error> {
+        Uniform::new(r.start, r.end)
+    }
+}
+
+impl<X: SampleUniform> TryFrom<RangeInclusive<X>> for Uniform<X> {
+    type Error = Error;
+
+    fn try_from(r: ::core::ops::RangeInclusive<X>) -> Result<Uniform<X>, Error> {
+        Uniform::new_inclusive(r.start(), r.end())
+    }
+}
+
+/// Helper trait similar to [`Borrow`] but implemented
+/// only for [`SampleUniform`] and references to [`SampleUniform`]
+/// in order to resolve ambiguity issues.
+///
+/// [`Borrow`]: std::borrow::Borrow
+pub trait SampleBorrow<Borrowed> {
+    /// Immutably borrows from an owned value. See [`Borrow::borrow`]
+    ///
+    /// [`Borrow::borrow`]: std::borrow::Borrow::borrow
+    fn borrow(&self) -> &Borrowed;
+}
+impl<Borrowed> SampleBorrow<Borrowed> for Borrowed
+where
+    Borrowed: SampleUniform,
+{
+    #[inline(always)]
+    fn borrow(&self) -> &Borrowed {
+        self
+    }
+}
+impl<'a, Borrowed> SampleBorrow<Borrowed> for &'a Borrowed
+where
+    Borrowed: SampleUniform,
+{
+    #[inline(always)]
+    fn borrow(&self) -> &Borrowed {
+        self
+    }
+}
+
+/// 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) -> Result<T, Error>;
+
+    /// 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) -> Result<T, Error> {
+        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) -> Result<T, Error> {
+        T::Sampler::sample_single_inclusive(self.start(), self.end(), rng)
+    }
+
+    #[inline]
+    fn is_empty(&self) -> bool {
+        !(self.start() <= self.end())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use core::time::Duration;
+
+    #[test]
+    #[cfg(feature = "serde1")]
+    fn test_uniform_serialization() {
+        let unit_box: Uniform<i32> = Uniform::new(-1, 1).unwrap();
+        let de_unit_box: Uniform<i32> =
+            bincode::deserialize(&bincode::serialize(&unit_box).unwrap()).unwrap();
+        assert_eq!(unit_box.0, de_unit_box.0);
+
+        let unit_box: Uniform<f32> = Uniform::new(-1., 1.).unwrap();
+        let de_unit_box: Uniform<f32> =
+            bincode::deserialize(&bincode::serialize(&unit_box).unwrap()).unwrap();
+        assert_eq!(unit_box.0, de_unit_box.0);
+    }
+
+    #[test]
+    fn test_custom_uniform() {
+        use crate::distr::uniform::{SampleBorrow, SampleUniform, UniformFloat, UniformSampler};
+        #[derive(Clone, Copy, PartialEq, PartialOrd)]
+        struct MyF32 {
+            x: f32,
+        }
+        #[derive(Clone, Copy, Debug)]
+        struct UniformMyF32(UniformFloat<f32>);
+        impl UniformSampler for UniformMyF32 {
+            type X = MyF32;
+
+            fn new<B1, B2>(low: B1, high: B2) -> Result<Self, Error>
+            where
+                B1: SampleBorrow<Self::X> + Sized,
+                B2: SampleBorrow<Self::X> + Sized,
+            {
+                UniformFloat::<f32>::new(low.borrow().x, high.borrow().x).map(UniformMyF32)
+            }
+
+            fn new_inclusive<B1, B2>(low: B1, high: B2) -> Result<Self, Error>
+            where
+                B1: SampleBorrow<Self::X> + Sized,
+                B2: SampleBorrow<Self::X> + Sized,
+            {
+                UniformSampler::new(low, high)
+            }
+
+            fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
+                MyF32 {
+                    x: self.0.sample(rng),
+                }
+            }
+        }
+        impl SampleUniform for MyF32 {
+            type Sampler = UniformMyF32;
+        }
+
+        let (low, high) = (MyF32 { x: 17.0f32 }, MyF32 { x: 22.0f32 });
+        let uniform = Uniform::new(low, high).unwrap();
+        let mut rng = crate::test::rng(804);
+        for _ in 0..100 {
+            let x: MyF32 = rng.sample(uniform);
+            assert!(low <= x && x < high);
+        }
+    }
+
+    #[test]
+    fn value_stability() {
+        fn test_samples<T: SampleUniform + Copy + fmt::Debug + PartialEq>(
+            lb: T,
+            ub: T,
+            expected_single: &[T],
+            expected_multiple: &[T],
+        ) where
+            Uniform<T>: Distribution<T>,
+        {
+            let mut rng = crate::test::rng(897);
+            let mut buf = [lb; 3];
+
+            for x in &mut buf {
+                *x = T::Sampler::sample_single(lb, ub, &mut rng).unwrap();
+            }
+            assert_eq!(&buf, expected_single);
+
+            let distr = Uniform::new(lb, ub).unwrap();
+            for x in &mut buf {
+                *x = rng.sample(&distr);
+            }
+            assert_eq!(&buf, expected_multiple);
+        }
+
+        // We test on a sub-set of types; possibly we should do more.
+        // TODO: SIMD types
+
+        test_samples(11u8, 219, &[17, 66, 214], &[181, 93, 165]);
+        test_samples(11u32, 219, &[17, 66, 214], &[181, 93, 165]);
+
+        test_samples(
+            0f32,
+            1e-2f32,
+            &[0.0003070104, 0.0026630748, 0.00979833],
+            &[0.008194133, 0.00398172, 0.007428536],
+        );
+        test_samples(
+            -1e10f64,
+            1e10f64,
+            &[-4673848682.871551, 6388267422.932352, 4857075081.198343],
+            &[1173375212.1808167, 1917642852.109581, 2365076174.3153973],
+        );
+
+        test_samples(
+            Duration::new(2, 0),
+            Duration::new(4, 0),
+            &[
+                Duration::new(2, 532615131),
+                Duration::new(3, 638826742),
+                Duration::new(3, 485707508),
+            ],
+            &[
+                Duration::new(3, 117337521),
+                Duration::new(3, 191764285),
+                Duration::new(3, 236507617),
+            ],
+        );
+    }
+
+    #[test]
+    fn uniform_distributions_can_be_compared() {
+        assert_eq!(
+            Uniform::new(1.0, 2.0).unwrap(),
+            Uniform::new(1.0, 2.0).unwrap()
+        );
+
+        // To cover UniformInt
+        assert_eq!(
+            Uniform::new(1_u32, 2_u32).unwrap(),
+            Uniform::new(1_u32, 2_u32).unwrap()
+        );
+    }
+}
diff --git a/src/distr/uniform_float.rs b/src/distr/uniform_float.rs
new file mode 100644
index 00000000000..b44e192c65d
--- /dev/null
+++ b/src/distr/uniform_float.rs
@@ -0,0 +1,450 @@
+// 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
+// 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.
+
+//! `UniformFloat` implementation
+
+use super::{Error, SampleBorrow, SampleUniform, UniformSampler};
+use crate::distr::float::IntoFloat;
+use crate::distr::utils::{BoolAsSIMD, FloatAsSIMD, FloatSIMDUtils, IntAsSIMD};
+use crate::Rng;
+
+#[cfg(feature = "simd_support")]
+use core::simd::prelude::*;
+// #[cfg(feature = "simd_support")]
+// use core::simd::{LaneCount, SupportedLaneCount};
+
+#[cfg(feature = "serde1")]
+use serde::{Deserialize, Serialize};
+
+/// The back-end implementing [`UniformSampler`] for floating-point types.
+///
+/// Unless you are implementing [`UniformSampler`] for your own type, this type
+/// should not be used directly, use [`Uniform`] instead.
+///
+/// # Implementation notes
+///
+/// Instead of generating a float in the `[0, 1)` range using [`Standard`], the
+/// `UniformFloat` implementation converts the output of an PRNG itself. This
+/// way one or two steps can be optimized out.
+///
+/// The floats are first converted to a value in the `[1, 2)` interval using a
+/// transmute-based method, and then mapped to the expected range with a
+/// multiply and addition. Values produced this way have what equals 23 bits of
+/// random digits for an `f32`, and 52 for an `f64`.
+///
+/// [`new`]: UniformSampler::new
+/// [`new_inclusive`]: UniformSampler::new_inclusive
+/// [`Standard`]: crate::distr::Standard
+/// [`Uniform`]: super::Uniform
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
+pub struct UniformFloat<X> {
+    low: X,
+    scale: X,
+}
+
+macro_rules! uniform_float_impl {
+    ($($meta:meta)?, $ty:ty, $uty:ident, $f_scalar:ident, $u_scalar:ident, $bits_to_discard:expr) => {
+        $(#[cfg($meta)])?
+        impl UniformFloat<$ty> {
+            /// Construct, reducing `scale` as required to ensure that rounding
+            /// can never yield values greater than `high`.
+            ///
+            /// Note: though it may be tempting to use a variant of this method
+            /// to ensure that samples from `[low, high)` are always strictly
+            /// less than `high`, this approach may be very slow where
+            /// `scale.abs()` is much smaller than `high.abs()`
+            /// (example: `low=0.99999999997819644, high=1.`).
+            fn new_bounded(low: $ty, high: $ty, mut scale: $ty) -> Self {
+                let max_rand = <$ty>::splat(1.0 as $f_scalar - $f_scalar::EPSILON);
+
+                loop {
+                    let mask = (scale * max_rand + low).gt_mask(high);
+                    if !mask.any() {
+                        break;
+                    }
+                    scale = scale.decrease_masked(mask);
+                }
+
+                debug_assert!(<$ty>::splat(0.0).all_le(scale));
+
+                UniformFloat { low, scale }
+            }
+        }
+
+        $(#[cfg($meta)])?
+        impl SampleUniform for $ty {
+            type Sampler = UniformFloat<$ty>;
+        }
+
+        $(#[cfg($meta)])?
+        impl UniformSampler for UniformFloat<$ty> {
+            type X = $ty;
+
+            fn new<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
+            where
+                B1: SampleBorrow<Self::X> + Sized,
+                B2: SampleBorrow<Self::X> + Sized,
+            {
+                let low = *low_b.borrow();
+                let high = *high_b.borrow();
+                #[cfg(debug_assertions)]
+                if !(low.all_finite()) || !(high.all_finite()) {
+                    return Err(Error::NonFinite);
+                }
+                if !(low.all_lt(high)) {
+                    return Err(Error::EmptyRange);
+                }
+
+                let scale = high - low;
+                if !(scale.all_finite()) {
+                    return Err(Error::NonFinite);
+                }
+
+                Ok(Self::new_bounded(low, high, scale))
+            }
+
+            fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
+            where
+                B1: SampleBorrow<Self::X> + Sized,
+                B2: SampleBorrow<Self::X> + Sized,
+            {
+                let low = *low_b.borrow();
+                let high = *high_b.borrow();
+                #[cfg(debug_assertions)]
+                if !(low.all_finite()) || !(high.all_finite()) {
+                    return Err(Error::NonFinite);
+                }
+                if !low.all_le(high) {
+                    return Err(Error::EmptyRange);
+                }
+
+                let max_rand = <$ty>::splat(1.0 as $f_scalar - $f_scalar::EPSILON);
+                let scale = (high - low) / max_rand;
+                if !scale.all_finite() {
+                    return Err(Error::NonFinite);
+                }
+
+                Ok(Self::new_bounded(low, high, scale))
+            }
+
+            fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
+                // Generate a value in the range [1, 2)
+                let value1_2 = (rng.random::<$uty>() >> $uty::splat($bits_to_discard)).into_float_with_exponent(0);
+
+                // Get a value in the range [0, 1) to avoid overflow when multiplying by scale
+                let value0_1 = value1_2 - <$ty>::splat(1.0);
+
+                // We don't use `f64::mul_add`, because it is not available with
+                // `no_std`. Furthermore, it is slower for some targets (but
+                // faster for others). However, the order of multiplication and
+                // addition is important, because on some platforms (e.g. ARM)
+                // it will be optimized to a single (non-FMA) instruction.
+                value0_1 * self.scale + self.low
+            }
+
+            #[inline]
+            fn sample_single<R: Rng + ?Sized, B1, B2>(low_b: B1, high_b: B2, rng: &mut R) -> Result<Self::X, Error>
+            where
+                B1: SampleBorrow<Self::X> + Sized,
+                B2: SampleBorrow<Self::X> + Sized,
+            {
+                Self::sample_single_inclusive(low_b, high_b, rng)
+            }
+
+            #[inline]
+            fn sample_single_inclusive<R: Rng + ?Sized, B1, B2>(low_b: B1, high_b: B2, rng: &mut R) -> Result<Self::X, Error>
+            where
+                B1: SampleBorrow<Self::X> + Sized,
+                B2: SampleBorrow<Self::X> + Sized,
+            {
+                let low = *low_b.borrow();
+                let high = *high_b.borrow();
+                #[cfg(debug_assertions)]
+                if !low.all_finite() || !high.all_finite() {
+                    return Err(Error::NonFinite);
+                }
+                if !low.all_le(high) {
+                    return Err(Error::EmptyRange);
+                }
+                let scale = high - low;
+                if !scale.all_finite() {
+                    return Err(Error::NonFinite);
+                }
+
+                // Generate a value in the range [1, 2)
+                let value1_2 =
+                    (rng.random::<$uty>() >> $uty::splat($bits_to_discard)).into_float_with_exponent(0);
+
+                // Get a value in the range [0, 1) to avoid overflow when multiplying by scale
+                let value0_1 = value1_2 - <$ty>::splat(1.0);
+
+                // Doing multiply before addition allows some architectures
+                // to use a single instruction.
+                Ok(value0_1 * scale + low)
+            }
+        }
+    };
+}
+
+uniform_float_impl! { , f32, u32, f32, u32, 32 - 23 }
+uniform_float_impl! { , f64, u64, f64, u64, 64 - 52 }
+
+#[cfg(feature = "simd_support")]
+uniform_float_impl! { feature = "simd_support", f32x2, u32x2, f32, u32, 32 - 23 }
+#[cfg(feature = "simd_support")]
+uniform_float_impl! { feature = "simd_support", f32x4, u32x4, f32, u32, 32 - 23 }
+#[cfg(feature = "simd_support")]
+uniform_float_impl! { feature = "simd_support", f32x8, u32x8, f32, u32, 32 - 23 }
+#[cfg(feature = "simd_support")]
+uniform_float_impl! { feature = "simd_support", f32x16, u32x16, f32, u32, 32 - 23 }
+
+#[cfg(feature = "simd_support")]
+uniform_float_impl! { feature = "simd_support", f64x2, u64x2, f64, u64, 64 - 52 }
+#[cfg(feature = "simd_support")]
+uniform_float_impl! { feature = "simd_support", f64x4, u64x4, f64, u64, 64 - 52 }
+#[cfg(feature = "simd_support")]
+uniform_float_impl! { feature = "simd_support", f64x8, u64x8, f64, u64, 64 - 52 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::distr::{utils::FloatSIMDScalarUtils, Uniform};
+    use crate::rngs::mock::StepRng;
+
+    #[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);
+        let mut max_rng = StepRng::new(0xffff_ffff_ffff_ffff, 0);
+        macro_rules! t {
+            ($ty:ty, $f_scalar:ident, $bits_shifted:expr) => {{
+                let v: &[($f_scalar, $f_scalar)] = &[
+                    (0.0, 100.0),
+                    (-1e35, -1e25),
+                    (1e-35, 1e-25),
+                    (-1e35, 1e35),
+                    (<$f_scalar>::from_bits(0), <$f_scalar>::from_bits(3)),
+                    (-<$f_scalar>::from_bits(10), -<$f_scalar>::from_bits(1)),
+                    (-<$f_scalar>::from_bits(5), 0.0),
+                    (-<$f_scalar>::from_bits(7), -0.0),
+                    (0.1 * $f_scalar::MAX, $f_scalar::MAX),
+                    (-$f_scalar::MAX * 0.2, $f_scalar::MAX * 0.7),
+                ];
+                for &(low_scalar, high_scalar) in v.iter() {
+                    for lane in 0..<$ty>::LEN {
+                        let low = <$ty>::splat(0.0 as $f_scalar).replace(lane, low_scalar);
+                        let high = <$ty>::splat(1.0 as $f_scalar).replace(lane, high_scalar);
+                        let my_uniform = Uniform::new(low, high).unwrap();
+                        let my_incl_uniform = Uniform::new_inclusive(low, high).unwrap();
+                        for _ in 0..100 {
+                            let v = rng.sample(my_uniform).extract(lane);
+                            assert!(low_scalar <= v && v <= high_scalar);
+                            let v = rng.sample(my_incl_uniform).extract(lane);
+                            assert!(low_scalar <= v && v <= high_scalar);
+                            let v =
+                                <$ty as SampleUniform>::Sampler::sample_single(low, high, &mut rng)
+                                    .unwrap()
+                                    .extract(lane);
+                            assert!(low_scalar <= v && v <= high_scalar);
+                            let v = <$ty as SampleUniform>::Sampler::sample_single_inclusive(
+                                low, high, &mut rng,
+                            )
+                            .unwrap()
+                            .extract(lane);
+                            assert!(low_scalar <= v && v <= high_scalar);
+                        }
+
+                        assert_eq!(
+                            rng.sample(Uniform::new_inclusive(low, low).unwrap())
+                                .extract(lane),
+                            low_scalar
+                        );
+
+                        assert_eq!(zero_rng.sample(my_uniform).extract(lane), low_scalar);
+                        assert_eq!(zero_rng.sample(my_incl_uniform).extract(lane), low_scalar);
+                        assert_eq!(
+                            <$ty as SampleUniform>::Sampler::sample_single(
+                                low,
+                                high,
+                                &mut zero_rng
+                            )
+                            .unwrap()
+                            .extract(lane),
+                            low_scalar
+                        );
+                        assert_eq!(
+                            <$ty as SampleUniform>::Sampler::sample_single_inclusive(
+                                low,
+                                high,
+                                &mut zero_rng
+                            )
+                            .unwrap()
+                            .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);
+                        // sample_single cannot cope with max_rng:
+                        // assert!(<$ty as SampleUniform>::Sampler
+                        //     ::sample_single(low, high, &mut max_rng).unwrap()
+                        //     .extract(lane) <= high_scalar);
+                        assert!(
+                            <$ty as SampleUniform>::Sampler::sample_single_inclusive(
+                                low,
+                                high,
+                                &mut max_rng
+                            )
+                            .unwrap()
+                            .extract(lane)
+                                <= high_scalar
+                        );
+
+                        // Don't run this test for really tiny differences between high and low
+                        // since for those rounding might result in selecting high for a very
+                        // long time.
+                        if (high_scalar - low_scalar) > 0.0001 {
+                            let mut lowering_max_rng = StepRng::new(
+                                0xffff_ffff_ffff_ffff,
+                                (-1i64 << $bits_shifted) as u64,
+                            );
+                            assert!(
+                                <$ty as SampleUniform>::Sampler::sample_single(
+                                    low,
+                                    high,
+                                    &mut lowering_max_rng
+                                )
+                                .unwrap()
+                                .extract(lane)
+                                    <= high_scalar
+                            );
+                        }
+                    }
+                }
+
+                assert_eq!(
+                    rng.sample(Uniform::new_inclusive($f_scalar::MAX, $f_scalar::MAX).unwrap()),
+                    $f_scalar::MAX
+                );
+                assert_eq!(
+                    rng.sample(Uniform::new_inclusive(-$f_scalar::MAX, -$f_scalar::MAX).unwrap()),
+                    -$f_scalar::MAX
+                );
+            }};
+        }
+
+        t!(f32, f32, 32 - 23);
+        t!(f64, f64, 64 - 52);
+        #[cfg(feature = "simd_support")]
+        {
+            t!(f32x2, f32, 32 - 23);
+            t!(f32x4, f32, 32 - 23);
+            t!(f32x8, f32, 32 - 23);
+            t!(f32x16, f32, 32 - 23);
+            t!(f64x2, f64, 64 - 52);
+            t!(f64x4, f64, 64 - 52);
+            t!(f64x8, f64, 64 - 52);
+        }
+    }
+
+    #[test]
+    fn test_float_overflow() {
+        assert_eq!(Uniform::try_from(f64::MIN..f64::MAX), Err(Error::NonFinite));
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_float_overflow_single() {
+        let mut rng = crate::test::rng(252);
+        rng.gen_range(f64::MIN..f64::MAX);
+    }
+
+    #[test]
+    #[cfg(all(feature = "std", panic = "unwind"))]
+    fn test_float_assertions() {
+        use super::SampleUniform;
+        fn range<T: SampleUniform>(low: T, high: T) -> Result<T, Error> {
+            let mut rng = crate::test::rng(253);
+            T::Sampler::sample_single(low, high, &mut rng)
+        }
+
+        macro_rules! t {
+            ($ty:ident, $f_scalar:ident) => {{
+                let v: &[($f_scalar, $f_scalar)] = &[
+                    ($f_scalar::NAN, 0.0),
+                    (1.0, $f_scalar::NAN),
+                    ($f_scalar::NAN, $f_scalar::NAN),
+                    (1.0, 0.5),
+                    ($f_scalar::MAX, -$f_scalar::MAX),
+                    ($f_scalar::INFINITY, $f_scalar::INFINITY),
+                    ($f_scalar::NEG_INFINITY, $f_scalar::NEG_INFINITY),
+                    ($f_scalar::NEG_INFINITY, 5.0),
+                    (5.0, $f_scalar::INFINITY),
+                    ($f_scalar::NAN, $f_scalar::INFINITY),
+                    ($f_scalar::NEG_INFINITY, $f_scalar::NAN),
+                    ($f_scalar::NEG_INFINITY, $f_scalar::INFINITY),
+                ];
+                for &(low_scalar, high_scalar) in v.iter() {
+                    for lane in 0..<$ty>::LEN {
+                        let low = <$ty>::splat(0.0 as $f_scalar).replace(lane, low_scalar);
+                        let high = <$ty>::splat(1.0 as $f_scalar).replace(lane, high_scalar);
+                        assert!(range(low, high).is_err());
+                        assert!(Uniform::new(low, high).is_err());
+                        assert!(Uniform::new_inclusive(low, high).is_err());
+                        assert!(Uniform::new(low, low).is_err());
+                    }
+                }
+            }};
+        }
+
+        t!(f32, f32);
+        t!(f64, f64);
+        #[cfg(feature = "simd_support")]
+        {
+            t!(f32x2, f32);
+            t!(f32x4, f32);
+            t!(f32x8, f32);
+            t!(f32x16, f32);
+            t!(f64x2, f64);
+            t!(f64x4, f64);
+            t!(f64x8, f64);
+        }
+    }
+
+    #[test]
+    fn test_uniform_from_std_range() {
+        let r = Uniform::try_from(2.0f64..7.0).unwrap();
+        assert_eq!(r.0.low, 2.0);
+        assert_eq!(r.0.scale, 5.0);
+    }
+
+    #[test]
+    fn test_uniform_from_std_range_bad_limits() {
+        #![allow(clippy::reversed_empty_ranges)]
+        assert!(Uniform::try_from(100.0..10.0).is_err());
+        assert!(Uniform::try_from(100.0..100.0).is_err());
+    }
+
+    #[test]
+    fn test_uniform_from_std_range_inclusive() {
+        let r = Uniform::try_from(2.0f64..=7.0).unwrap();
+        assert_eq!(r.0.low, 2.0);
+        assert!(r.0.scale > 5.0);
+        assert!(r.0.scale < 5.0 + 1e-14);
+    }
+
+    #[test]
+    fn test_uniform_from_std_range_inclusive_bad_limits() {
+        #![allow(clippy::reversed_empty_ranges)]
+        assert!(Uniform::try_from(100.0..=10.0).is_err());
+        assert!(Uniform::try_from(100.0..=99.0).is_err());
+    }
+}
diff --git a/src/distr/uniform_int.rs b/src/distr/uniform_int.rs
new file mode 100644
index 00000000000..5a6254058e0
--- /dev/null
+++ b/src/distr/uniform_int.rs
@@ -0,0 +1,521 @@
+// 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
+// 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.
+
+//! `UniformInt` implementation
+
+use super::{Error, SampleBorrow, SampleUniform, UniformSampler};
+use crate::distr::utils::WideningMultiply;
+#[cfg(feature = "simd_support")]
+use crate::distr::{Distribution, Standard};
+use crate::Rng;
+
+#[cfg(feature = "simd_support")]
+use core::simd::prelude::*;
+#[cfg(feature = "simd_support")]
+use core::simd::{LaneCount, SupportedLaneCount};
+
+#[cfg(feature = "serde1")]
+use serde::{Deserialize, Serialize};
+
+/// The back-end implementing [`UniformSampler`] for integer types.
+///
+/// Unless you are implementing [`UniformSampler`] for your own type, this type
+/// should not be used directly, use [`Uniform`] instead.
+///
+/// # Implementation notes
+///
+/// For simplicity, we use the same generic struct `UniformInt<X>` for all
+/// integer types `X`. This gives us only one field type, `X`; to store unsigned
+/// values of this size, we take use the fact that these conversions are no-ops.
+///
+/// For a closed range, the number of possible numbers we should generate is
+/// `range = (high - low + 1)`. To avoid bias, we must ensure that the size of
+/// our sample space, `zone`, is a multiple of `range`; other values must be
+/// rejected (by replacing with a new random sample).
+///
+/// As a special case, we use `range = 0` to represent the full range of the
+/// result type (i.e. for `new_inclusive($ty::MIN, $ty::MAX)`).
+///
+/// The optimum `zone` is the largest product of `range` which fits in our
+/// (unsigned) target type. We calculate this by calculating how many numbers we
+/// must reject: `reject = (MAX + 1) % range = (MAX - range + 1) % range`. Any (large)
+/// product of `range` will suffice, thus in `sample_single` we multiply by a
+/// power of 2 via bit-shifting (faster but may cause more rejections).
+///
+/// The smallest integer PRNGs generate is `u32`. For 8- and 16-bit outputs we
+/// use `u32` for our `zone` and samples (because it's not slower and because
+/// it reduces the chance of having to reject a sample). In this case we cannot
+/// store `zone` in the target type since it is too large, however we know
+/// `ints_to_reject < range <= $uty::MAX`.
+///
+/// An alternative to using a modulus is widening multiply: After a widening
+/// multiply by `range`, the result is in the high word. Then comparing the low
+/// word against `zone` makes sure our distribution is uniform.
+///
+/// [`Uniform`]: super::Uniform
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
+pub struct UniformInt<X> {
+    pub(super) low: X,
+    pub(super) range: X,
+    thresh: X, // effectively 2.pow(max(64, uty_bits)) % range
+}
+
+macro_rules! uniform_int_impl {
+    ($ty:ty, $uty:ty, $sample_ty:ident) => {
+        impl SampleUniform for $ty {
+            type Sampler = UniformInt<$ty>;
+        }
+
+        impl UniformSampler for UniformInt<$ty> {
+            // We play free and fast with unsigned vs signed here
+            // (when $ty is signed), but that's fine, since the
+            // contract of this macro is for $ty and $uty to be
+            // "bit-equal", so casting between them is a no-op.
+
+            type X = $ty;
+
+            #[inline] // if the range is constant, this helps LLVM to do the
+                      // calculations at compile-time.
+            fn new<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
+            where
+                B1: SampleBorrow<Self::X> + Sized,
+                B2: SampleBorrow<Self::X> + Sized,
+            {
+                let low = *low_b.borrow();
+                let high = *high_b.borrow();
+                if !(low < high) {
+                    return Err(Error::EmptyRange);
+                }
+                UniformSampler::new_inclusive(low, high - 1)
+            }
+
+            #[inline] // if the range is constant, this helps LLVM to do the
+                      // calculations at compile-time.
+            fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
+            where
+                B1: SampleBorrow<Self::X> + Sized,
+                B2: SampleBorrow<Self::X> + Sized,
+            {
+                let low = *low_b.borrow();
+                let high = *high_b.borrow();
+                if !(low <= high) {
+                    return Err(Error::EmptyRange);
+                }
+
+                let range = high.wrapping_sub(low).wrapping_add(1) as $uty;
+                let thresh = if range > 0 {
+                    let range = $sample_ty::from(range);
+                    (range.wrapping_neg() % range)
+                } else {
+                    0
+                };
+
+                Ok(UniformInt {
+                    low,
+                    range: range as $ty,           // type: $uty
+                    thresh: thresh as $uty as $ty, // type: $sample_ty
+                })
+            }
+
+            /// Sample from distribution, Lemire's method, unbiased
+            #[inline]
+            fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
+                let range = self.range as $uty as $sample_ty;
+                if range == 0 {
+                    return rng.random();
+                }
+
+                let thresh = self.thresh as $uty as $sample_ty;
+                let hi = loop {
+                    let (hi, lo) = rng.random::<$sample_ty>().wmul(range);
+                    if lo >= thresh {
+                        break hi;
+                    }
+                };
+                self.low.wrapping_add(hi as $ty)
+            }
+
+            #[inline]
+            fn sample_single<R: Rng + ?Sized, B1, B2>(
+                low_b: B1,
+                high_b: B2,
+                rng: &mut R,
+            ) -> Result<Self::X, Error>
+            where
+                B1: SampleBorrow<Self::X> + Sized,
+                B2: SampleBorrow<Self::X> + Sized,
+            {
+                let low = *low_b.borrow();
+                let high = *high_b.borrow();
+                if !(low < high) {
+                    return Err(Error::EmptyRange);
+                }
+                Self::sample_single_inclusive(low, high - 1, rng)
+            }
+
+            /// Sample single value, Canon's method, biased
+            ///
+            /// In the worst case, bias affects 1 in `2^n` samples where n is
+            /// 56 (`i8`), 48 (`i16`), 96 (`i32`), 64 (`i64`), 128 (`i128`).
+            #[cfg(not(feature = "unbiased"))]
+            #[inline]
+            fn sample_single_inclusive<R: Rng + ?Sized, B1, B2>(
+                low_b: B1,
+                high_b: B2,
+                rng: &mut R,
+            ) -> Result<Self::X, Error>
+            where
+                B1: SampleBorrow<Self::X> + Sized,
+                B2: SampleBorrow<Self::X> + Sized,
+            {
+                let low = *low_b.borrow();
+                let high = *high_b.borrow();
+                if !(low <= high) {
+                    return Err(Error::EmptyRange);
+                }
+                let range = high.wrapping_sub(low).wrapping_add(1) as $uty as $sample_ty;
+                if range == 0 {
+                    // Range is MAX+1 (unrepresentable), so we need a special case
+                    return Ok(rng.random());
+                }
+
+                // generate a sample using a sensible integer type
+                let (mut result, lo_order) = rng.random::<$sample_ty>().wmul(range);
+
+                // if the sample is biased...
+                if lo_order > range.wrapping_neg() {
+                    // ...generate a new sample to reduce bias...
+                    let (new_hi_order, _) = (rng.random::<$sample_ty>()).wmul(range as $sample_ty);
+                    // ... incrementing result on overflow
+                    let is_overflow = lo_order.checked_add(new_hi_order as $sample_ty).is_none();
+                    result += is_overflow as $sample_ty;
+                }
+
+                Ok(low.wrapping_add(result as $ty))
+            }
+
+            /// Sample single value, Canon's method, unbiased
+            #[cfg(feature = "unbiased")]
+            #[inline]
+            fn sample_single_inclusive<R: Rng + ?Sized, B1, B2>(
+                low_b: B1,
+                high_b: B2,
+                rng: &mut R,
+            ) -> Result<Self::X, Error>
+            where
+                B1: SampleBorrow<$ty> + Sized,
+                B2: SampleBorrow<$ty> + Sized,
+            {
+                let low = *low_b.borrow();
+                let high = *high_b.borrow();
+                if !(low <= high) {
+                    return Err(Error::EmptyRange);
+                }
+                let range = high.wrapping_sub(low).wrapping_add(1) as $uty as $sample_ty;
+                if range == 0 {
+                    // Range is MAX+1 (unrepresentable), so we need a special case
+                    return Ok(rng.random());
+                }
+
+                let (mut result, mut lo) = rng.random::<$sample_ty>().wmul(range);
+
+                // In contrast to the biased sampler, we use a loop:
+                while lo > range.wrapping_neg() {
+                    let (new_hi, new_lo) = (rng.random::<$sample_ty>()).wmul(range);
+                    match lo.checked_add(new_hi) {
+                        Some(x) if x < $sample_ty::MAX => {
+                            // Anything less than MAX: last term is 0
+                            break;
+                        }
+                        None => {
+                            // Overflow: last term is 1
+                            result += 1;
+                            break;
+                        }
+                        _ => {
+                            // Unlikely case: must check next sample
+                            lo = new_lo;
+                            continue;
+                        }
+                    }
+                }
+
+                Ok(low.wrapping_add(result as $ty))
+            }
+        }
+    };
+}
+
+uniform_int_impl! { i8, u8, u32 }
+uniform_int_impl! { i16, u16, u32 }
+uniform_int_impl! { i32, u32, u32 }
+uniform_int_impl! { i64, u64, u64 }
+uniform_int_impl! { i128, u128, u128 }
+uniform_int_impl! { isize, usize, usize }
+uniform_int_impl! { u8, u8, u32 }
+uniform_int_impl! { u16, u16, u32 }
+uniform_int_impl! { u32, u32, u32 }
+uniform_int_impl! { u64, u64, u64 }
+uniform_int_impl! { usize, usize, usize }
+uniform_int_impl! { u128, u128, u128 }
+
+#[cfg(feature = "simd_support")]
+macro_rules! uniform_simd_int_impl {
+    ($ty:ident, $unsigned:ident) => {
+        // The "pick the largest zone that can fit in an `u32`" optimization
+        // is less useful here. Multiple lanes complicate things, we don't
+        // know the PRNG's minimal output size, and casting to a larger vector
+        // is generally a bad idea for SIMD performance. The user can still
+        // implement it manually.
+
+        #[cfg(feature = "simd_support")]
+        impl<const LANES: usize> SampleUniform for Simd<$ty, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+            Simd<$unsigned, LANES>:
+                WideningMultiply<Output = (Simd<$unsigned, LANES>, Simd<$unsigned, LANES>)>,
+            Standard: Distribution<Simd<$unsigned, LANES>>,
+        {
+            type Sampler = UniformInt<Simd<$ty, LANES>>;
+        }
+
+        #[cfg(feature = "simd_support")]
+        impl<const LANES: usize> UniformSampler for UniformInt<Simd<$ty, LANES>>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+            Simd<$unsigned, LANES>:
+                WideningMultiply<Output = (Simd<$unsigned, LANES>, Simd<$unsigned, LANES>)>,
+            Standard: Distribution<Simd<$unsigned, LANES>>,
+        {
+            type X = Simd<$ty, LANES>;
+
+            #[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) -> Result<Self, Error>
+                where B1: SampleBorrow<Self::X> + Sized,
+                      B2: SampleBorrow<Self::X> + Sized
+            {
+                let low = *low_b.borrow();
+                let high = *high_b.borrow();
+                if !(low.simd_lt(high).all()) {
+                    return Err(Error::EmptyRange);
+                }
+                UniformSampler::new_inclusive(low, high - Simd::splat(1))
+            }
+
+            #[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) -> Result<Self, Error>
+                where B1: SampleBorrow<Self::X> + Sized,
+                      B2: SampleBorrow<Self::X> + Sized
+            {
+                let low = *low_b.borrow();
+                let high = *high_b.borrow();
+                if !(low.simd_le(high).all()) {
+                    return Err(Error::EmptyRange);
+                }
+
+                // NOTE: all `Simd` operations are inherently wrapping,
+                //       see https://doc.rust-lang.org/std/simd/struct.Simd.html
+                let range: Simd<$unsigned, LANES> = ((high - low) + Simd::splat(1)).cast();
+
+                // We must avoid divide-by-zero by using 0 % 1 == 0.
+                let not_full_range = range.simd_gt(Simd::splat(0));
+                let modulo = not_full_range.select(range, Simd::splat(1));
+                let ints_to_reject = range.wrapping_neg() % modulo;
+
+                Ok(UniformInt {
+                    low,
+                    // These are really $unsigned values, but store as $ty:
+                    range: range.cast(),
+                    thresh: ints_to_reject.cast(),
+                })
+            }
+
+            fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
+                let range: Simd<$unsigned, LANES> = self.range.cast();
+                let thresh: Simd<$unsigned, LANES> = self.thresh.cast();
+
+                // This might seem very slow, generating a whole new
+                // SIMD vector for every sample rejection. For most uses
+                // though, the chance of rejection is small and provides good
+                // general performance. With multiple lanes, that chance is
+                // multiplied. To mitigate this, we replace only the lanes of
+                // the vector which fail, iteratively reducing the chance of
+                // rejection. The replacement method does however add a little
+                // overhead. Benchmarking or calculating probabilities might
+                // reveal contexts where this replacement method is slower.
+                let mut v: Simd<$unsigned, LANES> = rng.random();
+                loop {
+                    let (hi, lo) = v.wmul(range);
+                    let mask = lo.simd_ge(thresh);
+                    if mask.all() {
+                        let hi: Simd<$ty, LANES> = hi.cast();
+                        // wrapping addition
+                        let result = self.low + hi;
+                        // `select` here compiles to a blend operation
+                        // When `range.eq(0).none()` the compare and blend
+                        // operations are avoided.
+                        let v: Simd<$ty, LANES> = v.cast();
+                        return range.simd_gt(Simd::splat(0)).select(result, v);
+                    }
+                    // Replace only the failing lanes
+                    v = mask.select(v, rng.random());
+                }
+            }
+        }
+    };
+
+    // bulk implementation
+    ($(($unsigned:ident, $signed:ident)),+) => {
+        $(
+            uniform_simd_int_impl!($unsigned, $unsigned);
+            uniform_simd_int_impl!($signed, $unsigned);
+        )+
+    };
+}
+
+#[cfg(feature = "simd_support")]
+uniform_simd_int_impl! { (u8, i8), (u16, i16), (u32, i32), (u64, i64) }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::distr::Uniform;
+
+    #[test]
+    fn test_uniform_bad_limits_equal_int() {
+        assert_eq!(Uniform::new(10, 10), Err(Error::EmptyRange));
+    }
+
+    #[test]
+    fn test_uniform_good_limits_equal_int() {
+        let mut rng = crate::test::rng(804);
+        let dist = Uniform::new_inclusive(10, 10).unwrap();
+        for _ in 0..20 {
+            assert_eq!(rng.sample(dist), 10);
+        }
+    }
+
+    #[test]
+    fn test_uniform_bad_limits_flipped_int() {
+        assert_eq!(Uniform::new(10, 5), Err(Error::EmptyRange));
+    }
+
+    #[test]
+    #[cfg_attr(miri, ignore)] // Miri is too slow
+    fn test_integers() {
+        let mut rng = crate::test::rng(251);
+        macro_rules! t {
+            ($ty:ident, $v:expr, $le:expr, $lt:expr) => {{
+                for &(low, high) in $v.iter() {
+                    let my_uniform = Uniform::new(low, high).unwrap();
+                    for _ in 0..1000 {
+                        let v: $ty = rng.sample(my_uniform);
+                        assert!($le(low, v) && $lt(v, high));
+                    }
+
+                    let my_uniform = Uniform::new_inclusive(low, high).unwrap();
+                    for _ in 0..1000 {
+                        let v: $ty = rng.sample(my_uniform);
+                        assert!($le(low, v) && $le(v, high));
+                    }
+
+                    let my_uniform = Uniform::new(&low, high).unwrap();
+                    for _ in 0..1000 {
+                        let v: $ty = rng.sample(my_uniform);
+                        assert!($le(low, v) && $lt(v, high));
+                    }
+
+                    let my_uniform = Uniform::new_inclusive(&low, &high).unwrap();
+                    for _ in 0..1000 {
+                        let v: $ty = rng.sample(my_uniform);
+                        assert!($le(low, v) && $le(v, high));
+                    }
+
+                    for _ in 0..1000 {
+                        let v = <$ty as SampleUniform>::Sampler::sample_single(low, high, &mut rng).unwrap();
+                        assert!($le(low, v) && $lt(v, high));
+                    }
+
+                    for _ in 0..1000 {
+                        let v = <$ty as SampleUniform>::Sampler::sample_single_inclusive(low, high, &mut rng).unwrap();
+                        assert!($le(low, v) && $le(v, high));
+                    }
+                }
+            }};
+
+            // scalar bulk
+            ($($ty:ident),*) => {{
+                $(t!(
+                    $ty,
+                    [(0, 10), (10, 127), ($ty::MIN, $ty::MAX)],
+                    |x, y| x <= y,
+                    |x, y| x < y
+                );)*
+            }};
+
+            // simd bulk
+            ($($ty:ident),* => $scalar:ident) => {{
+                $(t!(
+                    $ty,
+                    [
+                        ($ty::splat(0), $ty::splat(10)),
+                        ($ty::splat(10), $ty::splat(127)),
+                        ($ty::splat($scalar::MIN), $ty::splat($scalar::MAX)),
+                    ],
+                    |x: $ty, y| x.simd_le(y).all(),
+                    |x: $ty, y| x.simd_lt(y).all()
+                );)*
+            }};
+        }
+        t!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, i128, u128);
+
+        #[cfg(feature = "simd_support")]
+        {
+            t!(u8x4, u8x8, u8x16, u8x32, u8x64 => u8);
+            t!(i8x4, i8x8, i8x16, i8x32, i8x64 => i8);
+            t!(u16x2, u16x4, u16x8, u16x16, u16x32 => u16);
+            t!(i16x2, i16x4, i16x8, i16x16, i16x32 => i16);
+            t!(u32x2, u32x4, u32x8, u32x16 => u32);
+            t!(i32x2, i32x4, i32x8, i32x16 => i32);
+            t!(u64x2, u64x4, u64x8 => u64);
+            t!(i64x2, i64x4, i64x8 => i64);
+        }
+    }
+
+    #[test]
+    fn test_uniform_from_std_range() {
+        let r = Uniform::try_from(2u32..7).unwrap();
+        assert_eq!(r.0.low, 2);
+        assert_eq!(r.0.range, 5);
+    }
+
+    #[test]
+    fn test_uniform_from_std_range_bad_limits() {
+        #![allow(clippy::reversed_empty_ranges)]
+        assert!(Uniform::try_from(100..10).is_err());
+        assert!(Uniform::try_from(100..100).is_err());
+    }
+
+    #[test]
+    fn test_uniform_from_std_range_inclusive() {
+        let r = Uniform::try_from(2u32..=6).unwrap();
+        assert_eq!(r.0.low, 2);
+        assert_eq!(r.0.range, 5);
+    }
+
+    #[test]
+    fn test_uniform_from_std_range_inclusive_bad_limits() {
+        #![allow(clippy::reversed_empty_ranges)]
+        assert!(Uniform::try_from(100..=10).is_err());
+        assert!(Uniform::try_from(100..=99).is_err());
+    }
+}
diff --git a/src/distr/uniform_other.rs b/src/distr/uniform_other.rs
new file mode 100644
index 00000000000..af10eed50d1
--- /dev/null
+++ b/src/distr/uniform_other.rs
@@ -0,0 +1,322 @@
+// 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
+// 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.
+
+//! `UniformChar`, `UniformDuration` implementations
+
+use super::{Error, SampleBorrow, SampleUniform, Uniform, UniformInt, UniformSampler};
+use crate::distr::Distribution;
+use crate::Rng;
+use core::time::Duration;
+
+#[cfg(feature = "serde1")]
+use serde::{Deserialize, Serialize};
+
+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, PartialEq, Eq)]
+#[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) -> Result<Self, Error>
+    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);
+        sampler.map(|sampler| 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) -> Result<Self, Error>
+    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);
+        sampler.map(|sampler| 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) }
+    }
+}
+
+/// Note: the `String` is potentially left with excess capacity if the range
+/// includes non ascii chars; optionally the user may call
+/// `string.shrink_to_fit()` afterwards.
+#[cfg(feature = "alloc")]
+impl crate::distr::DistString for Uniform<char> {
+    fn append_string<R: Rng + ?Sized>(
+        &self,
+        rng: &mut R,
+        string: &mut alloc::string::String,
+        len: usize,
+    ) {
+        // Getting the hi value to assume the required length to reserve in string.
+        let mut hi = self.0.sampler.low + self.0.sampler.range - 1;
+        if hi >= CHAR_SURROGATE_START {
+            hi += CHAR_SURROGATE_LEN;
+        }
+        // Get the utf8 length of hi to minimize extra space.
+        let max_char_len = char::from_u32(hi).map(char::len_utf8).unwrap_or(4);
+        string.reserve(max_char_len * len);
+        string.extend(self.sample_iter(rng).take(len))
+    }
+}
+
+/// The back-end implementing [`UniformSampler`] for `Duration`.
+///
+/// Unless you are implementing [`UniformSampler`] for your own types, this type
+/// should not be used directly, use [`Uniform`] instead.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
+pub struct UniformDuration {
+    mode: UniformDurationMode,
+    offset: u32,
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
+enum UniformDurationMode {
+    Small {
+        secs: u64,
+        nanos: Uniform<u32>,
+    },
+    Medium {
+        nanos: Uniform<u64>,
+    },
+    Large {
+        max_secs: u64,
+        max_nanos: u32,
+        secs: Uniform<u64>,
+    },
+}
+
+impl SampleUniform for Duration {
+    type Sampler = UniformDuration;
+}
+
+impl UniformSampler for UniformDuration {
+    type X = Duration;
+
+    #[inline]
+    fn new<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
+    where
+        B1: SampleBorrow<Self::X> + Sized,
+        B2: SampleBorrow<Self::X> + Sized,
+    {
+        let low = *low_b.borrow();
+        let high = *high_b.borrow();
+        if !(low < high) {
+            return Err(Error::EmptyRange);
+        }
+        UniformDuration::new_inclusive(low, high - Duration::new(0, 1))
+    }
+
+    #[inline]
+    fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
+    where
+        B1: SampleBorrow<Self::X> + Sized,
+        B2: SampleBorrow<Self::X> + Sized,
+    {
+        let low = *low_b.borrow();
+        let high = *high_b.borrow();
+        if !(low <= high) {
+            return Err(Error::EmptyRange);
+        }
+
+        let low_s = low.as_secs();
+        let low_n = low.subsec_nanos();
+        let mut high_s = high.as_secs();
+        let mut high_n = high.subsec_nanos();
+
+        if high_n < low_n {
+            high_s -= 1;
+            high_n += 1_000_000_000;
+        }
+
+        let mode = if low_s == high_s {
+            UniformDurationMode::Small {
+                secs: low_s,
+                nanos: Uniform::new_inclusive(low_n, high_n)?,
+            }
+        } else {
+            let max = high_s
+                .checked_mul(1_000_000_000)
+                .and_then(|n| n.checked_add(u64::from(high_n)));
+
+            if let Some(higher_bound) = max {
+                let lower_bound = low_s * 1_000_000_000 + u64::from(low_n);
+                UniformDurationMode::Medium {
+                    nanos: Uniform::new_inclusive(lower_bound, higher_bound)?,
+                }
+            } else {
+                // An offset is applied to simplify generation of nanoseconds
+                let max_nanos = high_n - low_n;
+                UniformDurationMode::Large {
+                    max_secs: high_s,
+                    max_nanos,
+                    secs: Uniform::new_inclusive(low_s, high_s)?,
+                }
+            }
+        };
+        Ok(UniformDuration {
+            mode,
+            offset: low_n,
+        })
+    }
+
+    #[inline]
+    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Duration {
+        match self.mode {
+            UniformDurationMode::Small { secs, nanos } => {
+                let n = nanos.sample(rng);
+                Duration::new(secs, n)
+            }
+            UniformDurationMode::Medium { nanos } => {
+                let nanos = nanos.sample(rng);
+                Duration::new(nanos / 1_000_000_000, (nanos % 1_000_000_000) as u32)
+            }
+            UniformDurationMode::Large {
+                max_secs,
+                max_nanos,
+                secs,
+            } => {
+                // constant folding means this is at least as fast as `Rng::sample(Range)`
+                let nano_range = Uniform::new(0, 1_000_000_000).unwrap();
+                loop {
+                    let s = secs.sample(rng);
+                    let n = nano_range.sample(rng);
+                    if !(s == max_secs && n > max_nanos) {
+                        let sum = n + self.offset;
+                        break Duration::new(s, sum);
+                    }
+                }
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    #[cfg(feature = "serde1")]
+    fn test_serialization_uniform_duration() {
+        let distr = UniformDuration::new(Duration::from_secs(10), Duration::from_secs(60)).unwrap();
+        let de_distr: UniformDuration =
+            bincode::deserialize(&bincode::serialize(&distr).unwrap()).unwrap();
+        assert_eq!(distr, de_distr);
+    }
+
+    #[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!(c.is_ascii_uppercase());
+            max = max.max(c);
+        }
+        assert_eq!(max, 'Z');
+        let d = Uniform::new(
+            core::char::from_u32(0xD7F0).unwrap(),
+            core::char::from_u32(0xE010).unwrap(),
+        )
+        .unwrap();
+        for _ in 0..100 {
+            let c = d.sample(&mut rng);
+            assert!((c as u32) < 0xD800 || (c as u32) > 0xDFFF);
+        }
+        #[cfg(feature = "alloc")]
+        {
+            use crate::distr::DistString;
+            let string1 = d.sample_string(&mut rng, 100);
+            assert_eq!(string1.capacity(), 300);
+            let string2 = Uniform::new(
+                core::char::from_u32(0x0000).unwrap(),
+                core::char::from_u32(0x0080).unwrap(),
+            )
+            .unwrap()
+            .sample_string(&mut rng, 100);
+            assert_eq!(string2.capacity(), 100);
+            let string3 = Uniform::new_inclusive(
+                core::char::from_u32(0x0000).unwrap(),
+                core::char::from_u32(0x0080).unwrap(),
+            )
+            .unwrap()
+            .sample_string(&mut rng, 100);
+            assert_eq!(string3.capacity(), 200);
+        }
+    }
+
+    #[test]
+    #[cfg_attr(miri, ignore)] // Miri is too slow
+    fn test_durations() {
+        let mut rng = crate::test::rng(253);
+
+        let v = &[
+            (Duration::new(10, 50000), Duration::new(100, 1234)),
+            (Duration::new(0, 100), Duration::new(1, 50)),
+            (Duration::new(0, 0), Duration::new(u64::MAX, 999_999_999)),
+        ];
+        for &(low, high) in v.iter() {
+            let my_uniform = Uniform::new(low, high).unwrap();
+            for _ in 0..1000 {
+                let v = rng.sample(my_uniform);
+                assert!(low <= v && v < high);
+            }
+        }
+    }
+}
diff --git a/src/distributions/utils.rs b/src/distr/utils.rs
similarity index 100%
rename from src/distributions/utils.rs
rename to src/distr/utils.rs
diff --git a/src/distributions/weighted_index.rs b/src/distr/weighted_index.rs
similarity index 98%
rename from src/distributions/weighted_index.rs
rename to src/distr/weighted_index.rs
index 88fad5a88ad..c0ceefee5d1 100644
--- a/src/distributions/weighted_index.rs
+++ b/src/distr/weighted_index.rs
@@ -8,8 +8,8 @@
 
 //! Weighted index sampling
 
-use crate::distributions::uniform::{SampleBorrow, SampleUniform, UniformSampler};
-use crate::distributions::Distribution;
+use crate::distr::uniform::{SampleBorrow, SampleUniform, UniformSampler};
+use crate::distr::Distribution;
 use crate::Rng;
 use core::fmt;
 
@@ -59,7 +59,7 @@ use serde::{Deserialize, Serialize};
 ///
 /// ```
 /// use rand::prelude::*;
-/// use rand::distributions::WeightedIndex;
+/// use rand::distr::WeightedIndex;
 ///
 /// let choices = ['a', 'b', 'c'];
 /// let weights = [2,   1,   1];
@@ -78,7 +78,7 @@ use serde::{Deserialize, Serialize};
 /// }
 /// ```
 ///
-/// [`Uniform<X>`]: crate::distributions::Uniform
+/// [`Uniform<X>`]: crate::distr::Uniform
 /// [`RngCore`]: crate::RngCore
 /// [`rand_distr::weighted_alias`]: https://docs.rs/rand_distr/*/rand_distr/weighted_alias/index.html
 /// [`rand_distr::weighted_tree`]: https://docs.rs/rand_distr/*/rand_distr/weighted_tree/index.html
@@ -101,7 +101,7 @@ impl<X: SampleUniform + PartialOrd> WeightedIndex<X> {
     /// -   [`WeightError::InsufficientNonZero`] when the sum of all weights is zero.
     /// -   [`WeightError::Overflow`] when the sum of all weights overflows.
     ///
-    /// [`Uniform<X>`]: crate::distributions::uniform::Uniform
+    /// [`Uniform<X>`]: crate::distr::uniform::Uniform
     pub fn new<I>(weights: I) -> Result<WeightedIndex<X>, WeightError>
     where
         I: IntoIterator,
@@ -306,7 +306,7 @@ impl<X: SampleUniform + PartialOrd + Clone> WeightedIndex<X> {
     /// # Example
     ///
     /// ```
-    /// use rand::distributions::WeightedIndex;
+    /// use rand::distr::WeightedIndex;
     ///
     /// let weights = [0, 1, 2];
     /// let dist = WeightedIndex::new(&weights).unwrap();
@@ -341,7 +341,7 @@ impl<X: SampleUniform + PartialOrd + Clone> WeightedIndex<X> {
     /// # Example
     ///
     /// ```
-    /// use rand::distributions::WeightedIndex;
+    /// use rand::distr::WeightedIndex;
     ///
     /// let weights = [1, 2, 3];
     /// let mut dist = WeightedIndex::new(&weights).unwrap();
diff --git a/src/distributions/uniform.rs b/src/distributions/uniform.rs
deleted file mode 100644
index 306b0cced65..00000000000
--- a/src/distributions/uniform.rs
+++ /dev/null
@@ -1,1774 +0,0 @@
-// 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
-// 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.
-
-//! A distribution uniformly sampling numbers within a given range.
-//!
-//! [`Uniform`] is the standard distribution to sample uniformly from a range;
-//! e.g. `Uniform::new_inclusive(1, 6).unwrap()` can sample integers from 1 to 6, like a
-//! standard die. [`Rng::gen_range`] supports any type supported by [`Uniform`].
-//!
-//! This distribution is provided with support for several primitive types
-//! (all integer and floating-point types) as well as [`std::time::Duration`],
-//! and supports extension to user-defined types via a type-specific *back-end*
-//! implementation.
-//!
-//! The types [`UniformInt`], [`UniformFloat`] and [`UniformDuration`] are the
-//! back-ends supporting sampling from primitive integer and floating-point
-//! ranges as well as from [`std::time::Duration`]; these types do not normally
-//! need to be used directly (unless implementing a derived back-end).
-//!
-//! # Example usage
-//!
-//! ```
-//! use rand::{Rng, thread_rng};
-//! use rand::distributions::Uniform;
-//!
-//! let mut rng = thread_rng();
-//! let side = Uniform::new(-10.0, 10.0).unwrap();
-//!
-//! // sample between 1 and 10 points
-//! 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);
-//! }
-//! ```
-//!
-//! # Extending `Uniform` to support a custom type
-//!
-//! To extend [`Uniform`] to support your own types, write a back-end which
-//! implements the [`UniformSampler`] trait, then implement the [`SampleUniform`]
-//! helper trait to "register" your back-end. See the `MyF32` example below.
-//!
-//! At a minimum, the back-end needs to store any parameters needed for sampling
-//! (e.g. the target range) and implement `new`, `new_inclusive` and `sample`.
-//! Those methods should include an assertion to check the range is valid (i.e.
-//! `low < high`). The example below merely wraps another back-end.
-//!
-//! The `new`, `new_inclusive`, `sample_single` and `sample_single_inclusive`
-//! functions use arguments of
-//! type `SampleBorrow<X>` to support passing in values by reference or
-//! by value. In the implementation of these functions, you can choose to
-//! simply use the reference returned by [`SampleBorrow::borrow`], or you can choose
-//! to copy or clone the value, whatever is appropriate for your type.
-//!
-//! ```
-//! use rand::prelude::*;
-//! use rand::distributions::uniform::{Uniform, SampleUniform,
-//!         UniformSampler, UniformFloat, SampleBorrow, Error};
-//!
-//! struct MyF32(f32);
-//!
-//! #[derive(Clone, Copy, Debug)]
-//! struct UniformMyF32(UniformFloat<f32>);
-//!
-//! impl UniformSampler for UniformMyF32 {
-//!     type X = MyF32;
-//!
-//!     fn new<B1, B2>(low: B1, high: B2) -> Result<Self, Error>
-//!         where B1: SampleBorrow<Self::X> + Sized,
-//!               B2: SampleBorrow<Self::X> + Sized
-//!     {
-//!         UniformFloat::<f32>::new(low.borrow().0, high.borrow().0).map(UniformMyF32)
-//!     }
-//!     fn new_inclusive<B1, B2>(low: B1, high: B2) -> Result<Self, Error>
-//!         where B1: SampleBorrow<Self::X> + Sized,
-//!               B2: SampleBorrow<Self::X> + Sized
-//!     {
-//!         UniformFloat::<f32>::new_inclusive(low.borrow().0, high.borrow().0).map(UniformMyF32)
-//!     }
-//!     fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
-//!         MyF32(self.0.sample(rng))
-//!     }
-//! }
-//!
-//! impl SampleUniform for MyF32 {
-//!     type Sampler = UniformMyF32;
-//! }
-//!
-//! let (low, high) = (MyF32(17.0f32), MyF32(22.0f32));
-//! let uniform = Uniform::new(low, high).unwrap();
-//! let x = uniform.sample(&mut thread_rng());
-//! ```
-//!
-//! [`SampleUniform`]: crate::distributions::uniform::SampleUniform
-//! [`UniformSampler`]: crate::distributions::uniform::UniformSampler
-//! [`UniformInt`]: crate::distributions::uniform::UniformInt
-//! [`UniformFloat`]: crate::distributions::uniform::UniformFloat
-//! [`UniformDuration`]: crate::distributions::uniform::UniformDuration
-//! [`SampleBorrow::borrow`]: crate::distributions::uniform::SampleBorrow::borrow
-
-use core::fmt;
-use core::ops::{Range, RangeInclusive};
-use core::time::Duration;
-
-use crate::distributions::float::IntoFloat;
-use crate::distributions::utils::{
-    BoolAsSIMD, FloatAsSIMD, FloatSIMDUtils, IntAsSIMD, WideningMultiply,
-};
-use crate::distributions::Distribution;
-#[cfg(feature = "simd_support")]
-use crate::distributions::Standard;
-use crate::{Rng, RngCore};
-
-#[cfg(feature = "simd_support")]
-use core::simd::prelude::*;
-#[cfg(feature = "simd_support")]
-use core::simd::{LaneCount, SupportedLaneCount};
-
-/// Error type returned from [`Uniform::new`] and `new_inclusive`.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum Error {
-    /// `low > high`, or equal in case of exclusive range.
-    EmptyRange,
-    /// Input or range `high - low` is non-finite. Not relevant to integer types.
-    NonFinite,
-}
-
-impl fmt::Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.write_str(match self {
-            Error::EmptyRange => "low > high (or equal if exclusive) in uniform distribution",
-            Error::NonFinite => "Non-finite range in uniform distribution",
-        })
-    }
-}
-
-#[cfg(feature = "std")]
-impl std::error::Error for Error {}
-
-#[cfg(feature = "serde1")]
-use serde::{Deserialize, Serialize};
-
-/// 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. 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
-/// the full range of integer types, this should have comparable performance to
-/// the `Standard` distribution.
-///
-/// Steps are taken to avoid bias, which might be present in naive
-/// implementations; for example `rng.gen::<u8>() % 170` samples from the range
-/// `[0, 169]` but is twice as likely to select numbers less than 85 than other
-/// values. Further, the implementations here give more weight to the high-bits
-/// generated by the RNG than the low bits, since with some RNGs the low-bits
-/// are of lower quality than the high bits.
-///
-/// Implementations must sample in `[low, high)` range for
-/// `Uniform::new(low, high)`, i.e., excluding `high`. In particular, care must
-/// be taken to ensure that rounding never results values `< low` or `>= high`.
-///
-/// # Example
-///
-/// ```
-/// use rand::distributions::{Distribution, Uniform};
-///
-/// let between = Uniform::try_from(10..10000).unwrap();
-/// 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 preferred:
-///
-/// ```
-/// 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, PartialEq, Eq)]
-#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
-#[cfg_attr(feature = "serde1", serde(bound(serialize = "X::Sampler: Serialize")))]
-#[cfg_attr(
-    feature = "serde1",
-    serde(bound(deserialize = "X::Sampler: Deserialize<'de>"))
-)]
-pub struct Uniform<X: SampleUniform>(X::Sampler);
-
-impl<X: SampleUniform> Uniform<X> {
-    /// Create a new `Uniform` instance, which samples uniformly from the half
-    /// open range `[low, high)` (excluding `high`).
-    ///
-    /// For discrete types (e.g. integers), samples will always be strictly less
-    /// than `high`. For (approximations of) continuous types (e.g. `f32`, `f64`),
-    /// samples may equal `high` due to loss of precision but may not be
-    /// greater than `high`.
-    ///
-    /// Fails if `low >= high`, or if `low`, `high` or the range `high - low` is
-    /// non-finite. In release mode, only the range is checked.
-    pub fn new<B1, B2>(low: B1, high: B2) -> Result<Uniform<X>, Error>
-    where
-        B1: SampleBorrow<X> + Sized,
-        B2: SampleBorrow<X> + Sized,
-    {
-        X::Sampler::new(low, high).map(Uniform)
-    }
-
-    /// Create a new `Uniform` instance, which samples uniformly from the closed
-    /// range `[low, high]` (inclusive).
-    ///
-    /// Fails if `low > high`, or if `low`, `high` or the range `high - low` is
-    /// non-finite. In release mode, only the range is checked.
-    pub fn new_inclusive<B1, B2>(low: B1, high: B2) -> Result<Uniform<X>, Error>
-    where
-        B1: SampleBorrow<X> + Sized,
-        B2: SampleBorrow<X> + Sized,
-    {
-        X::Sampler::new_inclusive(low, high).map(Uniform)
-    }
-}
-
-impl<X: SampleUniform> Distribution<X> for Uniform<X> {
-    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> X {
-        self.0.sample(rng)
-    }
-}
-
-/// Helper trait for creating objects using the correct implementation of
-/// [`UniformSampler`] for the sampling type.
-///
-/// See the [module documentation] on how to implement [`Uniform`] range
-/// sampling for a custom type.
-///
-/// [module documentation]: crate::distributions::uniform
-pub trait SampleUniform: Sized {
-    /// The `UniformSampler` implementation supporting type `X`.
-    type Sampler: UniformSampler<X = Self>;
-}
-
-/// Helper trait handling actual uniform sampling.
-///
-/// See the [module documentation] on how to implement [`Uniform`] range
-/// sampling for a custom type.
-///
-/// Implementation of [`sample_single`] is optional, and is only useful when
-/// the implementation can be faster than `Self::new(low, high).sample(rng)`.
-///
-/// [module documentation]: crate::distributions::uniform
-/// [`sample_single`]: UniformSampler::sample_single
-pub trait UniformSampler: Sized {
-    /// The type sampled by this implementation.
-    type X;
-
-    /// Construct self, with inclusive lower bound and exclusive upper bound `[low, high)`.
-    ///
-    /// For discrete types (e.g. integers), samples will always be strictly less
-    /// than `high`. For (approximations of) continuous types (e.g. `f32`, `f64`),
-    /// samples may equal `high` due to loss of precision but may not be
-    /// greater than `high`.
-    ///
-    /// Usually users should not call this directly but prefer to use
-    /// [`Uniform::new`].
-    fn new<B1, B2>(low: B1, high: B2) -> Result<Self, Error>
-    where
-        B1: SampleBorrow<Self::X> + Sized,
-        B2: SampleBorrow<Self::X> + Sized;
-
-    /// Construct self, with inclusive bounds `[low, high]`.
-    ///
-    /// Usually users should not call this directly but prefer to use
-    /// [`Uniform::new_inclusive`].
-    fn new_inclusive<B1, B2>(low: B1, high: B2) -> Result<Self, Error>
-    where
-        B1: SampleBorrow<Self::X> + Sized,
-        B2: SampleBorrow<Self::X> + Sized;
-
-    /// Sample a value.
-    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X;
-
-    /// Sample a single value uniformly from a range with inclusive lower bound
-    /// and exclusive upper bound `[low, high)`.
-    ///
-    /// For discrete types (e.g. integers), samples will always be strictly less
-    /// than `high`. For (approximations of) continuous types (e.g. `f32`, `f64`),
-    /// samples may equal `high` due to loss of precision but may not be
-    /// greater than `high`.
-    ///
-    /// By default this is implemented using
-    /// `UniformSampler::new(low, high).sample(rng)`. However, for some types
-    /// more optimal implementations for single usage may be provided via this
-    /// method (which is the case for integers and floats).
-    /// Results may not be identical.
-    ///
-    /// Note that to use this method in a generic context, the type needs to be
-    /// retrieved via `SampleUniform::Sampler` as follows:
-    /// ```
-    /// use rand::{thread_rng, distributions::uniform::{SampleUniform, UniformSampler}};
-    /// # #[allow(unused)]
-    /// fn sample_from_range<T: SampleUniform>(lb: T, ub: T) -> T {
-    ///     let mut rng = thread_rng();
-    ///     <T as SampleUniform>::Sampler::sample_single(lb, ub, &mut rng).unwrap()
-    /// }
-    /// ```
-    fn sample_single<R: Rng + ?Sized, B1, B2>(
-        low: B1,
-        high: B2,
-        rng: &mut R,
-    ) -> Result<Self::X, Error>
-    where
-        B1: SampleBorrow<Self::X> + Sized,
-        B2: SampleBorrow<Self::X> + Sized,
-    {
-        let uniform: Self = UniformSampler::new(low, high)?;
-        Ok(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,
-    ) -> Result<Self::X, Error>
-    where
-        B1: SampleBorrow<Self::X> + Sized,
-        B2: SampleBorrow<Self::X> + Sized,
-    {
-        let uniform: Self = UniformSampler::new_inclusive(low, high)?;
-        Ok(uniform.sample(rng))
-    }
-}
-
-impl<X: SampleUniform> TryFrom<Range<X>> for Uniform<X> {
-    type Error = Error;
-
-    fn try_from(r: Range<X>) -> Result<Uniform<X>, Error> {
-        Uniform::new(r.start, r.end)
-    }
-}
-
-impl<X: SampleUniform> TryFrom<RangeInclusive<X>> for Uniform<X> {
-    type Error = Error;
-
-    fn try_from(r: ::core::ops::RangeInclusive<X>) -> Result<Uniform<X>, Error> {
-        Uniform::new_inclusive(r.start(), r.end())
-    }
-}
-
-/// Helper trait similar to [`Borrow`] but implemented
-/// only for [`SampleUniform`] and references to [`SampleUniform`]
-/// in order to resolve ambiguity issues.
-///
-/// [`Borrow`]: std::borrow::Borrow
-pub trait SampleBorrow<Borrowed> {
-    /// Immutably borrows from an owned value. See [`Borrow::borrow`]
-    ///
-    /// [`Borrow::borrow`]: std::borrow::Borrow::borrow
-    fn borrow(&self) -> &Borrowed;
-}
-impl<Borrowed> SampleBorrow<Borrowed> for Borrowed
-where
-    Borrowed: SampleUniform,
-{
-    #[inline(always)]
-    fn borrow(&self) -> &Borrowed {
-        self
-    }
-}
-impl<'a, Borrowed> SampleBorrow<Borrowed> for &'a Borrowed
-where
-    Borrowed: SampleUniform,
-{
-    #[inline(always)]
-    fn borrow(&self) -> &Borrowed {
-        self
-    }
-}
-
-/// 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) -> Result<T, Error>;
-
-    /// 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) -> Result<T, Error> {
-        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) -> Result<T, Error> {
-        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.
-
-/// The back-end implementing [`UniformSampler`] for integer types.
-///
-/// Unless you are implementing [`UniformSampler`] for your own type, this type
-/// should not be used directly, use [`Uniform`] instead.
-///
-/// # Implementation notes
-///
-/// For simplicity, we use the same generic struct `UniformInt<X>` for all
-/// integer types `X`. This gives us only one field type, `X`; to store unsigned
-/// values of this size, we take use the fact that these conversions are no-ops.
-///
-/// For a closed range, the number of possible numbers we should generate is
-/// `range = (high - low + 1)`. To avoid bias, we must ensure that the size of
-/// our sample space, `zone`, is a multiple of `range`; other values must be
-/// rejected (by replacing with a new random sample).
-///
-/// As a special case, we use `range = 0` to represent the full range of the
-/// result type (i.e. for `new_inclusive($ty::MIN, $ty::MAX)`).
-///
-/// The optimum `zone` is the largest product of `range` which fits in our
-/// (unsigned) target type. We calculate this by calculating how many numbers we
-/// must reject: `reject = (MAX + 1) % range = (MAX - range + 1) % range`. Any (large)
-/// product of `range` will suffice, thus in `sample_single` we multiply by a
-/// power of 2 via bit-shifting (faster but may cause more rejections).
-///
-/// The smallest integer PRNGs generate is `u32`. For 8- and 16-bit outputs we
-/// use `u32` for our `zone` and samples (because it's not slower and because
-/// it reduces the chance of having to reject a sample). In this case we cannot
-/// store `zone` in the target type since it is too large, however we know
-/// `ints_to_reject < range <= $uty::MAX`.
-///
-/// An alternative to using a modulus is widening multiply: After a widening
-/// multiply by `range`, the result is in the high word. Then comparing the low
-/// word against `zone` makes sure our distribution is uniform.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
-pub struct UniformInt<X> {
-    low: X,
-    range: X,
-    thresh: X, // effectively 2.pow(max(64, uty_bits)) % range
-}
-
-macro_rules! uniform_int_impl {
-    ($ty:ty, $uty:ty, $sample_ty:ident) => {
-        impl SampleUniform for $ty {
-            type Sampler = UniformInt<$ty>;
-        }
-
-        impl UniformSampler for UniformInt<$ty> {
-            // We play free and fast with unsigned vs signed here
-            // (when $ty is signed), but that's fine, since the
-            // contract of this macro is for $ty and $uty to be
-            // "bit-equal", so casting between them is a no-op.
-
-            type X = $ty;
-
-            #[inline] // if the range is constant, this helps LLVM to do the
-                      // calculations at compile-time.
-            fn new<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
-            where
-                B1: SampleBorrow<Self::X> + Sized,
-                B2: SampleBorrow<Self::X> + Sized,
-            {
-                let low = *low_b.borrow();
-                let high = *high_b.borrow();
-                if !(low < high) {
-                    return Err(Error::EmptyRange);
-                }
-                UniformSampler::new_inclusive(low, high - 1)
-            }
-
-            #[inline] // if the range is constant, this helps LLVM to do the
-                      // calculations at compile-time.
-            fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
-            where
-                B1: SampleBorrow<Self::X> + Sized,
-                B2: SampleBorrow<Self::X> + Sized,
-            {
-                let low = *low_b.borrow();
-                let high = *high_b.borrow();
-                if !(low <= high) {
-                    return Err(Error::EmptyRange);
-                }
-
-                let range = high.wrapping_sub(low).wrapping_add(1) as $uty;
-                let thresh = if range > 0 {
-                    let range = $sample_ty::from(range);
-                    (range.wrapping_neg() % range)
-                } else {
-                    0
-                };
-
-                Ok(UniformInt {
-                    low,
-                    range: range as $ty,           // type: $uty
-                    thresh: thresh as $uty as $ty, // type: $sample_ty
-                })
-            }
-
-            /// Sample from distribution, Lemire's method, unbiased
-            #[inline]
-            fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
-                let range = self.range as $uty as $sample_ty;
-                if range == 0 {
-                    return rng.random();
-                }
-
-                let thresh = self.thresh as $uty as $sample_ty;
-                let hi = loop {
-                    let (hi, lo) = rng.random::<$sample_ty>().wmul(range);
-                    if lo >= thresh {
-                        break hi;
-                    }
-                };
-                self.low.wrapping_add(hi as $ty)
-            }
-
-            #[inline]
-            fn sample_single<R: Rng + ?Sized, B1, B2>(
-                low_b: B1,
-                high_b: B2,
-                rng: &mut R,
-            ) -> Result<Self::X, Error>
-            where
-                B1: SampleBorrow<Self::X> + Sized,
-                B2: SampleBorrow<Self::X> + Sized,
-            {
-                let low = *low_b.borrow();
-                let high = *high_b.borrow();
-                if !(low < high) {
-                    return Err(Error::EmptyRange);
-                }
-                Self::sample_single_inclusive(low, high - 1, rng)
-            }
-
-            /// Sample single value, Canon's method, biased
-            ///
-            /// In the worst case, bias affects 1 in `2^n` samples where n is
-            /// 56 (`i8`), 48 (`i16`), 96 (`i32`), 64 (`i64`), 128 (`i128`).
-            #[cfg(not(feature = "unbiased"))]
-            #[inline]
-            fn sample_single_inclusive<R: Rng + ?Sized, B1, B2>(
-                low_b: B1,
-                high_b: B2,
-                rng: &mut R,
-            ) -> Result<Self::X, Error>
-            where
-                B1: SampleBorrow<Self::X> + Sized,
-                B2: SampleBorrow<Self::X> + Sized,
-            {
-                let low = *low_b.borrow();
-                let high = *high_b.borrow();
-                if !(low <= high) {
-                    return Err(Error::EmptyRange);
-                }
-                let range = high.wrapping_sub(low).wrapping_add(1) as $uty as $sample_ty;
-                if range == 0 {
-                    // Range is MAX+1 (unrepresentable), so we need a special case
-                    return Ok(rng.random());
-                }
-
-                // generate a sample using a sensible integer type
-                let (mut result, lo_order) = rng.random::<$sample_ty>().wmul(range);
-
-                // if the sample is biased...
-                if lo_order > range.wrapping_neg() {
-                    // ...generate a new sample to reduce bias...
-                    let (new_hi_order, _) = (rng.random::<$sample_ty>()).wmul(range as $sample_ty);
-                    // ... incrementing result on overflow
-                    let is_overflow = lo_order.checked_add(new_hi_order as $sample_ty).is_none();
-                    result += is_overflow as $sample_ty;
-                }
-
-                Ok(low.wrapping_add(result as $ty))
-            }
-
-            /// Sample single value, Canon's method, unbiased
-            #[cfg(feature = "unbiased")]
-            #[inline]
-            fn sample_single_inclusive<R: Rng + ?Sized, B1, B2>(
-                low_b: B1,
-                high_b: B2,
-                rng: &mut R,
-            ) -> Result<Self::X, Error>
-            where
-                B1: SampleBorrow<$ty> + Sized,
-                B2: SampleBorrow<$ty> + Sized,
-            {
-                let low = *low_b.borrow();
-                let high = *high_b.borrow();
-                if !(low <= high) {
-                    return Err(Error::EmptyRange);
-                }
-                let range = high.wrapping_sub(low).wrapping_add(1) as $uty as $sample_ty;
-                if range == 0 {
-                    // Range is MAX+1 (unrepresentable), so we need a special case
-                    return Ok(rng.random());
-                }
-
-                let (mut result, mut lo) = rng.random::<$sample_ty>().wmul(range);
-
-                // In contrast to the biased sampler, we use a loop:
-                while lo > range.wrapping_neg() {
-                    let (new_hi, new_lo) = (rng.random::<$sample_ty>()).wmul(range);
-                    match lo.checked_add(new_hi) {
-                        Some(x) if x < $sample_ty::MAX => {
-                            // Anything less than MAX: last term is 0
-                            break;
-                        }
-                        None => {
-                            // Overflow: last term is 1
-                            result += 1;
-                            break;
-                        }
-                        _ => {
-                            // Unlikely case: must check next sample
-                            lo = new_lo;
-                            continue;
-                        }
-                    }
-                }
-
-                Ok(low.wrapping_add(result as $ty))
-            }
-        }
-    };
-}
-
-uniform_int_impl! { i8, u8, u32 }
-uniform_int_impl! { i16, u16, u32 }
-uniform_int_impl! { i32, u32, u32 }
-uniform_int_impl! { i64, u64, u64 }
-uniform_int_impl! { i128, u128, u128 }
-uniform_int_impl! { isize, usize, usize }
-uniform_int_impl! { u8, u8, u32 }
-uniform_int_impl! { u16, u16, u32 }
-uniform_int_impl! { u32, u32, u32 }
-uniform_int_impl! { u64, u64, u64 }
-uniform_int_impl! { usize, usize, usize }
-uniform_int_impl! { u128, u128, u128 }
-
-#[cfg(feature = "simd_support")]
-macro_rules! uniform_simd_int_impl {
-    ($ty:ident, $unsigned:ident) => {
-        // The "pick the largest zone that can fit in an `u32`" optimization
-        // is less useful here. Multiple lanes complicate things, we don't
-        // know the PRNG's minimal output size, and casting to a larger vector
-        // is generally a bad idea for SIMD performance. The user can still
-        // implement it manually.
-
-        #[cfg(feature = "simd_support")]
-        impl<const LANES: usize> SampleUniform for Simd<$ty, LANES>
-        where
-            LaneCount<LANES>: SupportedLaneCount,
-            Simd<$unsigned, LANES>:
-                WideningMultiply<Output = (Simd<$unsigned, LANES>, Simd<$unsigned, LANES>)>,
-            Standard: Distribution<Simd<$unsigned, LANES>>,
-        {
-            type Sampler = UniformInt<Simd<$ty, LANES>>;
-        }
-
-        #[cfg(feature = "simd_support")]
-        impl<const LANES: usize> UniformSampler for UniformInt<Simd<$ty, LANES>>
-        where
-            LaneCount<LANES>: SupportedLaneCount,
-            Simd<$unsigned, LANES>:
-                WideningMultiply<Output = (Simd<$unsigned, LANES>, Simd<$unsigned, LANES>)>,
-            Standard: Distribution<Simd<$unsigned, LANES>>,
-        {
-            type X = Simd<$ty, LANES>;
-
-            #[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) -> Result<Self, Error>
-                where B1: SampleBorrow<Self::X> + Sized,
-                      B2: SampleBorrow<Self::X> + Sized
-            {
-                let low = *low_b.borrow();
-                let high = *high_b.borrow();
-                if !(low.simd_lt(high).all()) {
-                    return Err(Error::EmptyRange);
-                }
-                UniformSampler::new_inclusive(low, high - Simd::splat(1))
-            }
-
-            #[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) -> Result<Self, Error>
-                where B1: SampleBorrow<Self::X> + Sized,
-                      B2: SampleBorrow<Self::X> + Sized
-            {
-                let low = *low_b.borrow();
-                let high = *high_b.borrow();
-                if !(low.simd_le(high).all()) {
-                    return Err(Error::EmptyRange);
-                }
-
-                // NOTE: all `Simd` operations are inherently wrapping,
-                //       see https://doc.rust-lang.org/std/simd/struct.Simd.html
-                let range: Simd<$unsigned, LANES> = ((high - low) + Simd::splat(1)).cast();
-
-                // We must avoid divide-by-zero by using 0 % 1 == 0.
-                let not_full_range = range.simd_gt(Simd::splat(0));
-                let modulo = not_full_range.select(range, Simd::splat(1));
-                let ints_to_reject = range.wrapping_neg() % modulo;
-
-                Ok(UniformInt {
-                    low,
-                    // These are really $unsigned values, but store as $ty:
-                    range: range.cast(),
-                    thresh: ints_to_reject.cast(),
-                })
-            }
-
-            fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
-                let range: Simd<$unsigned, LANES> = self.range.cast();
-                let thresh: Simd<$unsigned, LANES> = self.thresh.cast();
-
-                // This might seem very slow, generating a whole new
-                // SIMD vector for every sample rejection. For most uses
-                // though, the chance of rejection is small and provides good
-                // general performance. With multiple lanes, that chance is
-                // multiplied. To mitigate this, we replace only the lanes of
-                // the vector which fail, iteratively reducing the chance of
-                // rejection. The replacement method does however add a little
-                // overhead. Benchmarking or calculating probabilities might
-                // reveal contexts where this replacement method is slower.
-                let mut v: Simd<$unsigned, LANES> = rng.random();
-                loop {
-                    let (hi, lo) = v.wmul(range);
-                    let mask = lo.simd_ge(thresh);
-                    if mask.all() {
-                        let hi: Simd<$ty, LANES> = hi.cast();
-                        // wrapping addition
-                        let result = self.low + hi;
-                        // `select` here compiles to a blend operation
-                        // When `range.eq(0).none()` the compare and blend
-                        // operations are avoided.
-                        let v: Simd<$ty, LANES> = v.cast();
-                        return range.simd_gt(Simd::splat(0)).select(result, v);
-                    }
-                    // Replace only the failing lanes
-                    v = mask.select(v, rng.random());
-                }
-            }
-        }
-    };
-
-    // bulk implementation
-    ($(($unsigned:ident, $signed:ident)),+) => {
-        $(
-            uniform_simd_int_impl!($unsigned, $unsigned);
-            uniform_simd_int_impl!($signed, $unsigned);
-        )+
-    };
-}
-
-#[cfg(feature = "simd_support")]
-uniform_simd_int_impl! { (u8, i8), (u16, i16), (u32, i32), (u64, i64) }
-
-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, PartialEq, Eq)]
-#[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) -> Result<Self, Error>
-    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);
-        sampler.map(|sampler| 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) -> Result<Self, Error>
-    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);
-        sampler.map(|sampler| 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) }
-    }
-}
-
-/// Note: the `String` is potentially left with excess capacity if the range
-/// includes non ascii chars; optionally the user may call
-/// `string.shrink_to_fit()` afterwards.
-#[cfg(feature = "alloc")]
-impl super::DistString for Uniform<char> {
-    fn append_string<R: Rng + ?Sized>(
-        &self,
-        rng: &mut R,
-        string: &mut alloc::string::String,
-        len: usize,
-    ) {
-        // Getting the hi value to assume the required length to reserve in string.
-        let mut hi = self.0.sampler.low + self.0.sampler.range - 1;
-        if hi >= CHAR_SURROGATE_START {
-            hi += CHAR_SURROGATE_LEN;
-        }
-        // Get the utf8 length of hi to minimize extra space.
-        let max_char_len = char::from_u32(hi).map(char::len_utf8).unwrap_or(4);
-        string.reserve(max_char_len * len);
-        string.extend(self.sample_iter(rng).take(len))
-    }
-}
-
-/// The back-end implementing [`UniformSampler`] for floating-point types.
-///
-/// Unless you are implementing [`UniformSampler`] for your own type, this type
-/// should not be used directly, use [`Uniform`] instead.
-///
-/// # Implementation notes
-///
-/// Instead of generating a float in the `[0, 1)` range using [`Standard`], the
-/// `UniformFloat` implementation converts the output of an PRNG itself. This
-/// way one or two steps can be optimized out.
-///
-/// The floats are first converted to a value in the `[1, 2)` interval using a
-/// transmute-based method, and then mapped to the expected range with a
-/// multiply and addition. Values produced this way have what equals 23 bits of
-/// random digits for an `f32`, and 52 for an `f64`.
-///
-/// [`new`]: UniformSampler::new
-/// [`new_inclusive`]: UniformSampler::new_inclusive
-/// [`Standard`]: crate::distributions::Standard
-#[derive(Clone, Copy, Debug, PartialEq)]
-#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
-pub struct UniformFloat<X> {
-    low: X,
-    scale: X,
-}
-
-macro_rules! uniform_float_impl {
-    ($($meta:meta)?, $ty:ty, $uty:ident, $f_scalar:ident, $u_scalar:ident, $bits_to_discard:expr) => {
-        $(#[cfg($meta)])?
-        impl UniformFloat<$ty> {
-            /// Construct, reducing `scale` as required to ensure that rounding
-            /// can never yield values greater than `high`.
-            ///
-            /// Note: though it may be tempting to use a variant of this method
-            /// to ensure that samples from `[low, high)` are always strictly
-            /// less than `high`, this approach may be very slow where
-            /// `scale.abs()` is much smaller than `high.abs()`
-            /// (example: `low=0.99999999997819644, high=1.`).
-            fn new_bounded(low: $ty, high: $ty, mut scale: $ty) -> Self {
-                let max_rand = <$ty>::splat(1.0 as $f_scalar - $f_scalar::EPSILON);
-
-                loop {
-                    let mask = (scale * max_rand + low).gt_mask(high);
-                    if !mask.any() {
-                        break;
-                    }
-                    scale = scale.decrease_masked(mask);
-                }
-
-                debug_assert!(<$ty>::splat(0.0).all_le(scale));
-
-                UniformFloat { low, scale }
-            }
-        }
-
-        $(#[cfg($meta)])?
-        impl SampleUniform for $ty {
-            type Sampler = UniformFloat<$ty>;
-        }
-
-        $(#[cfg($meta)])?
-        impl UniformSampler for UniformFloat<$ty> {
-            type X = $ty;
-
-            fn new<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
-            where
-                B1: SampleBorrow<Self::X> + Sized,
-                B2: SampleBorrow<Self::X> + Sized,
-            {
-                let low = *low_b.borrow();
-                let high = *high_b.borrow();
-                #[cfg(debug_assertions)]
-                if !(low.all_finite()) || !(high.all_finite()) {
-                    return Err(Error::NonFinite);
-                }
-                if !(low.all_lt(high)) {
-                    return Err(Error::EmptyRange);
-                }
-
-                let scale = high - low;
-                if !(scale.all_finite()) {
-                    return Err(Error::NonFinite);
-                }
-
-                Ok(Self::new_bounded(low, high, scale))
-            }
-
-            fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
-            where
-                B1: SampleBorrow<Self::X> + Sized,
-                B2: SampleBorrow<Self::X> + Sized,
-            {
-                let low = *low_b.borrow();
-                let high = *high_b.borrow();
-                #[cfg(debug_assertions)]
-                if !(low.all_finite()) || !(high.all_finite()) {
-                    return Err(Error::NonFinite);
-                }
-                if !low.all_le(high) {
-                    return Err(Error::EmptyRange);
-                }
-
-                let max_rand = <$ty>::splat(1.0 as $f_scalar - $f_scalar::EPSILON);
-                let scale = (high - low) / max_rand;
-                if !scale.all_finite() {
-                    return Err(Error::NonFinite);
-                }
-
-                Ok(Self::new_bounded(low, high, scale))
-            }
-
-            fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
-                // Generate a value in the range [1, 2)
-                let value1_2 = (rng.random::<$uty>() >> $uty::splat($bits_to_discard)).into_float_with_exponent(0);
-
-                // Get a value in the range [0, 1) to avoid overflow when multiplying by scale
-                let value0_1 = value1_2 - <$ty>::splat(1.0);
-
-                // We don't use `f64::mul_add`, because it is not available with
-                // `no_std`. Furthermore, it is slower for some targets (but
-                // faster for others). However, the order of multiplication and
-                // addition is important, because on some platforms (e.g. ARM)
-                // it will be optimized to a single (non-FMA) instruction.
-                value0_1 * self.scale + self.low
-            }
-
-            #[inline]
-            fn sample_single<R: Rng + ?Sized, B1, B2>(low_b: B1, high_b: B2, rng: &mut R) -> Result<Self::X, Error>
-            where
-                B1: SampleBorrow<Self::X> + Sized,
-                B2: SampleBorrow<Self::X> + Sized,
-            {
-                Self::sample_single_inclusive(low_b, high_b, rng)
-            }
-
-            #[inline]
-            fn sample_single_inclusive<R: Rng + ?Sized, B1, B2>(low_b: B1, high_b: B2, rng: &mut R) -> Result<Self::X, Error>
-            where
-                B1: SampleBorrow<Self::X> + Sized,
-                B2: SampleBorrow<Self::X> + Sized,
-            {
-                let low = *low_b.borrow();
-                let high = *high_b.borrow();
-                #[cfg(debug_assertions)]
-                if !low.all_finite() || !high.all_finite() {
-                    return Err(Error::NonFinite);
-                }
-                if !low.all_le(high) {
-                    return Err(Error::EmptyRange);
-                }
-                let scale = high - low;
-                if !scale.all_finite() {
-                    return Err(Error::NonFinite);
-                }
-
-                // Generate a value in the range [1, 2)
-                let value1_2 =
-                    (rng.random::<$uty>() >> $uty::splat($bits_to_discard)).into_float_with_exponent(0);
-
-                // Get a value in the range [0, 1) to avoid overflow when multiplying by scale
-                let value0_1 = value1_2 - <$ty>::splat(1.0);
-
-                // Doing multiply before addition allows some architectures
-                // to use a single instruction.
-                Ok(value0_1 * scale + low)
-            }
-        }
-    };
-}
-
-uniform_float_impl! { , f32, u32, f32, u32, 32 - 23 }
-uniform_float_impl! { , f64, u64, f64, u64, 64 - 52 }
-
-#[cfg(feature = "simd_support")]
-uniform_float_impl! { feature = "simd_support", f32x2, u32x2, f32, u32, 32 - 23 }
-#[cfg(feature = "simd_support")]
-uniform_float_impl! { feature = "simd_support", f32x4, u32x4, f32, u32, 32 - 23 }
-#[cfg(feature = "simd_support")]
-uniform_float_impl! { feature = "simd_support", f32x8, u32x8, f32, u32, 32 - 23 }
-#[cfg(feature = "simd_support")]
-uniform_float_impl! { feature = "simd_support", f32x16, u32x16, f32, u32, 32 - 23 }
-
-#[cfg(feature = "simd_support")]
-uniform_float_impl! { feature = "simd_support", f64x2, u64x2, f64, u64, 64 - 52 }
-#[cfg(feature = "simd_support")]
-uniform_float_impl! { feature = "simd_support", f64x4, u64x4, f64, u64, 64 - 52 }
-#[cfg(feature = "simd_support")]
-uniform_float_impl! { feature = "simd_support", f64x8, u64x8, f64, u64, 64 - 52 }
-
-/// The back-end implementing [`UniformSampler`] for `Duration`.
-///
-/// Unless you are implementing [`UniformSampler`] for your own types, this type
-/// should not be used directly, use [`Uniform`] instead.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
-pub struct UniformDuration {
-    mode: UniformDurationMode,
-    offset: u32,
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
-enum UniformDurationMode {
-    Small {
-        secs: u64,
-        nanos: Uniform<u32>,
-    },
-    Medium {
-        nanos: Uniform<u64>,
-    },
-    Large {
-        max_secs: u64,
-        max_nanos: u32,
-        secs: Uniform<u64>,
-    },
-}
-
-impl SampleUniform for Duration {
-    type Sampler = UniformDuration;
-}
-
-impl UniformSampler for UniformDuration {
-    type X = Duration;
-
-    #[inline]
-    fn new<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
-    where
-        B1: SampleBorrow<Self::X> + Sized,
-        B2: SampleBorrow<Self::X> + Sized,
-    {
-        let low = *low_b.borrow();
-        let high = *high_b.borrow();
-        if !(low < high) {
-            return Err(Error::EmptyRange);
-        }
-        UniformDuration::new_inclusive(low, high - Duration::new(0, 1))
-    }
-
-    #[inline]
-    fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
-    where
-        B1: SampleBorrow<Self::X> + Sized,
-        B2: SampleBorrow<Self::X> + Sized,
-    {
-        let low = *low_b.borrow();
-        let high = *high_b.borrow();
-        if !(low <= high) {
-            return Err(Error::EmptyRange);
-        }
-
-        let low_s = low.as_secs();
-        let low_n = low.subsec_nanos();
-        let mut high_s = high.as_secs();
-        let mut high_n = high.subsec_nanos();
-
-        if high_n < low_n {
-            high_s -= 1;
-            high_n += 1_000_000_000;
-        }
-
-        let mode = if low_s == high_s {
-            UniformDurationMode::Small {
-                secs: low_s,
-                nanos: Uniform::new_inclusive(low_n, high_n)?,
-            }
-        } else {
-            let max = high_s
-                .checked_mul(1_000_000_000)
-                .and_then(|n| n.checked_add(u64::from(high_n)));
-
-            if let Some(higher_bound) = max {
-                let lower_bound = low_s * 1_000_000_000 + u64::from(low_n);
-                UniformDurationMode::Medium {
-                    nanos: Uniform::new_inclusive(lower_bound, higher_bound)?,
-                }
-            } else {
-                // An offset is applied to simplify generation of nanoseconds
-                let max_nanos = high_n - low_n;
-                UniformDurationMode::Large {
-                    max_secs: high_s,
-                    max_nanos,
-                    secs: Uniform::new_inclusive(low_s, high_s)?,
-                }
-            }
-        };
-        Ok(UniformDuration {
-            mode,
-            offset: low_n,
-        })
-    }
-
-    #[inline]
-    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Duration {
-        match self.mode {
-            UniformDurationMode::Small { secs, nanos } => {
-                let n = nanos.sample(rng);
-                Duration::new(secs, n)
-            }
-            UniformDurationMode::Medium { nanos } => {
-                let nanos = nanos.sample(rng);
-                Duration::new(nanos / 1_000_000_000, (nanos % 1_000_000_000) as u32)
-            }
-            UniformDurationMode::Large {
-                max_secs,
-                max_nanos,
-                secs,
-            } => {
-                // constant folding means this is at least as fast as `Rng::sample(Range)`
-                let nano_range = Uniform::new(0, 1_000_000_000).unwrap();
-                loop {
-                    let s = secs.sample(rng);
-                    let n = nano_range.sample(rng);
-                    if !(s == max_secs && n > max_nanos) {
-                        let sum = n + self.offset;
-                        break Duration::new(s, sum);
-                    }
-                }
-            }
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::distributions::utils::FloatSIMDScalarUtils;
-    use crate::rngs::mock::StepRng;
-
-    #[test]
-    #[cfg(feature = "serde1")]
-    fn test_serialization_uniform_duration() {
-        let distr = UniformDuration::new(Duration::from_secs(10), Duration::from_secs(60)).unwrap();
-        let de_distr: UniformDuration =
-            bincode::deserialize(&bincode::serialize(&distr).unwrap()).unwrap();
-        assert_eq!(distr, de_distr);
-    }
-
-    #[test]
-    #[cfg(feature = "serde1")]
-    fn test_uniform_serialization() {
-        let unit_box: Uniform<i32> = Uniform::new(-1, 1).unwrap();
-        let de_unit_box: Uniform<i32> =
-            bincode::deserialize(&bincode::serialize(&unit_box).unwrap()).unwrap();
-        assert_eq!(unit_box.0, de_unit_box.0);
-
-        let unit_box: Uniform<f32> = Uniform::new(-1., 1.).unwrap();
-        let de_unit_box: Uniform<f32> =
-            bincode::deserialize(&bincode::serialize(&unit_box).unwrap()).unwrap();
-        assert_eq!(unit_box.0, de_unit_box.0);
-    }
-
-    #[test]
-    fn test_uniform_bad_limits_equal_int() {
-        assert_eq!(Uniform::new(10, 10), Err(Error::EmptyRange));
-    }
-
-    #[test]
-    fn test_uniform_good_limits_equal_int() {
-        let mut rng = crate::test::rng(804);
-        let dist = Uniform::new_inclusive(10, 10).unwrap();
-        for _ in 0..20 {
-            assert_eq!(rng.sample(dist), 10);
-        }
-    }
-
-    #[test]
-    fn test_uniform_bad_limits_flipped_int() {
-        assert_eq!(Uniform::new(10, 5), Err(Error::EmptyRange));
-    }
-
-    #[test]
-    #[cfg_attr(miri, ignore)] // Miri is too slow
-    fn test_integers() {
-        let mut rng = crate::test::rng(251);
-        macro_rules! t {
-            ($ty:ident, $v:expr, $le:expr, $lt:expr) => {{
-                for &(low, high) in $v.iter() {
-                    let my_uniform = Uniform::new(low, high).unwrap();
-                    for _ in 0..1000 {
-                        let v: $ty = rng.sample(my_uniform);
-                        assert!($le(low, v) && $lt(v, high));
-                    }
-
-                    let my_uniform = Uniform::new_inclusive(low, high).unwrap();
-                    for _ in 0..1000 {
-                        let v: $ty = rng.sample(my_uniform);
-                        assert!($le(low, v) && $le(v, high));
-                    }
-
-                    let my_uniform = Uniform::new(&low, high).unwrap();
-                    for _ in 0..1000 {
-                        let v: $ty = rng.sample(my_uniform);
-                        assert!($le(low, v) && $lt(v, high));
-                    }
-
-                    let my_uniform = Uniform::new_inclusive(&low, &high).unwrap();
-                    for _ in 0..1000 {
-                        let v: $ty = rng.sample(my_uniform);
-                        assert!($le(low, v) && $le(v, high));
-                    }
-
-                    for _ in 0..1000 {
-                        let v = <$ty as SampleUniform>::Sampler::sample_single(low, high, &mut rng).unwrap();
-                        assert!($le(low, v) && $lt(v, high));
-                    }
-
-                    for _ in 0..1000 {
-                        let v = <$ty as SampleUniform>::Sampler::sample_single_inclusive(low, high, &mut rng).unwrap();
-                        assert!($le(low, v) && $le(v, high));
-                    }
-                }
-            }};
-
-            // scalar bulk
-            ($($ty:ident),*) => {{
-                $(t!(
-                    $ty,
-                    [(0, 10), (10, 127), ($ty::MIN, $ty::MAX)],
-                    |x, y| x <= y,
-                    |x, y| x < y
-                );)*
-            }};
-
-            // simd bulk
-            ($($ty:ident),* => $scalar:ident) => {{
-                $(t!(
-                    $ty,
-                    [
-                        ($ty::splat(0), $ty::splat(10)),
-                        ($ty::splat(10), $ty::splat(127)),
-                        ($ty::splat($scalar::MIN), $ty::splat($scalar::MAX)),
-                    ],
-                    |x: $ty, y| x.simd_le(y).all(),
-                    |x: $ty, y| x.simd_lt(y).all()
-                );)*
-            }};
-        }
-        t!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, i128, u128);
-
-        #[cfg(feature = "simd_support")]
-        {
-            t!(u8x4, u8x8, u8x16, u8x32, u8x64 => u8);
-            t!(i8x4, i8x8, i8x16, i8x32, i8x64 => i8);
-            t!(u16x2, u16x4, u16x8, u16x16, u16x32 => u16);
-            t!(i16x2, i16x4, i16x8, i16x16, i16x32 => i16);
-            t!(u32x2, u32x4, u32x8, u32x16 => u32);
-            t!(i32x2, i32x4, i32x8, i32x16 => i32);
-            t!(u64x2, u64x4, u64x8 => u64);
-            t!(i64x2, i64x4, i64x8 => i64);
-        }
-    }
-
-    #[test]
-    #[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!(c.is_ascii_uppercase());
-            max = max.max(c);
-        }
-        assert_eq!(max, 'Z');
-        let d = Uniform::new(
-            core::char::from_u32(0xD7F0).unwrap(),
-            core::char::from_u32(0xE010).unwrap(),
-        )
-        .unwrap();
-        for _ in 0..100 {
-            let c = d.sample(&mut rng);
-            assert!((c as u32) < 0xD800 || (c as u32) > 0xDFFF);
-        }
-        #[cfg(feature = "alloc")]
-        {
-            use crate::distributions::DistString;
-            let string1 = d.sample_string(&mut rng, 100);
-            assert_eq!(string1.capacity(), 300);
-            let string2 = Uniform::new(
-                core::char::from_u32(0x0000).unwrap(),
-                core::char::from_u32(0x0080).unwrap(),
-            )
-            .unwrap()
-            .sample_string(&mut rng, 100);
-            assert_eq!(string2.capacity(), 100);
-            let string3 = Uniform::new_inclusive(
-                core::char::from_u32(0x0000).unwrap(),
-                core::char::from_u32(0x0080).unwrap(),
-            )
-            .unwrap()
-            .sample_string(&mut rng, 100);
-            assert_eq!(string3.capacity(), 200);
-        }
-    }
-
-    #[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);
-        let mut max_rng = StepRng::new(0xffff_ffff_ffff_ffff, 0);
-        macro_rules! t {
-            ($ty:ty, $f_scalar:ident, $bits_shifted:expr) => {{
-                let v: &[($f_scalar, $f_scalar)] = &[
-                    (0.0, 100.0),
-                    (-1e35, -1e25),
-                    (1e-35, 1e-25),
-                    (-1e35, 1e35),
-                    (<$f_scalar>::from_bits(0), <$f_scalar>::from_bits(3)),
-                    (-<$f_scalar>::from_bits(10), -<$f_scalar>::from_bits(1)),
-                    (-<$f_scalar>::from_bits(5), 0.0),
-                    (-<$f_scalar>::from_bits(7), -0.0),
-                    (0.1 * $f_scalar::MAX, $f_scalar::MAX),
-                    (-$f_scalar::MAX * 0.2, $f_scalar::MAX * 0.7),
-                ];
-                for &(low_scalar, high_scalar) in v.iter() {
-                    for lane in 0..<$ty>::LEN {
-                        let low = <$ty>::splat(0.0 as $f_scalar).replace(lane, low_scalar);
-                        let high = <$ty>::splat(1.0 as $f_scalar).replace(lane, high_scalar);
-                        let my_uniform = Uniform::new(low, high).unwrap();
-                        let my_incl_uniform = Uniform::new_inclusive(low, high).unwrap();
-                        for _ in 0..100 {
-                            let v = rng.sample(my_uniform).extract(lane);
-                            assert!(low_scalar <= v && v <= high_scalar);
-                            let v = rng.sample(my_incl_uniform).extract(lane);
-                            assert!(low_scalar <= v && v <= high_scalar);
-                            let v =
-                                <$ty as SampleUniform>::Sampler::sample_single(low, high, &mut rng)
-                                    .unwrap()
-                                    .extract(lane);
-                            assert!(low_scalar <= v && v <= high_scalar);
-                            let v = <$ty as SampleUniform>::Sampler::sample_single_inclusive(
-                                low, high, &mut rng,
-                            )
-                            .unwrap()
-                            .extract(lane);
-                            assert!(low_scalar <= v && v <= high_scalar);
-                        }
-
-                        assert_eq!(
-                            rng.sample(Uniform::new_inclusive(low, low).unwrap())
-                                .extract(lane),
-                            low_scalar
-                        );
-
-                        assert_eq!(zero_rng.sample(my_uniform).extract(lane), low_scalar);
-                        assert_eq!(zero_rng.sample(my_incl_uniform).extract(lane), low_scalar);
-                        assert_eq!(
-                            <$ty as SampleUniform>::Sampler::sample_single(
-                                low,
-                                high,
-                                &mut zero_rng
-                            )
-                            .unwrap()
-                            .extract(lane),
-                            low_scalar
-                        );
-                        assert_eq!(
-                            <$ty as SampleUniform>::Sampler::sample_single_inclusive(
-                                low,
-                                high,
-                                &mut zero_rng
-                            )
-                            .unwrap()
-                            .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);
-                        // sample_single cannot cope with max_rng:
-                        // assert!(<$ty as SampleUniform>::Sampler
-                        //     ::sample_single(low, high, &mut max_rng).unwrap()
-                        //     .extract(lane) <= high_scalar);
-                        assert!(
-                            <$ty as SampleUniform>::Sampler::sample_single_inclusive(
-                                low,
-                                high,
-                                &mut max_rng
-                            )
-                            .unwrap()
-                            .extract(lane)
-                                <= high_scalar
-                        );
-
-                        // Don't run this test for really tiny differences between high and low
-                        // since for those rounding might result in selecting high for a very
-                        // long time.
-                        if (high_scalar - low_scalar) > 0.0001 {
-                            let mut lowering_max_rng = StepRng::new(
-                                0xffff_ffff_ffff_ffff,
-                                (-1i64 << $bits_shifted) as u64,
-                            );
-                            assert!(
-                                <$ty as SampleUniform>::Sampler::sample_single(
-                                    low,
-                                    high,
-                                    &mut lowering_max_rng
-                                )
-                                .unwrap()
-                                .extract(lane)
-                                    <= high_scalar
-                            );
-                        }
-                    }
-                }
-
-                assert_eq!(
-                    rng.sample(Uniform::new_inclusive($f_scalar::MAX, $f_scalar::MAX).unwrap()),
-                    $f_scalar::MAX
-                );
-                assert_eq!(
-                    rng.sample(Uniform::new_inclusive(-$f_scalar::MAX, -$f_scalar::MAX).unwrap()),
-                    -$f_scalar::MAX
-                );
-            }};
-        }
-
-        t!(f32, f32, 32 - 23);
-        t!(f64, f64, 64 - 52);
-        #[cfg(feature = "simd_support")]
-        {
-            t!(f32x2, f32, 32 - 23);
-            t!(f32x4, f32, 32 - 23);
-            t!(f32x8, f32, 32 - 23);
-            t!(f32x16, f32, 32 - 23);
-            t!(f64x2, f64, 64 - 52);
-            t!(f64x4, f64, 64 - 52);
-            t!(f64x8, f64, 64 - 52);
-        }
-    }
-
-    #[test]
-    fn test_float_overflow() {
-        assert_eq!(Uniform::try_from(f64::MIN..f64::MAX), Err(Error::NonFinite));
-    }
-
-    #[test]
-    #[should_panic]
-    fn test_float_overflow_single() {
-        let mut rng = crate::test::rng(252);
-        rng.gen_range(f64::MIN..f64::MAX);
-    }
-
-    #[test]
-    #[cfg(all(feature = "std", panic = "unwind"))]
-    fn test_float_assertions() {
-        use super::SampleUniform;
-        fn range<T: SampleUniform>(low: T, high: T) -> Result<T, Error> {
-            let mut rng = crate::test::rng(253);
-            T::Sampler::sample_single(low, high, &mut rng)
-        }
-
-        macro_rules! t {
-            ($ty:ident, $f_scalar:ident) => {{
-                let v: &[($f_scalar, $f_scalar)] = &[
-                    ($f_scalar::NAN, 0.0),
-                    (1.0, $f_scalar::NAN),
-                    ($f_scalar::NAN, $f_scalar::NAN),
-                    (1.0, 0.5),
-                    ($f_scalar::MAX, -$f_scalar::MAX),
-                    ($f_scalar::INFINITY, $f_scalar::INFINITY),
-                    ($f_scalar::NEG_INFINITY, $f_scalar::NEG_INFINITY),
-                    ($f_scalar::NEG_INFINITY, 5.0),
-                    (5.0, $f_scalar::INFINITY),
-                    ($f_scalar::NAN, $f_scalar::INFINITY),
-                    ($f_scalar::NEG_INFINITY, $f_scalar::NAN),
-                    ($f_scalar::NEG_INFINITY, $f_scalar::INFINITY),
-                ];
-                for &(low_scalar, high_scalar) in v.iter() {
-                    for lane in 0..<$ty>::LEN {
-                        let low = <$ty>::splat(0.0 as $f_scalar).replace(lane, low_scalar);
-                        let high = <$ty>::splat(1.0 as $f_scalar).replace(lane, high_scalar);
-                        assert!(range(low, high).is_err());
-                        assert!(Uniform::new(low, high).is_err());
-                        assert!(Uniform::new_inclusive(low, high).is_err());
-                        assert!(Uniform::new(low, low).is_err());
-                    }
-                }
-            }};
-        }
-
-        t!(f32, f32);
-        t!(f64, f64);
-        #[cfg(feature = "simd_support")]
-        {
-            t!(f32x2, f32);
-            t!(f32x4, f32);
-            t!(f32x8, f32);
-            t!(f32x16, f32);
-            t!(f64x2, f64);
-            t!(f64x4, f64);
-            t!(f64x8, f64);
-        }
-    }
-
-    #[test]
-    #[cfg_attr(miri, ignore)] // Miri is too slow
-    fn test_durations() {
-        let mut rng = crate::test::rng(253);
-
-        let v = &[
-            (Duration::new(10, 50000), Duration::new(100, 1234)),
-            (Duration::new(0, 100), Duration::new(1, 50)),
-            (Duration::new(0, 0), Duration::new(u64::MAX, 999_999_999)),
-        ];
-        for &(low, high) in v.iter() {
-            let my_uniform = Uniform::new(low, high).unwrap();
-            for _ in 0..1000 {
-                let v = rng.sample(my_uniform);
-                assert!(low <= v && v < high);
-            }
-        }
-    }
-
-    #[test]
-    fn test_custom_uniform() {
-        use crate::distributions::uniform::{
-            SampleBorrow, SampleUniform, UniformFloat, UniformSampler,
-        };
-        #[derive(Clone, Copy, PartialEq, PartialOrd)]
-        struct MyF32 {
-            x: f32,
-        }
-        #[derive(Clone, Copy, Debug)]
-        struct UniformMyF32(UniformFloat<f32>);
-        impl UniformSampler for UniformMyF32 {
-            type X = MyF32;
-
-            fn new<B1, B2>(low: B1, high: B2) -> Result<Self, Error>
-            where
-                B1: SampleBorrow<Self::X> + Sized,
-                B2: SampleBorrow<Self::X> + Sized,
-            {
-                UniformFloat::<f32>::new(low.borrow().x, high.borrow().x).map(UniformMyF32)
-            }
-
-            fn new_inclusive<B1, B2>(low: B1, high: B2) -> Result<Self, Error>
-            where
-                B1: SampleBorrow<Self::X> + Sized,
-                B2: SampleBorrow<Self::X> + Sized,
-            {
-                UniformSampler::new(low, high)
-            }
-
-            fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
-                MyF32 {
-                    x: self.0.sample(rng),
-                }
-            }
-        }
-        impl SampleUniform for MyF32 {
-            type Sampler = UniformMyF32;
-        }
-
-        let (low, high) = (MyF32 { x: 17.0f32 }, MyF32 { x: 22.0f32 });
-        let uniform = Uniform::new(low, high).unwrap();
-        let mut rng = crate::test::rng(804);
-        for _ in 0..100 {
-            let x: MyF32 = rng.sample(uniform);
-            assert!(low <= x && x < high);
-        }
-    }
-
-    #[test]
-    fn test_uniform_from_std_range() {
-        let r = Uniform::try_from(2u32..7).unwrap();
-        assert_eq!(r.0.low, 2);
-        assert_eq!(r.0.range, 5);
-        let r = Uniform::try_from(2.0f64..7.0).unwrap();
-        assert_eq!(r.0.low, 2.0);
-        assert_eq!(r.0.scale, 5.0);
-    }
-
-    #[test]
-    fn test_uniform_from_std_range_bad_limits() {
-        #![allow(clippy::reversed_empty_ranges)]
-        assert!(Uniform::try_from(100..10).is_err());
-        assert!(Uniform::try_from(100..100).is_err());
-        assert!(Uniform::try_from(100.0..10.0).is_err());
-        assert!(Uniform::try_from(100.0..100.0).is_err());
-    }
-
-    #[test]
-    fn test_uniform_from_std_range_inclusive() {
-        let r = Uniform::try_from(2u32..=6).unwrap();
-        assert_eq!(r.0.low, 2);
-        assert_eq!(r.0.range, 5);
-        let r = Uniform::try_from(2.0f64..=7.0).unwrap();
-        assert_eq!(r.0.low, 2.0);
-        assert!(r.0.scale > 5.0);
-        assert!(r.0.scale < 5.0 + 1e-14);
-    }
-
-    #[test]
-    fn test_uniform_from_std_range_inclusive_bad_limits() {
-        #![allow(clippy::reversed_empty_ranges)]
-        assert!(Uniform::try_from(100..=10).is_err());
-        assert!(Uniform::try_from(100..=99).is_err());
-        assert!(Uniform::try_from(100.0..=10.0).is_err());
-        assert!(Uniform::try_from(100.0..=99.0).is_err());
-    }
-
-    #[test]
-    fn value_stability() {
-        fn test_samples<T: SampleUniform + Copy + fmt::Debug + PartialEq>(
-            lb: T,
-            ub: T,
-            expected_single: &[T],
-            expected_multiple: &[T],
-        ) where
-            Uniform<T>: Distribution<T>,
-        {
-            let mut rng = crate::test::rng(897);
-            let mut buf = [lb; 3];
-
-            for x in &mut buf {
-                *x = T::Sampler::sample_single(lb, ub, &mut rng).unwrap();
-            }
-            assert_eq!(&buf, expected_single);
-
-            let distr = Uniform::new(lb, ub).unwrap();
-            for x in &mut buf {
-                *x = rng.sample(&distr);
-            }
-            assert_eq!(&buf, expected_multiple);
-        }
-
-        // We test on a sub-set of types; possibly we should do more.
-        // TODO: SIMD types
-
-        test_samples(11u8, 219, &[17, 66, 214], &[181, 93, 165]);
-        test_samples(11u32, 219, &[17, 66, 214], &[181, 93, 165]);
-
-        test_samples(
-            0f32,
-            1e-2f32,
-            &[0.0003070104, 0.0026630748, 0.00979833],
-            &[0.008194133, 0.00398172, 0.007428536],
-        );
-        test_samples(
-            -1e10f64,
-            1e10f64,
-            &[-4673848682.871551, 6388267422.932352, 4857075081.198343],
-            &[1173375212.1808167, 1917642852.109581, 2365076174.3153973],
-        );
-
-        test_samples(
-            Duration::new(2, 0),
-            Duration::new(4, 0),
-            &[
-                Duration::new(2, 532615131),
-                Duration::new(3, 638826742),
-                Duration::new(3, 485707508),
-            ],
-            &[
-                Duration::new(3, 117337521),
-                Duration::new(3, 191764285),
-                Duration::new(3, 236507617),
-            ],
-        );
-    }
-
-    #[test]
-    fn uniform_distributions_can_be_compared() {
-        assert_eq!(
-            Uniform::new(1.0, 2.0).unwrap(),
-            Uniform::new(1.0, 2.0).unwrap()
-        );
-
-        // To cover UniformInt
-        assert_eq!(
-            Uniform::new(1_u32, 2_u32).unwrap(),
-            Uniform::new(1_u32, 2_u32).unwrap()
-        );
-    }
-}
diff --git a/src/lib.rs b/src/lib.rs
index 8b43f0320f9..ce0206db09b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -17,7 +17,7 @@
 //! To get you started quickly, the easiest and highest-level way to get
 //! a random value is to use [`random()`]; alternatively you can use
 //! [`thread_rng()`]. The [`Rng`] trait provides a useful API on all RNGs, while
-//! the [`distributions`] and [`seq`] modules provide further
+//! the [`distr`] and [`seq`] modules provide further
 //! functionality on top of RNGs.
 //!
 //! ```
@@ -97,7 +97,7 @@ macro_rules! error { ($($x:tt)*) => (
 pub use rand_core::{CryptoRng, RngCore, SeedableRng, TryCryptoRng, TryRngCore};
 
 // Public modules
-pub mod distributions;
+pub mod distr;
 pub mod prelude;
 mod rng;
 pub mod rngs;
@@ -109,7 +109,7 @@ pub use crate::rngs::thread::thread_rng;
 pub use rng::{Fill, Rng};
 
 #[cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))]
-use crate::distributions::{Distribution, Standard};
+use crate::distr::{Distribution, Standard};
 
 /// Generates a random value using the thread-local random number generator.
 ///
@@ -153,7 +153,7 @@ use crate::distributions::{Distribution, Standard};
 /// }
 /// ```
 ///
-/// [`Standard`]: distributions::Standard
+/// [`Standard`]: distr::Standard
 /// [`ThreadRng`]: rngs::ThreadRng
 #[cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))]
 #[inline]
diff --git a/src/prelude.rs b/src/prelude.rs
index 2605bca91f4..37b703742df 100644
--- a/src/prelude.rs
+++ b/src/prelude.rs
@@ -19,7 +19,7 @@
 //! ```
 
 #[doc(no_inline)]
-pub use crate::distributions::Distribution;
+pub use crate::distr::Distribution;
 #[cfg(feature = "small_rng")]
 #[doc(no_inline)]
 pub use crate::rngs::SmallRng;
diff --git a/src/rng.rs b/src/rng.rs
index 06fc2bb741e..9c015eddd41 100644
--- a/src/rng.rs
+++ b/src/rng.rs
@@ -9,8 +9,8 @@
 
 //! [`Rng`] trait
 
-use crate::distributions::uniform::{SampleRange, SampleUniform};
-use crate::distributions::{self, Distribution, Standard};
+use crate::distr::uniform::{SampleRange, SampleUniform};
+use crate::distr::{self, Distribution, Standard};
 use core::num::Wrapping;
 use core::{mem, slice};
 use rand_core::RngCore;
@@ -86,7 +86,7 @@ pub trait Rng: RngCore {
     /// rng.fill(&mut arr2);                    // array fill
     /// ```
     ///
-    /// [`Standard`]: distributions::Standard
+    /// [`Standard`]: distr::Standard
     #[inline]
     fn random<T>(&mut self) -> T
     where
@@ -125,7 +125,7 @@ pub trait Rng: RngCore {
     /// println!("{}", n);
     /// ```
     ///
-    /// [`Uniform`]: distributions::uniform::Uniform
+    /// [`Uniform`]: distr::uniform::Uniform
     #[track_caller]
     fn gen_range<T, R>(&mut self, range: R) -> T
     where
@@ -139,7 +139,7 @@ pub trait Rng: RngCore {
     /// Generate values via an iterator
     ///
     /// This is a just a wrapper over [`Rng::sample_iter`] using
-    /// [`distributions::Standard`].
+    /// [`distr::Standard`].
     ///
     /// Note: this method consumes its argument. Use
     /// `(&mut rng).gen_iter()` to avoid consuming the RNG.
@@ -154,7 +154,7 @@ pub trait Rng: RngCore {
     /// assert_eq!(&v, &[1, 2, 3, 4, 5]);
     /// ```
     #[inline]
-    fn gen_iter<T>(self) -> distributions::DistIter<Standard, Self, T>
+    fn gen_iter<T>(self) -> distr::DistIter<Standard, Self, T>
     where
         Self: Sized,
         Standard: Distribution<T>,
@@ -168,7 +168,7 @@ pub trait Rng: RngCore {
     ///
     /// ```
     /// use rand::{thread_rng, Rng};
-    /// use rand::distributions::Uniform;
+    /// use rand::distr::Uniform;
     ///
     /// let mut rng = thread_rng();
     /// let x = rng.sample(Uniform::new(10u32, 15).unwrap());
@@ -189,7 +189,7 @@ pub trait Rng: RngCore {
     ///
     /// ```
     /// use rand::{thread_rng, Rng};
-    /// use rand::distributions::{Alphanumeric, Uniform, Standard};
+    /// use rand::distr::{Alphanumeric, Uniform, Standard};
     ///
     /// let mut rng = thread_rng();
     ///
@@ -213,7 +213,7 @@ pub trait Rng: RngCore {
     ///     println!("Not a 6; rolling again!");
     /// }
     /// ```
-    fn sample_iter<T, D>(self, distr: D) -> distributions::DistIter<D, Self, T>
+    fn sample_iter<T, D>(self, distr: D) -> distr::DistIter<D, Self, T>
     where
         D: Distribution<T>,
         Self: Sized,
@@ -259,11 +259,11 @@ pub trait Rng: RngCore {
     ///
     /// If `p < 0` or `p > 1`.
     ///
-    /// [`Bernoulli`]: distributions::Bernoulli
+    /// [`Bernoulli`]: distr::Bernoulli
     #[inline]
     #[track_caller]
     fn gen_bool(&mut self, p: f64) -> bool {
-        match distributions::Bernoulli::new(p) {
+        match distr::Bernoulli::new(p) {
             Ok(d) => self.sample(d),
             Err(_) => panic!("p={:?} is outside range [0.0, 1.0]", p),
         }
@@ -291,11 +291,11 @@ pub trait Rng: RngCore {
     /// println!("{}", rng.gen_ratio(2, 3));
     /// ```
     ///
-    /// [`Bernoulli`]: distributions::Bernoulli
+    /// [`Bernoulli`]: distr::Bernoulli
     #[inline]
     #[track_caller]
     fn gen_ratio(&mut self, numerator: u32, denominator: u32) -> bool {
-        match distributions::Bernoulli::from_ratio(numerator, denominator) {
+        match distr::Bernoulli::from_ratio(numerator, denominator) {
             Ok(d) => self.sample(d),
             Err(_) => panic!(
                 "p={}/{} is outside range [0.0, 1.0]",
@@ -554,7 +554,7 @@ mod test {
 
     #[test]
     fn test_rng_trait_object() {
-        use crate::distributions::{Distribution, Standard};
+        use crate::distr::{Distribution, Standard};
         let mut rng = rng(109);
         let mut r = &mut rng as &mut dyn RngCore;
         r.next_u32();
@@ -566,7 +566,7 @@ mod test {
     #[test]
     #[cfg(feature = "alloc")]
     fn test_rng_boxed_trait() {
-        use crate::distributions::{Distribution, Standard};
+        use crate::distr::{Distribution, Standard};
         let rng = rng(110);
         let mut r = Box::new(rng) as Box<dyn RngCore>;
         r.next_u32();
diff --git a/src/rngs/mock.rs b/src/rngs/mock.rs
index a01a6bd7b4e..6218626db9b 100644
--- a/src/rngs/mock.rs
+++ b/src/rngs/mock.rs
@@ -22,7 +22,7 @@ use serde::{Deserialize, Serialize};
 /// Other integer types (64-bit and smaller) are produced via cast from `u64`.
 ///
 /// Other types are produced via their implementation of [`Rng`](crate::Rng) or
-/// [`Distribution`](crate::distributions::Distribution).
+/// [`Distribution`](crate::distr::Distribution).
 /// Output values may not be intuitive and may change in future releases but
 /// are considered
 /// [portable](https://rust-random.github.io/book/portability.html).
@@ -95,7 +95,7 @@ mod tests {
     #[test]
     #[cfg(feature = "alloc")]
     fn test_bool() {
-        use crate::{distributions::Standard, Rng};
+        use crate::{distr::Standard, Rng};
 
         // If this result ever changes, update doc on StepRng!
         let rng = StepRng::new(0, 1 << 31);
diff --git a/src/seq/index.rs b/src/seq/index.rs
index e37198bd67a..d7d1636570c 100644
--- a/src/seq/index.rs
+++ b/src/seq/index.rs
@@ -7,19 +7,16 @@
 // except according to those terms.
 
 //! Low-level API for sampling indices
-use super::gen_index;
-#[cfg(feature = "alloc")]
 use alloc::vec::{self, Vec};
 use core::slice;
 use core::{hash::Hash, ops::AddAssign};
 // BTreeMap is not as fast in tests, but better than nothing.
 #[cfg(feature = "std")]
 use super::WeightError;
-use crate::distributions::uniform::SampleUniform;
-#[cfg(feature = "alloc")]
-use crate::distributions::{Distribution, Uniform};
+use crate::distr::uniform::SampleUniform;
+use crate::distr::{Distribution, Uniform};
 use crate::Rng;
-#[cfg(all(feature = "alloc", not(feature = "std")))]
+#[cfg(not(feature = "std"))]
 use alloc::collections::BTreeSet;
 #[cfg(feature = "serde1")]
 use serde::{Deserialize, Serialize};
@@ -30,7 +27,6 @@ use std::collections::HashSet;
 ///
 /// Multiple internal representations are possible.
 #[derive(Clone, Debug)]
-#[cfg(feature = "alloc")]
 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub enum IndexVec {
     #[doc(hidden)]
@@ -39,7 +35,6 @@ pub enum IndexVec {
     USize(Vec<usize>),
 }
 
-#[cfg(feature = "alloc")]
 impl IndexVec {
     /// Returns the number of indices
     #[inline]
@@ -90,7 +85,6 @@ impl IndexVec {
     }
 }
 
-#[cfg(feature = "alloc")]
 impl IntoIterator for IndexVec {
     type IntoIter = IndexVecIntoIter;
     type Item = usize;
@@ -105,7 +99,6 @@ impl IntoIterator for IndexVec {
     }
 }
 
-#[cfg(feature = "alloc")]
 impl PartialEq for IndexVec {
     fn eq(&self, other: &IndexVec) -> bool {
         use self::IndexVec::*;
@@ -122,7 +115,6 @@ impl PartialEq for IndexVec {
     }
 }
 
-#[cfg(feature = "alloc")]
 impl From<Vec<u32>> for IndexVec {
     #[inline]
     fn from(v: Vec<u32>) -> Self {
@@ -130,7 +122,6 @@ impl From<Vec<u32>> for IndexVec {
     }
 }
 
-#[cfg(feature = "alloc")]
 impl From<Vec<usize>> for IndexVec {
     #[inline]
     fn from(v: Vec<usize>) -> Self {
@@ -171,7 +162,6 @@ impl<'a> Iterator for IndexVecIter<'a> {
 impl<'a> ExactSizeIterator for IndexVecIter<'a> {}
 
 /// Return type of `IndexVec::into_iter`.
-#[cfg(feature = "alloc")]
 #[derive(Clone, Debug)]
 pub enum IndexVecIntoIter {
     #[doc(hidden)]
@@ -180,7 +170,6 @@ pub enum IndexVecIntoIter {
     USize(vec::IntoIter<usize>),
 }
 
-#[cfg(feature = "alloc")]
 impl Iterator for IndexVecIntoIter {
     type Item = usize;
 
@@ -203,7 +192,6 @@ impl Iterator for IndexVecIntoIter {
     }
 }
 
-#[cfg(feature = "alloc")]
 impl ExactSizeIterator for IndexVecIntoIter {}
 
 /// Randomly sample exactly `amount` distinct indices from `0..length`, and
@@ -228,7 +216,6 @@ impl ExactSizeIterator for IndexVecIntoIter {}
 /// to adapt the internal `sample_floyd` implementation.
 ///
 /// Panics if `amount > length`.
-#[cfg(feature = "alloc")]
 #[track_caller]
 pub fn sample<R>(rng: &mut R, length: usize, amount: usize) -> IndexVec
 where
@@ -271,33 +258,6 @@ where
     }
 }
 
-/// Randomly sample exactly `N` distinct indices from `0..len`, and
-/// return them in random order (fully shuffled).
-///
-/// This is implemented via Floyd's algorithm. Time complexity is `O(N^2)`
-/// and memory complexity is `O(N)`.
-///
-/// Returns `None` if (and only if) `N > len`.
-pub fn sample_array<R, const N: usize>(rng: &mut R, len: usize) -> Option<[usize; N]>
-where
-    R: Rng + ?Sized,
-{
-    if N > len {
-        return None;
-    }
-
-    // Floyd's algorithm
-    let mut indices = [0; N];
-    for (i, j) in (len - N..len).enumerate() {
-        let t = gen_index(rng, j + 1);
-        if let Some(pos) = indices[0..i].iter().position(|&x| x == t) {
-            indices[pos] = j;
-        }
-        indices[i] = t;
-    }
-    Some(indices)
-}
-
 /// 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`,
@@ -432,7 +392,6 @@ where
 /// The output values are fully shuffled. (Overhead is under 50%.)
 ///
 /// This implementation uses `O(amount)` memory and `O(amount^2)` time.
-#[cfg(feature = "alloc")]
 fn sample_floyd<R>(rng: &mut R, length: u32, amount: u32) -> IndexVec
 where
     R: Rng + ?Sized,
@@ -464,7 +423,6 @@ where
 /// performance in all cases).
 ///
 /// Set-up is `O(length)` time and memory and shuffling is `O(amount)` time.
-#[cfg(feature = "alloc")]
 fn sample_inplace<R>(rng: &mut R, length: u32, amount: u32) -> IndexVec
 where
     R: Rng + ?Sized,
@@ -483,6 +441,7 @@ where
 
 trait UInt: Copy + PartialOrd + Ord + PartialEq + Eq + SampleUniform + Hash + AddAssign {
     fn zero() -> Self;
+    #[cfg_attr(feature = "alloc", allow(dead_code))]
     fn one() -> Self;
     fn as_usize(self) -> usize;
 }
@@ -530,7 +489,6 @@ impl UInt for usize {
 ///
 /// This function  is generic over X primarily so that results are value-stable
 /// over 32-bit and 64-bit platforms.
-#[cfg(feature = "alloc")]
 fn sample_rejection<X: UInt, R>(rng: &mut R, length: X, amount: X) -> IndexVec
 where
     R: Rng + ?Sized,
@@ -555,7 +513,6 @@ where
     IndexVec::from(indices)
 }
 
-#[cfg(feature = "alloc")]
 #[cfg(test)]
 mod test {
     use super::*;
diff --git a/src/seq/mod.rs b/src/seq/mod.rs
index b7cd1729d21..0015517907a 100644
--- a/src/seq/mod.rs
+++ b/src/seq/mod.rs
@@ -19,7 +19,7 @@
 //!
 //! Also see:
 //!
-//! *   [`crate::distributions::WeightedIndex`] distribution which provides
+//! *   [`crate::distr::WeightedIndex`] distribution which provides
 //!     weighted index sampling.
 //!
 //! In order to make results reproducible across 32-64 bit architectures, all
@@ -31,11 +31,13 @@ mod increasing_uniform;
 mod iterator;
 mod slice;
 
-pub mod index;
+#[cfg(feature = "alloc")]
+#[path = "index.rs"]
+mod index_;
 
 #[cfg(feature = "alloc")]
 #[doc(no_inline)]
-pub use crate::distributions::WeightError;
+pub use crate::distr::WeightError;
 pub use iterator::IteratorRandom;
 #[cfg(feature = "alloc")]
 pub use slice::SliceChooseIter;
@@ -54,3 +56,40 @@ fn gen_index<R: Rng + ?Sized>(rng: &mut R, ubound: usize) -> usize {
         rng.gen_range(0..ubound)
     }
 }
+
+/// Low-level API for sampling indices
+pub mod index {
+    use super::gen_index;
+    use crate::Rng;
+
+    #[cfg(feature = "alloc")]
+    #[doc(inline)]
+    pub use super::index_::*;
+
+    /// Randomly sample exactly `N` distinct indices from `0..len`, and
+    /// return them in random order (fully shuffled).
+    ///
+    /// This is implemented via Floyd's algorithm. Time complexity is `O(N^2)`
+    /// and memory complexity is `O(N)`.
+    ///
+    /// Returns `None` if (and only if) `N > len`.
+    pub fn sample_array<R, const N: usize>(rng: &mut R, len: usize) -> Option<[usize; N]>
+    where
+        R: Rng + ?Sized,
+    {
+        if N > len {
+            return None;
+        }
+
+        // Floyd's algorithm
+        let mut indices = [0; N];
+        for (i, j) in (len - N..len).enumerate() {
+            let t = gen_index(rng, j + 1);
+            if let Some(pos) = indices[0..i].iter().position(|&x| x == t) {
+                indices[pos] = j;
+            }
+            indices[i] = t;
+        }
+        Some(indices)
+    }
+}
diff --git a/src/seq/slice.rs b/src/seq/slice.rs
index c82998fd358..7c86f00a736 100644
--- a/src/seq/slice.rs
+++ b/src/seq/slice.rs
@@ -11,9 +11,9 @@
 use super::increasing_uniform::IncreasingUniform;
 use super::{gen_index, index};
 #[cfg(feature = "alloc")]
-use crate::distributions::uniform::{SampleBorrow, SampleUniform};
+use crate::distr::uniform::{SampleBorrow, SampleUniform};
 #[cfg(feature = "alloc")]
-use crate::distributions::{Weight, WeightError};
+use crate::distr::{Weight, WeightError};
 use crate::Rng;
 use core::ops::{Index, IndexMut};
 
@@ -137,7 +137,7 @@ pub trait IndexedRandom: Index<usize> {
     ///
     /// For slices of length `n`, complexity is `O(n)`.
     /// For more information about the underlying algorithm,
-    /// see [`distributions::WeightedIndex`].
+    /// see [`distr::WeightedIndex`].
     ///
     /// See also [`choose_weighted_mut`].
     ///
@@ -154,7 +154,7 @@ pub trait IndexedRandom: Index<usize> {
     /// ```
     /// [`choose`]: IndexedRandom::choose
     /// [`choose_weighted_mut`]: IndexedMutRandom::choose_weighted_mut
-    /// [`distributions::WeightedIndex`]: crate::distributions::WeightedIndex
+    /// [`distr::WeightedIndex`]: crate::distr::WeightedIndex
     #[cfg(feature = "alloc")]
     fn choose_weighted<R, F, B, X>(
         &self,
@@ -167,7 +167,7 @@ pub trait IndexedRandom: Index<usize> {
         B: SampleBorrow<X>,
         X: SampleUniform + Weight + PartialOrd<X>,
     {
-        use crate::distributions::{Distribution, WeightedIndex};
+        use crate::distr::{Distribution, WeightedIndex};
         let distr = WeightedIndex::new((0..self.len()).map(|idx| weight(&self[idx])))?;
         Ok(&self[distr.sample(rng)])
     }
@@ -268,13 +268,13 @@ pub trait IndexedMutRandom: IndexedRandom + IndexMut<usize> {
     ///
     /// For slices of length `n`, complexity is `O(n)`.
     /// For more information about the underlying algorithm,
-    /// see [`distributions::WeightedIndex`].
+    /// see [`distr::WeightedIndex`].
     ///
     /// See also [`choose_weighted`].
     ///
     /// [`choose_mut`]: IndexedMutRandom::choose_mut
     /// [`choose_weighted`]: IndexedRandom::choose_weighted
-    /// [`distributions::WeightedIndex`]: crate::distributions::WeightedIndex
+    /// [`distr::WeightedIndex`]: crate::distr::WeightedIndex
     #[cfg(feature = "alloc")]
     fn choose_weighted_mut<R, F, B, X>(
         &mut self,
@@ -287,7 +287,7 @@ pub trait IndexedMutRandom: IndexedRandom + IndexMut<usize> {
         B: SampleBorrow<X>,
         X: SampleUniform + Weight + PartialOrd<X>,
     {
-        use crate::distributions::{Distribution, WeightedIndex};
+        use crate::distr::{Distribution, WeightedIndex};
         let distr = WeightedIndex::new((0..self.len()).map(|idx| weight(&self[idx])))?;
         let index = distr.sample(rng);
         Ok(&mut self[index])
diff --git a/utils/ziggurat_tables.py b/utils/ziggurat_tables.py
index 88cfdab6ba2..87a766ccc36 100755
--- a/utils/ziggurat_tables.py
+++ b/utils/ziggurat_tables.py
@@ -10,7 +10,7 @@
 # except according to those terms.
 
 # This creates the tables used for distributions implemented using the
-# ziggurat algorithm in `rand::distributions;`. They are
+# ziggurat algorithm in `rand::distr;`. They are
 # (basically) the tables as used in the ZIGNOR variant (Doornik 2005).
 # They are changed rarely, so the generated file should be checked in
 # to git.