1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
// 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))]
#![cfg_attr(docsrs, feature(doc_alias))]

//! 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:
//!
//! - [`Mt19937GenRand32`], 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).
//! - [`Mt19937GenRand64`], 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.
//! [`Mt19937GenRand32`] uses a 32-bit seed. [`Mt19937GenRand64`] 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 to use the default (fixed) seeds that are specified in the
//! reference implementations:
//!
//! ```
//! # use rand_mt::Mt;
//! let default = Mt::default();
//! let mt = Mt::new_unseeded();
//! assert_eq!(default, mt);
//! ```
//!
//! # 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 `RngCore` and `SeedableRng` on the RNGs in this crate.
//! - **std** - Enables a dependency on the Rust Standard Library. Activating
//!   this feature enables [`std::error::Error`] impls on error types 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 = "std"),
    doc = "[`std::error::Error`]: https://doc.rust-lang.org/std/error/trait.Error.html"
)]
#![cfg_attr(feature = "std", doc = "[`Box`]: std::boxed::Box")]
#![cfg_attr(
    not(feature = "std"),
    doc = "[`Box`]: https://doc.rust-lang.org/std/boxed/struct.Box.html"
)]
#![cfg_attr(
    not(feature = "rand_core"),
    doc = "[`rand_core`]: https://crates.io/crates/rand_core"
)]
//!

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

#[cfg(feature = "std")]
extern crate std;

use core::fmt;

pub use crate::mt::Mt19937GenRand32;
pub use crate::mt64::Mt19937GenRand64;

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

/// A type alias for [`Mt19937GenRand32`], 32-bit Mersenne Twister.
pub type Mt = Mt19937GenRand32;

/// A type alias for [`Mt19937GenRand64`], 64-bit Mersenne Twister.
pub type Mt64 = Mt19937GenRand64;

/// Error returned from fallible Mersenne Twister recovery constructors.
///
/// When the `std` feature is enabled, this type implements `std::error::Error`.
#[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
            ),
        }
    }
}

#[cfg(feature = "std")]
impl std::error::Error for RecoverRngError {}

#[cfg(test)]
mod tests {
    #[cfg(feature = "std")]
    use super::RecoverRngError;

    #[test]
    #[cfg(feature = "std")]
    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!();