rand_mt 6.0.3

Reference Mersenne Twister random number generators.
Documentation
// src/lib.rs
//
// Copyright (c) 2015,2017 rust-mersenne-twister developers
// Copyright (c) 2020 Ryan Lopopolo <rjl@hyperbo.la>
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE> or <http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

#![deny(clippy::all)]
#![deny(clippy::pedantic)]
#![deny(clippy::cargo)]
#![allow(unknown_lints)]
#![deny(missing_debug_implementations)]
#![warn(missing_docs)]
#![warn(rust_2018_idioms)]
#![warn(trivial_casts, trivial_numeric_casts)]
#![warn(unused_qualifications)]
#![warn(variant_size_differences)]
#![forbid(unsafe_code)]
// Enable feature callouts in generated documentation:
// https://doc.rust-lang.org/beta/unstable-book/language-features/doc-cfg.html
//
// This approach is borrowed from tokio.
#![cfg_attr(docsrs, feature(doc_cfg))]

//! Mersenne Twister random number generators.
//!
//! This is a native Rust implementation of a selection of Mersenne Twister
//! generators. Mersenne Twister is not suitable for cryptographic use.
//!
//! This crate provides:
//!
//! - [`Mt`], the original reference Mersenne Twister implementation known as
//!   `MT19937`. This is a good choice on both 32-bit and 64-bit CPUs (for
//!   32-bit output).
//! - [`Mt64`], the 64-bit variant of `MT19937` known as `MT19937-64`. This
//!   algorithm produces a different output stream than `MT19937` and produces
//!   64-bit output. This is a good choice on 64-bit CPUs.
//!
//! Both of these RNGs use approximately 2.5 kilobytes of state. [`Mt`] uses a
//! 32-bit seed. [`Mt64`] uses a 64-bit seed. Both can be seeded from an
//! iterator of seeds.
//!
//! Both RNGs implement a `recover` constructor which can reconstruct the RNG
//! state from a sequence of output samples.
//!
//! # Usage
//!
//! You can seed a RNG and begin sampling it:
//!
//! ```
//! # use rand_mt::Mt64;
//! // Create the RNG.
//! let mut rng = Mt64::new(0x1234_567_89ab_cdef_u64);
//! // start grabbing randomness from rng...
//! let mut buf = vec![0; 512];
//! rng.fill_bytes(&mut buf);
//! ```
//!
//! Or if you want reproducible output from the default reference seed:
//!
//! ```
//! # use rand_mt::Mt;
//! let mut mt = Mt::new(Mt::DEFAULT_SEED);
//! assert_ne!(mt.next_u32(), mt.next_u32());
//! ```
//!
//! [`Mt::new_unseeded`] and [`Mt64::new_unseeded`] are deterministic shortcuts
//! for the reference seed. They are intended for reproducible streams and
//! tests and do not gather entropy.
//!
//! # Crate Features
//!
//! `rand_mt` is `no_std` compatible. `rand_mt` has several optional features
//! that are enabled by default:
//!
//! - **rand-traits** - Enables a dependency on [`rand_core`]. Activating this
//!   feature implements `Rng` and `SeedableRng` on the RNGs in this crate.
//!
//! Mersenne Twister requires approximately 2.5 kilobytes of internal state. To
//! make the RNGs implemented in this crate practical to embed in other structs,
//! you may wish to store the RNG in a [`Box`].
//!
#![cfg_attr(
    not(feature = "rand-traits"),
    doc = "[`rand_core`]: https://crates.io/crates/rand_core"
)]
//! [`Box`]: https://doc.rust-lang.org/std/boxed/struct.Box.html"

#![doc(html_root_url = "https://docs.rs/rand_mt/6.0.3")]
#![no_std]

#[cfg(any(test, doctest))]
extern crate std;

use core::fmt;

pub use crate::mt::Mt;
pub use crate::mt64::Mt64;

mod mt;
mod mt64;
#[cfg(test)]
mod vectors;

/// Error returned from fallible Mersenne Twister recovery constructors.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum RecoverRngError {
    /// Attempted to recover an RNG with too many samples.
    ///
    /// Recover constructors require an exact number of samples to ensure the
    /// recovered RNG matches the state of the RNG that supplied all of the
    /// samples.
    TooFewSamples(usize),
    /// Attempted to recover an RNG with too few samples.
    ///
    /// Too few samples leaves the internal state buffer partially
    /// uninitialized.
    ///
    /// Recover constructors require an exact number of samples to ensure the
    /// recovered RNG matches the state of the RNG that supplied all of the
    /// samples.
    TooManySamples(usize),
}

impl fmt::Display for RecoverRngError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::TooFewSamples(expected) => {
                write!(f, "Too few samples given to recover: expected {expected}")
            }
            Self::TooManySamples(expected) => {
                write!(f, "Too many samples given to recover: expected {expected}")
            }
        }
    }
}

impl core::error::Error for RecoverRngError {}

#[cfg(test)]
mod tests {
    use super::RecoverRngError;

    #[test]
    fn error_display_is_not_empty() {
        use core::fmt::Write as _;
        use std::string::String;

        let test_cases = [
            RecoverRngError::TooFewSamples(0),
            RecoverRngError::TooFewSamples(124),
            RecoverRngError::TooManySamples(0),
            RecoverRngError::TooManySamples(987),
        ];
        for tc in test_cases {
            let mut buf = String::new();
            write!(&mut buf, "{tc}").unwrap();
            assert!(!buf.is_empty());
        }
    }
}

// Ensure code blocks in `README.md` compile.
//
// This module and macro declaration should be kept at the end of the file, in
// order to not interfere with code coverage.
#[cfg(doctest)]
macro_rules! readme {
    ($x:expr) => {
        #[doc = $x]
        mod readme {}
    };
    () => {
        readme!(include_str!("../README.md"));
    };
}
#[cfg(doctest)]
readme!();