From 077861146bdd1264ebfaf30d458e8f15289a5570 Mon Sep 17 00:00:00 2001 From: Roy7Kim Date: Mon, 20 Mar 2023 14:38:16 +0900 Subject: [PATCH] Import random-fast-rng 0.1.1 --- .cargo_vcs_info.json | 5 ++ Cargo.toml | 35 ++++++++++ Cargo.toml.orig | 28 ++++++++ src/lib.rs | 156 +++++++++++++++++++++++++++++++++++++++++++ src/thread.rs | 32 +++++++++ 5 files changed, 256 insertions(+) create mode 100644 .cargo_vcs_info.json create mode 100644 Cargo.toml create mode 100644 Cargo.toml.orig create mode 100644 src/lib.rs create mode 100644 src/thread.rs diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json new file mode 100644 index 0000000..63ea7be --- /dev/null +++ b/.cargo_vcs_info.json @@ -0,0 +1,5 @@ +{ + "git": { + "sha1": "aac0983a35a81c1b22621961a881ddd3468fae49" + } +} diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..42c30a6 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,35 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "random-fast-rng" +version = "0.1.1" +authors = ["Elichai Turkel "] +include = ["**/*.rs", "Cargo.toml"] +description = "Rust library for Blazing fast non cryptographic random number generator" +readme = "README.md" +keywords = ["rand", "random", "random-rs", "rng"] +categories = ["algorithms", "no-std", "development-tools::testing"] +license = "MIT/Apache-2.0" +repository = "https://github.com/elichai/random-rs" +[dependencies.doc-comment] +version = "0.3" +optional = true + +[dependencies.random-trait] +version = "0.1" + +[features] +default = ["std"] +std = [] +[badges.travis-ci] +repository = "elichai/random-rs" diff --git a/Cargo.toml.orig b/Cargo.toml.orig new file mode 100644 index 0000000..a5308b8 --- /dev/null +++ b/Cargo.toml.orig @@ -0,0 +1,28 @@ +[package] +name = "random-fast-rng" +version = "0.1.1" +authors = ["Elichai Turkel "] +license = "MIT/Apache-2.0" +readme = "README.md" +description = "Rust library for Blazing fast non cryptographic random number generator" +categories = ["algorithms", "no-std", "development-tools::testing"] +keywords = ["rand", "random", "random-rs", "rng"] +repository = "https://github.com/elichai/random-rs" + +include = [ + "**/*.rs", + "Cargo.toml", +] + +[dependencies] +random-trait = { version = "0.1", path = "../random-trait" } + +doc-comment = { version = "0.3", optional = true } + + +[features] +default = ["std"] +std = [] + +[badges] +travis-ci = { repository = "elichai/random-rs" } diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..f66b352 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,156 @@ +#![no_std] +#![deny(missing_docs)] +#![cfg_attr(test, deny(warnings))] + +//! # Random-fast-rng +//! +//! This crate provides a fast **non cryptographic** random number generator that implements the [`Random`](trait.Random.html) trait.
+//! Currently it's implemented using the `Pcg32` algorithm, that generates 32 bit of random data for every state change.
+//! the exact algorithm might change in the future, but the properties should stay the same (Blazing fast, non cryptographic, and minimal I/O) +//! The crate is part of the `random-rs` facade, and as such supports older rust compilers(currently 1.13+) and should have only thin amount of dependencies. +//! +//! This Random generator is good for testing uses, and use cases that require some non-determinism. it shouldn't be used to generate keys/passwords.
+//! +//! By enabling the `std` feature this crate exposes a [`new()`](struct.FastRng.html#method.new) function that uses [`SystemTime::now()`](https://doc.rust-lang.org/std/time/struct.SystemTime.html) to seed the RNG.
+//! It also exposes a [`local_rng()`](fn.local_rng.html) function to give a persistent Rng that is seeded only once and is unique per thread (so there's no need to worry about dropping and reinitializing the Rng) +//! + +#[cfg(feature = "std")] +#[macro_use] +extern crate std; + +#[cfg(feature = "std")] +mod thread; + +pub extern crate random_trait; +pub use random_trait::Random; + +#[cfg(feature = "std")] +use thread::FromRawPtr; +#[cfg(feature = "std")] +pub use thread::ThreadFastRng; + +use core::mem; + +#[cfg(feature = "doc-comment")] +extern crate doc_comment; +#[cfg(feature = "doc-comment")] +doc_comment::doctest!("../README.md"); + +const PCG_DEFAULT_MULTIPLIER_64: u64 = 6_364_136_223_846_793_005; + +/// A FastRng struct implementing [`Random`](trait.Random.html). you can initialize it with your own seed using [`FastRng::seed()`](struct.FastRng.html#method.seed) +/// Or if the `std` feature is enabled call [`FastRng::new()`](struct.FastRng.html#method.seed) which will seed it with the system time.
+/// For ergonomics and ease of usability the Rng is also provided as a global thread local variable using [`FastRng::local_rng()`](fn.local_rng.html) +pub struct FastRng { + // Pcg32 + state: u64, + inc: u64, +} + +impl FastRng { + /// Creates a new instance of `FastRng` seeded with the system time. + /// + /// # Examples + /// ```rust + /// use random_fast_rng::{FastRng, Random}; + /// + /// let mut rng = FastRng::new(); + /// let random_u8 = rng.get_u8(); + /// let arr: [u8; 32] = rng.gen(); + /// ``` + /// + #[cfg(feature = "std")] + pub fn new() -> Self { + let (a, b) = time_seed(); + Self::seed(a, b) + } + + /// A function to manually seed the Rng in `no-std` cases. + pub fn seed(seed: u64, seq: u64) -> Self { + let init_inc = (seq << 1) | 1; + let init_state = seed + init_inc; + let mut rng = FastRng { state: init_state, inc: init_inc }; + rng.state = rng.state.wrapping_mul(PCG_DEFAULT_MULTIPLIER_64).wrapping_add(rng.inc); + rng + } + + fn gen_u32(&mut self) -> u32 { + let old_state = self.state; + self.state = self.state.wrapping_mul(PCG_DEFAULT_MULTIPLIER_64).wrapping_add(self.inc); + + let xorshift = (((old_state >> 18) ^ old_state) >> 27) as u32; + let rot = (old_state >> 59) as i32; + (xorshift >> rot) | (xorshift << ((-rot) & 31)) + } +} + +/// Returns a thread local instance which is seeded only once per thread (no need to worry about dropping and reinitializing) +/// +/// # Examples +/// ```rust +/// use random_fast_rng::{Random, local_rng}; +/// +/// let random_u8 = local_rng().get_u8(); +/// let arr: [u8; 32] = local_rng().gen(); +/// ``` +/// +#[cfg(feature = "std")] +pub fn local_rng() -> ThreadFastRng { + use std::cell::RefCell; + thread_local! { + pub static THREAD_FAST_RNG: RefCell = RefCell::new(FastRng::new()); + } + let ptr = THREAD_FAST_RNG.with(|r| r.as_ptr()); + ThreadFastRng::from_ptr(ptr) +} + +#[cfg(feature = "std")] +fn time_seed() -> (u64, u64) { + use std::time; + let now = time::SystemTime::now(); + let unix = now.duration_since(time::UNIX_EPOCH).unwrap(); + + (unix.as_secs(), u64::from(unix.subsec_nanos())) +} + +impl Random for FastRng { + type Error = (); + + fn try_fill_bytes(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> { + for chunk in buf.chunks_mut(4) { + let rand: [u8; 4] = unsafe { mem::transmute(self.gen_u32()) }; + let len = chunk.len(); + chunk.copy_from_slice(&rand[..len]); + } + Ok(()) + } + fn get_u32(&mut self) -> u32 { + self.gen_u32() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_local() { + let mut local_rng = local_rng(); + let a: u64 = local_rng.gen(); + let b: u32 = local_rng.gen(); + let c: [u8; 64] = local_rng.gen(); + assert_ne!(a, 0); + assert_ne!(b, 0); + assert_ne!(&c[..], &[0u8; 64][..]); + } + + #[test] + fn test_float() { + let mut rng = FastRng::new(); + let f: f32 = rng.gen(); + assert!(f > 0.0 && f < 1.0); + let f: f64 = rng.gen(); + assert!(f > 0.0 && f < 1.0); + } +} diff --git a/src/thread.rs b/src/thread.rs new file mode 100644 index 0000000..63a7265 --- /dev/null +++ b/src/thread.rs @@ -0,0 +1,32 @@ +use FastRng; + +use core::ops::{Deref, DerefMut}; + +/// A shim that points to the global `FastRng` instance. isn't safe for multi-threading. +/// +/// This struct is created by [`thread_local()`](../struct.FastRng.html#method.thread_local) +pub struct ThreadFastRng(*mut FastRng); + +impl Deref for ThreadFastRng { + type Target = FastRng; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.0 } + } +} + +impl DerefMut for ThreadFastRng { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *self.0 } + } +} + +pub trait FromRawPtr { + fn from_ptr(ptr: *mut T) -> Self; +} + +impl FromRawPtr for ThreadFastRng { + fn from_ptr(ptr: *mut FastRng) -> ThreadFastRng { + ThreadFastRng(ptr) + } +} -- 2.34.1