blob: 69f716312f1f9fd7b6ddc3ed89b301dd5bed9008 [file] [log] [blame]
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>html, body {
margin: 0;
padding: 0;
}
.app {
margin: 10px;
padding: 0;
}
.files-list {
margin: 10px 0 0;
width: 100%;
border-collapse: collapse;
}
.files-list__head {
border: 1px solid #999;
}
.files-list__head > tr > th {
padding: 10px;
border: 1px solid #999;
text-align: left;
font-weight: normal;
background: #ddd;
}
.files-list__body {
}
.files-list__file {
cursor: pointer;
}
.files-list__file:hover {
background: #ccf;
}
.files-list__file > td {
padding: 10px;
border: 1px solid #999;
}
.files-list__file > td:first-child::before {
content: '\01F4C4';
margin-right: 1em;
}
.files-list__file_low {
background: #fcc;
}
.files-list__file_medium {
background: #ffc;
}
.files-list__file_high {
background: #cfc;
}
.files-list__file_folder > td:first-child::before {
content: '\01F4C1';
margin-right: 1em;
}
.file-header {
border: 1px solid #999;
display: flex;
justify-content: space-between;
align-items: center;
}
.file-header__back {
margin: 10px;
cursor: pointer;
flex-shrink: 0;
flex-grow: 0;
text-decoration: underline;
color: #338;
}
.file-header__name {
margin: 10px;
flex-shrink: 2;
flex-grow: 2;
}
.file-header__stat {
margin: 10px;
flex-shrink: 0;
flex-grow: 0;
}
.file-content {
margin: 10px 0 0;
border: 1px solid #999;
padding: 10px;
}
.code-line {
margin: 0;
padding: 0.3em;
height: 1em;
}
.code-line_covered {
background: #cfc;
}
.code-line_uncovered {
background: #fcc;
}
</style>
</head>
<body>
<div id="root"></div>
<script>
var data = {"files":[{"path":["/","home","srv","hg","icefox","srht","icefox","oorandom","src","lib.rs"],"content":"//! A tiny, robust PRNG implementation.\n//!\n//! More specifically, it implements a single GOOD PRNG algorithm,\n//! which is currently a permuted congruential generator. It has two\n//! implementations, one that returns `u32` and one that returns\n//! `u64`. It also has functions that return floats or integer\n//! ranges. And that's it. What more do you need?\n//!\n//! For more info on PCG generators, see http://www.pcg-random.org/\n//!\n//! This was designed as a minimalist utility for video games. No\n//! promises are made about its quality, and if you use it for\n//! cryptography you will get what you deserve.\n//!\n//! Works with `#![no_std]`, has no global state, no dependencies\n//! apart from some in the unit tests, and is generally neato.\n\n#![forbid(unsafe_code)]\n#![forbid(missing_docs)]\n#![forbid(missing_debug_implementations)]\n#![forbid(unused_results)]\n#![no_std]\nuse core::ops::Range;\n\n/// A PRNG producing a 32-bit output.\n///\n/// The current implementation is `PCG-XSH-RR`.\n#[derive(Copy, Clone, Debug, PartialEq)]\npub struct Rand32 {\n state: u64,\n inc: u64,\n}\n\nimpl Rand32 {\n /// The default value for `increment`.\n /// This is basically arbitrary, it comes from the\n /// PCG reference C implementation:\n /// https://github.com/imneme/pcg-c/blob/master/include/pcg_variants.h#L284\n pub const DEFAULT_INC: u64 = 1442695040888963407;\n\n /// This is the number that you have to Really Get Right.\n ///\n /// The value used here is from the PCG C implementation:\n /// https://github.com/imneme/pcg-c/blob/master/include/pcg_variants.h#L278\n pub(crate) const MULTIPLIER: u64 = 6364136223846793005;\n\n /// Creates a new PRNG with the given seed and a default increment.\n pub fn new(seed: u64) -\u003e Self {\n Self::new_inc(seed, Self::DEFAULT_INC)\n }\n\n /// Creates a new PRNG. The two inputs, `seed` and `increment`,\n /// determine what you get; `increment` basically selects which\n /// sequence of all those possible the PRNG will produce, and the\n /// `seed` selects where in that sequence you start.\n ///\n /// Both are arbitrary; increment must be an odd number but this\n /// handles that for you\n pub fn new_inc(seed: u64, increment: u64) -\u003e Self {\n let mut rng = Self {\n state: 0,\n inc: increment.wrapping_shl(1) | 1,\n };\n // This initialization song-and-dance is a little odd,\n // but seems to be just how things go.\n let _ = rng.rand_u32();\n rng.state = rng.state.wrapping_add(seed);\n let _ = rng.rand_u32();\n rng\n }\n\n /// Returns the internal state of the PRNG. This allows\n /// you to save a PRNG and create a new one that will resume\n /// from the same spot in the sequence.\n pub fn state(\u0026self) -\u003e (u64, u64) {\n (self.state, self.inc)\n }\n\n /// Creates a new PRNG from a saved state from `Rand32::state()`.\n /// This is NOT quite the same as `new_inc()` because `new_inc()` does\n /// a little extra setup work to initialize the state.\n pub fn from_state(state: (u64, u64)) -\u003e Self {\n let (state, inc) = state;\n Self { state, inc }\n }\n\n /// Produces a random `u32` in the range `[0, u32::MAX]`.\n pub fn rand_u32(\u0026mut self) -\u003e u32 {\n let oldstate: u64 = self.state;\n self.state = oldstate\n .wrapping_mul(Self::MULTIPLIER)\n .wrapping_add(self.inc);\n let xorshifted: u32 = (((oldstate \u003e\u003e 18) ^ oldstate) \u003e\u003e 27) as u32;\n let rot: u32 = (oldstate \u003e\u003e 59) as u32;\n xorshifted.rotate_right(rot)\n }\n\n /// Produces a random `i32` in the range `[i32::MIN, i32::MAX]`.\n pub fn rand_i32(\u0026mut self) -\u003e i32 {\n self.rand_u32() as i32\n }\n\n /// Produces a random `f32` in the range `[0.0, 1.0)`.\n pub fn rand_float(\u0026mut self) -\u003e f32 {\n // This impl was taken more or less from `rand`, see\n // \u003chttps://docs.rs/rand/0.7.0/src/rand/distributions/float.rs.html#104-117\u003e\n // There MAY be better ways to do this, see:\n // https://mumble.net/~campbell/2014/04/28/uniform-random-float\n // https://mumble.net/~campbell/2014/04/28/random_real.c\n // https://github.com/Lokathor/randomize/issues/34\n const TOTAL_BITS: u32 = 32;\n const PRECISION: u32 = core::f32::MANTISSA_DIGITS + 1;\n const MANTISSA_SCALE: f32 = 1.0 / ((1u32 \u003c\u003c PRECISION) as f32);\n let mut u = self.rand_u32();\n u \u003e\u003e= TOTAL_BITS - PRECISION;\n u as f32 * MANTISSA_SCALE\n }\n\n /// Produces a random within the given bounds. Like any `Range`,\n /// it includes the lower bound and excludes the upper one.\n ///\n /// This should be faster than `Self::rand() % end + start`, but the\n /// real advantage is it's more convenient. Requires that\n /// `range.end \u003c= range.start`.\n pub fn rand_range(\u0026mut self, range: Range\u003cu32\u003e) -\u003e u32 {\n // This is harder to do well than it looks, it seems. I don't\n // trust Lokathor's implementation 'cause I don't understand\n // it, so I went to numpy's, which points me to \"Lemire's\n // rejection algorithm\": http://arxiv.org/abs/1805.10941\n //\n // Algorithms 3, 4 and 5 in that paper all seem fine modulo\n // minor performance differences, so this is algorithm 5.\n // It uses numpy's implementation, `buffered_bounded_lemire_uint32()`\n\n debug_assert!(range.start \u003c range.end);\n let range_starting_from_zero = 0..(range.end - range.start);\n\n let s: u32 = range_starting_from_zero.end;\n let mut m: u64 = u64::from(self.rand_u32()) * u64::from(s);\n let mut leftover: u32 = (m \u0026 0xFFFF_FFFF) as u32;\n\n if leftover \u003c s {\n // TODO: verify the wrapping_neg() here\n let threshold: u32 = s.wrapping_neg() % s;\n while leftover \u003c threshold {\n m = u64::from(self.rand_u32()).wrapping_mul(u64::from(s));\n leftover = (m \u0026 0xFFFF_FFFF) as u32;\n }\n }\n (m \u003e\u003e 32) as u32 + range.start\n }\n}\n\n/// A PRNG producing a 64-bit output.\n///\n/// The current implementation is `PCG-XSH-RR`.\n// BUGGO: The recommended algorithm is PCG-XSL-RR?\n// See https://github.com/imneme/pcg-c/blob/master/include/pcg_variants.h#L2405\n// Not sure if it matters?\n#[derive(Copy, Clone, Debug, PartialEq)]\npub struct Rand64 {\n state: u128,\n inc: u128,\n}\n\nimpl Rand64 {\n /// The default value for `increment`.\n ///\n /// The value used here is from the PCG default C implementation: http://www.pcg-random.org/download.html\n pub const DEFAULT_INC: u128 = 0x2FE0E169_FFBD06E3_5BC307BD_4D2F814F;\n\n /// This is the number that you have to Really Get Right.\n ///\n /// The value used here is from the PCG C implementation:\n /// https://github.com/imneme/pcg-c/blob/master/include/pcg_variants.h#L288\n pub(crate) const MULTIPLIER: u128 = 47026247687942121848144207491837523525;\n\n /// Creates a new PRNG with the given seed and a default increment.\n pub fn new(seed: u128) -\u003e Self {\n Self::new_inc(seed, Self::DEFAULT_INC)\n }\n\n /// Same as `Rand32::new_inc()`\n fn new_inc(seed: u128, increment: u128) -\u003e Self {\n let mut rng = Self {\n state: 0,\n inc: increment.wrapping_shl(1) | 1,\n };\n let _ = rng.rand_u64();\n rng.state = rng.state.wrapping_add(seed);\n let _ = rng.rand_u64();\n rng\n }\n\n /// Returns the internal state of the PRNG. This allows\n /// you to save a PRNG and create a new one that will resume\n /// from the same spot in the sequence.\n pub fn state(\u0026self) -\u003e (u128, u128) {\n (self.state, self.inc)\n }\n\n /// Creates a new PRNG from a saved state from `Rand32::state()`.\n /// This is NOT quite the same as `new_inc()` because `new_inc()` does\n /// a little extra setup work to initialize the state.\n pub fn from_state(state: (u128, u128)) -\u003e Self {\n let (state, inc) = state;\n Self { state, inc }\n }\n\n /// Produces a random `u64` in the range`[0, u64::MAX]`.\n pub fn rand_u64(\u0026mut self) -\u003e u64 {\n let oldstate: u128 = self.state;\n self.state = oldstate\n .wrapping_mul(Self::MULTIPLIER)\n .wrapping_add(self.inc);\n let xorshifted: u64 = (((oldstate \u003e\u003e 29) ^ oldstate) \u003e\u003e 58) as u64;\n let rot: u32 = (oldstate \u003e\u003e 122) as u32;\n xorshifted.rotate_right(rot)\n }\n\n /// Produces a random `i64` in the range `[i64::MIN, i64::MAX]`.\n pub fn rand_i64(\u0026mut self) -\u003e i64 {\n self.rand_u64() as i64\n }\n\n /// Produces a random `f64` in the range `[0.0, 1.0)`.\n pub fn rand_float(\u0026mut self) -\u003e f64 {\n const TOTAL_BITS: u32 = 64;\n const PRECISION: u32 = core::f64::MANTISSA_DIGITS + 1;\n const MANTISSA_SCALE: f64 = 1.0 / ((1u64 \u003c\u003c PRECISION) as f64);\n let mut u = self.rand_u64();\n u \u003e\u003e= TOTAL_BITS - PRECISION;\n u as f64 * MANTISSA_SCALE\n }\n\n /// Produces a random within the given bounds. Like any `Range`,\n /// it includes the lower bound and excludes the upper one.\n ///\n /// This should be faster than `Self::rand() % end + start`, but the\n /// real advantage is it's more convenient. Requires that\n /// `range.end \u003c= range.start`.\n pub fn rand_range(\u0026mut self, range: Range\u003cu64\u003e) -\u003e u64 {\n // Same as `Rand32::rand_range()`\n debug_assert!(range.start \u003c range.end);\n let range_starting_from_zero = 0..(range.end - range.start);\n\n let s: u64 = range_starting_from_zero.end;\n let mut m: u128 = u128::from(self.rand_u64()) * u128::from(s);\n let mut leftover: u64 = (m \u0026 0xFFFFFFFF_FFFFFFFF) as u64;\n\n if leftover \u003c s {\n // TODO: Verify the wrapping_negate() here\n let threshold: u64 = s.wrapping_neg() % s;\n while leftover \u003c threshold {\n m = u128::from(self.rand_u64()) * u128::from(s);\n leftover = (m \u0026 0xFFFFFFFF_FFFFFFFF) as u64;\n }\n }\n (m.wrapping_shr(64)) as u64 + range.start\n }\n}\n\n#[cfg(test)]\nmod tests {\n use super::*;\n use randomize::{self, PCG32, PCG64};\n\n #[test]\n fn test_rand32_vs_randomize() {\n // Generate some random numbers and validate them against\n // a known-good generator.\n {\n let seed = 54321;\n let mut r1 = Rand32::new(seed);\n let mut r2 = PCG32::seed(seed, Rand32::DEFAULT_INC);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u32(), r2.next_u32());\n assert_eq!(r1.rand_i32(), r2.next_u32() as i32);\n }\n }\n\n {\n let seed = 3141592653;\n let inc = 0xDEADBEEF;\n let mut r1 = Rand32::new_inc(seed, inc);\n let mut r2 = PCG32::seed(seed, inc);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u32(), r2.next_u32());\n assert_eq!(r1.rand_i32(), r2.next_u32() as i32);\n }\n }\n }\n\n #[test]\n fn test_rand64_vs_randomize() {\n // Generate some random numbers and validate them against\n // a known-good generator.\n {\n let seed = 54321;\n let mut r1 = Rand64::new(seed);\n let mut r2 = PCG64::seed(seed, Rand64::DEFAULT_INC);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u64(), r2.next_u64());\n assert_eq!(r1.rand_i64(), r2.next_u64() as i64);\n }\n }\n\n {\n let seed = 3141592653;\n let inc = 0xDEADBEEF;\n let mut r1 = Rand64::new_inc(seed, inc);\n let mut r2 = PCG64::seed(seed, inc);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u64(), r2.next_u64());\n assert_eq!(r1.rand_i64(), r2.next_u64() as i64);\n }\n }\n }\n\n #[test]\n fn test_float32() {\n {\n let seed = 2718281828;\n let mut r1 = Rand32::new(seed);\n let mut r2 = PCG32::seed(seed, Rand32::DEFAULT_INC);\n for _ in 0..1000 {\n // First just make sure they both work with randomize's\n // f32 conversion function -- sanity checks.\n let i1 = r1.rand_u32();\n let i2 = r2.next_u32();\n assert_eq!(i1, i2);\n let f1 = randomize::f32_half_open_right(i1);\n let f2 = randomize::f32_half_open_right(i2);\n // We can directly compare floats 'cause we do no math, it's\n // literally the same bitwise algorithm with the same inputs.\n assert_eq!(f1, f2);\n\n // Make sure result is in [0.0, 1.0)\n assert!(f1 \u003e= 0.0);\n assert!(f1 \u003c 1.0);\n }\n\n // At least make sure our float's from rand_float() are in the valid range.\n for _ in 0..1000 {\n let f1 = r1.rand_float();\n assert!(f1 \u003e= 0.0);\n assert!(f1 \u003c 1.0);\n }\n\n /*\n TODO: Randomize changed its int-to-float conversion functions and now they don't\n match ours.\n for _ in 0..1000 {\n // Now make sure our own float conversion function works.\n let f1 = r1.rand_float();\n //let f2 = randomize::f32_half_open_right(r2.next_u32());\n let f2 = randomize::f32_open(r2.next_u32());\n assert_eq!(f1, f2);\n assert!(f1 \u003e= 0.0);\n assert!(f1 \u003c 1.0);\n }\n */\n }\n }\n\n #[test]\n fn test_float64() {\n {\n let seed = 2718281828;\n let mut r1 = Rand64::new(seed);\n let mut r2 = PCG64::seed(seed, Rand64::DEFAULT_INC);\n for _ in 0..1000 {\n // First just make sure they both work with randomize's\n // f64 conversion function -- sanity checks.\n let i1 = r1.rand_u64();\n let i2 = r2.next_u64();\n assert_eq!(i1, i2);\n let f1 = randomize::f64_half_open_right(i1);\n let f2 = randomize::f64_half_open_right(i2);\n // We can directly compare floats 'cause we do no math, it's\n // literally the same bitwise algorithm with the same inputs.\n assert_eq!(f1, f2);\n\n // Make sure result is in [0.0, 1.0)\n assert!(f1 \u003e= 0.0);\n assert!(f1 \u003c 1.0);\n }\n\n // At least make sure our float's from rand_float() are in the valid range.\n for _ in 0..1000 {\n let f1 = r1.rand_float();\n assert!(f1 \u003e= 0.0);\n assert!(f1 \u003c 1.0);\n }\n\n /*\n TODO: Randomize changed its int-to-float conversion functions and now they don't\n match ours.\n for _ in 0..1000 {\n // Now make sure our own float conversion function works.\n let f1 = r1.rand_float();\n //let f2 = randomize::f32_half_open_right(r2.next_u32());\n let f2 = randomize::f32_open(r2.next_u32());\n assert_eq!(f1, f2);\n assert!(f1 \u003e= 0.0);\n assert!(f1 \u003c 1.0);\n }\n */\n }\n }\n\n #[test]\n fn test_randrange32() {\n // Make sure ranges are valid and in the given range\n let seed = 2342_3141;\n let mut r1 = Rand32::new(seed);\n for _ in 0..1000 {\n // Generate our bounds at random\n let a = r1.rand_u32();\n let b = r1.rand_u32();\n if a == b {\n continue;\n }\n let (low, high) = if a \u003c b { (a, b) } else { (b, a) };\n\n // Get a number in that range\n let in_range = r1.rand_range(low..high);\n assert!(in_range \u003e= low);\n assert!(in_range \u003c high);\n }\n }\n\n #[test]\n fn test_randrange64() {\n // Make sure ranges are valid and in the given range\n let seed = 2342_2718;\n let mut r1 = Rand64::new(seed);\n for _ in 0..1000 {\n // Generate our bounds at random\n let a = r1.rand_u64();\n let b = r1.rand_u64();\n if a == b {\n continue;\n }\n let (low, high) = if a \u003c b { (a, b) } else { (b, a) };\n\n // Get a number in that range\n let in_range = r1.rand_range(low..high);\n assert!(in_range \u003e= low);\n assert!(in_range \u003c high);\n }\n }\n\n #[test]\n fn test_rand32_vs_rand() {\n use rand_core::RngCore;\n use rand_pcg;\n {\n let seed = 54321;\n let mut r1 = Rand32::new(seed);\n let mut r2 = rand_pcg::Pcg32::new(seed, Rand32::DEFAULT_INC);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u32(), r2.next_u32());\n }\n }\n\n {\n let seed = 3141592653;\n let inc = 0xDEADBEEF;\n let mut r1 = Rand32::new_inc(seed, inc);\n let mut r2 = rand_pcg::Pcg32::new(seed, inc);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u32(), r2.next_u32());\n }\n }\n }\n\n // This doesn't work 'cause for 64-bit output `rand` uses\n // PCG-XSL-RR\n // and we use\n // PCG-XSH-RR\n /*\n #[test]\n fn test_rand64_vs_rand() {\n use rand_pcg;\n use rand_core::RngCore;\n {\n let seed = 54321;\n let mut r1 = Rand64::new(seed);\n let mut r2 = rand_pcg::Pcg64::new(seed, Rand64::DEFAULT_INC);\n for _ in 0..1000 {\n assert_eq!(r1.rand(), r2.next_u64());\n }\n }\n\n {\n let seed = 3141592653;\n let inc = 0xDEADBEEF;\n let mut r1 = Rand64::new_inc(seed, inc);\n let mut r2 = rand_pcg::Pcg64::new(seed, inc);\n for _ in 0..1000 {\n assert_eq!(r1.rand(), r2.next_u64());\n }\n }\n }\n */\n\n // Test vs. random-fast-rng, which I will call rfr\n // rfr's float conversion uses yet a different algorithm\n // than ours, so we can't really check that.\n #[test]\n fn test_rand32_vs_rfr() {\n use random_fast_rng as rfr;\n use rfr::Random;\n {\n let seed = 54321;\n let mut r1 = Rand32::new(seed);\n let mut r2 = rfr::FastRng::seed(seed, Rand32::DEFAULT_INC);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u32(), r2.get_u32());\n }\n }\n\n {\n let seed = 3141592653;\n let inc = 0xDEADBEEF;\n let mut r1 = Rand32::new_inc(seed, inc);\n let mut r2 = rfr::FastRng::seed(seed, inc);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u32(), r2.get_u32());\n }\n }\n }\n\n /// Make sure that saving a RNG state and restoring\n /// it works.\n /// See https://todo.sr.ht/~icefox/oorandom/1\n #[test]\n fn test_save_restore() {\n {\n let seed = 54321;\n let mut r1 = Rand32::new(seed);\n let s1 = r1.state();\n let mut r2 = Rand32::from_state(s1);\n assert_eq!(r1, r2);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u32(), r2.rand_u32());\n }\n }\n\n {\n let seed = 3141592653;\n let inc = 0xDEADBEEF;\n let mut r1 = Rand32::new_inc(seed, inc);\n let s1 = r1.state();\n let mut r2 = Rand32::from_state(s1);\n assert_eq!(r1, r2);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u32(), r2.rand_u32());\n }\n }\n\n {\n let seed = 54321;\n let mut r1 = Rand64::new(seed);\n let s1 = r1.state();\n let mut r2 = Rand64::from_state(s1);\n assert_eq!(r1, r2);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u64(), r2.rand_u64());\n }\n }\n\n {\n let seed = 3141592653;\n let inc = 0xDEADBEEF;\n let mut r1 = Rand64::new_inc(seed, inc);\n let s1 = r1.state();\n let mut r2 = Rand64::from_state(s1);\n assert_eq!(r1, r2);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u64(), r2.rand_u64());\n }\n }\n }\n}\n","traces":[{"line":48,"address":[4213216],"length":1,"stats":{"Line":3},"fn_name":"new"},{"line":49,"address":[4213225],"length":1,"stats":{"Line":3},"fn_name":null},{"line":59,"address":[4213264],"length":1,"stats":{"Line":3},"fn_name":"new_inc"},{"line":62,"address":[4213283],"length":1,"stats":{"Line":3},"fn_name":null},{"line":66,"address":[4213326],"length":1,"stats":{"Line":3},"fn_name":null},{"line":67,"address":[4213336],"length":1,"stats":{"Line":4},"fn_name":null},{"line":68,"address":[4213364],"length":1,"stats":{"Line":5},"fn_name":null},{"line":69,"address":[4213374],"length":1,"stats":{"Line":4},"fn_name":null},{"line":75,"address":[4213392],"length":1,"stats":{"Line":1},"fn_name":"state"},{"line":76,"address":[4213401],"length":1,"stats":{"Line":1},"fn_name":null},{"line":82,"address":[4213440],"length":1,"stats":{"Line":1},"fn_name":"from_state"},{"line":83,"address":[4213454],"length":1,"stats":{"Line":1},"fn_name":null},{"line":88,"address":[4213488],"length":1,"stats":{"Line":3},"fn_name":"rand_u32"},{"line":89,"address":[4213497],"length":1,"stats":{"Line":5},"fn_name":null},{"line":90,"address":[4213552,4213510],"length":1,"stats":{"Line":6},"fn_name":null},{"line":91,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":92,"address":[4213543],"length":1,"stats":{"Line":5},"fn_name":null},{"line":93,"address":[4213580],"length":1,"stats":{"Line":5},"fn_name":null},{"line":94,"address":[4213627],"length":1,"stats":{"Line":3},"fn_name":null},{"line":95,"address":[4213655],"length":1,"stats":{"Line":5},"fn_name":null},{"line":99,"address":[4213680],"length":1,"stats":{"Line":1},"fn_name":"rand_i32"},{"line":100,"address":[4213689],"length":1,"stats":{"Line":1},"fn_name":null},{"line":104,"address":[4213712],"length":1,"stats":{"Line":1},"fn_name":"rand_float"},{"line":114,"address":[4213721],"length":1,"stats":{"Line":1},"fn_name":null},{"line":115,"address":[4213730],"length":1,"stats":{"Line":1},"fn_name":null},{"line":116,"address":[4213757],"length":1,"stats":{"Line":1},"fn_name":null},{"line":125,"address":[4213792],"length":1,"stats":{"Line":1},"fn_name":"rand_range"},{"line":135,"address":[4213821,4213873],"length":1,"stats":{"Line":1},"fn_name":null},{"line":136,"address":[4213853,4213903,4214282],"length":1,"stats":{"Line":2},"fn_name":null},{"line":138,"address":[4213919],"length":1,"stats":{"Line":1},"fn_name":null},{"line":139,"address":[4213939,4214312],"length":1,"stats":{"Line":1},"fn_name":null},{"line":140,"address":[4214021],"length":1,"stats":{"Line":1},"fn_name":null},{"line":142,"address":[4214045,4214127],"length":1,"stats":{"Line":2},"fn_name":null},{"line":144,"address":[4214063,4214342],"length":1,"stats":{"Line":1},"fn_name":null},{"line":145,"address":[4214118,4214224],"length":1,"stats":{"Line":2},"fn_name":null},{"line":146,"address":[4214134],"length":1,"stats":{"Line":1},"fn_name":null},{"line":147,"address":[4214204],"length":1,"stats":{"Line":1},"fn_name":null},{"line":150,"address":[4214226,4214372,4214402],"length":1,"stats":{"Line":1},"fn_name":null},{"line":179,"address":[4214416],"length":1,"stats":{"Line":1},"fn_name":"new"},{"line":180,"address":[4214463],"length":1,"stats":{"Line":1},"fn_name":null},{"line":184,"address":[4214576],"length":1,"stats":{"Line":1},"fn_name":"new_inc"},{"line":187,"address":[4214620],"length":1,"stats":{"Line":1},"fn_name":null},{"line":189,"address":[4214701],"length":1,"stats":{"Line":1},"fn_name":null},{"line":190,"address":[4214711],"length":1,"stats":{"Line":1},"fn_name":null},{"line":191,"address":[4214766],"length":1,"stats":{"Line":1},"fn_name":null},{"line":192,"address":[4214776],"length":1,"stats":{"Line":1},"fn_name":null},{"line":198,"address":[4214832],"length":1,"stats":{"Line":1},"fn_name":"state"},{"line":199,"address":[4214844],"length":1,"stats":{"Line":1},"fn_name":null},{"line":205,"address":[4214928],"length":1,"stats":{"Line":1},"fn_name":"from_state"},{"line":206,"address":[4214955],"length":1,"stats":{"Line":1},"fn_name":null},{"line":211,"address":[4215040],"length":1,"stats":{"Line":1},"fn_name":"rand_u64"},{"line":212,"address":[4215052],"length":1,"stats":{"Line":1},"fn_name":null},{"line":213,"address":[4215097,4215164],"length":1,"stats":{"Line":2},"fn_name":null},{"line":214,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":215,"address":[4215146],"length":1,"stats":{"Line":1},"fn_name":null},{"line":216,"address":[4215211],"length":1,"stats":{"Line":1},"fn_name":null},{"line":217,"address":[4215301],"length":1,"stats":{"Line":1},"fn_name":null},{"line":218,"address":[4215338],"length":1,"stats":{"Line":2},"fn_name":null},{"line":222,"address":[4215376],"length":1,"stats":{"Line":1},"fn_name":"rand_i64"},{"line":223,"address":[4215385],"length":1,"stats":{"Line":1},"fn_name":null},{"line":227,"address":[4215408],"length":1,"stats":{"Line":1},"fn_name":"rand_float"},{"line":231,"address":[4215417],"length":1,"stats":{"Line":1},"fn_name":null},{"line":232,"address":[4215427],"length":1,"stats":{"Line":1},"fn_name":null},{"line":233,"address":[4215457],"length":1,"stats":{"Line":1},"fn_name":null},{"line":242,"address":[4215520],"length":1,"stats":{"Line":1},"fn_name":"rand_range"},{"line":244,"address":[4215551,4215628],"length":1,"stats":{"Line":1},"fn_name":null},{"line":245,"address":[4216411,4215658,4215603],"length":1,"stats":{"Line":2},"fn_name":null},{"line":247,"address":[4215686],"length":1,"stats":{"Line":1},"fn_name":null},{"line":248,"address":[4215718,4216441],"length":1,"stats":{"Line":1},"fn_name":null},{"line":249,"address":[4215965],"length":1,"stats":{"Line":1},"fn_name":null},{"line":251,"address":[4215989,4216094],"length":1,"stats":{"Line":2},"fn_name":null},{"line":253,"address":[4216471,4216012],"length":1,"stats":{"Line":1},"fn_name":null},{"line":254,"address":[4216331,4216084],"length":1,"stats":{"Line":2},"fn_name":null},{"line":255,"address":[4216107,4216501],"length":1,"stats":{"Line":1},"fn_name":null},{"line":256,"address":[4216315],"length":1,"stats":{"Line":1},"fn_name":null},{"line":259,"address":[4216561,4216336,4216531],"length":1,"stats":{"Line":1},"fn_name":null},{"line":269,"address":[4219504,4219509],"length":1,"stats":{"Line":3},"fn_name":"{{closure}}"},{"line":273,"address":[4222375],"length":1,"stats":{"Line":1},"fn_name":null},{"line":274,"address":[4222392],"length":1,"stats":{"Line":1},"fn_name":null},{"line":275,"address":[4222428],"length":1,"stats":{"Line":1},"fn_name":null},{"line":276,"address":[4222449,4222635,4223285],"length":1,"stats":{"Line":2},"fn_name":null},{"line":277,"address":[4222828,4222658],"length":1,"stats":{"Line":1},"fn_name":null},{"line":278,"address":[4223290,4222796,4223153],"length":1,"stats":{"Line":2},"fn_name":null},{"line":283,"address":[4222582],"length":1,"stats":{"Line":1},"fn_name":null},{"line":284,"address":[4222595],"length":1,"stats":{"Line":1},"fn_name":null},{"line":285,"address":[4222603],"length":1,"stats":{"Line":1},"fn_name":null},{"line":286,"address":[4223635],"length":1,"stats":{"Line":1},"fn_name":null},{"line":287,"address":[4223792,4224394,4223656],"length":1,"stats":{"Line":2},"fn_name":null},{"line":288,"address":[4223985,4223815],"length":1,"stats":{"Line":1},"fn_name":null},{"line":289,"address":[4224399,4223953,4224274],"length":1,"stats":{"Line":2},"fn_name":null},{"line":295,"address":[4219536,4219541],"length":1,"stats":{"Line":3},"fn_name":"{{closure}}"},{"line":299,"address":[4224695],"length":1,"stats":{"Line":1},"fn_name":null},{"line":300,"address":[4224736],"length":1,"stats":{"Line":1},"fn_name":null},{"line":301,"address":[4224842],"length":1,"stats":{"Line":1},"fn_name":null},{"line":302,"address":[4224911,4225205,4225865],"length":1,"stats":{"Line":2},"fn_name":null},{"line":303,"address":[4225403,4225228],"length":1,"stats":{"Line":1},"fn_name":null},{"line":304,"address":[4225370,4225728,4225870],"length":1,"stats":{"Line":2},"fn_name":null},{"line":309,"address":[4225047],"length":1,"stats":{"Line":1},"fn_name":null},{"line":310,"address":[4225072],"length":1,"stats":{"Line":1},"fn_name":null},{"line":311,"address":[4225112],"length":1,"stats":{"Line":1},"fn_name":null},{"line":312,"address":[4226235],"length":1,"stats":{"Line":1},"fn_name":null},{"line":313,"address":[4227082,4226470,4226334],"length":1,"stats":{"Line":2},"fn_name":null},{"line":314,"address":[4226668,4226493],"length":1,"stats":{"Line":1},"fn_name":null},{"line":315,"address":[4226957,4227087,4226635],"length":1,"stats":{"Line":2},"fn_name":null},{"line":321,"address":[4219573,4219568],"length":1,"stats":{"Line":3},"fn_name":"{{closure}}"},{"line":323,"address":[4227388],"length":1,"stats":{"Line":1},"fn_name":null},{"line":324,"address":[4227396],"length":1,"stats":{"Line":1},"fn_name":null},{"line":325,"address":[4227435],"length":1,"stats":{"Line":1},"fn_name":null},{"line":326,"address":[4228624,4227456,4227644],"length":1,"stats":{"Line":2},"fn_name":null},{"line":329,"address":[4227667],"length":1,"stats":{"Line":1},"fn_name":null},{"line":330,"address":[4227687],"length":1,"stats":{"Line":1},"fn_name":null},{"line":331,"address":[4227707,4227838],"length":1,"stats":{"Line":1},"fn_name":null},{"line":332,"address":[4227805],"length":1,"stats":{"Line":1},"fn_name":null},{"line":333,"address":[4228127],"length":1,"stats":{"Line":1},"fn_name":null},{"line":336,"address":[4228148,4228280],"length":1,"stats":{"Line":1},"fn_name":null},{"line":339,"address":[4228247,4228594],"length":1,"stats":{"Line":1},"fn_name":null},{"line":340,"address":[4228629,4228575],"length":1,"stats":{"Line":1},"fn_name":null},{"line":344,"address":[4228666,4228870,4228740,4227584],"length":1,"stats":{"Line":3},"fn_name":null},{"line":345,"address":[4228763],"length":1,"stats":{"Line":1},"fn_name":null},{"line":346,"address":[4228791,4228840],"length":1,"stats":{"Line":1},"fn_name":null},{"line":347,"address":[4228905,4228826,4228875],"length":1,"stats":{"Line":1},"fn_name":null},{"line":367,"address":[4219605,4219600],"length":1,"stats":{"Line":3},"fn_name":"{{closure}}"},{"line":369,"address":[4228924],"length":1,"stats":{"Line":1},"fn_name":null},{"line":370,"address":[4228956],"length":1,"stats":{"Line":1},"fn_name":null},{"line":371,"address":[4229065],"length":1,"stats":{"Line":1},"fn_name":null},{"line":372,"address":[4230317,4229322,4229134],"length":1,"stats":{"Line":2},"fn_name":null},{"line":375,"address":[4229345],"length":1,"stats":{"Line":1},"fn_name":null},{"line":376,"address":[4229366],"length":1,"stats":{"Line":1},"fn_name":null},{"line":377,"address":[4229387,4229521],"length":1,"stats":{"Line":1},"fn_name":null},{"line":378,"address":[4229487],"length":1,"stats":{"Line":1},"fn_name":null},{"line":379,"address":[4229816],"length":1,"stats":{"Line":1},"fn_name":null},{"line":382,"address":[4229972,4229838],"length":1,"stats":{"Line":1},"fn_name":null},{"line":385,"address":[4229938,4230287],"length":1,"stats":{"Line":1},"fn_name":null},{"line":386,"address":[4230267,4230322],"length":1,"stats":{"Line":1},"fn_name":null},{"line":390,"address":[4229262,4230565,4230433,4230359],"length":1,"stats":{"Line":3},"fn_name":null},{"line":391,"address":[4230456],"length":1,"stats":{"Line":1},"fn_name":null},{"line":392,"address":[4230535,4230484],"length":1,"stats":{"Line":1},"fn_name":null},{"line":393,"address":[4230600,4230520,4230570],"length":1,"stats":{"Line":1},"fn_name":null},{"line":413,"address":[4219632,4219637],"length":1,"stats":{"Line":3},"fn_name":"{{closure}}"},{"line":415,"address":[4230615],"length":1,"stats":{"Line":1},"fn_name":null},{"line":416,"address":[4230629],"length":1,"stats":{"Line":1},"fn_name":null},{"line":417,"address":[4230988,4230738,4230644],"length":1,"stats":{"Line":2},"fn_name":null},{"line":419,"address":[4230752],"length":1,"stats":{"Line":1},"fn_name":null},{"line":420,"address":[4230770],"length":1,"stats":{"Line":1},"fn_name":null},{"line":421,"address":[4230796],"length":1,"stats":{"Line":1},"fn_name":null},{"line":422,"address":[4230814],"length":1,"stats":{"Line":0},"fn_name":null},{"line":424,"address":[4230820,4230808],"length":1,"stats":{"Line":2},"fn_name":null},{"line":427,"address":[4230869],"length":1,"stats":{"Line":1},"fn_name":null},{"line":428,"address":[4230922,4230958],"length":1,"stats":{"Line":1},"fn_name":null},{"line":429,"address":[4230943,4231023,4230993],"length":1,"stats":{"Line":2},"fn_name":null},{"line":434,"address":[4219669,4219664],"length":1,"stats":{"Line":3},"fn_name":"{{closure}}"},{"line":436,"address":[4231031],"length":1,"stats":{"Line":1},"fn_name":null},{"line":437,"address":[4231069],"length":1,"stats":{"Line":1},"fn_name":null},{"line":438,"address":[4231114,4231217,4231551],"length":1,"stats":{"Line":2},"fn_name":null},{"line":440,"address":[4231240],"length":1,"stats":{"Line":1},"fn_name":null},{"line":441,"address":[4231263],"length":1,"stats":{"Line":1},"fn_name":null},{"line":442,"address":[4231296],"length":1,"stats":{"Line":1},"fn_name":null},{"line":443,"address":[4231318],"length":1,"stats":{"Line":0},"fn_name":null},{"line":445,"address":[4231311,4231328],"length":1,"stats":{"Line":2},"fn_name":null},{"line":448,"address":[4231409],"length":1,"stats":{"Line":1},"fn_name":null},{"line":449,"address":[4231521,4231482],"length":1,"stats":{"Line":1},"fn_name":null},{"line":450,"address":[4231586,4231505,4231556],"length":1,"stats":{"Line":1},"fn_name":null},{"line":455,"address":[4219701,4219696],"length":1,"stats":{"Line":3},"fn_name":"{{closure}}"},{"line":459,"address":[4231607],"length":1,"stats":{"Line":1},"fn_name":null},{"line":460,"address":[4231624],"length":1,"stats":{"Line":1},"fn_name":null},{"line":461,"address":[4231645],"length":1,"stats":{"Line":1},"fn_name":null},{"line":462,"address":[4231871,4231685,4232032],"length":1,"stats":{"Line":2},"fn_name":null},{"line":463,"address":[4232044,4231894],"length":1,"stats":{"Line":1},"fn_name":null},{"line":468,"address":[4231818],"length":1,"stats":{"Line":1},"fn_name":null},{"line":469,"address":[4231831],"length":1,"stats":{"Line":1},"fn_name":null},{"line":470,"address":[4231839],"length":1,"stats":{"Line":1},"fn_name":null},{"line":471,"address":[4232333],"length":1,"stats":{"Line":1},"fn_name":null},{"line":472,"address":[4232647,4232368,4232492],"length":1,"stats":{"Line":2},"fn_name":null},{"line":473,"address":[4232659,4232515],"length":1,"stats":{"Line":1},"fn_name":null},{"line":512,"address":[4219728,4219733],"length":1,"stats":{"Line":3},"fn_name":"{{closure}}"},{"line":516,"address":[4232951],"length":1,"stats":{"Line":1},"fn_name":null},{"line":517,"address":[4232968],"length":1,"stats":{"Line":1},"fn_name":null},{"line":518,"address":[4232989],"length":1,"stats":{"Line":1},"fn_name":null},{"line":519,"address":[4233377,4233029,4233215],"length":1,"stats":{"Line":2},"fn_name":null},{"line":520,"address":[4233238,4233389],"length":1,"stats":{"Line":1},"fn_name":null},{"line":525,"address":[4233162],"length":1,"stats":{"Line":1},"fn_name":null},{"line":526,"address":[4233175],"length":1,"stats":{"Line":1},"fn_name":null},{"line":527,"address":[4233183],"length":1,"stats":{"Line":1},"fn_name":null},{"line":528,"address":[4233678],"length":1,"stats":{"Line":1},"fn_name":null},{"line":529,"address":[4233837,4233713,4233993],"length":1,"stats":{"Line":2},"fn_name":null},{"line":530,"address":[4233860,4234005],"length":1,"stats":{"Line":1},"fn_name":null},{"line":539,"address":[4219760,4219765],"length":1,"stats":{"Line":3},"fn_name":"{{closure}}"},{"line":541,"address":[4234295],"length":1,"stats":{"Line":1},"fn_name":null},{"line":542,"address":[4234312],"length":1,"stats":{"Line":1},"fn_name":null},{"line":543,"address":[4234333],"length":1,"stats":{"Line":1},"fn_name":null},{"line":544,"address":[4234394],"length":1,"stats":{"Line":1},"fn_name":null},{"line":545,"address":[4234415,4234586],"length":1,"stats":{"Line":1},"fn_name":null},{"line":546,"address":[4234526,4235052,4235213,4234928],"length":1,"stats":{"Line":3},"fn_name":null},{"line":547,"address":[4235075,4235225],"length":1,"stats":{"Line":1},"fn_name":null},{"line":552,"address":[4234999],"length":1,"stats":{"Line":1},"fn_name":null},{"line":553,"address":[4235012],"length":1,"stats":{"Line":1},"fn_name":null},{"line":554,"address":[4235020],"length":1,"stats":{"Line":1},"fn_name":null},{"line":555,"address":[4235550],"length":1,"stats":{"Line":1},"fn_name":null},{"line":556,"address":[4235611],"length":1,"stats":{"Line":1},"fn_name":null},{"line":557,"address":[4235632,4235803],"length":1,"stats":{"Line":1},"fn_name":null},{"line":558,"address":[4236326,4236487,4236145,4235743],"length":1,"stats":{"Line":3},"fn_name":null},{"line":559,"address":[4236349,4236499],"length":1,"stats":{"Line":1},"fn_name":null},{"line":564,"address":[4236211],"length":1,"stats":{"Line":1},"fn_name":null},{"line":565,"address":[4236252],"length":1,"stats":{"Line":1},"fn_name":null},{"line":566,"address":[4236840],"length":1,"stats":{"Line":1},"fn_name":null},{"line":567,"address":[4236981],"length":1,"stats":{"Line":1},"fn_name":null},{"line":568,"address":[4237221,4237050],"length":1,"stats":{"Line":1},"fn_name":null},{"line":569,"address":[4237563,4237795,4237161,4237960],"length":1,"stats":{"Line":3},"fn_name":null},{"line":570,"address":[4237818,4237972],"length":1,"stats":{"Line":1},"fn_name":null},{"line":575,"address":[4237637],"length":1,"stats":{"Line":1},"fn_name":null},{"line":576,"address":[4237662],"length":1,"stats":{"Line":1},"fn_name":null},{"line":577,"address":[4237702],"length":1,"stats":{"Line":1},"fn_name":null},{"line":578,"address":[4238313],"length":1,"stats":{"Line":1},"fn_name":null},{"line":579,"address":[4238454],"length":1,"stats":{"Line":1},"fn_name":null},{"line":580,"address":[4238694,4238523],"length":1,"stats":{"Line":1},"fn_name":null},{"line":581,"address":[4239233,4239000,4238634,4239074],"length":1,"stats":{"Line":3},"fn_name":null},{"line":582,"address":[4239245,4239097],"length":1,"stats":{"Line":1},"fn_name":null}],"covered":213,"coverable":217}]};
var previousData = {"files":[{"path":["/","home","srv","hg","icefox","srht","icefox","oorandom","src","lib.rs"],"content":"//! A tiny, robust PRNG implementation.\n//!\n//! More specifically, it implements a single GOOD PRNG algorithm,\n//! which is currently a permuted congruential generator. It has two\n//! implementations, one that returns `u32` and one that returns\n//! `u64`. It also has functions that return floats or integer\n//! ranges. And that's it. What more do you need?\n//!\n//! For more info on PCG generators, see http://www.pcg-random.org/\n//!\n//! This was designed as a minimalist utility for video games. No\n//! promises are made about its quality, and if you use it for\n//! cryptography you will get what you deserve.\n//!\n//! Works with `#![no_std]`, has no global state, no dependencies\n//! apart from some in the unit tests, and is generally neato.\n\n#![forbid(unsafe_code)]\n#![forbid(missing_docs)]\n#![forbid(missing_debug_implementations)]\n#![forbid(unused_results)]\n#![no_std]\nuse core::ops::Range;\n\n/// A PRNG producing a 32-bit output.\n///\n/// The current implementation is `PCG-XSH-RR`.\n#[derive(Copy, Clone, Debug, PartialEq)]\npub struct Rand32 {\n state: u64,\n inc: u64,\n}\n\nimpl Rand32 {\n /// The default value for `increment`.\n /// This is basically arbitrary, it comes from the\n /// PCG reference C implementation:\n /// https://github.com/imneme/pcg-c/blob/master/include/pcg_variants.h#L284\n pub const DEFAULT_INC: u64 = 1442695040888963407;\n\n /// This is the number that you have to Really Get Right.\n ///\n /// The value used here is from the PCG C implementation:\n /// https://github.com/imneme/pcg-c/blob/master/include/pcg_variants.h#L278\n pub(crate) const MULTIPLIER: u64 = 6364136223846793005;\n\n /// Creates a new PRNG with the given seed and a default increment.\n pub fn new(seed: u64) -\u003e Self {\n Self::new_inc(seed, Self::DEFAULT_INC)\n }\n\n /// Creates a new PRNG. The two inputs, `seed` and `increment`,\n /// determine what you get; `increment` basically selects which\n /// sequence of all those possible the PRNG will produce, and the\n /// `seed` selects where in that sequence you start.\n ///\n /// Both are arbitrary; increment must be an odd number but this\n /// handles that for you\n pub fn new_inc(seed: u64, increment: u64) -\u003e Self {\n let mut rng = Self {\n state: 0,\n inc: increment.wrapping_shl(1) | 1,\n };\n // This initialization song-and-dance is a little odd,\n // but seems to be just how things go.\n let _ = rng.rand_u32();\n rng.state = rng.state.wrapping_add(seed);\n let _ = rng.rand_u32();\n rng\n }\n\n /// Returns the internal state of the PRNG. This allows\n /// you to save a PRNG and create a new one that will resume\n /// from the same spot in the sequence.\n pub fn state(\u0026self) -\u003e (u64, u64) {\n (self.state, self.inc)\n }\n\n /// Creates a new PRNG from a saved state from `Rand32::state()`.\n /// This is NOT quite the same as `new_inc()` because `new_inc()` does\n /// a little extra setup work to initialize the state.\n pub fn from_state(state: (u64, u64)) -\u003e Self {\n let (state, inc) = state;\n Self { state, inc }\n }\n\n /// Produces a random `u32` in the range `[0, u32::MAX]`.\n pub fn rand_u32(\u0026mut self) -\u003e u32 {\n let oldstate: u64 = self.state;\n self.state = oldstate\n .wrapping_mul(Self::MULTIPLIER)\n .wrapping_add(self.inc);\n let xorshifted: u32 = (((oldstate \u003e\u003e 18) ^ oldstate) \u003e\u003e 27) as u32;\n let rot: u32 = (oldstate \u003e\u003e 59) as u32;\n xorshifted.rotate_right(rot)\n }\n\n /// Produces a random `i32` in the range `[i32::MIN, i32::MAX]`.\n pub fn rand_i32(\u0026mut self) -\u003e i32 {\n self.rand_u32() as i32\n }\n\n /// Produces a random `f32` in the range `[0.0, 1.0)`.\n pub fn rand_float(\u0026mut self) -\u003e f32 {\n // This impl was taken more or less from `rand`, see\n // \u003chttps://docs.rs/rand/0.7.0/src/rand/distributions/float.rs.html#104-117\u003e\n // There MAY be better ways to do this, see:\n // https://mumble.net/~campbell/2014/04/28/uniform-random-float\n // https://mumble.net/~campbell/2014/04/28/random_real.c\n // https://github.com/Lokathor/randomize/issues/34\n const TOTAL_BITS: u32 = 32;\n const PRECISION: u32 = core::f32::MANTISSA_DIGITS + 1;\n const MANTISSA_SCALE: f32 = 1.0 / ((1u32 \u003c\u003c PRECISION) as f32);\n let mut u = self.rand_u32();\n u \u003e\u003e= TOTAL_BITS - PRECISION;\n u as f32 * MANTISSA_SCALE\n }\n\n /// Produces a random within the given bounds. Like any `Range`,\n /// it includes the lower bound and excludes the upper one.\n ///\n /// This should be faster than `Self::rand() % end + start`, but the\n /// real advantage is it's more convenient. Requires that\n /// `range.end \u003c= range.start`.\n pub fn rand_range(\u0026mut self, range: Range\u003cu32\u003e) -\u003e u32 {\n // This is harder to do well than it looks, it seems. I don't\n // trust Lokathor's implementation 'cause I don't understand\n // it, so I went to numpy's, which points me to \"Lemire's\n // rejection algorithm\": http://arxiv.org/abs/1805.10941\n //\n // Algorithms 3, 4 and 5 in that paper all seem fine modulo\n // minor performance differences, so this is algorithm 5.\n // It uses numpy's implementation, `buffered_bounded_lemire_uint32()`\n\n debug_assert!(range.start \u003c range.end);\n let range_starting_from_zero = 0..(range.end - range.start);\n\n let s: u32 = range_starting_from_zero.end;\n let mut m: u64 = u64::from(self.rand_u32()) * u64::from(s);\n let mut leftover: u32 = (m \u0026 0xFFFF_FFFF) as u32;\n\n if leftover \u003c s {\n // TODO: verify the wrapping_neg() here\n let threshold: u32 = s.wrapping_neg() % s;\n while leftover \u003c threshold {\n m = u64::from(self.rand_u32()).wrapping_mul(u64::from(s));\n leftover = (m \u0026 0xFFFF_FFFF) as u32;\n }\n }\n (m \u003e\u003e 32) as u32 + range.start\n }\n}\n\n/// A PRNG producing a 64-bit output.\n///\n/// The current implementation is `PCG-XSH-RR`.\n// BUGGO: The recommended algorithm is PCG-XSL-RR?\n// See https://github.com/imneme/pcg-c/blob/master/include/pcg_variants.h#L2405\n// Not sure if it matters?\n#[derive(Copy, Clone, Debug, PartialEq)]\npub struct Rand64 {\n state: u128,\n inc: u128,\n}\n\nimpl Rand64 {\n /// The default value for `increment`.\n ///\n /// The value used here is from the PCG default C implementation: http://www.pcg-random.org/download.html\n pub const DEFAULT_INC: u128 = 0x2FE0E169_FFBD06E3_5BC307BD_4D2F814F;\n\n /// This is the number that you have to Really Get Right.\n ///\n /// The value used here is from the PCG C implementation:\n /// https://github.com/imneme/pcg-c/blob/master/include/pcg_variants.h#L288\n pub(crate) const MULTIPLIER: u128 = 47026247687942121848144207491837523525;\n\n /// Creates a new PRNG with the given seed and a default increment.\n pub fn new(seed: u128) -\u003e Self {\n Self::new_inc(seed, Self::DEFAULT_INC)\n }\n\n /// Same as `Rand32::new_inc()`\n fn new_inc(seed: u128, increment: u128) -\u003e Self {\n let mut rng = Self {\n state: 0,\n inc: increment.wrapping_shl(1) | 1,\n };\n let _ = rng.rand_u64();\n rng.state = rng.state.wrapping_add(seed);\n let _ = rng.rand_u64();\n rng\n }\n\n /// Returns the internal state of the PRNG. This allows\n /// you to save a PRNG and create a new one that will resume\n /// from the same spot in the sequence.\n pub fn state(\u0026self) -\u003e (u128, u128) {\n (self.state, self.inc)\n }\n\n /// Creates a new PRNG from a saved state from `Rand32::state()`.\n /// This is NOT quite the same as `new_inc()` because `new_inc()` does\n /// a little extra setup work to initialize the state.\n pub fn from_state(state: (u128, u128)) -\u003e Self {\n let (state, inc) = state;\n Self { state, inc }\n }\n\n /// Produces a random `u64` in the range`[0, u64::MAX]`.\n pub fn rand_u64(\u0026mut self) -\u003e u64 {\n let oldstate: u128 = self.state;\n self.state = oldstate\n .wrapping_mul(Self::MULTIPLIER)\n .wrapping_add(self.inc);\n let xorshifted: u64 = (((oldstate \u003e\u003e 29) ^ oldstate) \u003e\u003e 58) as u64;\n let rot: u32 = (oldstate \u003e\u003e 122) as u32;\n xorshifted.rotate_right(rot)\n }\n\n /// Produces a random `i64` in the range `[i64::MIN, i64::MAX]`.\n pub fn rand_i64(\u0026mut self) -\u003e i64 {\n self.rand_u64() as i64\n }\n\n /// Produces a random `f64` in the range `[0.0, 1.0)`.\n pub fn rand_float(\u0026mut self) -\u003e f64 {\n const TOTAL_BITS: u32 = 64;\n const PRECISION: u32 = core::f64::MANTISSA_DIGITS + 1;\n const MANTISSA_SCALE: f64 = 1.0 / ((1u64 \u003c\u003c PRECISION) as f64);\n let mut u = self.rand_u64();\n u \u003e\u003e= TOTAL_BITS - PRECISION;\n u as f64 * MANTISSA_SCALE\n }\n\n /// Produces a random within the given bounds. Like any `Range`,\n /// it includes the lower bound and excludes the upper one.\n ///\n /// This should be faster than `Self::rand() % end + start`, but the\n /// real advantage is it's more convenient. Requires that\n /// `range.end \u003c= range.start`.\n pub fn rand_range(\u0026mut self, range: Range\u003cu64\u003e) -\u003e u64 {\n // Same as `Rand32::rand_range()`\n debug_assert!(range.start \u003c range.end);\n let range_starting_from_zero = 0..(range.end - range.start);\n\n let s: u64 = range_starting_from_zero.end;\n let mut m: u128 = u128::from(self.rand_u64()) * u128::from(s);\n let mut leftover: u64 = (m \u0026 0xFFFFFFFF_FFFFFFFF) as u64;\n\n if leftover \u003c s {\n // TODO: Verify the wrapping_negate() here\n let threshold: u64 = s.wrapping_neg() % s;\n while leftover \u003c threshold {\n m = u128::from(self.rand_u64()) * u128::from(s);\n leftover = (m \u0026 0xFFFFFFFF_FFFFFFFF) as u64;\n }\n }\n (m.wrapping_shr(64)) as u64 + range.start\n }\n}\n\n#[cfg(test)]\nmod tests {\n use super::*;\n use randomize::{self, PCG32, PCG64};\n\n #[test]\n fn test_rand32_vs_randomize() {\n // Generate some random numbers and validate them against\n // a known-good generator.\n {\n let seed = 54321;\n let mut r1 = Rand32::new(seed);\n let mut r2 = PCG32::seed(seed, Rand32::DEFAULT_INC);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u32(), r2.next_u32());\n assert_eq!(r1.rand_i32(), r2.next_u32() as i32);\n }\n }\n\n {\n let seed = 3141592653;\n let inc = 0xDEADBEEF;\n let mut r1 = Rand32::new_inc(seed, inc);\n let mut r2 = PCG32::seed(seed, inc);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u32(), r2.next_u32());\n assert_eq!(r1.rand_i32(), r2.next_u32() as i32);\n }\n }\n }\n\n #[test]\n fn test_rand64_vs_randomize() {\n // Generate some random numbers and validate them against\n // a known-good generator.\n {\n let seed = 54321;\n let mut r1 = Rand64::new(seed);\n let mut r2 = PCG64::seed(seed, Rand64::DEFAULT_INC);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u64(), r2.next_u64());\n assert_eq!(r1.rand_i64(), r2.next_u64() as i64);\n }\n }\n\n {\n let seed = 3141592653;\n let inc = 0xDEADBEEF;\n let mut r1 = Rand64::new_inc(seed, inc);\n let mut r2 = PCG64::seed(seed, inc);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u64(), r2.next_u64());\n assert_eq!(r1.rand_i64(), r2.next_u64() as i64);\n }\n }\n }\n\n #[test]\n fn test_float32() {\n {\n let seed = 2718281828;\n let mut r1 = Rand32::new(seed);\n let mut r2 = PCG32::seed(seed, Rand32::DEFAULT_INC);\n for _ in 0..1000 {\n // First just make sure they both work with randomize's\n // f32 conversion function -- sanity checks.\n let i1 = r1.rand_u32();\n let i2 = r2.next_u32();\n assert_eq!(i1, i2);\n let f1 = randomize::f32_half_open_right(i1);\n let f2 = randomize::f32_half_open_right(i2);\n // We can directly compare floats 'cause we do no math, it's\n // literally the same bitwise algorithm with the same inputs.\n assert_eq!(f1, f2);\n\n // Make sure result is in [0.0, 1.0)\n assert!(f1 \u003e= 0.0);\n assert!(f1 \u003c 1.0);\n }\n\n // At least make sure our float's from rand_float() are in the valid range.\n for _ in 0..1000 {\n let f1 = r1.rand_float();\n assert!(f1 \u003e= 0.0);\n assert!(f1 \u003c 1.0);\n }\n\n /*\n TODO: Randomize changed its int-to-float conversion functions and now they don't\n match ours.\n for _ in 0..1000 {\n // Now make sure our own float conversion function works.\n let f1 = r1.rand_float();\n //let f2 = randomize::f32_half_open_right(r2.next_u32());\n let f2 = randomize::f32_open(r2.next_u32());\n assert_eq!(f1, f2);\n assert!(f1 \u003e= 0.0);\n assert!(f1 \u003c 1.0);\n }\n */\n }\n }\n\n #[test]\n fn test_float64() {\n {\n let seed = 2718281828;\n let mut r1 = Rand64::new(seed);\n let mut r2 = PCG64::seed(seed, Rand64::DEFAULT_INC);\n for _ in 0..1000 {\n // First just make sure they both work with randomize's\n // f64 conversion function -- sanity checks.\n let i1 = r1.rand_u64();\n let i2 = r2.next_u64();\n assert_eq!(i1, i2);\n let f1 = randomize::f64_half_open_right(i1);\n let f2 = randomize::f64_half_open_right(i2);\n // We can directly compare floats 'cause we do no math, it's\n // literally the same bitwise algorithm with the same inputs.\n assert_eq!(f1, f2);\n\n // Make sure result is in [0.0, 1.0)\n assert!(f1 \u003e= 0.0);\n assert!(f1 \u003c 1.0);\n }\n\n // At least make sure our float's from rand_float() are in the valid range.\n for _ in 0..1000 {\n let f1 = r1.rand_float();\n assert!(f1 \u003e= 0.0);\n assert!(f1 \u003c 1.0);\n }\n\n /*\n TODO: Randomize changed its int-to-float conversion functions and now they don't\n match ours.\n for _ in 0..1000 {\n // Now make sure our own float conversion function works.\n let f1 = r1.rand_float();\n //let f2 = randomize::f32_half_open_right(r2.next_u32());\n let f2 = randomize::f32_open(r2.next_u32());\n assert_eq!(f1, f2);\n assert!(f1 \u003e= 0.0);\n assert!(f1 \u003c 1.0);\n }\n */\n }\n }\n\n #[test]\n fn test_randrange32() {\n // Make sure ranges are valid and in the given range\n let seed = 2342_3141;\n let mut r1 = Rand32::new(seed);\n for _ in 0..1000 {\n // Generate our bounds at random\n let a = r1.rand_u32();\n let b = r1.rand_u32();\n if a == b {\n continue;\n }\n let (low, high) = if a \u003c b { (a, b) } else { (b, a) };\n\n // Get a number in that range\n let in_range = r1.rand_range(low..high);\n assert!(in_range \u003e= low);\n assert!(in_range \u003c high);\n }\n }\n\n #[test]\n fn test_randrange64() {\n // Make sure ranges are valid and in the given range\n let seed = 2342_2718;\n let mut r1 = Rand64::new(seed);\n for _ in 0..1000 {\n // Generate our bounds at random\n let a = r1.rand_u64();\n let b = r1.rand_u64();\n if a == b {\n continue;\n }\n let (low, high) = if a \u003c b { (a, b) } else { (b, a) };\n\n // Get a number in that range\n let in_range = r1.rand_range(low..high);\n assert!(in_range \u003e= low);\n assert!(in_range \u003c high);\n }\n }\n\n #[test]\n fn test_rand32_vs_rand() {\n use rand_core::RngCore;\n use rand_pcg;\n {\n let seed = 54321;\n let mut r1 = Rand32::new(seed);\n let mut r2 = rand_pcg::Pcg32::new(seed, Rand32::DEFAULT_INC);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u32(), r2.next_u32());\n }\n }\n\n {\n let seed = 3141592653;\n let inc = 0xDEADBEEF;\n let mut r1 = Rand32::new_inc(seed, inc);\n let mut r2 = rand_pcg::Pcg32::new(seed, inc);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u32(), r2.next_u32());\n }\n }\n }\n\n // This doesn't work 'cause for 64-bit output `rand` uses\n // PCG-XSL-RR\n // and we use\n // PCG-XSH-RR\n /*\n #[test]\n fn test_rand64_vs_rand() {\n use rand_pcg;\n use rand_core::RngCore;\n {\n let seed = 54321;\n let mut r1 = Rand64::new(seed);\n let mut r2 = rand_pcg::Pcg64::new(seed, Rand64::DEFAULT_INC);\n for _ in 0..1000 {\n assert_eq!(r1.rand(), r2.next_u64());\n }\n }\n\n {\n let seed = 3141592653;\n let inc = 0xDEADBEEF;\n let mut r1 = Rand64::new_inc(seed, inc);\n let mut r2 = rand_pcg::Pcg64::new(seed, inc);\n for _ in 0..1000 {\n assert_eq!(r1.rand(), r2.next_u64());\n }\n }\n }\n */\n\n // Test vs. random-fast-rng, which I will call rfr\n // rfr's float conversion uses yet a different algorithm\n // than ours, so we can't really check that.\n #[test]\n fn test_rand32_vs_rfr() {\n use random_fast_rng as rfr;\n use rfr::Random;\n {\n let seed = 54321;\n let mut r1 = Rand32::new(seed);\n let mut r2 = rfr::FastRng::seed(seed, Rand32::DEFAULT_INC);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u32(), r2.get_u32());\n }\n }\n\n {\n let seed = 3141592653;\n let inc = 0xDEADBEEF;\n let mut r1 = Rand32::new_inc(seed, inc);\n let mut r2 = rfr::FastRng::seed(seed, inc);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u32(), r2.get_u32());\n }\n }\n }\n\n /// Make sure that saving a RNG state and restoring\n /// it works.\n /// See https://todo.sr.ht/~icefox/oorandom/1\n #[test]\n fn test_save_restore() {\n {\n let seed = 54321;\n let mut r1 = Rand32::new(seed);\n let s1 = r1.state();\n let mut r2 = Rand32::from_state(s1);\n assert_eq!(r1, r2);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u32(), r2.rand_u32());\n }\n }\n\n {\n let seed = 3141592653;\n let inc = 0xDEADBEEF;\n let mut r1 = Rand32::new_inc(seed, inc);\n let s1 = r1.state();\n let mut r2 = Rand32::from_state(s1);\n assert_eq!(r1, r2);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u32(), r2.rand_u32());\n }\n }\n\n {\n let seed = 54321;\n let mut r1 = Rand64::new(seed);\n let s1 = r1.state();\n let mut r2 = Rand64::from_state(s1);\n assert_eq!(r1, r2);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u64(), r2.rand_u64());\n }\n }\n\n {\n let seed = 3141592653;\n let inc = 0xDEADBEEF;\n let mut r1 = Rand64::new_inc(seed, inc);\n let s1 = r1.state();\n let mut r2 = Rand64::from_state(s1);\n assert_eq!(r1, r2);\n for _ in 0..1000 {\n assert_eq!(r1.rand_u64(), r2.rand_u64());\n }\n }\n }\n}\n","traces":[{"line":48,"address":[4213216],"length":1,"stats":{"Line":4},"fn_name":"new"},{"line":49,"address":[4213225],"length":1,"stats":{"Line":4},"fn_name":null},{"line":59,"address":[4213264],"length":1,"stats":{"Line":4},"fn_name":"new_inc"},{"line":62,"address":[4213283],"length":1,"stats":{"Line":4},"fn_name":null},{"line":66,"address":[4213326],"length":1,"stats":{"Line":4},"fn_name":null},{"line":67,"address":[4213336],"length":1,"stats":{"Line":4},"fn_name":null},{"line":68,"address":[4213364],"length":1,"stats":{"Line":5},"fn_name":null},{"line":69,"address":[4213374],"length":1,"stats":{"Line":4},"fn_name":null},{"line":75,"address":[4213392],"length":1,"stats":{"Line":1},"fn_name":"state"},{"line":76,"address":[4213401],"length":1,"stats":{"Line":1},"fn_name":null},{"line":82,"address":[4213440],"length":1,"stats":{"Line":1},"fn_name":"from_state"},{"line":83,"address":[4213454],"length":1,"stats":{"Line":1},"fn_name":null},{"line":88,"address":[4213488],"length":1,"stats":{"Line":4},"fn_name":"rand_u32"},{"line":89,"address":[4213497],"length":1,"stats":{"Line":5},"fn_name":null},{"line":90,"address":[4213552,4213510],"length":1,"stats":{"Line":8},"fn_name":null},{"line":91,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":92,"address":[4213543],"length":1,"stats":{"Line":5},"fn_name":null},{"line":93,"address":[4213580],"length":1,"stats":{"Line":5},"fn_name":null},{"line":94,"address":[4213627],"length":1,"stats":{"Line":4},"fn_name":null},{"line":95,"address":[4213655],"length":1,"stats":{"Line":5},"fn_name":null},{"line":99,"address":[4213680],"length":1,"stats":{"Line":1},"fn_name":"rand_i32"},{"line":100,"address":[4213689],"length":1,"stats":{"Line":1},"fn_name":null},{"line":104,"address":[4213712],"length":1,"stats":{"Line":1},"fn_name":"rand_float"},{"line":114,"address":[4213721],"length":1,"stats":{"Line":1},"fn_name":null},{"line":115,"address":[4213730],"length":1,"stats":{"Line":1},"fn_name":null},{"line":116,"address":[4213757],"length":1,"stats":{"Line":1},"fn_name":null},{"line":125,"address":[4213792],"length":1,"stats":{"Line":1},"fn_name":"rand_range"},{"line":135,"address":[4213821,4213873],"length":1,"stats":{"Line":1},"fn_name":null},{"line":136,"address":[4214282,4213853,4213903],"length":1,"stats":{"Line":2},"fn_name":null},{"line":138,"address":[4213919],"length":1,"stats":{"Line":1},"fn_name":null},{"line":139,"address":[4213939,4214312],"length":1,"stats":{"Line":1},"fn_name":null},{"line":140,"address":[4214021],"length":1,"stats":{"Line":1},"fn_name":null},{"line":142,"address":[4214127,4214045],"length":1,"stats":{"Line":2},"fn_name":null},{"line":144,"address":[4214342,4214063],"length":1,"stats":{"Line":1},"fn_name":null},{"line":145,"address":[4214118,4214224],"length":1,"stats":{"Line":2},"fn_name":null},{"line":146,"address":[4214134],"length":1,"stats":{"Line":1},"fn_name":null},{"line":147,"address":[4214204],"length":1,"stats":{"Line":1},"fn_name":null},{"line":150,"address":[4214402,4214372,4214226],"length":1,"stats":{"Line":1},"fn_name":null},{"line":179,"address":[4214416],"length":1,"stats":{"Line":1},"fn_name":"new"},{"line":180,"address":[4214463],"length":1,"stats":{"Line":1},"fn_name":null},{"line":184,"address":[4214576],"length":1,"stats":{"Line":1},"fn_name":"new_inc"},{"line":187,"address":[4214620],"length":1,"stats":{"Line":1},"fn_name":null},{"line":189,"address":[4214701],"length":1,"stats":{"Line":1},"fn_name":null},{"line":190,"address":[4214711],"length":1,"stats":{"Line":1},"fn_name":null},{"line":191,"address":[4214766],"length":1,"stats":{"Line":1},"fn_name":null},{"line":192,"address":[4214776],"length":1,"stats":{"Line":1},"fn_name":null},{"line":198,"address":[4214832],"length":1,"stats":{"Line":1},"fn_name":"state"},{"line":199,"address":[4214844],"length":1,"stats":{"Line":1},"fn_name":null},{"line":205,"address":[4214928],"length":1,"stats":{"Line":1},"fn_name":"from_state"},{"line":206,"address":[4214955],"length":1,"stats":{"Line":1},"fn_name":null},{"line":211,"address":[4215040],"length":1,"stats":{"Line":1},"fn_name":"rand_u64"},{"line":212,"address":[4215052],"length":1,"stats":{"Line":1},"fn_name":null},{"line":213,"address":[4215164,4215097],"length":1,"stats":{"Line":2},"fn_name":null},{"line":214,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":215,"address":[4215146],"length":1,"stats":{"Line":1},"fn_name":null},{"line":216,"address":[4215211],"length":1,"stats":{"Line":1},"fn_name":null},{"line":217,"address":[4215301],"length":1,"stats":{"Line":1},"fn_name":null},{"line":218,"address":[4215338],"length":1,"stats":{"Line":2},"fn_name":null},{"line":222,"address":[4215376],"length":1,"stats":{"Line":1},"fn_name":"rand_i64"},{"line":223,"address":[4215385],"length":1,"stats":{"Line":1},"fn_name":null},{"line":227,"address":[4215408],"length":1,"stats":{"Line":1},"fn_name":"rand_float"},{"line":231,"address":[4215417],"length":1,"stats":{"Line":1},"fn_name":null},{"line":232,"address":[4215427],"length":1,"stats":{"Line":1},"fn_name":null},{"line":233,"address":[4215457],"length":1,"stats":{"Line":1},"fn_name":null},{"line":242,"address":[4215520],"length":1,"stats":{"Line":1},"fn_name":"rand_range"},{"line":244,"address":[4215551,4215628],"length":1,"stats":{"Line":1},"fn_name":null},{"line":245,"address":[4216411,4215658,4215603],"length":1,"stats":{"Line":2},"fn_name":null},{"line":247,"address":[4215686],"length":1,"stats":{"Line":1},"fn_name":null},{"line":248,"address":[4216441,4215718],"length":1,"stats":{"Line":1},"fn_name":null},{"line":249,"address":[4215965],"length":1,"stats":{"Line":1},"fn_name":null},{"line":251,"address":[4216094,4215989],"length":1,"stats":{"Line":2},"fn_name":null},{"line":253,"address":[4216012,4216471],"length":1,"stats":{"Line":1},"fn_name":null},{"line":254,"address":[4216084,4216331],"length":1,"stats":{"Line":2},"fn_name":null},{"line":255,"address":[4216107,4216501],"length":1,"stats":{"Line":1},"fn_name":null},{"line":256,"address":[4216315],"length":1,"stats":{"Line":1},"fn_name":null},{"line":259,"address":[4216531,4216561,4216336],"length":1,"stats":{"Line":1},"fn_name":null},{"line":269,"address":[4219504,4219509],"length":1,"stats":{"Line":3},"fn_name":"{{closure}}"},{"line":273,"address":[4222375],"length":1,"stats":{"Line":1},"fn_name":null},{"line":274,"address":[4222392],"length":1,"stats":{"Line":1},"fn_name":null},{"line":275,"address":[4222428],"length":1,"stats":{"Line":1},"fn_name":null},{"line":276,"address":[4223285,4222635,4222449],"length":1,"stats":{"Line":2},"fn_name":null},{"line":277,"address":[4222658,4222828],"length":1,"stats":{"Line":1},"fn_name":null},{"line":278,"address":[4222796,4223153,4223290],"length":1,"stats":{"Line":2},"fn_name":null},{"line":283,"address":[4222582],"length":1,"stats":{"Line":1},"fn_name":null},{"line":284,"address":[4222595],"length":1,"stats":{"Line":1},"fn_name":null},{"line":285,"address":[4222603],"length":1,"stats":{"Line":1},"fn_name":null},{"line":286,"address":[4223635],"length":1,"stats":{"Line":1},"fn_name":null},{"line":287,"address":[4224394,4223792,4223656],"length":1,"stats":{"Line":2},"fn_name":null},{"line":288,"address":[4223985,4223815],"length":1,"stats":{"Line":1},"fn_name":null},{"line":289,"address":[4224274,4223953,4224399],"length":1,"stats":{"Line":2},"fn_name":null},{"line":295,"address":[4219541,4219536],"length":1,"stats":{"Line":3},"fn_name":"{{closure}}"},{"line":299,"address":[4224695],"length":1,"stats":{"Line":1},"fn_name":null},{"line":300,"address":[4224736],"length":1,"stats":{"Line":1},"fn_name":null},{"line":301,"address":[4224842],"length":1,"stats":{"Line":1},"fn_name":null},{"line":302,"address":[4225865,4224911,4225205],"length":1,"stats":{"Line":2},"fn_name":null},{"line":303,"address":[4225228,4225403],"length":1,"stats":{"Line":1},"fn_name":null},{"line":304,"address":[4225728,4225870,4225370],"length":1,"stats":{"Line":2},"fn_name":null},{"line":309,"address":[4225047],"length":1,"stats":{"Line":1},"fn_name":null},{"line":310,"address":[4225072],"length":1,"stats":{"Line":1},"fn_name":null},{"line":311,"address":[4225112],"length":1,"stats":{"Line":1},"fn_name":null},{"line":312,"address":[4226235],"length":1,"stats":{"Line":1},"fn_name":null},{"line":313,"address":[4227082,4226470,4226334],"length":1,"stats":{"Line":2},"fn_name":null},{"line":314,"address":[4226668,4226493],"length":1,"stats":{"Line":1},"fn_name":null},{"line":315,"address":[4227087,4226635,4226957],"length":1,"stats":{"Line":2},"fn_name":null},{"line":321,"address":[4219568,4219573],"length":1,"stats":{"Line":3},"fn_name":"{{closure}}"},{"line":323,"address":[4227388],"length":1,"stats":{"Line":1},"fn_name":null},{"line":324,"address":[4227396],"length":1,"stats":{"Line":1},"fn_name":null},{"line":325,"address":[4227435],"length":1,"stats":{"Line":1},"fn_name":null},{"line":326,"address":[4227456,4227644,4228624],"length":1,"stats":{"Line":2},"fn_name":null},{"line":329,"address":[4227667],"length":1,"stats":{"Line":1},"fn_name":null},{"line":330,"address":[4227687],"length":1,"stats":{"Line":1},"fn_name":null},{"line":331,"address":[4227838,4227707],"length":1,"stats":{"Line":1},"fn_name":null},{"line":332,"address":[4227805],"length":1,"stats":{"Line":1},"fn_name":null},{"line":333,"address":[4228127],"length":1,"stats":{"Line":1},"fn_name":null},{"line":336,"address":[4228148,4228280],"length":1,"stats":{"Line":1},"fn_name":null},{"line":339,"address":[4228247,4228594],"length":1,"stats":{"Line":1},"fn_name":null},{"line":340,"address":[4228629,4228575],"length":1,"stats":{"Line":1},"fn_name":null},{"line":344,"address":[4228740,4228870,4228666,4227584],"length":1,"stats":{"Line":3},"fn_name":null},{"line":345,"address":[4228763],"length":1,"stats":{"Line":1},"fn_name":null},{"line":346,"address":[4228791,4228840],"length":1,"stats":{"Line":1},"fn_name":null},{"line":347,"address":[4228875,4228826,4228905],"length":1,"stats":{"Line":1},"fn_name":null},{"line":367,"address":[4219605,4219600],"length":1,"stats":{"Line":3},"fn_name":"{{closure}}"},{"line":369,"address":[4228924],"length":1,"stats":{"Line":1},"fn_name":null},{"line":370,"address":[4228956],"length":1,"stats":{"Line":1},"fn_name":null},{"line":371,"address":[4229065],"length":1,"stats":{"Line":1},"fn_name":null},{"line":372,"address":[4229134,4229322,4230317],"length":1,"stats":{"Line":2},"fn_name":null},{"line":375,"address":[4229345],"length":1,"stats":{"Line":1},"fn_name":null},{"line":376,"address":[4229366],"length":1,"stats":{"Line":1},"fn_name":null},{"line":377,"address":[4229387,4229521],"length":1,"stats":{"Line":1},"fn_name":null},{"line":378,"address":[4229487],"length":1,"stats":{"Line":1},"fn_name":null},{"line":379,"address":[4229816],"length":1,"stats":{"Line":1},"fn_name":null},{"line":382,"address":[4229838,4229972],"length":1,"stats":{"Line":1},"fn_name":null},{"line":385,"address":[4229938,4230287],"length":1,"stats":{"Line":1},"fn_name":null},{"line":386,"address":[4230267,4230322],"length":1,"stats":{"Line":1},"fn_name":null},{"line":390,"address":[4229262,4230359,4230433,4230565],"length":1,"stats":{"Line":3},"fn_name":null},{"line":391,"address":[4230456],"length":1,"stats":{"Line":1},"fn_name":null},{"line":392,"address":[4230535,4230484],"length":1,"stats":{"Line":1},"fn_name":null},{"line":393,"address":[4230570,4230600,4230520],"length":1,"stats":{"Line":1},"fn_name":null},{"line":413,"address":[4219637,4219632],"length":1,"stats":{"Line":3},"fn_name":"{{closure}}"},{"line":415,"address":[4230615],"length":1,"stats":{"Line":1},"fn_name":null},{"line":416,"address":[4230629],"length":1,"stats":{"Line":1},"fn_name":null},{"line":417,"address":[4230738,4230988,4230644],"length":1,"stats":{"Line":2},"fn_name":null},{"line":419,"address":[4230752],"length":1,"stats":{"Line":1},"fn_name":null},{"line":420,"address":[4230770],"length":1,"stats":{"Line":1},"fn_name":null},{"line":421,"address":[4230796],"length":1,"stats":{"Line":1},"fn_name":null},{"line":422,"address":[4230814],"length":1,"stats":{"Line":0},"fn_name":null},{"line":424,"address":[4230808,4230820],"length":1,"stats":{"Line":2},"fn_name":null},{"line":427,"address":[4230869],"length":1,"stats":{"Line":1},"fn_name":null},{"line":428,"address":[4230958,4230922],"length":1,"stats":{"Line":1},"fn_name":null},{"line":429,"address":[4231023,4230943,4230993],"length":1,"stats":{"Line":2},"fn_name":null},{"line":434,"address":[4219669,4219664],"length":1,"stats":{"Line":3},"fn_name":"{{closure}}"},{"line":436,"address":[4231031],"length":1,"stats":{"Line":1},"fn_name":null},{"line":437,"address":[4231069],"length":1,"stats":{"Line":1},"fn_name":null},{"line":438,"address":[4231217,4231114,4231551],"length":1,"stats":{"Line":2},"fn_name":null},{"line":440,"address":[4231240],"length":1,"stats":{"Line":1},"fn_name":null},{"line":441,"address":[4231263],"length":1,"stats":{"Line":1},"fn_name":null},{"line":442,"address":[4231296],"length":1,"stats":{"Line":1},"fn_name":null},{"line":443,"address":[4231318],"length":1,"stats":{"Line":0},"fn_name":null},{"line":445,"address":[4231328,4231311],"length":1,"stats":{"Line":2},"fn_name":null},{"line":448,"address":[4231409],"length":1,"stats":{"Line":1},"fn_name":null},{"line":449,"address":[4231482,4231521],"length":1,"stats":{"Line":1},"fn_name":null},{"line":450,"address":[4231586,4231505,4231556],"length":1,"stats":{"Line":1},"fn_name":null},{"line":455,"address":[4219701,4219696],"length":1,"stats":{"Line":3},"fn_name":"{{closure}}"},{"line":459,"address":[4231607],"length":1,"stats":{"Line":1},"fn_name":null},{"line":460,"address":[4231624],"length":1,"stats":{"Line":1},"fn_name":null},{"line":461,"address":[4231645],"length":1,"stats":{"Line":1},"fn_name":null},{"line":462,"address":[4232032,4231685,4231871],"length":1,"stats":{"Line":2},"fn_name":null},{"line":463,"address":[4231894,4232044],"length":1,"stats":{"Line":1},"fn_name":null},{"line":468,"address":[4231818],"length":1,"stats":{"Line":1},"fn_name":null},{"line":469,"address":[4231831],"length":1,"stats":{"Line":1},"fn_name":null},{"line":470,"address":[4231839],"length":1,"stats":{"Line":1},"fn_name":null},{"line":471,"address":[4232333],"length":1,"stats":{"Line":1},"fn_name":null},{"line":472,"address":[4232492,4232368,4232647],"length":1,"stats":{"Line":2},"fn_name":null},{"line":473,"address":[4232659,4232515],"length":1,"stats":{"Line":1},"fn_name":null},{"line":512,"address":[4219733,4219728],"length":1,"stats":{"Line":3},"fn_name":"{{closure}}"},{"line":516,"address":[4232951],"length":1,"stats":{"Line":1},"fn_name":null},{"line":517,"address":[4232968],"length":1,"stats":{"Line":1},"fn_name":null},{"line":518,"address":[4232989],"length":1,"stats":{"Line":1},"fn_name":null},{"line":519,"address":[4233029,4233377,4233215],"length":1,"stats":{"Line":2},"fn_name":null},{"line":520,"address":[4233389,4233238],"length":1,"stats":{"Line":1},"fn_name":null},{"line":525,"address":[4233162],"length":1,"stats":{"Line":1},"fn_name":null},{"line":526,"address":[4233175],"length":1,"stats":{"Line":1},"fn_name":null},{"line":527,"address":[4233183],"length":1,"stats":{"Line":1},"fn_name":null},{"line":528,"address":[4233678],"length":1,"stats":{"Line":1},"fn_name":null},{"line":529,"address":[4233713,4233837,4233993],"length":1,"stats":{"Line":2},"fn_name":null},{"line":530,"address":[4234005,4233860],"length":1,"stats":{"Line":1},"fn_name":null},{"line":539,"address":[4219760,4219765],"length":1,"stats":{"Line":3},"fn_name":"{{closure}}"},{"line":541,"address":[4234295],"length":1,"stats":{"Line":1},"fn_name":null},{"line":542,"address":[4234312],"length":1,"stats":{"Line":1},"fn_name":null},{"line":543,"address":[4234333],"length":1,"stats":{"Line":1},"fn_name":null},{"line":544,"address":[4234394],"length":1,"stats":{"Line":1},"fn_name":null},{"line":545,"address":[4234586,4234415],"length":1,"stats":{"Line":1},"fn_name":null},{"line":546,"address":[4234928,4234526,4235213,4235052],"length":1,"stats":{"Line":3},"fn_name":null},{"line":547,"address":[4235075,4235225],"length":1,"stats":{"Line":1},"fn_name":null},{"line":552,"address":[4234999],"length":1,"stats":{"Line":1},"fn_name":null},{"line":553,"address":[4235012],"length":1,"stats":{"Line":1},"fn_name":null},{"line":554,"address":[4235020],"length":1,"stats":{"Line":1},"fn_name":null},{"line":555,"address":[4235550],"length":1,"stats":{"Line":1},"fn_name":null},{"line":556,"address":[4235611],"length":1,"stats":{"Line":1},"fn_name":null},{"line":557,"address":[4235803,4235632],"length":1,"stats":{"Line":1},"fn_name":null},{"line":558,"address":[4236487,4236326,4236145,4235743],"length":1,"stats":{"Line":3},"fn_name":null},{"line":559,"address":[4236349,4236499],"length":1,"stats":{"Line":1},"fn_name":null},{"line":564,"address":[4236211],"length":1,"stats":{"Line":1},"fn_name":null},{"line":565,"address":[4236252],"length":1,"stats":{"Line":1},"fn_name":null},{"line":566,"address":[4236840],"length":1,"stats":{"Line":1},"fn_name":null},{"line":567,"address":[4236981],"length":1,"stats":{"Line":1},"fn_name":null},{"line":568,"address":[4237050,4237221],"length":1,"stats":{"Line":1},"fn_name":null},{"line":569,"address":[4237795,4237161,4237563,4237960],"length":1,"stats":{"Line":3},"fn_name":null},{"line":570,"address":[4237818,4237972],"length":1,"stats":{"Line":1},"fn_name":null},{"line":575,"address":[4237637],"length":1,"stats":{"Line":1},"fn_name":null},{"line":576,"address":[4237662],"length":1,"stats":{"Line":1},"fn_name":null},{"line":577,"address":[4237702],"length":1,"stats":{"Line":1},"fn_name":null},{"line":578,"address":[4238313],"length":1,"stats":{"Line":1},"fn_name":null},{"line":579,"address":[4238454],"length":1,"stats":{"Line":1},"fn_name":null},{"line":580,"address":[4238694,4238523],"length":1,"stats":{"Line":1},"fn_name":null},{"line":581,"address":[4239233,4239074,4238634,4239000],"length":1,"stats":{"Line":3},"fn_name":null},{"line":582,"address":[4239245,4239097],"length":1,"stats":{"Line":1},"fn_name":null}],"covered":213,"coverable":217}]};
</script>
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<script>const e = React.createElement;
function pathToString(path) {
if (path[0] === '/') {
return '/' + path.slice(1).join('/');
} else {
return path.join('/');
}
}
function findCommonPath(files) {
if (!files || !files.length) {
return [];
}
function isPrefix(arr, prefix) {
if (arr.length < prefix.length) {
return false;
}
for (let i = prefix.length - 1; i >= 0; --i) {
if (arr[i] !== prefix[i]) {
return false;
}
}
return true;
}
let commonPath = files[0].path.slice(0, -1);
while (commonPath.length) {
if (files.every(file => isPrefix(file.path, commonPath))) {
break;
}
commonPath.pop();
}
return commonPath;
}
function findFolders(files) {
if (!files || !files.length) {
return [];
}
let folders = files.filter(file => file.path.length > 1).map(file => file.path[0]);
folders = [...new Set(folders)]; // unique
folders.sort();
folders = folders.map(folder => {
let filesInFolder = files
.filter(file => file.path[0] === folder)
.map(file => ({
...file,
path: file.path.slice(1),
parent: [...file.parent, file.path[0]],
}));
const children = findFolders(filesInFolder); // recursion
return {
is_folder: true,
path: [folder],
parent: files[0].parent,
children,
covered: children.reduce((sum, file) => sum + file.covered, 0),
coverable: children.reduce((sum, file) => sum + file.coverable, 0),
prevRun: {
covered: children.reduce((sum, file) => sum + file.prevRun.covered, 0),
coverable: children.reduce((sum, file) => sum + file.prevRun.coverable, 0),
}
};
});
return [
...folders,
...files.filter(file => file.path.length === 1),
];
}
class App extends React.Component {
constructor(...args) {
super(...args);
this.state = {
current: [],
};
}
componentDidMount() {
this.updateStateFromLocation();
window.addEventListener("hashchange", () => this.updateStateFromLocation(), false);
}
updateStateFromLocation() {
if (window.location.hash.length > 1) {
const current = window.location.hash.substr(1).split('/');
this.setState({current});
} else {
this.setState({current: []});
}
}
getCurrentPath() {
let file = this.props.root;
let path = [file];
for (let p of this.state.current) {
file = file.children.find(file => file.path[0] === p);
if (!file) {
return path;
}
path.push(file);
}
return path;
}
render() {
const path = this.getCurrentPath();
const file = path[path.length - 1];
let w = null;
if (file.is_folder) {
w = e(FilesList, {
folder: file,
onSelectFile: this.selectFile.bind(this),
onBack: path.length > 1 ? this.back.bind(this) : null,
});
} else {
w = e(DisplayFile, {
file,
onBack: this.back.bind(this),
});
}
return e('div', {className: 'app'}, w);
}
selectFile(file) {
this.setState(({current}) => {
return {current: [...current, file.path[0]]};
}, () => this.updateHash());
}
back(file) {
this.setState(({current}) => {
return {current: current.slice(0, current.length - 1)};
}, () => this.updateHash());
}
updateHash() {
if (!this.state.current || !this.state.current.length) {
window.location = '#';
} else {
window.location = '#' + this.state.current.join('/');
}
}
}
function FilesList({folder, onSelectFile, onBack}) {
let files = folder.children;
return e('div', {className: 'display-folder'},
e(FileHeader, {file: folder, onBack}),
e('table', {className: 'files-list'},
e('thead', {className: 'files-list__head'},
e('tr', null,
e('th', null, "Path"),
e('th', null, "Coverage")
)
),
e('tbody', {className: 'files-list__body'},
files.map(file => e(File, {file, onClick: onSelectFile}))
)
)
);
}
function File({file, onClick}) {
const coverage = file.coverable ? file.covered / file.coverable * 100 : -1;
const coverageDelta = file.prevRun &&
(file.covered / file.coverable * 100 - file.prevRun.covered / file.prevRun.coverable * 100);
return e('tr', {
className: 'files-list__file'
+ (coverage >= 0 && coverage < 50 ? ' files-list__file_low': '')
+ (coverage >= 50 && coverage < 80 ? ' files-list__file_medium': '')
+ (coverage >= 80 ? ' files-list__file_high': '')
+ (file.is_folder ? ' files-list__file_folder': ''),
onClick: () => onClick(file),
},
e('td', null, pathToString(file.path)),
e('td', null,
file.covered + ' / ' + file.coverable +
(coverage >= 0 ? ' (' + coverage.toFixed(2) + '%)' : ''),
e('span', {title: 'Change from the previous run'},
(coverageDelta ? ` (${coverageDelta > 0 ? '+' : ''}${coverageDelta.toFixed(2)}%)` : ''))
)
);
}
function DisplayFile({file, onBack}) {
return e('div', {className: 'display-file'},
e(FileHeader, {file, onBack}),
e(FileContent, {file})
);
}
function FileHeader({file, onBack}) {
const coverage = file.covered / file.coverable * 100;
const coverageDelta = file.prevRun && (coverage - file.prevRun.covered / file.prevRun.coverable * 100);
return e('div', {className: 'file-header'},
onBack ? e('a', {className: 'file-header__back', onClick: onBack}, 'Back') : null,
e('div', {className: 'file-header__name'}, pathToString([...file.parent, ...file.path])),
e('div', {className: 'file-header__stat'},
'Covered: ' + file.covered + ' of ' + file.coverable +
(file.coverable ? ' (' + coverage.toFixed(2) + '%)' : ''),
e('span', {title: 'Change from the previous run'},
(coverageDelta ? ` (${coverageDelta > 0 ? '+' : ''}${coverageDelta.toFixed(2)}%)` : ''))
)
);
}
function FileContent({file}) {
return e('div', {className: 'file-content'},
file.content.split(/\r?\n/).map((line, index) => {
const trace = file.traces.find(trace => trace.line === index + 1);
const covered = trace && trace.stats.Line;
const uncovered = trace && !trace.stats.Line;
return e('pre', {
className: 'code-line'
+ (covered ? ' code-line_covered' : '')
+ (uncovered ? ' code-line_uncovered' : ''),
title: trace ? JSON.stringify(trace.stats, null, 2) : null,
}, line);
})
);
}
(function(){
const commonPath = findCommonPath(data.files);
const prevFilesMap = new Map();
previousData && previousData.files.forEach((file) => {
const path = file.path.slice(commonPath.length).join('/');
prevFilesMap.set(path, file);
});
const files = data.files.map((file) => {
const path = file.path.slice(commonPath.length);
const { covered = 0, coverable = 0 } = prevFilesMap.get(path.join('/')) || {};
return {
...file,
path,
parent: commonPath,
prevRun: { covered, coverable },
};
});
const children = findFolders(files);
const root = {
is_folder: true,
children,
path: commonPath,
parent: [],
covered: children.reduce((sum, file) => sum + file.covered, 0),
coverable: children.reduce((sum, file) => sum + file.coverable, 0),
prevRun: {
covered: children.reduce((sum, file) => sum + file.prevRun.covered, 0),
coverable: children.reduce((sum, file) => sum + file.prevRun.coverable, 0),
}
};
ReactDOM.render(e(App, {root, prevFilesMap}), document.getElementById('root'));
}());
</script>
</body>
</html>