diff --git a/src/librand/chacha.rs b/src/librand/chacha.rs index 7dc0d19e6a6..e355eb44e46 100644 --- a/src/librand/chacha.rs +++ b/src/librand/chacha.rs @@ -10,6 +10,7 @@ //! The ChaCha random number generator. +use core::fmt; use {Rand, Rng, SeedableRng}; const KEY_WORDS: usize = 8; // 8 words for the 256-bit key @@ -32,6 +33,16 @@ pub struct ChaChaRng { index: usize, // Index into state } +impl fmt::Debug for ChaChaRng { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("ChaChaRng") + .field("buffer", &self.buffer.iter()) + .field("state", &self.state.iter()) + .field("index", &self.index) + .finish() + } +} + static EMPTY: ChaChaRng = ChaChaRng { buffer: [0; STATE_WORDS], state: [0; STATE_WORDS], diff --git a/src/librand/distributions/exponential.rs b/src/librand/distributions/exponential.rs index 5a8558efc02..3337cc2a627 100644 --- a/src/librand/distributions/exponential.rs +++ b/src/librand/distributions/exponential.rs @@ -10,6 +10,8 @@ //! The exponential distribution. +use core::fmt; + #[cfg(not(test))] // only necessary for no_std use FloatMath; @@ -55,6 +57,14 @@ impl Rand for Exp1 { } } +impl fmt::Debug for Exp1 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Exp1") + .field(&self.0) + .finish() + } +} + /// The exponential distribution `Exp(lambda)`. /// /// This distribution has density function: `f(x) = lambda * @@ -79,6 +89,7 @@ impl Sample for Exp { self.ind_sample(rng) } } + impl IndependentSample for Exp { fn ind_sample(&self, rng: &mut R) -> f64 { let Exp1(n) = rng.gen::(); @@ -86,6 +97,14 @@ impl IndependentSample for Exp { } } +impl fmt::Debug for Exp { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Exp") + .field("lambda_inverse", &self.lambda_inverse) + .finish() + } +} + #[cfg(test)] mod tests { use distributions::{IndependentSample, Sample}; diff --git a/src/librand/distributions/gamma.rs b/src/librand/distributions/gamma.rs index 9ca13e85b53..e024b62adfb 100644 --- a/src/librand/distributions/gamma.rs +++ b/src/librand/distributions/gamma.rs @@ -10,6 +10,8 @@ //! The Gamma and derived distributions. +use core::fmt; + use self::GammaRepr::*; use self::ChiSquaredRepr::*; @@ -44,6 +46,19 @@ pub struct Gamma { repr: GammaRepr, } +impl fmt::Debug for Gamma { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Gamma") + .field("repr", + &match self.repr { + GammaRepr::Large(_) => "Large", + GammaRepr::One(_) => "Exp", + GammaRepr::Small(_) => "Small" + }) + .finish() + } +} + enum GammaRepr { Large(GammaLargeShape), One(Exp), @@ -182,6 +197,18 @@ pub struct ChiSquared { repr: ChiSquaredRepr, } +impl fmt::Debug for ChiSquared { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("ChiSquared") + .field("repr", + &match self.repr { + ChiSquaredRepr::DoFExactlyOne => "DoFExactlyOne", + ChiSquaredRepr::DoFAnythingElse(_) => "DoFAnythingElse", + }) + .finish() + } +} + enum ChiSquaredRepr { // k == 1, Gamma(alpha, ..) is particularly slow for alpha < 1, // e.g. when alpha = 1/2 as it would be for this case, so special- @@ -203,11 +230,13 @@ impl ChiSquared { ChiSquared { repr: repr } } } + impl Sample for ChiSquared { fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } } + impl IndependentSample for ChiSquared { fn ind_sample(&self, rng: &mut R) -> f64 { match self.repr { @@ -248,17 +277,29 @@ impl FisherF { } } } + impl Sample for FisherF { fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } } + impl IndependentSample for FisherF { fn ind_sample(&self, rng: &mut R) -> f64 { self.numer.ind_sample(rng) / self.denom.ind_sample(rng) * self.dof_ratio } } +impl fmt::Debug for FisherF { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("FisherF") + .field("numer", &self.numer) + .field("denom", &self.denom) + .field("dof_ratio", &self.dof_ratio) + .finish() + } +} + /// The Student t distribution, `t(nu)`, where `nu` is the degrees of /// freedom. pub struct StudentT { @@ -277,11 +318,13 @@ impl StudentT { } } } + impl Sample for StudentT { fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } } + impl IndependentSample for StudentT { fn ind_sample(&self, rng: &mut R) -> f64 { let StandardNormal(norm) = rng.gen::(); @@ -289,6 +332,15 @@ impl IndependentSample for StudentT { } } +impl fmt::Debug for StudentT { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("StudentT") + .field("chi", &self.chi) + .field("dof", &self.dof) + .finish() + } +} + #[cfg(test)] mod tests { use distributions::{IndependentSample, Sample}; diff --git a/src/librand/distributions/mod.rs b/src/librand/distributions/mod.rs index 41175c81df8..eb9476efb7b 100644 --- a/src/librand/distributions/mod.rs +++ b/src/librand/distributions/mod.rs @@ -17,6 +17,8 @@ //! internally. The `IndependentSample` trait is for generating values //! that do not need to record state. +use core::fmt; + #[cfg(not(test))] // only necessary for no_std use core::num::Float; @@ -78,6 +80,12 @@ impl IndependentSample for RandSample { } } +impl fmt::Debug for RandSample { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("RandSample { .. }") + } +} + /// A value with a particular weight for use with `WeightedChoice`. pub struct Weighted { /// The numerical weight of this item @@ -86,6 +94,15 @@ pub struct Weighted { pub item: T, } +impl fmt::Debug for Weighted { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Weighted") + .field("weight", &self.weight) + .field("item", &self.item) + .finish() + } +} + /// A distribution that selects from a finite collection of weighted items. /// /// Each item has an associated weight that influences how likely it @@ -189,6 +206,15 @@ impl<'a, T: Clone> IndependentSample for WeightedChoice<'a, T> { } } +impl<'a, T: fmt::Debug> fmt::Debug for WeightedChoice<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("WeightedChoice") + .field("items", &self.items) + .field("weight_range", &self.weight_range) + .finish() + } +} + mod ziggurat_tables; /// Sample a random number using the Ziggurat method (specifically the diff --git a/src/librand/distributions/normal.rs b/src/librand/distributions/normal.rs index 811d5b14c71..33de11ab630 100644 --- a/src/librand/distributions/normal.rs +++ b/src/librand/distributions/normal.rs @@ -10,6 +10,8 @@ //! The normal and derived distributions. +use core::fmt; + #[cfg(not(test))] // only necessary for no_std use FloatMath; @@ -73,6 +75,14 @@ impl Rand for StandardNormal { } } +impl fmt::Debug for StandardNormal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("StandardNormal") + .field(&self.0) + .finish() + } +} + /// The normal distribution `N(mean, std_dev**2)`. /// /// This uses the ZIGNOR variant of the Ziggurat method, see @@ -98,11 +108,13 @@ impl Normal { } } } + impl Sample for Normal { fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } } + impl IndependentSample for Normal { fn ind_sample(&self, rng: &mut R) -> f64 { let StandardNormal(n) = rng.gen::(); @@ -110,6 +122,15 @@ impl IndependentSample for Normal { } } +impl fmt::Debug for Normal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Normal") + .field("mean", &self.mean) + .field("std_dev", &self.std_dev) + .finish() + } +} + /// The log-normal distribution `ln N(mean, std_dev**2)`. /// @@ -132,17 +153,27 @@ impl LogNormal { LogNormal { norm: Normal::new(mean, std_dev) } } } + impl Sample for LogNormal { fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } } + impl IndependentSample for LogNormal { fn ind_sample(&self, rng: &mut R) -> f64 { self.norm.ind_sample(rng).exp() } } +impl fmt::Debug for LogNormal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("LogNormal") + .field("norm", &self.norm) + .finish() + } +} + #[cfg(test)] mod tests { use distributions::{IndependentSample, Sample}; diff --git a/src/librand/distributions/range.rs b/src/librand/distributions/range.rs index ba8554a979b..be238b0b1ab 100644 --- a/src/librand/distributions/range.rs +++ b/src/librand/distributions/range.rs @@ -12,6 +12,7 @@ // this is surprisingly complicated to be both generic & correct +use core::fmt; use core::marker::Sized; use Rng; use distributions::{IndependentSample, Sample}; @@ -50,12 +51,23 @@ impl Sample for Range { self.ind_sample(rng) } } + impl IndependentSample for Range { fn ind_sample(&self, rng: &mut R) -> Sup { SampleRange::sample_range(self, rng) } } +impl fmt::Debug for Range { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Range") + .field("low", &self.low) + .field("range", &self.range) + .field("accept_zone", &self.accept_zone) + .finish() + } +} + /// The helper trait for types that have a sensible way to sample /// uniformly between two values. This should not be used directly, /// and is only to facilitate `Range`. diff --git a/src/librand/isaac.rs b/src/librand/isaac.rs index 69d5015f181..2baa07e370e 100644 --- a/src/librand/isaac.rs +++ b/src/librand/isaac.rs @@ -12,6 +12,7 @@ #![allow(non_camel_case_types)] +use core::fmt; use core::slice; use core::iter::repeat; use core::num::Wrapping as w; @@ -44,6 +45,19 @@ pub struct IsaacRng { c: w32, } +impl fmt::Debug for IsaacRng { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("IsaacRng") + .field("cnt", &self.cnt) + .field("rsl", &self.rsl.iter()) + .field("mem", &self.mem.iter()) + .field("a", &self.a) + .field("b", &self.b) + .field("c", &self.c) + .finish() + } +} + static EMPTY: IsaacRng = IsaacRng { cnt: 0, rsl: [w(0); RAND_SIZE_USIZE], @@ -322,6 +336,19 @@ pub struct Isaac64Rng { c: w64, } +impl fmt::Debug for Isaac64Rng { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Isaac64Rng") + .field("cnt", &self.cnt) + .field("rsl", &self.rsl.iter()) + .field("mem", &self.mem.iter()) + .field("a", &self.a) + .field("b", &self.b) + .field("c", &self.c) + .finish() + } +} + static EMPTY_64: Isaac64Rng = Isaac64Rng { cnt: 0, rsl: [w(0); RAND_SIZE_64], diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 0cf70880d32..f2b43a20f94 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -24,6 +24,7 @@ html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))))] #![deny(warnings)] +#![deny(missing_debug_implementations)] #![no_std] #![unstable(feature = "rand", reason = "use `rand` from crates.io", @@ -32,6 +33,7 @@ #![feature(staged_api)] #![feature(step_by)] #![feature(custom_attribute)] +#![feature(specialization)] #![allow(unused_attributes)] #![cfg_attr(not(test), feature(core_float))] // only necessary for no_std @@ -43,6 +45,7 @@ #[macro_use] extern crate std; +use core::fmt; use core::f64; use core::intrinsics; use core::marker::PhantomData; @@ -288,6 +291,14 @@ impl<'a, T: Rand, R: Rng> Iterator for Generator<'a, T, R> { } } +impl<'a, T, R: fmt::Debug> fmt::Debug for Generator<'a, T, R> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Generator") + .field("rng", &self.rng) + .finish() + } +} + /// Iterator which will continuously generate random ascii characters. /// /// This iterator is created via the `gen_ascii_chars` method on `Rng`. @@ -306,6 +317,14 @@ impl<'a, R: Rng> Iterator for AsciiGenerator<'a, R> { } } +impl<'a, R: fmt::Debug> fmt::Debug for AsciiGenerator<'a, R> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("AsciiGenerator") + .field("rng", &self.rng) + .finish() + } +} + /// A random number generator that can be explicitly seeded to produce /// the same stream of randomness multiple times. pub trait SeedableRng: Rng { @@ -326,7 +345,7 @@ pub trait SeedableRng: Rng { /// [1]: Marsaglia, George (July 2003). ["Xorshift /// RNGs"](http://www.jstatsoft.org/v08/i14/paper). *Journal of /// Statistical Software*. Vol. 8 (Issue 14). -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct XorShiftRng { x: u32, y: u32, @@ -415,6 +434,14 @@ impl Rand for XorShiftRng { /// `[0,1)`. pub struct Open01(pub F); +impl fmt::Debug for Open01 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Open01") + .field(&self.0) + .finish() + } +} + /// A wrapper for generating floating point numbers uniformly in the /// closed interval `[0,1]` (including both endpoints). /// @@ -423,6 +450,14 @@ pub struct Open01(pub F); /// `[0,1)`. pub struct Closed01(pub F); +impl fmt::Debug for Closed01 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Closed01") + .field(&self.0) + .finish() + } +} + #[cfg(test)] mod test { use std::__rand as rand; diff --git a/src/librand/reseeding.rs b/src/librand/reseeding.rs index b8a65842e2f..21684e38f7b 100644 --- a/src/librand/reseeding.rs +++ b/src/librand/reseeding.rs @@ -11,6 +11,7 @@ //! A wrapper around another RNG that reseeds it after it //! generates a certain number of random bytes. +use core::fmt; use {Rng, SeedableRng}; /// How many bytes of entropy the underling RNG is allowed to generate @@ -54,7 +55,6 @@ impl> ReseedingRng { } } - impl> Rng for ReseedingRng { fn next_u32(&mut self) -> u32 { self.reseed_if_necessary(); @@ -95,6 +95,17 @@ impl, Rsdr: Reseeder + Default> } } +impl fmt::Debug for ReseedingRng { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("ReseedingRng") + .field("rng", &self.rng) + .field("generation_threshold", &self.generation_threshold) + .field("bytes_generated", &self.bytes_generated) + .field("reseeder", &self.reseeder) + .finish() + } +} + /// Something that can be used to reseed an RNG via `ReseedingRng`. pub trait Reseeder { /// Reseed the given RNG. @@ -103,7 +114,7 @@ pub trait Reseeder { /// Reseed an RNG using a `Default` instance. This reseeds by /// replacing the RNG with the result of a `Default::default` call. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct ReseedWithDefault; impl Reseeder for ReseedWithDefault {