| <!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> |