From 796344009ccd0c131bd7ea62c6ca363a283bbc08 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Mon, 28 Jan 2019 17:29:24 -0800 Subject: [PATCH 01/24] Fix rand_jitter on older versions of rust In at least rust 1.26 on osx, rand_jitter has a compile error due to libc not being imported. I'm guessing this was fixed as part of the 2018 edition, which is why this isn't showing up on the stable build. --- rand_jitter/src/platform.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rand_jitter/src/platform.rs b/rand_jitter/src/platform.rs index f96d1cd7347..af531df0c3f 100644 --- a/rand_jitter/src/platform.rs +++ b/rand_jitter/src/platform.rs @@ -21,6 +21,8 @@ pub fn get_nstime() -> u64 { #[cfg(any(target_os = "macos", target_os = "ios"))] pub fn get_nstime() -> u64 { + use libc; + // On Mac OS and iOS std::time::SystemTime only has 1000ns resolution. // We use `mach_absolute_time` instead. This provides a CPU dependent // unit, to get real nanoseconds the result should by multiplied by From 11f51cb942370c51d10bcb247a96f6e32d0aa3a5 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Tue, 29 Jan 2019 10:23:08 +0000 Subject: [PATCH 02/24] rand_jitter: bump version to 0.1.1 --- rand_jitter/CHANGELOG.md | 4 ++++ rand_jitter/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/rand_jitter/CHANGELOG.md b/rand_jitter/CHANGELOG.md index 1e399169a2d..07587db64aa 100644 --- a/rand_jitter/CHANGELOG.md +++ b/rand_jitter/CHANGELOG.md @@ -4,5 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.1.1] - 2019-01-29 +- Fix for older rustc compilers on Mac OSX / iOS (#720) +- Misc. doc fixes + ## [0.1.0] - 2019-01-24 Initial release. diff --git a/rand_jitter/Cargo.toml b/rand_jitter/Cargo.toml index 52329fd26b7..c8774006f35 100644 --- a/rand_jitter/Cargo.toml +++ b/rand_jitter/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rand_jitter" -version = "0.1.0" +version = "0.1.1" authors = ["The Rand Project Developers"] license = "MIT/Apache-2.0" readme = "README.md" From 47794beb8fe01eefed311d236f96e6bf8740d080 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 29 Jan 2019 08:52:07 -0800 Subject: [PATCH 03/24] Run travis tests for 1.22.0 osx, stable on linux, nightly on osx Travis supports building on osx, but we aren't running the tests in a few configurations, like OSX with rust 1.22.0, native linux on stable, and OSX on nightly. This adds testers for these situations to make sure that bugs like #720 don't slip into the system again. --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.travis.yml b/.travis.yml index 7968b1d0a48..ff4017ac3e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,6 +60,9 @@ matrix: include: - rust: 1.22.0 env: DESCRIPTION="pinned stable Rust release" + os: + - linux + - osx script: # Differs from standard script: rand_pcg features - cargo test --lib --no-default-features @@ -77,6 +80,9 @@ matrix: - cargo test --manifest-path rand_jitter/Cargo.toml - cargo test --manifest-path rand_os/Cargo.toml + - rust: stable + env: DESCRIPTION="stable Rust release, linux" + - rust: stable env: DESCRIPTION="stable Rust release, macOS, iOS (cross-compile only)" os: osx @@ -104,6 +110,9 @@ matrix: env: DESCRIPTION="beta Rust release" - rust: nightly + os: + - linux + - osx env: DESCRIPTION="nightly features, benchmarks, documentation" install: - cargo --list | egrep "^\s*deadlinks$" -q || cargo install cargo-deadlinks From c03720809f2b16a85dc287776a84ea8860133b5e Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 30 Jan 2019 17:36:09 +0000 Subject: [PATCH 04/24] Fix rand_jitter on windows for older rust versions This is a similar issue to #720. --- rand_jitter/src/platform.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rand_jitter/src/platform.rs b/rand_jitter/src/platform.rs index af531df0c3f..8e3d0fb22fc 100644 --- a/rand_jitter/src/platform.rs +++ b/rand_jitter/src/platform.rs @@ -34,6 +34,8 @@ pub fn get_nstime() -> u64 { #[cfg(target_os = "windows")] pub fn get_nstime() -> u64 { + use winapi; + unsafe { let mut t = super::mem::zeroed(); winapi::um::profileapi::QueryPerformanceCounter(&mut t); From 734811aa658729307427f370e47a2ad837f1915b Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Thu, 31 Jan 2019 12:08:27 +0000 Subject: [PATCH 05/24] rand_jitter: bump version number to 0.1.2 --- rand_jitter/CHANGELOG.md | 3 +++ rand_jitter/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/rand_jitter/CHANGELOG.md b/rand_jitter/CHANGELOG.md index 07587db64aa..8aa3a1b9cbe 100644 --- a/rand_jitter/CHANGELOG.md +++ b/rand_jitter/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.1.2] - 2019-01-31 +- Fix for older rustc compilers on Windows (#722) + ## [0.1.1] - 2019-01-29 - Fix for older rustc compilers on Mac OSX / iOS (#720) - Misc. doc fixes diff --git a/rand_jitter/Cargo.toml b/rand_jitter/Cargo.toml index c8774006f35..03023657845 100644 --- a/rand_jitter/Cargo.toml +++ b/rand_jitter/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rand_jitter" -version = "0.1.1" +version = "0.1.2" authors = ["The Rand Project Developers"] license = "MIT/Apache-2.0" readme = "README.md" From af8a86dbdc10fce3d8ff9bf396564487bdb0d313 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 4 Feb 2019 10:44:14 +0000 Subject: [PATCH 06/24] rand_jitter: don't use std feature of libc --- rand_jitter/Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rand_jitter/Cargo.toml b/rand_jitter/Cargo.toml index 03023657845..59adc258b18 100644 --- a/rand_jitter/Cargo.toml +++ b/rand_jitter/Cargo.toml @@ -18,7 +18,9 @@ rand_core = { path = "../rand_core", version = "0.4" } log = { version = "0.4", optional = true } [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] -libc = "0.2" +# We don't need the 'use_std' feature and depending on it causes +# issues due to: https://github.com/rust-lang/cargo/issues/1197 +libc = { version = "0.2", default_features = false } [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3", features = ["profileapi"] } From 6357a4cb5d261f0c10b3830c0ce57b2e0c4a5b95 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 4 Feb 2019 10:46:43 +0000 Subject: [PATCH 07/24] rand: remove unused winapi dependency Both usages have moved to sub-crates now --- Cargo.toml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bbee73c88cc..1902f1a974b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,12 +65,9 @@ optional = true features = ["into_bits"] [target.'cfg(unix)'.dependencies] +# Used for fork protection (reseeding.rs) libc = { version = "0.2", default-features = false } -# TODO: check if all features are required -[target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["minwindef", "ntsecapi", "profileapi", "winnt"] } - [dev-dependencies] # This has a histogram implementation used for testing uniformity. average = "0.9.2" From 1ae59884f7d415cb54bac476c67732d57e08af90 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 4 Feb 2019 10:47:07 +0000 Subject: [PATCH 08/24] rand: support reseeding without libstd --- src/rngs/adapter/reseeding.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rngs/adapter/reseeding.rs b/src/rngs/adapter/reseeding.rs index ed2aab4cffa..a3e98c6d52e 100644 --- a/src/rngs/adapter/reseeding.rs +++ b/src/rngs/adapter/reseeding.rs @@ -282,12 +282,12 @@ where R: BlockRngCore + SeedableRng + CryptoRng, Rsdr: RngCore + CryptoRng {} -#[cfg(all(feature="std", unix, not(target_os="emscripten")))] +#[cfg(all(unix, not(target_os="emscripten")))] mod fork { extern crate libc; - use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; - use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT}; + use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; + use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT}; // Fork protection // @@ -323,7 +323,7 @@ mod fork { } } -#[cfg(not(all(feature="std", unix, not(target_os="emscripten"))))] +#[cfg(not(all(unix, not(target_os="emscripten"))))] mod fork { pub fn get_fork_counter() -> usize { 0 } pub fn register_fork_handler() {} From 4ca5ee360fe9280d5ae63681c8b84b1c92fb7e06 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 4 Feb 2019 10:52:19 +0000 Subject: [PATCH 09/24] rand_jitter: bump version number to 0.1.3 --- CHANGELOG.md | 4 ++++ rand_jitter/CHANGELOG.md | 3 +++ rand_jitter/Cargo.toml | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 955e872b093..5e6e3da14a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ A [separate changelog is kept for rand_core](rand_core/CHANGELOG.md). You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.html) useful. +## Unreleased +- Enable fork protection of ReseedingRng without `std` +- Remove dependency on `winapi` + ## [0.6.5] - 2019-01-28 ### Crates - Update `rand_core` to 0.4 (#703) diff --git a/rand_jitter/CHANGELOG.md b/rand_jitter/CHANGELOG.md index 8aa3a1b9cbe..961946e1d92 100644 --- a/rand_jitter/CHANGELOG.md +++ b/rand_jitter/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.1.3] - 2019-02-05 +- Use libc in `no_std` mode to fix #723 + ## [0.1.2] - 2019-01-31 - Fix for older rustc compilers on Windows (#722) diff --git a/rand_jitter/Cargo.toml b/rand_jitter/Cargo.toml index 59adc258b18..c8a350b0e0d 100644 --- a/rand_jitter/Cargo.toml +++ b/rand_jitter/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rand_jitter" -version = "0.1.2" +version = "0.1.3" authors = ["The Rand Project Developers"] license = "MIT/Apache-2.0" readme = "README.md" From 32f613bb68560c966c44e88dd91f551668a81d46 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 11 Feb 2019 15:34:29 +0000 Subject: [PATCH 10/24] Restrict doc deployment to Linux nightly --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ff4017ac3e4..a364da2a43c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -140,7 +140,7 @@ matrix: - cargo doc --no-deps --all --all-features - cargo deadlinks --dir target/doc after_success: - - travis-cargo --only nightly doc-upload + - test "$TRAVIS_OS_NAME" = "linux" && travis-cargo --only nightly doc-upload - rust: nightly env: DESCRIPTION="WASM via emscripten, stdweb and wasm-bindgen" From b9e3e95fec1b3d090e91ea17fc31515efcd82b96 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Tue, 12 Feb 2019 11:47:34 +0000 Subject: [PATCH 11/24] Add rustfmt configuration and accept a few of its changes --- examples/monte-carlo.rs | 36 ++++---- examples/monty-hall.rs | 7 +- rustfmt.toml | 32 +++++++ src/lib.rs | 19 ++-- src/seq/index.rs | 16 ++-- src/seq/mod.rs | 190 +++++++++++++++++++++------------------- tests/uniformity.rs | 8 +- 7 files changed, 176 insertions(+), 132 deletions(-) create mode 100644 rustfmt.toml diff --git a/examples/monte-carlo.rs b/examples/monte-carlo.rs index 91629968610..b79c6a5afa0 100644 --- a/examples/monte-carlo.rs +++ b/examples/monte-carlo.rs @@ -11,7 +11,7 @@ //! //! Imagine that we have a square with sides of length 2 and a unit circle //! (radius = 1), both centered at the origin. The areas are: -//! +//! //! ```text //! area of circle = πr² = π * r * r = π //! area of square = 2² = 4 @@ -24,7 +24,7 @@ //! the square at random, calculate the fraction that fall within the circle, //! and multiply this fraction by 4. -#![cfg(feature="std")] +#![cfg(feature = "std")] extern crate rand; @@ -32,20 +32,20 @@ extern crate rand; use rand::distributions::{Distribution, Uniform}; fn main() { - let range = Uniform::new(-1.0f64, 1.0); - let mut rng = rand::thread_rng(); - - let total = 1_000_000; - let mut in_circle = 0; - - for _ in 0..total { - let a = range.sample(&mut rng); - let b = range.sample(&mut rng); - if a*a + b*b <= 1.0 { - in_circle += 1; - } - } - - // prints something close to 3.14159... - println!("π is approximately {}", 4. * (in_circle as f64) / (total as f64)); + let range = Uniform::new(-1.0f64, 1.0); + let mut rng = rand::thread_rng(); + + let total = 1_000_000; + let mut in_circle = 0; + + for _ in 0..total { + let a = range.sample(&mut rng); + let b = range.sample(&mut rng); + if a*a + b*b <= 1.0 { + in_circle += 1; + } + } + + // prints something close to 3.14159... + println!("π is approximately {}", 4. * (in_circle as f64) / (total as f64)); } diff --git a/examples/monty-hall.rs b/examples/monty-hall.rs index 0932c5efb51..643fbb5116e 100644 --- a/examples/monty-hall.rs +++ b/examples/monty-hall.rs @@ -26,13 +26,13 @@ //! //! [Monty Hall Problem]: https://en.wikipedia.org/wiki/Monty_Hall_problem -#![cfg(feature="std")] +#![cfg(feature = "std")] extern crate rand; -use rand::Rng; use rand::distributions::{Distribution, Uniform}; +use rand::Rng; struct SimulationResult { win: bool, @@ -40,8 +40,7 @@ struct SimulationResult { } // Run a single simulation of the Monty Hall problem. -fn simulate(random_door: &Uniform, rng: &mut R) - -> SimulationResult { +fn simulate(random_door: &Uniform, rng: &mut R) -> SimulationResult { let car = random_door.sample(rng); // This is our initial choice diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 00000000000..4fe708f4c55 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,32 @@ +# This rustfmt file is added for configuration, but in practice much of our +# code is hand-formatted, frequently with more readable results. + +# Comments: +normalize_comments = true +wrap_comments = false +format_doc_comments = true +comment_width = 90 # small excess is okay but prefer 80 + +# Arguments: +use_small_heuristics = "max" +fn_args_density = "compressed" +fn_single_line = false +overflow_delimited_expr = true +where_single_line = true + +# enum_discrim_align_threshold = 20 +# struct_field_align_threshold = 20 + +# Compatibility: +use_try_shorthand = true # stable since Rustc 1.13.0 +use_field_init_shorthand = true # stable since Rustc 1.17.0 +edition = "2015" # we require compatibility back to 1.22.0 + +# Misc: +blank_lines_upper_bound = 2 +reorder_impl_items = true +# report_todo = "Unnumbered" +# report_fixme = "Unnumbered" + +# Ignored files: +ignore = [] diff --git a/src/lib.rs b/src/lib.rs index 9c0482f328e..419dd812fb2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -211,7 +211,8 @@ pub trait Rng: RngCore { /// println!("{:?}", rng.gen::<(f64, bool)>()); /// ``` #[inline] - fn gen(&mut self) -> T where Standard: Distribution { + fn gen(&mut self) -> T + where Standard: Distribution { Standard.sample(self) } @@ -240,8 +241,10 @@ pub trait Rng: RngCore { /// /// [`Uniform`]: distributions::uniform::Uniform fn gen_range(&mut self, low: B1, high: B2) -> T - where B1: SampleBorrow + Sized, - B2: SampleBorrow + Sized { + where + B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized, + { T::Sampler::sample_single(low, high, self) } @@ -290,9 +293,10 @@ pub trait Rng: RngCore { /// println!("Not a 6; rolling again!"); /// } /// ``` - fn sample_iter<'a, T, D: Distribution>(&'a mut self, distr: &'a D) - -> distributions::DistIter<'a, D, Self, T> where Self: Sized - { + fn sample_iter<'a, T, D: Distribution>( + &'a mut self, distr: &'a D, + ) -> distributions::DistIter<'a, D, Self, T> + where Self: Sized { distr.sample_iter(self) } @@ -649,7 +653,8 @@ impl FromEntropy for R { /// [`Standard`]: distributions::Standard #[cfg(feature="std")] #[inline] -pub fn random() -> T where Standard: Distribution { +pub fn random() -> T +where Standard: Distribution { thread_rng().gen() } diff --git a/src/seq/index.rs b/src/seq/index.rs index a70c7367f85..c64357acc3b 100644 --- a/src/seq/index.rs +++ b/src/seq/index.rs @@ -173,14 +173,13 @@ impl ExactSizeIterator for IndexVecIntoIter {} /// Note that performance is significantly better over `u32` indices than over /// `u64` indices. Because of this we hide the underlying type behind an /// abstraction, `IndexVec`. -/// +/// /// If an allocation-free `no_std` function is required, it is suggested /// to adapt the internal `sample_floyd` implementation. /// /// Panics if `amount > length`. pub fn sample(rng: &mut R, length: usize, amount: usize) -> IndexVec - where R: Rng + ?Sized, -{ +where R: Rng + ?Sized { if amount > length { panic!("`amount` of samples must be less than or equal to `length`"); } @@ -227,8 +226,7 @@ pub fn sample(rng: &mut R, length: usize, amount: usize) -> IndexVec /// /// This implementation uses `O(amount)` memory and `O(amount^2)` time. fn sample_floyd(rng: &mut R, length: u32, amount: u32) -> IndexVec - where R: Rng + ?Sized, -{ +where R: Rng + ?Sized { // For small amount we use Floyd's fully-shuffled variant. For larger // amounts this is slow due to Vec::insert performance, so we shuffle // afterwards. Benchmarks show little overhead from extra logic. @@ -274,8 +272,7 @@ fn sample_floyd(rng: &mut R, length: u32, amount: u32) -> IndexVec /// /// Set-up is `O(length)` time and memory and shuffling is `O(amount)` time. fn sample_inplace(rng: &mut R, length: u32, amount: u32) -> IndexVec - where R: Rng + ?Sized, -{ +where R: Rng + ?Sized { debug_assert!(amount <= length); let mut indices: Vec = Vec::with_capacity(length as usize); indices.extend(0..length); @@ -290,13 +287,12 @@ fn sample_inplace(rng: &mut R, length: u32, amount: u32) -> IndexVec /// Randomly sample exactly `amount` indices from `0..length`, using rejection /// sampling. -/// +/// /// Since `amount <<< length` there is a low chance of a random sample in /// `0..length` being a duplicate. We test for duplicates and resample where /// necessary. The algorithm is `O(amount)` time and memory. fn sample_rejection(rng: &mut R, length: usize, amount: usize) -> IndexVec - where R: Rng + ?Sized, -{ +where R: Rng + ?Sized { debug_assert!(amount < length); #[cfg(feature="std")] let mut cache = HashSet::with_capacity(amount); #[cfg(not(feature="std"))] let mut cache = BTreeSet::new(); diff --git a/src/seq/mod.rs b/src/seq/mod.rs index d0f83084a66..eff8a8817f6 100644 --- a/src/seq/mod.rs +++ b/src/seq/mod.rs @@ -46,33 +46,33 @@ pub trait SliceRandom { /// assert_eq!(choices[..0].choose(&mut rng), None); /// ``` fn choose(&self, rng: &mut R) -> Option<&Self::Item> - where R: Rng + ?Sized; + where R: Rng + ?Sized; /// Returns a mutable reference to one random element of the slice, or /// `None` if the slice is empty. - /// + /// /// Depending on the implementation, complexity is expected to be `O(1)`. fn choose_mut(&mut self, rng: &mut R) -> Option<&mut Self::Item> - where R: Rng + ?Sized; + where R: Rng + ?Sized; /// Produces an iterator that chooses `amount` elements from the slice at /// random without repeating any, and returns them in random order. - /// + /// /// In case this API is not sufficiently flexible, use `index::sample` then /// apply the indices to the slice. - /// + /// /// Complexity is expected to be the same as `index::sample`. - /// + /// /// # Example /// ``` /// use rand::seq::SliceRandom; - /// + /// /// let mut rng = &mut rand::thread_rng(); /// let sample = "Hello, audience!".as_bytes(); - /// + /// /// // collect the results into a vector: /// let v: Vec = sample.choose_multiple(&mut rng, 3).cloned().collect(); - /// + /// /// // store in a buffer: /// let mut buf = [0u8; 5]; /// for (b, slot) in sample.choose_multiple(&mut rng, buf.len()).zip(buf.iter_mut()) { @@ -81,7 +81,7 @@ pub trait SliceRandom { /// ``` #[cfg(feature = "alloc")] fn choose_multiple(&self, rng: &mut R, amount: usize) -> SliceChooseIter - where R: Rng + ?Sized; + where R: Rng + ?Sized; /// Similar to [`choose`], where the likelihood of each outcome may be /// specified. The specified function `weight` maps items `x` to a relative @@ -100,15 +100,18 @@ pub trait SliceRandom { /// ``` /// [`choose`]: SliceRandom::choose #[cfg(feature = "alloc")] - fn choose_weighted(&self, rng: &mut R, weight: F) -> Result<&Self::Item, WeightedError> - where R: Rng + ?Sized, - F: Fn(&Self::Item) -> B, - B: SampleBorrow, - X: SampleUniform + - for<'a> ::core::ops::AddAssign<&'a X> + - ::core::cmp::PartialOrd + - Clone + - Default; + fn choose_weighted( + &self, rng: &mut R, weight: F, + ) -> Result<&Self::Item, WeightedError> + where + R: Rng + ?Sized, + F: Fn(&Self::Item) -> B, + B: SampleBorrow, + X: SampleUniform + + for<'a> ::core::ops::AddAssign<&'a X> + + ::core::cmp::PartialOrd + + Clone + + Default; /// Similar to [`choose_mut`], where the likelihood of each outcome may be /// specified. The specified function `weight` maps items `x` to a relative @@ -120,25 +123,28 @@ pub trait SliceRandom { /// [`choose_mut`]: SliceRandom::choose_mut /// [`choose_weighted`]: SliceRandom::choose_weighted #[cfg(feature = "alloc")] - fn choose_weighted_mut(&mut self, rng: &mut R, weight: F) -> Result<&mut Self::Item, WeightedError> - where R: Rng + ?Sized, - F: Fn(&Self::Item) -> B, - B: SampleBorrow, - X: SampleUniform + - for<'a> ::core::ops::AddAssign<&'a X> + - ::core::cmp::PartialOrd + - Clone + - Default; + fn choose_weighted_mut( + &mut self, rng: &mut R, weight: F, + ) -> Result<&mut Self::Item, WeightedError> + where + R: Rng + ?Sized, + F: Fn(&Self::Item) -> B, + B: SampleBorrow, + X: SampleUniform + + for<'a> ::core::ops::AddAssign<&'a X> + + ::core::cmp::PartialOrd + + Clone + + Default; /// Shuffle a mutable slice in place. - /// + /// /// Depending on the implementation, complexity is expected to be `O(1)`. /// /// # Example /// /// ``` - /// use rand::thread_rng; /// use rand::seq::SliceRandom; + /// use rand::thread_rng; /// /// let mut rng = thread_rng(); /// let mut y = [1, 2, 3, 4, 5]; @@ -146,7 +152,8 @@ pub trait SliceRandom { /// y.shuffle(&mut rng); /// println!("Shuffled: {:?}", y); /// ``` - fn shuffle(&mut self, rng: &mut R) where R: Rng + ?Sized; + fn shuffle(&mut self, rng: &mut R) + where R: Rng + ?Sized; /// Shuffle a slice in place, but exit early. /// @@ -165,8 +172,10 @@ pub trait SliceRandom { /// will perform a full shuffle. /// /// Complexity is expected to be `O(m)` where `m = amount`. - fn partial_shuffle(&mut self, rng: &mut R, amount: usize) - -> (&mut [Self::Item], &mut [Self::Item]) where R: Rng + ?Sized; + fn partial_shuffle( + &mut self, rng: &mut R, amount: usize, + ) -> (&mut [Self::Item], &mut [Self::Item]) + where R: Rng + ?Sized; } /// Extension trait on iterators, providing random sampling methods. @@ -176,7 +185,7 @@ pub trait IteratorRandom: Iterator + Sized { /// functions using the slice instead. /// /// Returns `None` if and only if the iterator is empty. - /// + /// /// Complexity is `O(n)`, where `n` is the length of the iterator. /// This likely consumes multiple random numbers, but the exact number /// is unspecified. @@ -184,8 +193,7 @@ pub trait IteratorRandom: Iterator + Sized { /// [`choose`]: SliceRandom::method.choose /// [`choose_mut`]: SliceRandom::choose_mut fn choose(mut self, rng: &mut R) -> Option - where R: Rng + ?Sized - { + where R: Rng + ?Sized { let (mut lower, mut upper) = self.size_hint(); let mut consumed = 0; let mut result = None; @@ -232,19 +240,18 @@ pub trait IteratorRandom: Iterator + Sized { /// Collects `amount` values at random from the iterator into a supplied /// buffer. - /// + /// /// Although the elements are selected randomly, the order of elements in /// the buffer is neither stable nor fully random. If random ordering is /// desired, shuffle the result. - /// + /// /// Returns the number of elements added to the buffer. This equals `amount` /// unless the iterator contains insufficient elements, in which case this /// equals the number of elements available. - /// + /// /// Complexity is `O(n)` where `n` is the length of the iterator. - fn choose_multiple_fill(mut self, rng: &mut R, buf: &mut [Self::Item]) - -> usize where R: Rng + ?Sized - { + fn choose_multiple_fill(mut self, rng: &mut R, buf: &mut [Self::Item]) -> usize + where R: Rng + ?Sized { let amount = buf.len(); let mut len = 0; while len < amount { @@ -274,16 +281,15 @@ pub trait IteratorRandom: Iterator + Sized { /// Although the elements are selected randomly, the order of elements in /// the buffer is neither stable nor fully random. If random ordering is /// desired, shuffle the result. - /// + /// /// The length of the returned vector equals `amount` unless the iterator /// contains insufficient elements, in which case it equals the number of /// elements available. - /// + /// /// Complexity is `O(n)` where `n` is the length of the iterator. #[cfg(feature = "alloc")] fn choose_multiple(mut self, rng: &mut R, amount: usize) -> Vec - where R: Rng + ?Sized - { + where R: Rng + ?Sized { let mut reservoir = Vec::with_capacity(amount); reservoir.extend(self.by_ref().take(amount)); @@ -312,8 +318,7 @@ impl SliceRandom for [T] { type Item = T; fn choose(&self, rng: &mut R) -> Option<&Self::Item> - where R: Rng + ?Sized - { + where R: Rng + ?Sized { if self.is_empty() { None } else { @@ -322,8 +327,7 @@ impl SliceRandom for [T] { } fn choose_mut(&mut self, rng: &mut R) -> Option<&mut Self::Item> - where R: Rng + ?Sized - { + where R: Rng + ?Sized { if self.is_empty() { None } else { @@ -333,10 +337,8 @@ impl SliceRandom for [T] { } #[cfg(feature = "alloc")] - fn choose_multiple(&self, rng: &mut R, amount: usize) - -> SliceChooseIter - where R: Rng + ?Sized - { + fn choose_multiple(&self, rng: &mut R, amount: usize) -> SliceChooseIter + where R: Rng + ?Sized { let amount = ::core::cmp::min(amount, self.len()); SliceChooseIter { slice: self, @@ -346,54 +348,63 @@ impl SliceRandom for [T] { } #[cfg(feature = "alloc")] - fn choose_weighted(&self, rng: &mut R, weight: F) -> Result<&Self::Item, WeightedError> - where R: Rng + ?Sized, - F: Fn(&Self::Item) -> B, - B: SampleBorrow, - X: SampleUniform + - for<'a> ::core::ops::AddAssign<&'a X> + - ::core::cmp::PartialOrd + - Clone + - Default { + fn choose_weighted( + &self, rng: &mut R, weight: F, + ) -> Result<&Self::Item, WeightedError> + where + R: Rng + ?Sized, + F: Fn(&Self::Item) -> B, + B: SampleBorrow, + X: SampleUniform + + for<'a> ::core::ops::AddAssign<&'a X> + + ::core::cmp::PartialOrd + + Clone + + Default, + { use distributions::{Distribution, WeightedIndex}; let distr = WeightedIndex::new(self.iter().map(weight))?; Ok(&self[distr.sample(rng)]) } #[cfg(feature = "alloc")] - fn choose_weighted_mut(&mut self, rng: &mut R, weight: F) -> Result<&mut Self::Item, WeightedError> - where R: Rng + ?Sized, - F: Fn(&Self::Item) -> B, - B: SampleBorrow, - X: SampleUniform + - for<'a> ::core::ops::AddAssign<&'a X> + - ::core::cmp::PartialOrd + - Clone + - Default { + fn choose_weighted_mut( + &mut self, rng: &mut R, weight: F, + ) -> Result<&mut Self::Item, WeightedError> + where + R: Rng + ?Sized, + F: Fn(&Self::Item) -> B, + B: SampleBorrow, + X: SampleUniform + + for<'a> ::core::ops::AddAssign<&'a X> + + ::core::cmp::PartialOrd + + Clone + + Default, + { use distributions::{Distribution, WeightedIndex}; let distr = WeightedIndex::new(self.iter().map(weight))?; Ok(&mut self[distr.sample(rng)]) } - fn shuffle(&mut self, rng: &mut R) where R: Rng + ?Sized - { + fn shuffle(&mut self, rng: &mut R) + where R: Rng + ?Sized { for i in (1..self.len()).rev() { // invariant: elements with index > i have been locked in place. self.swap(i, rng.gen_range(0, i + 1)); } } - fn partial_shuffle(&mut self, rng: &mut R, amount: usize) - -> (&mut [Self::Item], &mut [Self::Item]) where R: Rng + ?Sized - { + fn partial_shuffle( + &mut self, rng: &mut R, amount: usize, + ) -> (&mut [Self::Item], &mut [Self::Item]) + where R: Rng + ?Sized { // This applies Durstenfeld's algorithm for the // [Fisher–Yates shuffle](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm) // for an unbiased permutation, but exits early after choosing `amount` // elements. - + let len = self.len(); let end = if amount >= len { 0 } else { len - amount }; - + for i in (end..len).rev() { // invariant: elements with index > i have been locked in place. self.swap(i, rng.gen_range(0, i + 1)); @@ -423,7 +434,7 @@ impl<'a, S: Index + ?Sized + 'a, T: 'a> Iterator for SliceCho // TODO: investigate using SliceIndex::get_unchecked when stable self.indices.next().map(|i| &self.slice[i as usize]) } - + fn size_hint(&self) -> (usize, Option) { (self.indices.len(), Some(self.indices.len())) } @@ -443,10 +454,11 @@ impl<'a, S: Index + ?Sized + 'a, T: 'a> ExactSizeIterator /// /// Deprecated: use [`IteratorRandom::choose_multiple`] instead. #[cfg(feature = "alloc")] -#[deprecated(since="0.6.0", note="use IteratorRandom::choose_multiple instead")] +#[deprecated(since = "0.6.0", note = "use IteratorRandom::choose_multiple instead")] pub fn sample_iter(rng: &mut R, iterable: I, amount: usize) -> Result, Vec> - where I: IntoIterator, - R: Rng + ?Sized, +where + I: IntoIterator, + R: Rng + ?Sized, { use seq::IteratorRandom; let iter = iterable.into_iter(); @@ -468,10 +480,11 @@ pub fn sample_iter(rng: &mut R, iterable: I, amount: usize) -> Result(rng: &mut R, slice: &[T], amount: usize) -> Vec - where R: Rng + ?Sized, - T: Clone +where + R: Rng + ?Sized, + T: Clone, { let indices = index::sample(rng, slice.len(), amount).into_iter(); @@ -490,10 +503,9 @@ pub fn sample_slice(rng: &mut R, slice: &[T], amount: usize) -> Vec /// /// Deprecated: use [`SliceRandom::choose_multiple`] instead. #[cfg(feature = "alloc")] -#[deprecated(since="0.6.0", note="use SliceRandom::choose_multiple instead")] +#[deprecated(since = "0.6.0", note = "use SliceRandom::choose_multiple instead")] pub fn sample_slice_ref<'a, R, T>(rng: &mut R, slice: &'a [T], amount: usize) -> Vec<&'a T> - where R: Rng + ?Sized -{ +where R: Rng + ?Sized { let indices = index::sample(rng, slice.len(), amount).into_iter(); let mut out = Vec::with_capacity(amount); diff --git a/tests/uniformity.rs b/tests/uniformity.rs index b8f74a62e5b..3b9c7493e14 100644 --- a/tests/uniformity.rs +++ b/tests/uniformity.rs @@ -12,10 +12,10 @@ extern crate average; extern crate rand; -use std as core; -use rand::FromEntropy; -use rand::distributions::Distribution; use average::Histogram; +use rand::distributions::Distribution; +use rand::FromEntropy; +use std as core; const N_BINS: usize = 100; const N_SAMPLES: u32 = 1_000_000; @@ -50,7 +50,7 @@ fn unit_sphere() { #[test] fn unit_circle() { - use ::std::f64::consts::PI; + use std::f64::consts::PI; let mut h = Histogram100::with_const_width(-PI, PI); let dist = rand::distributions::UnitCircle::new(); let mut rng = rand::rngs::SmallRng::from_entropy(); From 23f0a5139bb91099b0011b0cd1e1972696e959cf Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Fri, 15 Feb 2019 09:24:22 +0000 Subject: [PATCH 12/24] =?UTF-8?q?Implement=20Standard=20support=20for=20No?= =?UTF-8?q?nZero*=20types=20(Rustc=20=E2=89=A5=201.28)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- benches/distributions.rs | 27 +++++++++++++++++++++++++++ build.rs | 1 + src/distributions/integer.rs | 23 +++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/benches/distributions.rs b/benches/distributions.rs index 069a82856a5..56a8d43b791 100644 --- a/benches/distributions.rs +++ b/benches/distributions.rs @@ -14,6 +14,8 @@ extern crate rand; const RAND_BENCH_N: u64 = 1000; use std::mem::size_of; +#[cfg(rustc_1_28)] +use std::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128}; use test::Bencher; use std::time::Duration; @@ -41,6 +43,26 @@ macro_rules! distr_int { } } +macro_rules! distr_nz_int { + ($fnn:ident, $tynz:ty, $ty:ty, $distr:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = SmallRng::from_entropy(); + let distr = $distr; + + b.iter(|| { + let mut accum = 0 as $ty; + for _ in 0..::RAND_BENCH_N { + let x: $tynz = distr.sample(&mut rng); + accum = accum.wrapping_add(x.get()); + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N; + } + } +} + macro_rules! distr_float { ($fnn:ident, $ty:ty, $distr:expr) => { #[bench] @@ -156,6 +178,11 @@ distr_int!(distr_standard_i16, i16, Standard); distr_int!(distr_standard_i32, i32, Standard); distr_int!(distr_standard_i64, i64, Standard); distr_int!(distr_standard_i128, i128, Standard); +#[cfg(rustc_1_28)] distr_nz_int!(distr_standard_nz8, NonZeroU8, u8, Standard); +#[cfg(rustc_1_28)] distr_nz_int!(distr_standard_nz16, NonZeroU16, u16, Standard); +#[cfg(rustc_1_28)] distr_nz_int!(distr_standard_nz32, NonZeroU32, u32, Standard); +#[cfg(rustc_1_28)] distr_nz_int!(distr_standard_nz64, NonZeroU64, u64, Standard); +#[cfg(rustc_1_28)] distr_nz_int!(distr_standard_nz128, NonZeroU128, u128, Standard); distr!(distr_standard_bool, bool, Standard); distr!(distr_standard_alphanumeric, char, Alphanumeric); diff --git a/build.rs b/build.rs index a554ad9875e..c5085c98041 100644 --- a/build.rs +++ b/build.rs @@ -7,4 +7,5 @@ fn main() { ac.emit_rustc_version(1, 25); ac.emit_rustc_version(1, 26); ac.emit_rustc_version(1, 27); + ac.emit_rustc_version(1, 28); } diff --git a/src/distributions/integer.rs b/src/distributions/integer.rs index 7e408dbf1b2..973f8940cac 100644 --- a/src/distributions/integer.rs +++ b/src/distributions/integer.rs @@ -10,6 +10,8 @@ use {Rng}; use distributions::{Distribution, Standard}; +#[cfg(rustc_1_28)] +use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize}; #[cfg(feature="simd_support")] use packed_simd::*; #[cfg(all(target_arch = "x86", feature="nightly"))] @@ -88,6 +90,27 @@ impl_int_from_uint! { i64, u64 } #[cfg(all(rustc_1_26, not(target_os = "emscripten")))] impl_int_from_uint! { i128, u128 } impl_int_from_uint! { isize, usize } +macro_rules! impl_nzint { + ($ty:ty, $new:path) => { + impl Distribution<$ty> for Standard { + fn sample(&self, rng: &mut R) -> $ty { + loop { + if let Some(nz) = $new(rng.gen()) { + break nz; + } + } + } + } + } +} + +#[cfg(rustc_1_28)] impl_nzint!(NonZeroU8, NonZeroU8::new); +#[cfg(rustc_1_28)] impl_nzint!(NonZeroU16, NonZeroU16::new); +#[cfg(rustc_1_28)] impl_nzint!(NonZeroU32, NonZeroU32::new); +#[cfg(rustc_1_28)] impl_nzint!(NonZeroU64, NonZeroU64::new); +#[cfg(all(rustc_1_28, not(target_os = "emscripten")))] impl_nzint!(NonZeroU128, NonZeroU128::new); +#[cfg(rustc_1_28)] impl_nzint!(NonZeroUsize, NonZeroUsize::new); + #[cfg(feature="simd_support")] macro_rules! simd_impl { ($(($intrinsic:ident, $vec:ty),)+) => {$( From bc0c8da28f1fae55cfc177daf2314bc169dd6954 Mon Sep 17 00:00:00 2001 From: Jason King Date: Wed, 6 Feb 2019 05:40:57 +0000 Subject: [PATCH 13/24] 637 Solaris getrandom() support breaks illumos --- rand_os/src/lib.rs | 6 +- rand_os/src/{solaris.rs => solarish.rs} | 87 +++++++++++++++---------- 2 files changed, 57 insertions(+), 36 deletions(-) rename rand_os/src/{solaris.rs => solarish.rs} (68%) diff --git a/rand_os/src/lib.rs b/rand_os/src/lib.rs index 907c6298d47..1b9cb254827 100644 --- a/rand_os/src/lib.rs +++ b/rand_os/src/lib.rs @@ -283,7 +283,8 @@ trait OsRngImpl where Self: Sized { #[cfg(any(target_os = "linux", target_os = "android", target_os = "netbsd", target_os = "dragonfly", target_os = "solaris", target_os = "redox", - target_os = "haiku", target_os = "emscripten"))] + target_os = "haiku", target_os = "emscripten", + target_os = "illumos"))] mod random_device; macro_rules! mod_use { @@ -309,7 +310,7 @@ mod_use!(cfg(target_os = "macos"), macos); mod_use!(cfg(target_os = "netbsd"), netbsd); mod_use!(cfg(target_os = "openbsd"), openbsd_bitrig); mod_use!(cfg(target_os = "redox"), redox); -mod_use!(cfg(target_os = "solaris"), solaris); +mod_use!(cfg(any(target_os = "solaris", target_os = "illumos")), solarish); mod_use!(cfg(windows), windows); mod_use!(cfg(target_env = "sgx"), sgx); @@ -376,6 +377,7 @@ mod imp { target_os = "openbsd", target_os = "redox", target_os = "solaris", + target_os = "illumos", windows, target_arch = "wasm32", target_env = "sgx" diff --git a/rand_os/src/solaris.rs b/rand_os/src/solarish.rs similarity index 68% rename from rand_os/src/solaris.rs rename to rand_os/src/solarish.rs index e8965fd92cc..72b955d0ff8 100644 --- a/rand_os/src/solaris.rs +++ b/rand_os/src/solarish.rs @@ -28,8 +28,9 @@ use std::io; use std::io::Read; use std::fs::{File, OpenOptions}; use std::os::unix::fs::OpenOptionsExt; -use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; +use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering, AtomicUsize}; use std::cmp; +use std::mem; #[derive(Clone, Debug)] pub struct OsRng { @@ -97,9 +98,10 @@ impl OsRngImpl for OsRng { } fn max_chunk_size(&self) -> usize { - // The documentation says 1024 is the maximum for getrandom, but - // 1040 for /dev/random. - 1024 + // This is the largest size that's guaranteed to not block across + // all the Solarish platforms, though some may allow for larger + // sizes. + 256 } fn method_str(&self) -> &'static str { @@ -110,18 +112,50 @@ impl OsRngImpl for OsRng { } } -fn getrandom(buf: &mut [u8], blocking: bool) -> libc::c_long { - extern "C" { - fn syscall(number: libc::c_long, ...) -> libc::c_long; - } +#[cfg(target_os = "illumos")] +type GetRandomFn = unsafe extern fn(*mut u8, libc::size_t, libc::c_uint) + -> libc::ssize_t; +#[cfg(target_os = "solaris")] +type GetRandomFn = unsafe extern fn(*mut u8, libc::size_t, libc::c_uint) + -> libc::c_int; + +// Use dlsym to determine if getrandom(2) is present in libc. On Solarish +// systems, the syscall interface is not stable and can change between +// updates. Even worse, issuing unsupported syscalls will cause the system +// to generate a SIGSYS signal (usually terminating the program). +// Instead the stable APIs are exposed via libc. Cache the result of the +// lookup for future calls. This is loosely modeled after the +// libstd::sys::unix::weak macro which unfortunately is not exported. +fn fetch() -> Option<&'static GetRandomFn> { + static FPTR: AtomicUsize = AtomicUsize::new(1); - const SYS_GETRANDOM: libc::c_long = 143; + unsafe { + if FPTR.load(Ordering::SeqCst) == 1 { + let name = "getrandom\0"; + let addr = libc::dlsym(libc::RTLD_DEFAULT, + name.as_ptr() as *const _) as usize; + FPTR.store(addr, Ordering::SeqCst); + } + + if FPTR.load(Ordering::SeqCst) == 0 { + return None; + } else { + mem::transmute::<&AtomicUsize, Option<&GetRandomFn>>(&FPTR) + } + } +} + +fn getrandom(buf: &mut [u8], blocking: bool) -> libc::ssize_t { const GRND_NONBLOCK: libc::c_uint = 0x0001; const GRND_RANDOM: libc::c_uint = 0x0002; - unsafe { - syscall(SYS_GETRANDOM, buf.as_mut_ptr(), buf.len(), - if blocking { 0 } else { GRND_NONBLOCK } | GRND_RANDOM) + if let Some(rand) = fetch() { + unsafe { + rand(buf.as_mut_ptr(), buf.len(), + if blocking { 0 } else { GRND_NONBLOCK } | GRND_RANDOM) as libc::ssize_t + } + } else { + -1 } } @@ -143,7 +177,7 @@ fn getrandom_try_fill(dest: &mut [u8], blocking: bool) -> Result<(), Error> { err, )); } - } else if result != dest.len() as i64 { + } else if result != dest.len() as libc::ssize_t { return Err(Error::new(ErrorKind::Unavailable, "unexpected getrandom error")); } @@ -151,25 +185,10 @@ fn getrandom_try_fill(dest: &mut [u8], blocking: bool) -> Result<(), Error> { } fn is_getrandom_available() -> bool { - use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; - use std::sync::{Once, ONCE_INIT}; - - static CHECKER: Once = ONCE_INIT; - static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT; - - CHECKER.call_once(|| { - debug!("OsRng: testing getrandom"); - let mut buf: [u8; 0] = []; - let result = getrandom(&mut buf, false); - let available = if result == -1 { - let err = io::Error::last_os_error().raw_os_error(); - err != Some(libc::ENOSYS) - } else { - true - }; - AVAILABLE.store(available, Ordering::Relaxed); - info!("OsRng: using {}", if available { "getrandom" } else { "/dev/random" }); - }); - - AVAILABLE.load(Ordering::Relaxed) + let available = match fetch() { + Some(_) => true, + None => false, + }; + info!("OsRng: using {}", if available { "getrandom" } else { "/dev/random" }); + available } From d80f5c1211289e96f8a67ae35b9b54772674ad45 Mon Sep 17 00:00:00 2001 From: Jason King Date: Sat, 16 Feb 2019 21:11:35 +0000 Subject: [PATCH 14/24] Minimize unsafe regions --- rand_os/src/solarish.rs | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/rand_os/src/solarish.rs b/rand_os/src/solarish.rs index 72b955d0ff8..952643fa7d7 100644 --- a/rand_os/src/solarish.rs +++ b/rand_os/src/solarish.rs @@ -126,23 +126,21 @@ type GetRandomFn = unsafe extern fn(*mut u8, libc::size_t, libc::c_uint) // Instead the stable APIs are exposed via libc. Cache the result of the // lookup for future calls. This is loosely modeled after the // libstd::sys::unix::weak macro which unfortunately is not exported. -fn fetch() -> Option<&'static GetRandomFn> { +fn fetch() -> Option { static FPTR: AtomicUsize = AtomicUsize::new(1); + if FPTR.load(Ordering::SeqCst) == 1 { + let name = "getrandom\0"; + let addr = unsafe { + libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _) as usize + }; + FPTR.store(addr, Ordering::SeqCst); + } + + let ptr = FPTR.load(Ordering::SeqCst); unsafe { - if FPTR.load(Ordering::SeqCst) == 1 { - let name = "getrandom\0"; - let addr = libc::dlsym(libc::RTLD_DEFAULT, - name.as_ptr() as *const _) as usize; - FPTR.store(addr, Ordering::SeqCst); - } - - if FPTR.load(Ordering::SeqCst) == 0 { - return None; - } else { - mem::transmute::<&AtomicUsize, Option<&GetRandomFn>>(&FPTR) - } - } + mem::transmute::>(ptr) + } } fn getrandom(buf: &mut [u8], blocking: bool) -> libc::ssize_t { @@ -150,9 +148,9 @@ fn getrandom(buf: &mut [u8], blocking: bool) -> libc::ssize_t { const GRND_RANDOM: libc::c_uint = 0x0002; if let Some(rand) = fetch() { + let flag = if blocking { 0 } else { GRND_NONBLOCK } | GRND_RANDOM; unsafe { - rand(buf.as_mut_ptr(), buf.len(), - if blocking { 0 } else { GRND_NONBLOCK } | GRND_RANDOM) as libc::ssize_t + rand(buf.as_mut_ptr(), buf.len(), flag) as libc::ssize_t } } else { -1 From a987d05eff4462cc8ea320f11361e2823815712e Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Fri, 22 Feb 2019 09:26:11 +0000 Subject: [PATCH 15/24] rand_pcg: prepare 0.1.2 release with i128 auto-detection --- rand_pcg/CHANGELOG.md | 6 +++--- rand_pcg/Cargo.toml | 7 +++---- rand_pcg/README.md | 12 ++---------- 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/rand_pcg/CHANGELOG.md b/rand_pcg/CHANGELOG.md index 6f793cf7c35..69572248012 100644 --- a/rand_pcg/CHANGELOG.md +++ b/rand_pcg/CHANGELOG.md @@ -4,9 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.1.2] - unreleased -- potential blocker: https://github.com/TyOverby/bincode/issues/250 -- make `bincode` a dev-dependency again +## [0.1.2] - 2019-02-23 +- require `bincode` 1.1.2 for i128 auto-detection +- make `bincode` a dev-dependency again #663 - clean up tests and Serde support ## [0.1.1] - 2018-10-04 diff --git a/rand_pcg/Cargo.toml b/rand_pcg/Cargo.toml index 5ebf2db69d0..9b7faa552fa 100644 --- a/rand_pcg/Cargo.toml +++ b/rand_pcg/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rand_pcg" -version = "0.1.1" +version = "0.1.2" authors = ["The Rand Project Developers"] license = "MIT/Apache-2.0" readme = "README.md" @@ -29,9 +29,8 @@ serde_derive = { version = "^1.0.38", optional = true } [dev-dependencies] # This is for testing serde, unfortunately we can't specify feature-gated dev # deps yet, see: https://github.com/rust-lang/cargo/issues/1596 -# TODO: we shouldn't have to depend on i128 directly; it breaks tests on old -# compilers. `bincode` should automatically support this. -bincode = { version = "1", features = ["i128"] } +# We require at least 1.1.2 for i128 auto-detection +bincode = { version = "1.1.2" } [build-dependencies] autocfg = "0.1" diff --git a/rand_pcg/README.md b/rand_pcg/README.md index 4599813efb1..ae583a1a4b8 100644 --- a/rand_pcg/README.md +++ b/rand_pcg/README.md @@ -29,18 +29,10 @@ Links: ## Crate Features -`rand_pcg` is `no_std` compatible. It does not require any functionality -outside of the `core` lib, thus there are no features to configure. +`rand_pcg` is `no_std` compatible by default. The `serde1` feature includes implementations of `Serialize` and `Deserialize` -for the included RNGs. NOTE: to use binary serialisation with any of the 64-bit -output (128-bit internal) RNGs, you must add the following dependency, since the -`i128` feature is not current enabled by default (this should be fixed soon): - -``` -bincode = { version = "1", features = ["i128"] } -``` - +for the included RNGs. ## License From 790aa8a002c258fe46206bbb31c9d108da3e02db Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Thu, 21 Feb 2019 14:40:45 +0100 Subject: [PATCH 16/24] Fix deprecation warnings for atomics initialization Since Rust 1.34, `ATOMIC_*_INIT` is deprecated in favor of `Atomic*::new`. However, this requires the latter to be `const`, which is not the case for older Rust versions. Alternatively, we could detect the Rust version by introducing build scripts to the crates lacking them. However, this increases build time for a very minor benefit, so the deprecation warnings are ignored instead. Fixes #736. --- rand_jitter/src/lib.rs | 6 +++++- rand_os/src/linux_android.rs | 6 +++++- rand_os/src/netbsd.rs | 5 ++++- rand_os/src/solarish.rs | 5 ++++- src/rngs/adapter/reseeding.rs | 7 +++++-- 5 files changed, 23 insertions(+), 6 deletions(-) diff --git a/rand_jitter/src/lib.rs b/rand_jitter/src/lib.rs index ab9ae396de9..e2e7ae1d00e 100644 --- a/rand_jitter/src/lib.rs +++ b/rand_jitter/src/lib.rs @@ -75,7 +75,10 @@ pub use error::TimerError; use core::{fmt, mem, ptr}; #[cfg(feature = "std")] -use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; +use std::sync::atomic::{AtomicUsize, Ordering}; +#[cfg(feature = "std")] +#[allow(deprecated)] // Required for compatibility with Rust < 1.24. +use std::sync::atomic::ATOMIC_USIZE_INIT; const MEMORY_BLOCKS: usize = 64; const MEMORY_BLOCKSIZE: usize = 32; @@ -167,6 +170,7 @@ impl Clone for JitterRng { // Initialise to zero; must be positive #[cfg(all(feature = "std", not(target_arch = "wasm32")))] +#[allow(deprecated)] static JITTER_ROUNDS: AtomicUsize = ATOMIC_USIZE_INIT; impl JitterRng { diff --git a/rand_os/src/linux_android.rs b/rand_os/src/linux_android.rs index 9622f93b63d..255c2200210 100644 --- a/rand_os/src/linux_android.rs +++ b/rand_os/src/linux_android.rs @@ -18,7 +18,9 @@ use std::io; use std::io::Read; use std::fs::{File, OpenOptions}; use std::os::unix::fs::OpenOptionsExt; -use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; +use std::sync::atomic::{AtomicBool, Ordering}; +#[allow(deprecated)] // Required for compatibility with Rust < 1.24. +use std::sync::atomic::ATOMIC_BOOL_INIT; use std::sync::{Once, ONCE_INIT}; #[derive(Clone, Debug)] @@ -53,6 +55,7 @@ impl OsRngImpl for OsRng { fn test_initialized(&mut self, dest: &mut [u8], blocking: bool) -> Result { + #[allow(deprecated)] static OS_RNG_INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT; if !self.initialized { self.initialized = OS_RNG_INITIALIZED.load(Ordering::Relaxed); @@ -160,6 +163,7 @@ fn getrandom_try_fill(dest: &mut [u8], blocking: bool) -> Result<(), Error> { fn is_getrandom_available() -> bool { static CHECKER: Once = ONCE_INIT; + #[allow(deprecated)] static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT; if NR_GETRANDOM == 0 { return false }; diff --git a/rand_os/src/netbsd.rs b/rand_os/src/netbsd.rs index cf4b6c74f5d..34517bfeb3f 100644 --- a/rand_os/src/netbsd.rs +++ b/rand_os/src/netbsd.rs @@ -14,7 +14,9 @@ use super::OsRngImpl; use std::fs::File; use std::io::Read; -use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; +use std::sync::atomic::{AtomicBool, Ordering}; +#[allow(deprecated)] // Required for compatibility with Rust < 1.24. +use std::sync::atomic::ATOMIC_BOOL_INIT; #[derive(Clone, Debug)] pub struct OsRng { initialized: bool } @@ -34,6 +36,7 @@ impl OsRngImpl for OsRng { fn test_initialized(&mut self, dest: &mut [u8], _blocking: bool) -> Result { + #[allow(deprecated)] static OS_RNG_INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT; if !self.initialized { self.initialized = OS_RNG_INITIALIZED.load(Ordering::Relaxed); diff --git a/rand_os/src/solarish.rs b/rand_os/src/solarish.rs index 952643fa7d7..471768adc7d 100644 --- a/rand_os/src/solarish.rs +++ b/rand_os/src/solarish.rs @@ -28,7 +28,9 @@ use std::io; use std::io::Read; use std::fs::{File, OpenOptions}; use std::os::unix::fs::OpenOptionsExt; -use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering, AtomicUsize}; +use std::sync::atomic::{AtomicBool, Ordering, AtomicUsize}; +#[allow(deprecated)] // Required for compatibility with Rust < 1.24. +use std::sync::atomic::ATOMIC_BOOL_INIT; use std::cmp; use std::mem; @@ -68,6 +70,7 @@ impl OsRngImpl for OsRng { fn test_initialized(&mut self, dest: &mut [u8], blocking: bool) -> Result { + #[allow(deprecated)] static OS_RNG_INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT; if !self.initialized { self.initialized = OS_RNG_INITIALIZED.load(Ordering::Relaxed); diff --git a/src/rngs/adapter/reseeding.rs b/src/rngs/adapter/reseeding.rs index a3e98c6d52e..5017673d087 100644 --- a/src/rngs/adapter/reseeding.rs +++ b/src/rngs/adapter/reseeding.rs @@ -286,8 +286,9 @@ where R: BlockRngCore + SeedableRng + CryptoRng, mod fork { extern crate libc; - use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; - use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT}; + use core::sync::atomic::{AtomicUsize, AtomicBool, Ordering}; + #[allow(deprecated)] // Required for compatibility with Rust < 1.24. + use core::sync::atomic::{ATOMIC_USIZE_INIT, ATOMIC_BOOL_INIT}; // Fork protection // @@ -301,12 +302,14 @@ mod fork { // don't update `fork_counter`, so a reseed is attempted as soon as // possible. + #[allow(deprecated)] static RESEEDING_RNG_FORK_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; pub fn get_fork_counter() -> usize { RESEEDING_RNG_FORK_COUNTER.load(Ordering::Relaxed) } + #[allow(deprecated)] static FORK_HANDLER_REGISTERED: AtomicBool = ATOMIC_BOOL_INIT; extern fn fork_handler() { From 0a44f513f5de7b5617fae4376391e8ce53a9de6c Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Tue, 19 Feb 2019 17:03:25 +0100 Subject: [PATCH 17/24] Binomial: Faster sampling for n * p < 10 Fixes #734. --- src/distributions/binomial.rs | 115 +++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 50 deletions(-) diff --git a/src/distributions/binomial.rs b/src/distributions/binomial.rs index 2df393e53ab..907155b24ed 100644 --- a/src/distributions/binomial.rs +++ b/src/distributions/binomial.rs @@ -10,7 +10,7 @@ //! The binomial distribution. use Rng; -use distributions::{Distribution, Bernoulli, Cauchy}; +use distributions::{Distribution, Cauchy}; use distributions::utils::log_gamma; /// The binomial distribution `Binomial(n, p)`. @@ -55,19 +55,7 @@ impl Distribution for Binomial { } else if self.p == 1.0 { return self.n; } - - // For low n, it is faster to sample directly. For both methods, - // performance is independent of p. On Intel Haswell CPU this method - // appears to be faster for approx n < 300. - if self.n < 300 { - let mut result = 0; - let d = Bernoulli::new(self.p); - for _ in 0 .. self.n { - result += rng.sample(d) as u32; - } - return result as u64; - } - + // binomial distribution is symmetrical with respect to p -> 1-p, k -> n-k // switch p so that it is less than 0.5 - this allows for lower expected values // we will just invert the result at the end @@ -77,53 +65,80 @@ impl Distribution for Binomial { 1.0 - self.p }; - // prepare some cached values - let float_n = self.n as f64; - let ln_fact_n = log_gamma(float_n + 1.0); - let pc = 1.0 - p; - let log_p = p.ln(); - let log_pc = pc.ln(); - let expected = self.n as f64 * p; - let sq = (expected * (2.0 * pc)).sqrt(); - - let mut lresult; - - // we use the Cauchy distribution as the comparison distribution - // f(x) ~ 1/(1+x^2) - let cauchy = Cauchy::new(0.0, 1.0); - loop { - let mut comp_dev: f64; + let result; + + // For small n * min(p, 1 - p), the BINV algorithm based on the inverse + // transformation of the binomial distribution is more efficient: + // + // Voratas Kachitvichyanukul and Bruce W. Schmeiser. 1988. Binomial + // random variate generation. Commun. ACM 31, 2 (February 1988), + // 216-222. http://dx.doi.org/10.1145/42372.42381 + if (self.n as f64) * p < 10. { + let q = 1. - p; + let s = p / q; + let a = ((self.n + 1) as f64) * s; + let mut r = q.powf(self.n as f64); + // FIXME: Using integer exponentiation should be faster, but it is not available for + // `u64` exponents, neither in `std` or `num`. + let mut u: f64 = rng.gen(); + let mut x = 0; + while u > r as f64 { + u -= r; + x += 1; + r *= a / (x as f64) - s; + } + result = x; + } else { + // FIXME: Using the BTPE algorithm is probably faster. + + // prepare some cached values + let float_n = self.n as f64; + let ln_fact_n = log_gamma(float_n + 1.0); + let pc = 1.0 - p; + let log_p = p.ln(); + let log_pc = pc.ln(); + let expected = self.n as f64 * p; + let sq = (expected * (2.0 * pc)).sqrt(); + let mut lresult; + + // we use the Cauchy distribution as the comparison distribution + // f(x) ~ 1/(1+x^2) + let cauchy = Cauchy::new(0.0, 1.0); loop { - // draw from the Cauchy distribution - comp_dev = rng.sample(cauchy); - // shift the peak of the comparison ditribution - lresult = expected + sq * comp_dev; - // repeat the drawing until we are in the range of possible values - if lresult >= 0.0 && lresult < float_n + 1.0 { - break; + let mut comp_dev: f64; + loop { + // draw from the Cauchy distribution + comp_dev = rng.sample(cauchy); + // shift the peak of the comparison ditribution + lresult = expected + sq * comp_dev; + // repeat the drawing until we are in the range of possible values + if lresult >= 0.0 && lresult < float_n + 1.0 { + break; + } } - } - // the result should be discrete - lresult = lresult.floor(); + // the result should be discrete + lresult = lresult.floor(); - let log_binomial_dist = ln_fact_n - log_gamma(lresult+1.0) - - log_gamma(float_n - lresult + 1.0) + lresult*log_p + (float_n - lresult)*log_pc; - // this is the binomial probability divided by the comparison probability - // we will generate a uniform random value and if it is larger than this, - // we interpret it as a value falling out of the distribution and repeat - let comparison_coeff = (log_binomial_dist.exp() * sq) * (1.2 * (1.0 + comp_dev*comp_dev)); + let log_binomial_dist = ln_fact_n - log_gamma(lresult+1.0) - + log_gamma(float_n - lresult + 1.0) + lresult*log_p + (float_n - lresult)*log_pc; + // this is the binomial probability divided by the comparison probability + // we will generate a uniform random value and if it is larger than this, + // we interpret it as a value falling out of the distribution and repeat + let comparison_coeff = (log_binomial_dist.exp() * sq) * (1.2 * (1.0 + comp_dev*comp_dev)); - if comparison_coeff >= rng.gen() { - break; + if comparison_coeff >= rng.gen() { + break; + } } + result = lresult as u64; } // invert the result for p < 0.5 if p != self.p { - self.n - lresult as u64 + self.n - result } else { - lresult as u64 + result } } } From 6323d2951ec2a827b0113e2d81c038e846613b8d Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Tue, 19 Feb 2019 17:14:09 +0100 Subject: [PATCH 18/24] Binomial: Add benchmark for small n * p Our previous implementation was very slow (#734). The benchmarks makes sure we won't have such regressions in the future. --- benches/distributions.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/benches/distributions.rs b/benches/distributions.rs index 56a8d43b791..5ff91f56e2b 100644 --- a/benches/distributions.rs +++ b/benches/distributions.rs @@ -203,6 +203,7 @@ distr_float!(distr_gamma_large_shape, f64, Gamma::new(10., 1.0)); distr_float!(distr_gamma_small_shape, f64, Gamma::new(0.1, 1.0)); distr_float!(distr_cauchy, f64, Cauchy::new(4.2, 6.9)); distr_int!(distr_binomial, u64, Binomial::new(20, 0.7)); +distr_int!(distr_binomial_small, u64, Binomial::new(1000000, 1e-30)); distr_int!(distr_poisson, u64, Poisson::new(4.0)); distr!(distr_bernoulli, bool, Bernoulli::new(0.18)); distr_arr!(distr_circle, [f64; 2], UnitCircle::new()); From 5f6f89e5c7903da9fd6984dfc95300ccd0af630b Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Mon, 25 Feb 2019 14:05:00 +0100 Subject: [PATCH 19/24] Binomial: Use integer exponentation This increase performance significantly, see below. However, it requires shipping our own integer exponentiation implementation, because `u64` exponents are not supported by `std` or `num`. Before: ``` test distr_binomial ... bench: 88,365 ns/iter (+/- 2,215) =90 MB/s test distr_binomial_small ... bench: 33,775 ns/iter (+/- 5,494) =236 MB/s test misc_binomial_1 ... bench: 13 ns/iter (+/- 2) test misc_binomial_10 ... bench: 72 ns/iter (+/- 1) test misc_binomial_100 ... bench: 71 ns/iter (+/- 11) test misc_binomial_1000 ... bench: 624 ns/iter (+/- 19) test misc_binomial_1e12 ... bench: 681 ns/iter (+/- 18) ``` After: ``` test distr_binomial ... bench: 44,354 ns/iter (+/- 3,518) = 180 MB/s test distr_binomial_small ... bench: 22,736 ns/iter (+/- 514) = 351 MB/s test misc_binomial_1 ... bench: 10 ns/iter (+/- 0) test misc_binomial_10 ... bench: 23 ns/iter (+/- 0) test misc_binomial_100 ... bench: 27 ns/iter (+/- 4) test misc_binomial_1000 ... bench: 621 ns/iter (+/- 15) test misc_binomial_1e12 ... bench: 686 ns/iter (+/- 20) ``` --- src/distributions/binomial.rs | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/distributions/binomial.rs b/src/distributions/binomial.rs index 907155b24ed..2bad03b78bd 100644 --- a/src/distributions/binomial.rs +++ b/src/distributions/binomial.rs @@ -47,6 +47,31 @@ impl Binomial { } } +/// Raise a `base` to the power of `exp`, using exponentiation by squaring. +/// +/// This implementation is based on the one in the `num_traits` crate. It is +/// slightly modified to accept `u64` exponents. +fn pow(mut base: f64, mut exp: u64) -> f64 { + if exp == 0 { + return 1.; + } + + while exp & 1 == 0 { + base *= base; + exp >>= 1; + } + + let mut acc = base; + while exp > 1 { + exp >>= 1; + base *= base; + if exp & 1 == 1 { + acc *= base; + } + } + acc +} + impl Distribution for Binomial { fn sample(&self, rng: &mut R) -> u64 { // Handle these values directly. @@ -77,9 +102,7 @@ impl Distribution for Binomial { let q = 1. - p; let s = p / q; let a = ((self.n + 1) as f64) * s; - let mut r = q.powf(self.n as f64); - // FIXME: Using integer exponentiation should be faster, but it is not available for - // `u64` exponents, neither in `std` or `num`. + let mut r = pow(q, self.n); let mut u: f64 = rng.gen(); let mut x = 0; while u > r as f64 { From ddcbe40cb0224f357ab3a50dc679e88793ecfd61 Mon Sep 17 00:00:00 2001 From: "Andre B. Reis" Date: Wed, 27 Feb 2019 18:02:49 +0000 Subject: [PATCH 20/24] Fix docs for choose_multiple_fills --- src/seq/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/seq/mod.rs b/src/seq/mod.rs index eff8a8817f6..cd0412f8894 100644 --- a/src/seq/mod.rs +++ b/src/seq/mod.rs @@ -238,16 +238,16 @@ pub trait IteratorRandom: Iterator + Sized { } } - /// Collects `amount` values at random from the iterator into a supplied - /// buffer. + /// Collects values at random from the iterator into a supplied buffer + /// until that buffer is filled. /// /// Although the elements are selected randomly, the order of elements in /// the buffer is neither stable nor fully random. If random ordering is /// desired, shuffle the result. /// - /// Returns the number of elements added to the buffer. This equals `amount` - /// unless the iterator contains insufficient elements, in which case this - /// equals the number of elements available. + /// Returns the number of elements added to the buffer. This equals the length + /// of the buffer unless the iterator contains insufficient elements, in which + /// case this equals the number of elements available. /// /// Complexity is `O(n)` where `n` is the length of the iterator. fn choose_multiple_fill(mut self, rng: &mut R, buf: &mut [Self::Item]) -> usize From ab9bf2771da0f567b96cb894f725664decbfc019 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 4 Mar 2019 08:50:01 +0000 Subject: [PATCH 21/24] Ignore temporary files associated with wasm_bindgen test --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index a9d37c560c6..ac38e8174a6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ target Cargo.lock +rand_wasm_bindgen_test*.[tj]s +rand_wasm_bindgen_test*.wasm From bce70e348242a3a4f91b85b0bf90de2d03527f08 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 4 Mar 2019 08:54:07 +0000 Subject: [PATCH 22/24] rand_os: prepare 0.1.3 release --- rand_os/CHANGELOG.md | 5 +++++ rand_os/Cargo.toml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/rand_os/CHANGELOG.md b/rand_os/CHANGELOG.md index 97a8e84e44f..1ce36fc6cc7 100644 --- a/rand_os/CHANGELOG.md +++ b/rand_os/CHANGELOG.md @@ -5,6 +5,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.1.3] - 2019-03-05 +### Changes +- Fix support for Illumos (#730) +- Fix deprecation warnings from atomic init (#739) + ## [0.1.2] - 2019-01-28 ### Changes - Fuchsia: Replaced fuchsia-zircon with fuchsia-cprng diff --git a/rand_os/Cargo.toml b/rand_os/Cargo.toml index 1483c369540..6bb639a4598 100644 --- a/rand_os/Cargo.toml +++ b/rand_os/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rand_os" -version = "0.1.2" +version = "0.1.3" authors = ["The Rand Project Developers"] license = "MIT/Apache-2.0" readme = "README.md" From b6768e15588b1425989a54dc619178b90ae78b05 Mon Sep 17 00:00:00 2001 From: TheIronBorn Date: Mon, 4 Mar 2019 09:20:37 +0000 Subject: [PATCH 23/24] inline float cast --- src/distributions/utils.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/distributions/utils.rs b/src/distributions/utils.rs index d4d36426392..980c75ecb27 100644 --- a/src/distributions/utils.rs +++ b/src/distributions/utils.rs @@ -383,6 +383,7 @@ macro_rules! simd_impl { <$ty>::from_bits(<$uty>::from_bits(self) + <$uty>::from_bits(mask)) } type UInt = $uty; + #[inline] fn cast_from_int(i: Self::UInt) -> Self { i.cast() } } } From 57181a9cb6013bb77de3693984661d33615adee4 Mon Sep 17 00:00:00 2001 From: Rob Donnelly Date: Mon, 4 Mar 2019 09:17:18 -0800 Subject: [PATCH 24/24] Fix typo --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e6e3da14a1..2d356251cc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ You may also find the [Upgrade Guide](https://rust-random.github.io/book/update. ### Crates - Update `rand_core` to 0.4 (#703) - Move `JitterRng` to its own crate (#685) -- Add a warm-bindgen test crate (#696) +- Add a wasm-bindgen test crate (#696) ### Platforms - Fuchsia: Replaced fuchsia-zircon with fuchsia-cprng