1<!doctype html> 2<html> 3<head> 4 <meta charset="utf-8"> 5 <style>html, body { 6 margin: 0; 7 padding: 0; 8} 9 10.app { 11 margin: 10px; 12 padding: 0; 13} 14 15.files-list { 16 margin: 10px 0 0; 17 width: 100%; 18 border-collapse: collapse; 19} 20.files-list__head { 21 border: 1px solid #999; 22} 23.files-list__head > tr > th { 24 padding: 10px; 25 border: 1px solid #999; 26 text-align: left; 27 font-weight: normal; 28 background: #ddd; 29} 30.files-list__body { 31} 32.files-list__file { 33 cursor: pointer; 34} 35.files-list__file:hover { 36 background: #ccf; 37} 38.files-list__file > td { 39 padding: 10px; 40 border: 1px solid #999; 41} 42.files-list__file > td:first-child::before { 43 content: '\01F4C4'; 44 margin-right: 1em; 45} 46.files-list__file_low { 47 background: #fcc; 48} 49.files-list__file_medium { 50 background: #ffc; 51} 52.files-list__file_high { 53 background: #cfc; 54} 55.files-list__file_folder > td:first-child::before { 56 content: '\01F4C1'; 57 margin-right: 1em; 58} 59 60.file-header { 61 border: 1px solid #999; 62 display: flex; 63 justify-content: space-between; 64 align-items: center; 65} 66 67.file-header__back { 68 margin: 10px; 69 cursor: pointer; 70 flex-shrink: 0; 71 flex-grow: 0; 72 text-decoration: underline; 73 color: #338; 74} 75 76.file-header__name { 77 margin: 10px; 78 flex-shrink: 2; 79 flex-grow: 2; 80} 81 82.file-header__stat { 83 margin: 10px; 84 flex-shrink: 0; 85 flex-grow: 0; 86} 87 88.file-content { 89 margin: 10px 0 0; 90 border: 1px solid #999; 91 padding: 10px; 92} 93 94.code-line { 95 margin: 0; 96 padding: 0.3em; 97 height: 1em; 98} 99.code-line_covered { 100 background: #cfc; 101} 102.code-line_uncovered { 103 background: #fcc; 104} 105</style> 106</head> 107<body> 108 <div id="root"></div> 109 <script> 110 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}]}; 111 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}]}; 112 </script> 113 <script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script> 114 <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script> 115 <script>const e = React.createElement; 116 117function pathToString(path) { 118 if (path[0] === '/') { 119 return '/' + path.slice(1).join('/'); 120 } else { 121 return path.join('/'); 122 } 123} 124 125function findCommonPath(files) { 126 if (!files || !files.length) { 127 return []; 128 } 129 130 function isPrefix(arr, prefix) { 131 if (arr.length < prefix.length) { 132 return false; 133 } 134 for (let i = prefix.length - 1; i >= 0; --i) { 135 if (arr[i] !== prefix[i]) { 136 return false; 137 } 138 } 139 return true; 140 } 141 142 let commonPath = files[0].path.slice(0, -1); 143 while (commonPath.length) { 144 if (files.every(file => isPrefix(file.path, commonPath))) { 145 break; 146 } 147 commonPath.pop(); 148 } 149 return commonPath; 150} 151 152function findFolders(files) { 153 if (!files || !files.length) { 154 return []; 155 } 156 157 let folders = files.filter(file => file.path.length > 1).map(file => file.path[0]); 158 folders = [...new Set(folders)]; // unique 159 folders.sort(); 160 161 folders = folders.map(folder => { 162 let filesInFolder = files 163 .filter(file => file.path[0] === folder) 164 .map(file => ({ 165 ...file, 166 path: file.path.slice(1), 167 parent: [...file.parent, file.path[0]], 168 })); 169 170 const children = findFolders(filesInFolder); // recursion 171 172 return { 173 is_folder: true, 174 path: [folder], 175 parent: files[0].parent, 176 children, 177 covered: children.reduce((sum, file) => sum + file.covered, 0), 178 coverable: children.reduce((sum, file) => sum + file.coverable, 0), 179 prevRun: { 180 covered: children.reduce((sum, file) => sum + file.prevRun.covered, 0), 181 coverable: children.reduce((sum, file) => sum + file.prevRun.coverable, 0), 182 } 183 }; 184 }); 185 186 return [ 187 ...folders, 188 ...files.filter(file => file.path.length === 1), 189 ]; 190} 191 192class App extends React.Component { 193 constructor(...args) { 194 super(...args); 195 196 this.state = { 197 current: [], 198 }; 199 } 200 201 componentDidMount() { 202 this.updateStateFromLocation(); 203 window.addEventListener("hashchange", () => this.updateStateFromLocation(), false); 204 } 205 206 updateStateFromLocation() { 207 if (window.location.hash.length > 1) { 208 const current = window.location.hash.substr(1).split('/'); 209 this.setState({current}); 210 } else { 211 this.setState({current: []}); 212 } 213 } 214 215 getCurrentPath() { 216 let file = this.props.root; 217 let path = [file]; 218 for (let p of this.state.current) { 219 file = file.children.find(file => file.path[0] === p); 220 if (!file) { 221 return path; 222 } 223 path.push(file); 224 } 225 return path; 226 } 227 228 render() { 229 const path = this.getCurrentPath(); 230 const file = path[path.length - 1]; 231 232 let w = null; 233 if (file.is_folder) { 234 w = e(FilesList, { 235 folder: file, 236 onSelectFile: this.selectFile.bind(this), 237 onBack: path.length > 1 ? this.back.bind(this) : null, 238 }); 239 } else { 240 w = e(DisplayFile, { 241 file, 242 onBack: this.back.bind(this), 243 }); 244 } 245 246 return e('div', {className: 'app'}, w); 247 } 248 249 selectFile(file) { 250 this.setState(({current}) => { 251 return {current: [...current, file.path[0]]}; 252 }, () => this.updateHash()); 253 } 254 255 back(file) { 256 this.setState(({current}) => { 257 return {current: current.slice(0, current.length - 1)}; 258 }, () => this.updateHash()); 259 } 260 261 updateHash() { 262 if (!this.state.current || !this.state.current.length) { 263 window.location = '#'; 264 } else { 265 window.location = '#' + this.state.current.join('/'); 266 } 267 } 268} 269 270function FilesList({folder, onSelectFile, onBack}) { 271 let files = folder.children; 272 return e('div', {className: 'display-folder'}, 273 e(FileHeader, {file: folder, onBack}), 274 e('table', {className: 'files-list'}, 275 e('thead', {className: 'files-list__head'}, 276 e('tr', null, 277 e('th', null, "Path"), 278 e('th', null, "Coverage") 279 ) 280 ), 281 e('tbody', {className: 'files-list__body'}, 282 files.map(file => e(File, {file, onClick: onSelectFile})) 283 ) 284 ) 285 ); 286} 287 288function File({file, onClick}) { 289 const coverage = file.coverable ? file.covered / file.coverable * 100 : -1; 290 const coverageDelta = file.prevRun && 291 (file.covered / file.coverable * 100 - file.prevRun.covered / file.prevRun.coverable * 100); 292 293 return e('tr', { 294 className: 'files-list__file' 295 + (coverage >= 0 && coverage < 50 ? ' files-list__file_low': '') 296 + (coverage >= 50 && coverage < 80 ? ' files-list__file_medium': '') 297 + (coverage >= 80 ? ' files-list__file_high': '') 298 + (file.is_folder ? ' files-list__file_folder': ''), 299 onClick: () => onClick(file), 300 }, 301 e('td', null, pathToString(file.path)), 302 e('td', null, 303 file.covered + ' / ' + file.coverable + 304 (coverage >= 0 ? ' (' + coverage.toFixed(2) + '%)' : ''), 305 e('span', {title: 'Change from the previous run'}, 306 (coverageDelta ? ` (${coverageDelta > 0 ? '+' : ''}${coverageDelta.toFixed(2)}%)` : '')) 307 ) 308 ); 309} 310 311function DisplayFile({file, onBack}) { 312 return e('div', {className: 'display-file'}, 313 e(FileHeader, {file, onBack}), 314 e(FileContent, {file}) 315 ); 316} 317 318function FileHeader({file, onBack}) { 319 const coverage = file.covered / file.coverable * 100; 320 const coverageDelta = file.prevRun && (coverage - file.prevRun.covered / file.prevRun.coverable * 100); 321 322 return e('div', {className: 'file-header'}, 323 onBack ? e('a', {className: 'file-header__back', onClick: onBack}, 'Back') : null, 324 e('div', {className: 'file-header__name'}, pathToString([...file.parent, ...file.path])), 325 e('div', {className: 'file-header__stat'}, 326 'Covered: ' + file.covered + ' of ' + file.coverable + 327 (file.coverable ? ' (' + coverage.toFixed(2) + '%)' : ''), 328 e('span', {title: 'Change from the previous run'}, 329 (coverageDelta ? ` (${coverageDelta > 0 ? '+' : ''}${coverageDelta.toFixed(2)}%)` : '')) 330 ) 331 ); 332} 333 334function FileContent({file}) { 335 return e('div', {className: 'file-content'}, 336 file.content.split(/\r?\n/).map((line, index) => { 337 const trace = file.traces.find(trace => trace.line === index + 1); 338 const covered = trace && trace.stats.Line; 339 const uncovered = trace && !trace.stats.Line; 340 return e('pre', { 341 className: 'code-line' 342 + (covered ? ' code-line_covered' : '') 343 + (uncovered ? ' code-line_uncovered' : ''), 344 title: trace ? JSON.stringify(trace.stats, null, 2) : null, 345 }, line); 346 }) 347 ); 348} 349 350(function(){ 351 const commonPath = findCommonPath(data.files); 352 const prevFilesMap = new Map(); 353 354 previousData && previousData.files.forEach((file) => { 355 const path = file.path.slice(commonPath.length).join('/'); 356 prevFilesMap.set(path, file); 357 }); 358 359 const files = data.files.map((file) => { 360 const path = file.path.slice(commonPath.length); 361 const { covered = 0, coverable = 0 } = prevFilesMap.get(path.join('/')) || {}; 362 return { 363 ...file, 364 path, 365 parent: commonPath, 366 prevRun: { covered, coverable }, 367 }; 368 }); 369 370 const children = findFolders(files); 371 372 const root = { 373 is_folder: true, 374 children, 375 path: commonPath, 376 parent: [], 377 covered: children.reduce((sum, file) => sum + file.covered, 0), 378 coverable: children.reduce((sum, file) => sum + file.coverable, 0), 379 prevRun: { 380 covered: children.reduce((sum, file) => sum + file.prevRun.covered, 0), 381 coverable: children.reduce((sum, file) => sum + file.prevRun.coverable, 0), 382 } 383 }; 384 385 ReactDOM.render(e(App, {root, prevFilesMap}), document.getElementById('root')); 386}()); 387</script> 388</body> 389</html>