diff --git a/CHANGELOG.md b/CHANGELOG.md
index 103abea7a31..4003661609f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,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]
+### Additions
+- Added a `serde1` feature and added Serialize/Deserialize to `UniformInt` and `WeightedIndex` (#974)
+
## [0.7.3] - 2020-01-10
### Fixes
- The `Bernoulli` distribution constructors now reports an error on NaN and on
diff --git a/Cargo.toml b/Cargo.toml
index e0581952329..ce5f53e9ce4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -24,7 +24,7 @@ appveyor = { repository = "rust-random/rand" }
# Meta-features:
default = ["std", "std_rng"]
nightly = ["simd_support"] # enables all features requiring nightly rust
-serde1 = [] # does nothing, deprecated
+serde1 = ["serde"]
# Option (enabled by default): without "std" rand uses libcore; this option
# enables functionality expected to be available on a standard platform.
@@ -58,6 +58,7 @@ members = [
rand_core = { path = "rand_core", version = "0.5.1" }
rand_pcg = { path = "rand_pcg", version = "0.2", optional = true }
log = { version = "0.4.4", optional = true }
+serde = { version = "1.0.103", features = ["derive"], optional = true }
[dependencies.packed_simd]
# NOTE: so far no version works reliably due to dependence on unstable features
@@ -81,6 +82,8 @@ rand_hc = { path = "rand_hc", version = "0.2", optional = true }
rand_pcg = { path = "rand_pcg", version = "0.2" }
# Only for benches:
rand_hc = { path = "rand_hc", version = "0.2" }
+# Only to test serde1
+bincode = "1.2.1"
[package.metadata.docs.rs]
all-features = true
diff --git a/src/distributions/bernoulli.rs b/src/distributions/bernoulli.rs
index a1fa86e14d4..b968ca046ed 100644
--- a/src/distributions/bernoulli.rs
+++ b/src/distributions/bernoulli.rs
@@ -12,6 +12,8 @@ use crate::distributions::Distribution;
use crate::Rng;
use core::{fmt, u64};
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
/// The Bernoulli distribution.
///
/// This is a special case of the Binomial distribution where `n = 1`.
@@ -32,6 +34,7 @@ use core::{fmt, u64};
/// so only probabilities that are multiples of 2-64 can be
/// represented.
#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Bernoulli {
/// Probability of success, relative to the maximal integer.
p_int: u64,
@@ -143,6 +146,15 @@ mod test {
use crate::distributions::Distribution;
use crate::Rng;
+ #[test]
+ #[cfg(feature="serde1")]
+ fn test_serializing_deserializing_bernoulli() {
+ let coin_flip = Bernoulli::new(0.5).unwrap();
+ let de_coin_flip : Bernoulli = bincode::deserialize(&bincode::serialize(&coin_flip).unwrap()).unwrap();
+
+ assert_eq!(coin_flip.p_int, de_coin_flip.p_int);
+ }
+
#[test]
fn test_trivial() {
let mut r = crate::test::rng(1);
diff --git a/src/distributions/float.rs b/src/distributions/float.rs
index 0a45f397743..733a40394dd 100644
--- a/src/distributions/float.rs
+++ b/src/distributions/float.rs
@@ -14,6 +14,9 @@ use crate::Rng;
use core::mem;
#[cfg(feature = "simd_support")] use packed_simd::*;
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
+
/// A distribution to sample floating point numbers uniformly in the half-open
/// interval `(0, 1]`, i.e. including 1 but not 0.
///
@@ -39,6 +42,7 @@ use core::mem;
/// [`Open01`]: crate::distributions::Open01
/// [`Uniform`]: crate::distributions::uniform::Uniform
#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct OpenClosed01;
/// A distribution to sample floating point numbers uniformly in the open
@@ -65,6 +69,7 @@ pub struct OpenClosed01;
/// [`OpenClosed01`]: crate::distributions::OpenClosed01
/// [`Uniform`]: crate::distributions::uniform::Uniform
#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Open01;
diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs
index cf1c8b19815..525e29eddd6 100644
--- a/src/distributions/mod.rs
+++ b/src/distributions/mod.rs
@@ -111,6 +111,9 @@ pub mod uniform;
#[cfg(feature = "alloc")] pub mod weighted;
#[cfg(feature = "alloc")] mod weighted_index;
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
+
mod float;
#[doc(hidden)]
pub mod hidden_export {
@@ -320,6 +323,7 @@ where
///
/// [`Uniform`]: uniform::Uniform
#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Standard;
diff --git a/src/distributions/other.rs b/src/distributions/other.rs
index c95060e5104..32cc470d1eb 100644
--- a/src/distributions/other.rs
+++ b/src/distributions/other.rs
@@ -14,6 +14,9 @@ use core::num::Wrapping;
use crate::distributions::{Distribution, Standard, Uniform};
use crate::Rng;
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
+
// ----- Sampling distributions -----
/// Sample a `char`, uniformly distributed over ASCII letters and numbers:
@@ -34,6 +37,7 @@ use crate::Rng;
/// println!("Random chars: {}", chars);
/// ```
#[derive(Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Alphanumeric;
diff --git a/src/distributions/uniform.rs b/src/distributions/uniform.rs
index 8584152f039..a8fb0dc3f27 100644
--- a/src/distributions/uniform.rs
+++ b/src/distributions/uniform.rs
@@ -115,9 +115,11 @@ use crate::Rng;
#[allow(unused_imports)] // rustc doesn't detect that this is actually used
use crate::distributions::utils::Float;
-
#[cfg(feature = "simd_support")] use packed_simd::*;
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
+
/// Sample values uniformly between two bounds.
///
/// [`Uniform::new`] and [`Uniform::new_inclusive`] construct a uniform
@@ -159,6 +161,7 @@ use crate::distributions::utils::Float;
/// [`new`]: Uniform::new
/// [`new_inclusive`]: Uniform::new_inclusive
#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Uniform(X::Sampler);
impl Uniform {
@@ -347,6 +350,7 @@ where Borrowed: SampleUniform
/// multiply by `range`, the result is in the high word. Then comparing the low
/// word against `zone` makes sure our distribution is uniform.
#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UniformInt {
low: X,
range: X,
@@ -644,6 +648,7 @@ uniform_simd_int_impl! {
/// [`new_inclusive`]: UniformSampler::new_inclusive
/// [`Standard`]: crate::distributions::Standard
#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UniformFloat {
low: X,
scale: X,
@@ -837,12 +842,14 @@ uniform_float_impl! { f64x8, u64x8, f64, u64, 64 - 52 }
/// Unless you are implementing [`UniformSampler`] for your own types, this type
/// should not be used directly, use [`Uniform`] instead.
#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UniformDuration {
mode: UniformDurationMode,
offset: u32,
}
#[derive(Debug, Copy, Clone)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
enum UniformDurationMode {
Small {
secs: u64,
@@ -967,6 +974,56 @@ mod tests {
use super::*;
use crate::rngs::mock::StepRng;
+ #[test]
+ #[cfg(feature = "serde1")]
+ fn test_serialization_uniform_duration() {
+ let distr = UniformDuration::new(std::time::Duration::from_secs(10), std::time::Duration::from_secs(60));
+ let de_distr: UniformDuration = bincode::deserialize(&bincode::serialize(&distr).unwrap()).unwrap();
+ assert_eq!(
+ distr.offset, de_distr.offset
+ );
+ match (distr.mode, de_distr.mode) {
+ (UniformDurationMode::Small {secs: a_secs, nanos: a_nanos}, UniformDurationMode::Small {secs, nanos}) => {
+ assert_eq!(a_secs, secs);
+
+ assert_eq!(a_nanos.0.low, nanos.0.low);
+ assert_eq!(a_nanos.0.range, nanos.0.range);
+ assert_eq!(a_nanos.0.z, nanos.0.z);
+ }
+ (UniformDurationMode::Medium {nanos: a_nanos} , UniformDurationMode::Medium {nanos}) => {
+ assert_eq!(a_nanos.0.low, nanos.0.low);
+ assert_eq!(a_nanos.0.range, nanos.0.range);
+ assert_eq!(a_nanos.0.z, nanos.0.z);
+ }
+ (UniformDurationMode::Large {max_secs:a_max_secs, max_nanos:a_max_nanos, secs:a_secs}, UniformDurationMode::Large {max_secs, max_nanos, secs} ) => {
+ assert_eq!(a_max_secs, max_secs);
+ assert_eq!(a_max_nanos, max_nanos);
+
+ assert_eq!(a_secs.0.low, secs.0.low);
+ assert_eq!(a_secs.0.range, secs.0.range);
+ assert_eq!(a_secs.0.z, secs.0.z);
+ }
+ _ => panic!("`UniformDurationMode` was not serialized/deserialized correctly")
+ }
+ }
+
+ #[test]
+ #[cfg(feature = "serde1")]
+ fn test_uniform_serialization() {
+ let unit_box: Uniform = Uniform::new(-1, 1);
+ let de_unit_box: Uniform = bincode::deserialize(&bincode::serialize(&unit_box).unwrap()).unwrap();
+
+ assert_eq!(unit_box.0.low, de_unit_box.0.low);
+ assert_eq!(unit_box.0.range, de_unit_box.0.range);
+ assert_eq!(unit_box.0.z, de_unit_box.0.z);
+
+ let unit_box: Uniform = Uniform::new(-1., 1.);
+ let de_unit_box: Uniform = bincode::deserialize(&bincode::serialize(&unit_box).unwrap()).unwrap();
+
+ assert_eq!(unit_box.0.low, de_unit_box.0.low);
+ assert_eq!(unit_box.0.scale, de_unit_box.0.scale);
+ }
+
#[should_panic]
#[test]
fn test_uniform_bad_limits_equal_int() {
diff --git a/src/distributions/weighted_index.rs b/src/distributions/weighted_index.rs
index b73bc43af02..a75d41eae0c 100644
--- a/src/distributions/weighted_index.rs
+++ b/src/distributions/weighted_index.rs
@@ -17,6 +17,9 @@ use core::fmt;
// Note that this whole module is only imported if feature="alloc" is enabled.
#[cfg(not(feature = "std"))] use crate::alloc::vec::Vec;
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
+
/// A distribution using weighted sampling of discrete items
///
/// Sampling a `WeightedIndex` distribution returns the index of a randomly
@@ -73,6 +76,7 @@ use core::fmt;
/// [`Uniform`]: crate::distributions::uniform::Uniform
/// [`RngCore`]: crate::RngCore
#[derive(Debug, Clone)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct WeightedIndex {
cumulative_weights: Vec,
total_weight: X,
@@ -236,6 +240,23 @@ where X: SampleUniform + PartialOrd
mod test {
use super::*;
+ #[cfg(feature = "serde1")]
+ #[test]
+ fn test_weightedindex_serde1() {
+ let weighted_index = WeightedIndex::new(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).unwrap();
+
+ let ser_weighted_index = bincode::serialize(&weighted_index).unwrap();
+ let de_weighted_index: WeightedIndex =
+ bincode::deserialize(&ser_weighted_index).unwrap();
+
+ assert_eq!(
+ de_weighted_index.cumulative_weights,
+ weighted_index.cumulative_weights
+ );
+ assert_eq!(de_weighted_index.total_weight, weighted_index.total_weight);
+ }
+
+
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_weightedindex() {
diff --git a/src/rngs/mock.rs b/src/rngs/mock.rs
index 9a47264a762..86190fd9826 100644
--- a/src/rngs/mock.rs
+++ b/src/rngs/mock.rs
@@ -10,6 +10,9 @@
use rand_core::{impls, Error, RngCore};
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
+
/// A simple implementation of `RngCore` for testing purposes.
///
/// This generates an arithmetic sequence (i.e. adds a constant each step)
@@ -25,6 +28,7 @@ use rand_core::{impls, Error, RngCore};
/// assert_eq!(sample, [2, 3, 4]);
/// ```
#[derive(Debug, Clone)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct StepRng {
v: u64,
a: u64,
@@ -65,3 +69,18 @@ impl RngCore for StepRng {
Ok(())
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ #[cfg(feature = "serde1")]
+ fn test_serialization_step_rng() {
+ let some_rng = StepRng::new(42, 7);
+ let de_some_rng: StepRng = bincode::deserialize(&bincode::serialize(&some_rng).unwrap()).unwrap();
+ assert_eq!(some_rng.v, de_some_rng.v);
+ assert_eq!(some_rng.a, de_some_rng.a);
+
+ }
+}
diff --git a/src/seq/index.rs b/src/seq/index.rs
index 79cc5e9c11c..92be0a33fd2 100644
--- a/src/seq/index.rs
+++ b/src/seq/index.rs
@@ -22,10 +22,14 @@ use crate::alloc::collections::BTreeSet;
use crate::distributions::{uniform::SampleUniform, Distribution, Uniform};
use crate::Rng;
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
+
/// A vector of indices.
///
/// Multiple internal representations are possible.
#[derive(Clone, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum IndexVec {
#[doc(hidden)]
U32(Vec),
@@ -376,6 +380,23 @@ where
#[cfg(test)]
mod test {
use super::*;
+
+ #[test]
+ #[cfg(feature = "serde1")]
+ fn test_serialization_index_vec() {
+ let some_index_vec = IndexVec::from(vec![254_usize, 234, 2, 1]);
+ let de_some_index_vec: IndexVec = bincode::deserialize(&bincode::serialize(&some_index_vec).unwrap()).unwrap();
+ match (some_index_vec, de_some_index_vec) {
+ (IndexVec::U32(a), IndexVec::U32(b)) => {
+ assert_eq!(a, b);
+ },
+ (IndexVec::USize(a), IndexVec::USize(b)) => {
+ assert_eq!(a, b);
+ },
+ _ => {panic!("failed to seralize/deserialize `IndexVec`")}
+ }
+ }
+
#[cfg(all(feature = "alloc", not(feature = "std")))] use crate::alloc::vec;
#[cfg(feature = "std")] use std::vec;