diff options
| author | Ziad Hatahet <hatahet@gmail.com> | 2013-10-23 10:09:06 -0700 |
|---|---|---|
| committer | Ziad Hatahet <hatahet@gmail.com> | 2013-10-23 10:09:06 -0700 |
| commit | 7d69837bd263f334aa9dea4235698c006f7b1ce8 (patch) | |
| tree | b43315adfc734b0ab480b40674721c99902f3eb2 /src/libstd | |
| parent | 60245b9290388671edac86d6db1619f60a9ccb68 (diff) | |
| parent | a4ec8af4c549bd806522826b756e18fbf0b5c47b (diff) | |
| download | rust-7d69837bd263f334aa9dea4235698c006f7b1ce8.tar.gz rust-7d69837bd263f334aa9dea4235698c006f7b1ce8.zip | |
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'src/libstd')
39 files changed, 1043 insertions, 452 deletions
diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs index e7fa81fc87a..9d5c9c1a5cd 100644 --- a/src/libstd/fmt/mod.rs +++ b/src/libstd/fmt/mod.rs @@ -490,7 +490,6 @@ pub struct Formatter<'self> { /// Output buffer. buf: &'self mut io::Writer, - priv curarg: vec::VecIterator<'self, Argument<'self>>, priv args: &'self [Argument<'self>], } diff --git a/src/libstd/io.rs b/src/libstd/io.rs index 94a6b7cfea8..4e55c5fe60e 100644 --- a/src/libstd/io.rs +++ b/src/libstd/io.rs @@ -1009,7 +1009,7 @@ impl<R:Reader,C> Reader for Wrapper<R, C> { } pub struct FILERes { - f: *libc::FILE, + priv f: *libc::FILE, } impl FILERes { @@ -1282,7 +1282,7 @@ impl Writer for fd_t { } pub struct FdRes { - fd: fd_t, + priv fd: fd_t, } impl FdRes { @@ -1792,7 +1792,7 @@ pub mod fsync { // Artifacts that need to fsync on destruction pub struct Res<t> { - arg: Arg<t>, + priv arg: Arg<t>, } impl <t> Res<t> { @@ -1815,9 +1815,9 @@ pub mod fsync { } pub struct Arg<t> { - val: t, - opt_level: Option<Level>, - fsync_fn: extern "Rust" fn(f: &t, Level) -> int, + priv val: t, + priv opt_level: Option<Level>, + priv fsync_fn: extern "Rust" fn(f: &t, Level) -> int, } // fsync file after executing blk diff --git a/src/libstd/iter.rs b/src/libstd/iter.rs index 01af3d93157..771be3b2a13 100644 --- a/src/libstd/iter.rs +++ b/src/libstd/iter.rs @@ -1790,9 +1790,9 @@ impl<'self, A, St> Iterator<A> for Unfold<'self, A, St> { #[deriving(Clone)] pub struct Counter<A> { /// The current state the counter is at (next value to be yielded) - state: A, + priv state: A, /// The amount that this iterator is stepping by - step: A + priv step: A } /// Creates a new counter with the specified start/step diff --git a/src/libstd/rand/distributions.rs b/src/libstd/rand/distributions.rs index 0902100dca6..e7bcf8ce5d3 100644 --- a/src/libstd/rand/distributions.rs +++ b/src/libstd/rand/distributions.rs @@ -8,38 +8,226 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Sampling from random distributions +/*! +Sampling from random distributions. -// Some implementations use the Ziggurat method -// https://en.wikipedia.org/wiki/Ziggurat_algorithm -// -// The version used here is ZIGNOR [Doornik 2005, "An Improved -// Ziggurat Method to Generate Normal Random Samples"] which is slower -// (about double, it generates an extra random number) than the -// canonical version [Marsaglia & Tsang 2000, "The Ziggurat Method for -// Generating Random Variables"], but more robust. If one wanted, one -// could implement VIZIGNOR the ZIGNOR paper for more speed. +This is a generalization of `Rand` to allow parameters to control the +exact properties of the generated values, e.g. the mean and standard +deviation of a normal distribution. The `Sample` trait is the most +general, and allows for generating values that change some state +internally. The `IndependentSample` trait is for generating values +that do not need to record state. + +*/ +use iter::range; +use option::{Some, None}; use num; use rand::{Rng,Rand}; +use clone::Clone; + +pub use self::range::Range; + +pub mod range; + +/// Types that can be used to create a random instance of `Support`. +pub trait Sample<Support> { + /// Generate a random value of `Support`, using `rng` as the + /// source of randomness. + fn sample<R: Rng>(&mut self, rng: &mut R) -> Support; +} + +/// `Sample`s that do not require keeping track of state. +/// +/// Since no state is recored, each sample is (statistically) +/// independent of all others, assuming the `Rng` used has this +/// property. +// XXX maybe having this separate is overkill (the only reason is to +// take &self rather than &mut self)? or maybe this should be the +// trait called `Sample` and the other should be `DependentSample`. +pub trait IndependentSample<Support>: Sample<Support> { + /// Generate a random value. + fn ind_sample<R: Rng>(&self, &mut R) -> Support; +} + +/// A wrapper for generating types that implement `Rand` via the +/// `Sample` & `IndependentSample` traits. +pub struct RandSample<Sup>; + +impl<Sup: Rand> Sample<Sup> for RandSample<Sup> { + fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) } +} + +impl<Sup: Rand> IndependentSample<Sup> for RandSample<Sup> { + fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup { + rng.gen() + } +} + +/// A value with a particular weight for use with `WeightedChoice`. +pub struct Weighted<T> { + /// The numerical weight of this item + weight: uint, + /// The actual item which is being weighted + item: T, +} + +/// A distribution that selects from a finite collection of weighted items. +/// +/// Each item has an associated weight that influences how likely it +/// is to be chosen: higher weight is more likely. +/// +/// The `Clone` restriction is a limitation of the `Sample` and +/// `IndepedentSample` traits. Note that `&T` is (cheaply) `Clone` for +/// all `T`, as is `uint`, so one can store references or indices into +/// another vector. +/// +/// # Example +/// +/// ```rust +/// use std::rand; +/// use std::rand::distributions::{Weighted, WeightedChoice, IndepedentSample}; +/// +/// fn main() { +/// let wc = WeightedChoice::new(~[Weighted { weight: 2, item: 'a' }, +/// Weighted { weight: 4, item: 'b' }, +/// Weighted { weight: 1, item: 'c' }]); +/// let rng = rand::task_rng(); +/// for _ in range(0, 16) { +/// // on average prints 'a' 4 times, 'b' 8 and 'c' twice. +/// println!("{}", wc.ind_sample(rng)); +/// } +/// } +/// ``` +pub struct WeightedChoice<T> { + priv items: ~[Weighted<T>], + priv weight_range: Range<uint> +} + +impl<T: Clone> WeightedChoice<T> { + /// Create a new `WeightedChoice`. + /// + /// Fails if: + /// - `v` is empty + /// - the total weight is 0 + /// - the total weight is larger than a `uint` can contain. + pub fn new(mut items: ~[Weighted<T>]) -> WeightedChoice<T> { + // strictly speaking, this is subsumed by the total weight == 0 case + assert!(!items.is_empty(), "WeightedChoice::new called with no items"); + + let mut running_total = 0u; + + // we convert the list from individual weights to cumulative + // weights so we can binary search. This *could* drop elements + // with weight == 0 as an optimisation. + for item in items.mut_iter() { + running_total = running_total.checked_add(&item.weight) + .expect("WeightedChoice::new called with a total weight larger \ + than a uint can contain"); + + item.weight = running_total; + } + assert!(running_total != 0, "WeightedChoice::new called with a total weight of 0"); + + WeightedChoice { + items: items, + // we're likely to be generating numbers in this range + // relatively often, so might as well cache it + weight_range: Range::new(0, running_total) + } + } +} + +impl<T: Clone> Sample<T> for WeightedChoice<T> { + fn sample<R: Rng>(&mut self, rng: &mut R) -> T { self.ind_sample(rng) } +} + +impl<T: Clone> IndependentSample<T> for WeightedChoice<T> { + fn ind_sample<R: Rng>(&self, rng: &mut R) -> T { + // we want to find the first element that has cumulative + // weight > sample_weight, which we do by binary since the + // cumulative weights of self.items are sorted. + + // choose a weight in [0, total_weight) + let sample_weight = self.weight_range.ind_sample(rng); + + // short circuit when it's the first item + if sample_weight < self.items[0].weight { + return self.items[0].item.clone(); + } + + let mut idx = 0; + let mut modifier = self.items.len(); + + // now we know that every possibility has an element to the + // left, so we can just search for the last element that has + // cumulative weight <= sample_weight, then the next one will + // be "it". (Note that this greatest element will never be the + // last element of the vector, since sample_weight is chosen + // in [0, total_weight) and the cumulative weight of the last + // one is exactly the total weight.) + while modifier > 1 { + let i = idx + modifier / 2; + if self.items[i].weight <= sample_weight { + // we're small, so look to the right, but allow this + // exact element still. + idx = i; + // we need the `/ 2` to round up otherwise we'll drop + // the trailing elements when `modifier` is odd. + modifier += 1; + } else { + // otherwise we're too big, so go left. (i.e. do + // nothing) + } + modifier /= 2; + } + return self.items[idx + 1].item.clone(); + } +} mod ziggurat_tables; -// inlining should mean there is no performance penalty for this -#[inline] +/// Sample a random number using the Ziggurat method (specifically the +/// ZIGNOR variant from Doornik 2005). Most of the arguments are +/// directly from the paper: +/// +/// * `rng`: source of randomness +/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0. +/// * `X`: the $x_i$ abscissae. +/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$) +/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$ +/// * `pdf`: the probability density function +/// * `zero_case`: manual sampling from the tail when we chose the +/// bottom box (i.e. i == 0) + +// the perf improvement (25-50%) is definitely worth the extra code +// size from force-inlining. +#[inline(always)] fn ziggurat<R:Rng>(rng: &mut R, - center_u: bool, + symmetric: bool, X: ziggurat_tables::ZigTable, F: ziggurat_tables::ZigTable, F_DIFF: ziggurat_tables::ZigTable, - pdf: &'static fn(f64) -> f64, // probability density function + pdf: &'static fn(f64) -> f64, zero_case: &'static fn(&mut R, f64) -> f64) -> f64 { + static SCALE: f64 = (1u64 << 53) as f64; loop { - let u = if center_u {2.0 * rng.gen() - 1.0} else {rng.gen()}; - let i: uint = rng.gen::<uint>() & 0xff; + // reimplement the f64 generation as an optimisation suggested + // by the Doornik paper: we have a lot of precision-space + // (i.e. there are 11 bits of the 64 of a u64 to use after + // creating a f64), so we might as well reuse some to save + // generating a whole extra random number. (Seems to be 15% + // faster.) + let bits: u64 = rng.gen(); + let i = (bits & 0xff) as uint; + let f = (bits >> 11) as f64 / SCALE; + + // u is either U(-1, 1) or U(0, 1) depending on if this is a + // symmetric distribution or not. + let u = if symmetric {2.0 * f - 1.0} else {f}; let x = u * X[i]; - let test_x = if center_u {num::abs(x)} else {x}; + let test_x = if symmetric {num::abs(x)} else {x}; // algebraically equivalent to |u| < X[i+1]/X[i] (or u < X[i+1]/X[i]) if test_x < X[i + 1] { @@ -49,30 +237,25 @@ fn ziggurat<R:Rng>(rng: &mut R, return zero_case(rng, u); } // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1 - if F[i+1] + F_DIFF[i+1] * rng.gen() < pdf(x) { + if F[i + 1] + F_DIFF[i + 1] * rng.gen() < pdf(x) { return x; } } } -/// A wrapper around an `f64` to generate N(0, 1) random numbers (a.k.a. a -/// standard normal, or Gaussian). Multiplying the generated values by the -/// desired standard deviation `sigma` then adding the desired mean `mu` will -/// give N(mu, sigma^2) distributed random numbers. +/// A wrapper around an `f64` to generate N(0, 1) random numbers +/// (a.k.a. a standard normal, or Gaussian). /// -/// Note that this has to be unwrapped before use as an `f64` (using either -/// `*` or `cast::transmute` is safe). +/// See `Normal` for the general normal distribution. That this has to +/// be unwrapped before use as an `f64` (using either `*` or +/// `cast::transmute` is safe). /// -/// # Example +/// Implemented via the ZIGNOR variant[1] of the Ziggurat method. /// -/// ``` -/// use std::rand::distributions::StandardNormal; -/// -/// fn main() { -/// let normal = 2.0 + (*rand::random::<StandardNormal>()) * 3.0; -/// println!("{} is from a N(2, 9) distribution", normal) -/// } -/// ``` +/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to +/// Generate Normal Random +/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield +/// College, Oxford pub struct StandardNormal(f64); impl Rand for StandardNormal { @@ -110,23 +293,62 @@ impl Rand for StandardNormal { } } -/// A wrapper around an `f64` to generate Exp(1) random numbers. Dividing by -/// the desired rate `lambda` will give Exp(lambda) distributed random -/// numbers. +/// The normal distribution `N(mean, std_dev**2)`. /// -/// Note that this has to be unwrapped before use as an `f64` (using either -/// `*` or `cast::transmute` is safe). +/// This uses the ZIGNOR variant of the Ziggurat method, see +/// `StandardNormal` for more details. /// /// # Example /// /// ``` -/// use std::rand::distributions::Exp1; +/// use std::rand; +/// use std::rand::distributions::{Normal, IndependentSample}; /// /// fn main() { -/// let exp2 = (*rand::random::<Exp1>()) * 0.5; -/// println!("{} is from a Exp(2) distribution", exp2); +/// let normal = Normal::new(2.0, 3.0); +/// let v = normal.ind_sample(rand::task_rng()); +/// println!("{} is from a N(2, 9) distribution", v) /// } /// ``` +pub struct Normal { + priv mean: f64, + priv std_dev: f64 +} + +impl Normal { + /// Construct a new `Normal` distribution with the given mean and + /// standard deviation. Fails if `std_dev < 0`. + pub fn new(mean: f64, std_dev: f64) -> Normal { + assert!(std_dev >= 0.0, "Normal::new called with `std_dev` < 0"); + Normal { + mean: mean, + std_dev: std_dev + } + } +} +impl Sample<f64> for Normal { + fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } +} +impl IndependentSample<f64> for Normal { + fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 { + self.mean + self.std_dev * (*rng.gen::<StandardNormal>()) + } +} + +/// A wrapper around an `f64` to generate Exp(1) random numbers. +/// +/// See `Exp` for the general exponential distribution.Note that this + // has to be unwrapped before use as an `f64` (using either +/// `*` or `cast::transmute` is safe). +/// +/// Implemented via the ZIGNOR variant[1] of the Ziggurat method. The +/// exact description in the paper was adjusted to use tables for the +/// exponential distribution rather than normal. +/// +/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to +/// Generate Normal Random +/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield +/// College, Oxford pub struct Exp1(f64); // This could be done via `-rng.gen::<f64>().ln()` but that is slower. @@ -148,3 +370,221 @@ impl Rand for Exp1 { pdf, zero_case)) } } + +/// The exponential distribution `Exp(lambda)`. +/// +/// This distribution has density function: `f(x) = lambda * +/// exp(-lambda * x)` for `x > 0`. +/// +/// # Example +/// +/// ``` +/// use std::rand; +/// use std::rand::distributions::{Exp, IndependentSample}; +/// +/// fn main() { +/// let exp = Exp::new(2.0); +/// let v = exp.ind_sample(rand::task_rng()); +/// println!("{} is from a Exp(2) distribution", v); +/// } +/// ``` +pub struct Exp { + /// `lambda` stored as `1/lambda`, since this is what we scale by. + priv lambda_inverse: f64 +} + +impl Exp { + /// Construct a new `Exp` with the given shape parameter + /// `lambda`. Fails if `lambda <= 0`. + pub fn new(lambda: f64) -> Exp { + assert!(lambda > 0.0, "Exp::new called with `lambda` <= 0"); + Exp { lambda_inverse: 1.0 / lambda } + } +} + +impl Sample<f64> for Exp { + fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } +} +impl IndependentSample<f64> for Exp { + fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 { + (*rng.gen::<Exp1>()) * self.lambda_inverse + } +} + +#[cfg(test)] +mod tests { + use rand::*; + use super::*; + use iter::range; + use option::{Some, None}; + + struct ConstRand(uint); + impl Rand for ConstRand { + fn rand<R: Rng>(_: &mut R) -> ConstRand { + ConstRand(0) + } + } + + // 0, 1, 2, 3, ... + struct CountingRng { i: u32 } + impl Rng for CountingRng { + fn next_u32(&mut self) -> u32 { + self.i += 1; + self.i - 1 + } + fn next_u64(&mut self) -> u64 { + self.next_u32() as u64 + } + } + + #[test] + fn test_rand_sample() { + let mut rand_sample = RandSample::<ConstRand>; + + assert_eq!(*rand_sample.sample(task_rng()), 0); + assert_eq!(*rand_sample.ind_sample(task_rng()), 0); + } + + #[test] + fn test_normal() { + let mut norm = Normal::new(10.0, 10.0); + let rng = task_rng(); + for _ in range(0, 1000) { + norm.sample(rng); + norm.ind_sample(rng); + } + } + #[test] + #[should_fail] + fn test_normal_invalid_sd() { + Normal::new(10.0, -1.0); + } + + #[test] + fn test_exp() { + let mut exp = Exp::new(10.0); + let rng = task_rng(); + for _ in range(0, 1000) { + assert!(exp.sample(rng) >= 0.0); + assert!(exp.ind_sample(rng) >= 0.0); + } + } + #[test] + #[should_fail] + fn test_exp_invalid_lambda_zero() { + Exp::new(0.0); + } + #[test] + #[should_fail] + fn test_exp_invalid_lambda_neg() { + Exp::new(-10.0); + } + + #[test] + fn test_weighted_choice() { + // this makes assumptions about the internal implementation of + // WeightedChoice, specifically: it doesn't reorder the items, + // it doesn't do weird things to the RNG (so 0 maps to 0, 1 to + // 1, internally; modulo a modulo operation). + + macro_rules! t ( + ($items:expr, $expected:expr) => {{ + let wc = WeightedChoice::new($items); + let expected = $expected; + + let mut rng = CountingRng { i: 0 }; + + for &val in expected.iter() { + assert_eq!(wc.ind_sample(&mut rng), val) + } + }} + ); + + t!(~[Weighted { weight: 1, item: 10}], ~[10]); + + // skip some + t!(~[Weighted { weight: 0, item: 20}, + Weighted { weight: 2, item: 21}, + Weighted { weight: 0, item: 22}, + Weighted { weight: 1, item: 23}], + ~[21,21, 23]); + + // different weights + t!(~[Weighted { weight: 4, item: 30}, + Weighted { weight: 3, item: 31}], + ~[30,30,30,30, 31,31,31]); + + // check that we're binary searching + // correctly with some vectors of odd + // length. + t!(~[Weighted { weight: 1, item: 40}, + Weighted { weight: 1, item: 41}, + Weighted { weight: 1, item: 42}, + Weighted { weight: 1, item: 43}, + Weighted { weight: 1, item: 44}], + ~[40, 41, 42, 43, 44]); + t!(~[Weighted { weight: 1, item: 50}, + Weighted { weight: 1, item: 51}, + Weighted { weight: 1, item: 52}, + Weighted { weight: 1, item: 53}, + Weighted { weight: 1, item: 54}, + Weighted { weight: 1, item: 55}, + Weighted { weight: 1, item: 56}], + ~[50, 51, 52, 53, 54, 55, 56]); + } + + #[test] #[should_fail] + fn test_weighted_choice_no_items() { + WeightedChoice::<int>::new(~[]); + } + #[test] #[should_fail] + fn test_weighted_choice_zero_weight() { + WeightedChoice::new(~[Weighted { weight: 0, item: 0}, + Weighted { weight: 0, item: 1}]); + } + #[test] #[should_fail] + fn test_weighted_choice_weight_overflows() { + let x = (-1) as uint / 2; // x + x + 2 is the overflow + WeightedChoice::new(~[Weighted { weight: x, item: 0 }, + Weighted { weight: 1, item: 1 }, + Weighted { weight: x, item: 2 }, + Weighted { weight: 1, item: 3 }]); + } +} + +#[cfg(test)] +mod bench { + use extra::test::BenchHarness; + use rand::*; + use super::*; + use iter::range; + use option::{Some, None}; + use mem::size_of; + + static N: u64 = 100; + + #[bench] + fn rand_normal(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + let mut normal = Normal::new(-2.71828, 3.14159); + + do bh.iter { + for _ in range(0, N) { + normal.sample(&mut rng); + } + } + bh.bytes = size_of::<f64>() as u64 * N; + } + #[bench] + fn rand_exp(bh: &mut BenchHarness) { + let mut rng = XorShiftRng::new(); + let mut exp = Exp::new(2.71828 * 3.14159); + + do bh.iter { + for _ in range(0, N) { + exp.sample(&mut rng); + } + } + bh.bytes = size_of::<f64>() as u64 * N; + } +} diff --git a/src/libstd/rand/isaac.rs b/src/libstd/rand/isaac.rs index 0068b60cfa5..42254b211a1 100644 --- a/src/libstd/rand/isaac.rs +++ b/src/libstd/rand/isaac.rs @@ -10,18 +10,24 @@ //! The ISAAC random number generator. -use cast; use rand::{Rng, SeedableRng, OSRng}; use iter::{Iterator, range, range_step, Repeat}; use option::{None, Some}; +use vec::raw; +use mem; static RAND_SIZE_LEN: u32 = 8; static RAND_SIZE: u32 = 1 << RAND_SIZE_LEN; -/// A random number generator that uses the [ISAAC -/// algorithm](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29). +/// A random number generator that uses the ISAAC algorithm[1]. /// -/// The ISAAC algorithm is suitable for cryptographic purposes. +/// The ISAAC algorithm is generally accepted as suitable for +/// cryptographic purposes, but this implementation has not be +/// verified as such. Prefer a generator like `OSRng` that defers to +/// the operating system for cases that need high security. +/// +/// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number +/// generator*](http://www.burtleburtle.net/bob/rand/isaacafa.html) pub struct IsaacRng { priv cnt: u32, priv rsl: [u32, .. RAND_SIZE], @@ -42,9 +48,12 @@ impl IsaacRng { pub fn new() -> IsaacRng { let mut rng = EMPTY; - { - let bytes = unsafe {cast::transmute::<&mut [u32], &mut [u8]>(rng.rsl)}; - OSRng::new().fill_bytes(bytes); + unsafe { + let ptr = raw::to_mut_ptr(rng.rsl); + + do raw::mut_buf_as_slice(ptr as *mut u8, mem::size_of_val(&rng.rsl)) |slice| { + OSRng::new().fill_bytes(slice); + } } rng.init(true); @@ -212,11 +221,16 @@ impl<'self> SeedableRng<&'self [u32]> for IsaacRng { static RAND_SIZE_64_LEN: uint = 8; static RAND_SIZE_64: uint = 1 << RAND_SIZE_64_LEN; -/// A random number generator that uses the 64-bit variant of the -/// [ISAAC -/// algorithm](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29). +/// A random number generator that uses ISAAC-64[1], the 64-bit +/// variant of the ISAAC algorithm. +/// +/// The ISAAC algorithm is generally accepted as suitable for +/// cryptographic purposes, but this implementation has not be +/// verified as such. Prefer a generator like `OSRng` that defers to +/// the operating system for cases that need high security. /// -/// The ISAAC algorithm is suitable for cryptographic purposes. +/// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number +/// generator*](http://www.burtleburtle.net/bob/rand/isaacafa.html) pub struct Isaac64Rng { priv cnt: uint, priv rsl: [u64, .. RAND_SIZE_64], @@ -238,10 +252,15 @@ impl Isaac64Rng { /// seed. pub fn new() -> Isaac64Rng { let mut rng = EMPTY_64; - { - let bytes = unsafe {cast::transmute::<&mut [u64], &mut [u8]>(rng.rsl)}; - OSRng::new().fill_bytes(bytes); + + unsafe { + let ptr = raw::to_mut_ptr(rng.rsl); + + do raw::mut_buf_as_slice(ptr as *mut u8, mem::size_of_val(&rng.rsl)) |slice| { + OSRng::new().fill_bytes(slice); + } } + rng.init(true); rng } @@ -434,14 +453,14 @@ mod test { #[test] fn test_rng_32_seeded() { - let seed = &[2, 32, 4, 32, 51]; + let seed = &[1, 23, 456, 7890, 12345]; let mut ra: IsaacRng = SeedableRng::from_seed(seed); let mut rb: IsaacRng = SeedableRng::from_seed(seed); assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u)); } #[test] fn test_rng_64_seeded() { - let seed = &[2, 32, 4, 32, 51]; + let seed = &[1, 23, 456, 7890, 12345]; let mut ra: Isaac64Rng = SeedableRng::from_seed(seed); let mut rb: Isaac64Rng = SeedableRng::from_seed(seed); assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u)); @@ -472,46 +491,46 @@ mod test { #[test] fn test_rng_32_true_values() { - let seed = &[2, 32, 4, 32, 51]; + let seed = &[1, 23, 456, 7890, 12345]; let mut ra: IsaacRng = SeedableRng::from_seed(seed); // Regression test that isaac is actually using the above vector let v = vec::from_fn(10, |_| ra.next_u32()); assert_eq!(v, - ~[447462228, 2081944040, 3163797308, 2379916134, 2377489184, - 1132373754, 536342443, 2995223415, 1265094839, 345325140]); + ~[2558573138, 873787463, 263499565, 2103644246, 3595684709, + 4203127393, 264982119, 2765226902, 2737944514, 3900253796]); - let seed = &[500, -4000, 123456, 9876543, 1, 1, 1, 1, 1]; + let seed = &[12345, 67890, 54321, 9876]; let mut rb: IsaacRng = SeedableRng::from_seed(seed); // skip forward to the 10000th number for _ in range(0, 10000) { rb.next_u32(); } let v = vec::from_fn(10, |_| rb.next_u32()); assert_eq!(v, - ~[612373032, 292987903, 1819311337, 3141271980, 422447569, - 310096395, 1083172510, 867909094, 2478664230, 2073577855]); + ~[3676831399, 3183332890, 2834741178, 3854698763, 2717568474, + 1576568959, 3507990155, 179069555, 141456972, 2478885421]); } #[test] fn test_rng_64_true_values() { - let seed = &[2, 32, 4, 32, 51]; + let seed = &[1, 23, 456, 7890, 12345]; let mut ra: Isaac64Rng = SeedableRng::from_seed(seed); // Regression test that isaac is actually using the above vector let v = vec::from_fn(10, |_| ra.next_u64()); assert_eq!(v, - ~[15015576812873463115, 12461067598045625862, 14818626436142668771, - 5562406406765984441, 11813289907965514161, 13443797187798420053, - 6935026941854944442, 7750800609318664042, 14428747036317928637, - 14028894460301215947]); + ~[547121783600835980, 14377643087320773276, 17351601304698403469, + 1238879483818134882, 11952566807690396487, 13970131091560099343, + 4469761996653280935, 15552757044682284409, 6860251611068737823, + 13722198873481261842]); - let seed = &[500, -4000, 123456, 9876543, 1, 1, 1, 1, 1]; + let seed = &[12345, 67890, 54321, 9876]; let mut rb: Isaac64Rng = SeedableRng::from_seed(seed); // skip forward to the 10000th number for _ in range(0, 10000) { rb.next_u64(); } let v = vec::from_fn(10, |_| rb.next_u64()); assert_eq!(v, - ~[13557216323596688637, 17060829581390442094, 4927582063811333743, - 2699639759356482270, 4819341314392384881, 6047100822963614452, - 11086255989965979163, 11901890363215659856, 5370800226050011580, - 16496463556025356451]); + ~[18143823860592706164, 8491801882678285927, 2699425367717515619, + 17196852593171130876, 2606123525235546165, 15790932315217671084, + 596345674630742204, 9947027391921273664, 11788097613744130851, + 10391409374914919106]); } } diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index f5c60417bac..a6efdfc66db 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -28,6 +28,23 @@ from an operating-system source of randomness, e.g. `/dev/urandom` on Unix systems, and will automatically reseed itself from this source after generating 32 KiB of random data. +# Cryptographic security + +An application that requires random numbers for cryptographic purposes +should prefer `OSRng`, which reads randomness from one of the source +that the operating system provides (e.g. `/dev/urandom` on +Unixes). The other random number generators provided by this module +are either known to be insecure (`XorShiftRng`), or are not verified +to be secure (`IsaacRng`, `Isaac64Rng` and `StdRng`). + +*Note*: on Linux, `/dev/random` is more secure than `/dev/urandom`, +but it is a blocking RNG, and will wait until it has determined that +it has collected enough entropy to fulfill a request for random +data. It can be used with the `Rng` trait provided by this module by +opening the file and passing it to `reader::ReaderRng`. Since it +blocks, `/dev/random` should only be used to retrieve small amounts of +randomness. + # Examples ```rust @@ -52,20 +69,21 @@ fn main () { ``` */ -use mem::size_of; -use unstable::raw::Slice; use cast; +use cmp::Ord; use container::Container; use iter::{Iterator, range}; use local_data; use prelude::*; use str; -use u64; use vec; pub use self::isaac::{IsaacRng, Isaac64Rng}; pub use self::os::OSRng; +use self::distributions::{Range, IndependentSample}; +use self::distributions::range::SampleRange; + pub mod distributions; pub mod isaac; pub mod os; @@ -80,14 +98,6 @@ pub trait Rand { fn rand<R: Rng>(rng: &mut R) -> Self; } -/// A value with a particular weight compared to other values -pub struct Weighted<T> { - /// The numerical weight of this item - weight: uint, - /// The actual item which is being weighted - item: T, -} - /// A random number generator pub trait Rng { /// Return the next random u32. This rarely needs to be called @@ -136,46 +146,26 @@ pub trait Rng { /// } /// ``` fn fill_bytes(&mut self, dest: &mut [u8]) { - let mut slice: Slice<u64> = unsafe { cast::transmute_copy(&dest) }; - slice.len /= size_of::<u64>(); - let as_u64: &mut [u64] = unsafe { cast::transmute(slice) }; - for dest in as_u64.mut_iter() { - *dest = self.next_u64(); - } - - // the above will have filled up the vector as much as - // possible in multiples of 8 bytes. - let mut remaining = dest.len() % 8; - - // space for a u32 - if remaining >= 4 { - let mut slice: Slice<u32> = unsafe { cast::transmute_copy(&dest) }; - slice.len /= size_of::<u32>(); - let as_u32: &mut [u32] = unsafe { cast::transmute(slice) }; - as_u32[as_u32.len() - 1] = self.next_u32(); - remaining -= 4; - } - // exactly filled - if remaining == 0 { return } - - // now we know we've either got 1, 2 or 3 spots to go, - // i.e. exactly one u32 is enough. - let rand = self.next_u32(); - let remaining_index = dest.len() - remaining; - match dest.mut_slice_from(remaining_index) { - [ref mut a] => { - *a = rand as u8; - } - [ref mut a, ref mut b] => { - *a = rand as u8; - *b = (rand >> 8) as u8; - } - [ref mut a, ref mut b, ref mut c] => { - *a = rand as u8; - *b = (rand >> 8) as u8; - *c = (rand >> 16) as u8; + // this could, in theory, be done by transmuting dest to a + // [u64], but this is (1) likely to be undefined behaviour for + // LLVM, (2) has to be very careful about alignment concerns, + // (3) adds more `unsafe` that needs to be checked, (4) + // probably doesn't give much performance gain if + // optimisations are on. + let mut count = 0; + let mut num = 0; + for byte in dest.mut_iter() { + if count == 0 { + // we could micro-optimise here by generating a u32 if + // we only need a few more bytes to fill the vector + // (i.e. at most 4). + num = self.next_u64(); + count = 8; } - _ => fail!("Rng.fill_bytes: the impossible occurred: remaining != 1, 2 or 3") + + *byte = (num & 0xff) as u8; + num >>= 8; + count -= 1; } } @@ -218,14 +208,14 @@ pub trait Rng { vec::from_fn(len, |_| self.gen()) } - /// Generate a random primitive integer in the range [`low`, - /// `high`). Fails if `low >= high`. + /// Generate a random value in the range [`low`, `high`). Fails if + /// `low >= high`. /// - /// This gives a uniform distribution (assuming this RNG is itself - /// uniform), even for edge cases like `gen_integer_range(0u8, - /// 170)`, which a naive modulo operation would return numbers - /// less than 85 with double the probability to those greater than - /// 85. + /// This is a convenience wrapper around + /// `distributions::Range`. If this function will be called + /// repeatedly with the same arguments, one should use `Range`, as + /// that will amortize the computations that allow for perfect + /// uniformity, as they only happen on initialization. /// /// # Example /// @@ -235,22 +225,15 @@ pub trait Rng { /// /// fn main() { /// let mut rng = rand::task_rng(); - /// let n: uint = rng.gen_integer_range(0u, 10); + /// let n: uint = rng.gen_range(0u, 10); /// println!("{}", n); - /// let m: int = rng.gen_integer_range(-40, 400); + /// let m: float = rng.gen_range(-40.0, 1.3e5); /// println!("{}", m); /// } /// ``` - fn gen_integer_range<T: Rand + Int>(&mut self, low: T, high: T) -> T { - assert!(low < high, "RNG.gen_integer_range called with low >= high"); - let range = (high - low).to_u64().unwrap(); - let accept_zone = u64::max_value - u64::max_value % range; - loop { - let rand = self.gen::<u64>(); - if rand < accept_zone { - return low + NumCast::from(rand % range).unwrap(); - } - } + fn gen_range<T: Ord + SampleRange>(&mut self, low: T, high: T) -> T { + assert!(low < high, "Rng.gen_range called with low >= high"); + Range::new(low, high).ind_sample(self) } /// Return a bool with a 1 in n chance of true @@ -267,7 +250,7 @@ pub trait Rng { /// } /// ``` fn gen_weighted_bool(&mut self, n: uint) -> bool { - n == 0 || self.gen_integer_range(0, n) == 0 + n == 0 || self.gen_range(0, n) == 0 } /// Return a random string of the specified length composed of @@ -317,93 +300,8 @@ pub trait Rng { if values.is_empty() { None } else { - Some(&values[self.gen_integer_range(0u, values.len())]) - } - } - - /// Choose an item respecting the relative weights, failing if the sum of - /// the weights is 0 - /// - /// # Example - /// - /// ```rust - /// use std::rand; - /// use std::rand::Rng; - /// - /// fn main() { - /// let mut rng = rand::rng(); - /// let x = [rand::Weighted {weight: 4, item: 'a'}, - /// rand::Weighted {weight: 2, item: 'b'}, - /// rand::Weighted {weight: 2, item: 'c'}]; - /// println!("{}", rng.choose_weighted(x)); - /// } - /// ``` - fn choose_weighted<T:Clone>(&mut self, v: &[Weighted<T>]) -> T { - self.choose_weighted_option(v).expect("Rng.choose_weighted: total weight is 0") - } - - /// Choose Some(item) respecting the relative weights, returning none if - /// the sum of the weights is 0 - /// - /// # Example - /// - /// ```rust - /// use std::rand; - /// use std::rand::Rng; - /// - /// fn main() { - /// let mut rng = rand::rng(); - /// let x = [rand::Weighted {weight: 4, item: 'a'}, - /// rand::Weighted {weight: 2, item: 'b'}, - /// rand::Weighted {weight: 2, item: 'c'}]; - /// println!("{:?}", rng.choose_weighted_option(x)); - /// } - /// ``` - fn choose_weighted_option<T:Clone>(&mut self, v: &[Weighted<T>]) - -> Option<T> { - let mut total = 0u; - for item in v.iter() { - total += item.weight; - } - if total == 0u { - return None; - } - let chosen = self.gen_integer_range(0u, total); - let mut so_far = 0u; - for item in v.iter() { - so_far += item.weight; - if so_far > chosen { - return Some(item.item.clone()); - } + Some(&values[self.gen_range(0u, values.len())]) } - unreachable!(); - } - - /// Return a vec containing copies of the items, in order, where - /// the weight of the item determines how many copies there are - /// - /// # Example - /// - /// ```rust - /// use std::rand; - /// use std::rand::Rng; - /// - /// fn main() { - /// let mut rng = rand::rng(); - /// let x = [rand::Weighted {weight: 4, item: 'a'}, - /// rand::Weighted {weight: 2, item: 'b'}, - /// rand::Weighted {weight: 2, item: 'c'}]; - /// println!("{}", rng.weighted_vec(x)); - /// } - /// ``` - fn weighted_vec<T:Clone>(&mut self, v: &[Weighted<T>]) -> ~[T] { - let mut r = ~[]; - for item in v.iter() { - for _ in range(0u, item.weight) { - r.push(item.item.clone()); - } - } - r } /// Shuffle a vec @@ -447,7 +345,7 @@ pub trait Rng { // invariant: elements with index >= i have been locked in place. i -= 1u; // lock element i in place. - values.swap(i, self.gen_integer_range(0u, i + 1u)); + values.swap(i, self.gen_range(0u, i + 1u)); } } @@ -473,7 +371,7 @@ pub trait Rng { continue } - let k = self.gen_integer_range(0, i + 1); + let k = self.gen_range(0, i + 1); if k < reservoir.len() { reservoir[k] = elem } @@ -520,8 +418,8 @@ pub trait SeedableRng<Seed>: Rng { /// Create a random number generator with a default algorithm and seed. /// -/// It returns the cryptographically-safest `Rng` algorithm currently -/// available in Rust. If you require a specifically seeded `Rng` for +/// It returns the strongest `Rng` algorithm currently implemented in +/// pure Rust. If you require a specifically seeded `Rng` for /// consistency over time you should pick one algorithm and create the /// `Rng` yourself. /// @@ -596,12 +494,16 @@ pub fn weak_rng() -> XorShiftRng { XorShiftRng::new() } -/// An [Xorshift random number -/// generator](http://en.wikipedia.org/wiki/Xorshift). +/// An Xorshift[1] random number +/// generator. /// /// The Xorshift algorithm is not suitable for cryptographic purposes /// but is very fast. If you do not know for sure that it fits your -/// requirements, use a more secure one such as `IsaacRng`. +/// requirements, use a more secure one such as `IsaacRng` or `OSRng`. +/// +/// [1]: Marsaglia, George (July 2003). ["Xorshift +/// RNGs"](http://www.jstatsoft.org/v08/i14/paper). *Journal of +/// Statistical Software*. Vol. 8 (Issue 14). pub struct XorShiftRng { priv x: u32, priv y: u32, @@ -749,47 +651,68 @@ pub fn random<T: Rand>() -> T { mod test { use iter::{Iterator, range}; use option::{Option, Some}; + use vec; use super::*; + struct ConstRng { i: u64 } + impl Rng for ConstRng { + fn next_u32(&mut self) -> u32 { self.i as u32 } + fn next_u64(&mut self) -> u64 { self.i } + + // no fill_bytes on purpose + } + #[test] fn test_fill_bytes_default() { - let mut r = weak_rng(); - - let mut v = [0u8, .. 100]; - r.fill_bytes(v); + let mut r = ConstRng { i: 0x11_22_33_44_55_66_77_88 }; + + // check every remainder mod 8, both in small and big vectors. + let lengths = [0, 1, 2, 3, 4, 5, 6, 7, + 80, 81, 82, 83, 84, 85, 86, 87]; + for &n in lengths.iter() { + let mut v = vec::from_elem(n, 0u8); + r.fill_bytes(v); + + // use this to get nicer error messages. + for (i, &byte) in v.iter().enumerate() { + if byte == 0 { + fail!("byte {} of {} is zero", i, n) + } + } + } } #[test] - fn test_gen_integer_range() { + fn test_gen_range() { let mut r = rng(); for _ in range(0, 1000) { - let a = r.gen_integer_range(-3i, 42); + let a = r.gen_range(-3i, 42); assert!(a >= -3 && a < 42); - assert_eq!(r.gen_integer_range(0, 1), 0); - assert_eq!(r.gen_integer_range(-12, -11), -12); + assert_eq!(r.gen_range(0, 1), 0); + assert_eq!(r.gen_range(-12, -11), -12); } for _ in range(0, 1000) { - let a = r.gen_integer_range(10, 42); + let a = r.gen_range(10, 42); assert!(a >= 10 && a < 42); - assert_eq!(r.gen_integer_range(0, 1), 0); - assert_eq!(r.gen_integer_range(3_000_000u, 3_000_001), 3_000_000); + assert_eq!(r.gen_range(0, 1), 0); + assert_eq!(r.gen_range(3_000_000u, 3_000_001), 3_000_000); } } #[test] #[should_fail] - fn test_gen_integer_range_fail_int() { + fn test_gen_range_fail_int() { let mut r = rng(); - r.gen_integer_range(5i, -2); + r.gen_range(5i, -2); } #[test] #[should_fail] - fn test_gen_integer_range_fail_uint() { + fn test_gen_range_fail_uint() { let mut r = rng(); - r.gen_integer_range(5u, 2u); + r.gen_range(5u, 2u); } #[test] @@ -844,44 +767,6 @@ mod test { } #[test] - fn test_choose_weighted() { - let mut r = rng(); - assert!(r.choose_weighted([ - Weighted { weight: 1u, item: 42 }, - ]) == 42); - assert!(r.choose_weighted([ - Weighted { weight: 0u, item: 42 }, - Weighted { weight: 1u, item: 43 }, - ]) == 43); - } - - #[test] - fn test_choose_weighted_option() { - let mut r = rng(); - assert!(r.choose_weighted_option([ - Weighted { weight: 1u, item: 42 }, - ]) == Some(42)); - assert!(r.choose_weighted_option([ - Weighted { weight: 0u, item: 42 }, - Weighted { weight: 1u, item: 43 }, - ]) == Some(43)); - let v: Option<int> = r.choose_weighted_option([]); - assert!(v.is_none()); - } - - #[test] - fn test_weighted_vec() { - let mut r = rng(); - let empty: ~[int] = ~[]; - assert_eq!(r.weighted_vec([]), empty); - assert!(r.weighted_vec([ - Weighted { weight: 0u, item: 3u }, - Weighted { weight: 1u, item: 2u }, - Weighted { weight: 2u, item: 1u }, - ]) == ~[2u, 1u, 1u]); - } - - #[test] fn test_shuffle() { let mut r = rng(); let empty: ~[int] = ~[]; @@ -894,7 +779,7 @@ mod test { let mut r = task_rng(); r.gen::<int>(); assert_eq!(r.shuffle(~[1, 1, 1]), ~[1, 1, 1]); - assert_eq!(r.gen_integer_range(0u, 1u), 0u); + assert_eq!(r.gen_range(0u, 1u), 0u); } #[test] @@ -953,41 +838,53 @@ mod bench { use extra::test::BenchHarness; use rand::*; use mem::size_of; + use iter::range; + use option::{Some, None}; + + static N: u64 = 100; #[bench] fn rand_xorshift(bh: &mut BenchHarness) { let mut rng = XorShiftRng::new(); do bh.iter { - rng.gen::<uint>(); + for _ in range(0, N) { + rng.gen::<uint>(); + } } - bh.bytes = size_of::<uint>() as u64; + bh.bytes = size_of::<uint>() as u64 * N; } #[bench] fn rand_isaac(bh: &mut BenchHarness) { let mut rng = IsaacRng::new(); do bh.iter { - rng.gen::<uint>(); + for _ in range(0, N) { + rng.gen::<uint>(); + } } - bh.bytes = size_of::<uint>() as u64; + bh.bytes = size_of::<uint>() as u64 * N; } #[bench] fn rand_isaac64(bh: &mut BenchHarness) { let mut rng = Isaac64Rng::new(); do bh.iter { - rng.gen::<uint>(); + for _ in range(0, N) { + rng.gen::<uint>(); + } } - bh.bytes = size_of::<uint>() as u64; + bh.bytes = size_of::<uint>() as u64 * N; } #[bench] fn rand_std(bh: &mut BenchHarness) { let mut rng = StdRng::new(); do bh.iter { - rng.gen::<uint>(); + for _ in range(0, N) { + rng.gen::<uint>(); + } } - bh.bytes = size_of::<uint>() as u64; + bh.bytes = size_of::<uint>() as u64 * N; } #[bench] diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 4c8cf06c55e..5ed8d6b10d1 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -30,8 +30,12 @@ type HCRYPTPROV = c_long; // assume they work when we call them. /// A random number generator that retrieves randomness straight from -/// the operating system. On Unix-like systems this reads from -/// `/dev/urandom`, on Windows this uses `CryptGenRandom`. +/// the operating system. Platform sources: +/// +/// - Unix-like systems (Linux, Android, Mac OSX): read directly from +/// `/dev/urandom`. +/// - Windows: calls `CryptGenRandom`, using the default cryptographic +/// service provider with the `PROV_RSA_FULL` type. /// /// This does not block. #[cfg(unix)] @@ -39,8 +43,12 @@ pub struct OSRng { priv inner: ReaderRng<file::FileStream> } /// A random number generator that retrieves randomness straight from -/// the operating system. On Unix-like systems this reads from -/// `/dev/urandom`, on Windows this uses `CryptGenRandom`. +/// the operating system. Platform sources: +/// +/// - Unix-like systems (Linux, Android, Mac OSX): read directly from +/// `/dev/urandom`. +/// - Windows: calls `CryptGenRandom`, using the default cryptographic +/// service provider with the `PROV_RSA_FULL` type. /// /// This does not block. #[cfg(windows)] diff --git a/src/libstd/rand/range.rs b/src/libstd/rand/range.rs new file mode 100644 index 00000000000..1b805a0b8f7 --- /dev/null +++ b/src/libstd/rand/range.rs @@ -0,0 +1,235 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Generating numbers between two others. + +// this is surprisingly complicated to be both generic & correct + +use cmp::Ord; +use num::Bounded; +use rand::Rng; +use rand::distributions::{Sample, IndependentSample}; + +/// Sample values uniformly between two bounds. +/// +/// This gives a uniform distribution (assuming the RNG used to sample +/// it is itself uniform & the `SampleRange` implementation for the +/// given type is correct), even for edge cases like `low = 0u8`, +/// `high = 170u8`, for which a naive modulo operation would return +/// numbers less than 85 with double the probability to those greater +/// than 85. +/// +/// Types should attempt to sample in `[low, high)`, i.e., not +/// including `high`, but this may be very difficult. All the +/// primitive integer types satisfy this property, and the float types +/// normally satisfy it, but rounding may mean `high` can occur. +/// +/// # Example +/// +/// ```rust +/// use std::rand; +/// use std::rand::distributions::{IndependentSample, Range}; +/// +/// fn main() { +/// let between = Range::new(10u, 10000u); +/// let rng = rand::task_rng(); +/// let mut sum = 0; +/// for _ in range(0, 1000) { +/// sum += between.ind_sample(rng); +/// } +/// println!("{}", sum); +/// } +/// ``` +pub struct Range<X> { + priv low: X, + priv range: X, + priv accept_zone: X +} + +impl<X: SampleRange + Ord> Range<X> { + /// Create a new `Range` instance that samples uniformly from + /// `[low, high)`. Fails if `low >= high`. + pub fn new(low: X, high: X) -> Range<X> { + assert!(low < high, "Range::new called with `low >= high`"); + SampleRange::construct_range(low, high) + } +} + +impl<Sup: SampleRange> Sample<Sup> for Range<Sup> { + #[inline] + fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) } +} +impl<Sup: SampleRange> IndependentSample<Sup> for Range<Sup> { + fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup { + SampleRange::sample_range(self, rng) + } +} + +/// The helper trait for types that have a sensible way to sample +/// uniformly between two values. This should not be used directly, +/// and is only to facilitate `Range`. +pub trait SampleRange { + /// Construct the `Range` object that `sample_range` + /// requires. This should not ever be called directly, only via + /// `Range::new`, which will check that `low < high`, so this + /// function doesn't have to repeat the check. + fn construct_range(low: Self, high: Self) -> Range<Self>; + + /// Sample a value from the given `Range` with the given `Rng` as + /// a source of randomness. + fn sample_range<R: Rng>(r: &Range<Self>, rng: &mut R) -> Self; +} + +macro_rules! integer_impl { + ($ty:ty, $unsigned:ty) => { + impl SampleRange for $ty { + // we play free and fast with unsigned vs signed here + // (when $ty is signed), but that's fine, since the + // contract of this macro is for $ty and $unsigned to be + // "bit-equal", so casting between them is a no-op & a + // bijection. + + fn construct_range(low: $ty, high: $ty) -> Range<$ty> { + let range = high as $unsigned - low as $unsigned; + let unsigned_max: $unsigned = Bounded::max_value(); + + // this is the largest number that fits into $unsigned + // that `range` divides evenly, so, if we've sampled + // `n` uniformly from this region, then `n % range` is + // uniform in [0, range) + let zone = unsigned_max - unsigned_max % range; + + Range { + low: low, + range: range as $ty, + accept_zone: zone as $ty + } + } + #[inline] + fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty { + loop { + // rejection sample + let v = rng.gen::<$unsigned>(); + // until we find something that fits into the + // region which r.range evenly divides (this will + // be uniformly distributed) + if v < r.accept_zone as $unsigned { + // and return it, with some adjustments + return r.low + (v % r.range as $unsigned) as $ty; + } + } + } + } + } +} + +integer_impl! { i8, u8 } +integer_impl! { i16, u16 } +integer_impl! { i32, u32 } +integer_impl! { i64, u64 } +integer_impl! { int, uint } +integer_impl! { u8, u8 } +integer_impl! { u16, u16 } +integer_impl! { u32, u32 } +integer_impl! { u64, u64 } +integer_impl! { uint, uint } + +macro_rules! float_impl { + ($ty:ty) => { + impl SampleRange for $ty { + fn construct_range(low: $ty, high: $ty) -> Range<$ty> { + Range { + low: low, + range: high - low, + accept_zone: 0.0 // unused + } + } + fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty { + r.low + r.range * rng.gen() + } + } + } +} + +float_impl! { f32 } +float_impl! { f64 } + +#[cfg(test)] +mod tests { + use super::*; + use rand::*; + use num::Bounded; + use iter::range; + use option::{Some, None}; + use vec::ImmutableVector; + + #[should_fail] + #[test] + fn test_range_bad_limits_equal() { + Range::new(10, 10); + } + #[should_fail] + #[test] + fn test_range_bad_limits_flipped() { + Range::new(10, 5); + } + + #[test] + fn test_integers() { + let rng = task_rng(); + macro_rules! t ( + ($($ty:ty),*) => {{ + $( + let v: &[($ty, $ty)] = [(0, 10), + (10, 127), + (Bounded::min_value(), Bounded::max_value())]; + for &(low, high) in v.iter() { + let mut sampler: Range<$ty> = Range::new(low, high); + for _ in range(0, 1000) { + let v = sampler.sample(rng); + assert!(low <= v && v < high); + let v = sampler.ind_sample(rng); + assert!(low <= v && v < high); + } + } + )* + }} + ); + t!(i8, i16, i32, i64, int, + u8, u16, u32, u64, uint) + } + + #[test] + fn test_floats() { + let rng = task_rng(); + macro_rules! t ( + ($($ty:ty),*) => {{ + $( + let v: &[($ty, $ty)] = [(0.0, 100.0), + (-1e35, -1e25), + (1e-35, 1e-25), + (-1e35, 1e35)]; + for &(low, high) in v.iter() { + let mut sampler: Range<$ty> = Range::new(low, high); + for _ in range(0, 1000) { + let v = sampler.sample(rng); + assert!(low <= v && v < high); + let v = sampler.ind_sample(rng); + assert!(low <= v && v < high); + } + } + )* + }} + ); + + t!(f32, f64) + } + +} diff --git a/src/libstd/reflect.rs b/src/libstd/reflect.rs index 1cd76727716..d63b14f982d 100644 --- a/src/libstd/reflect.rs +++ b/src/libstd/reflect.rs @@ -41,7 +41,7 @@ pub fn align(size: uint, align: uint) -> uint { /// Adaptor to wrap around visitors implementing MovePtr. pub struct MovePtrAdaptor<V> { - inner: V + priv inner: V } pub fn MovePtrAdaptor<V:TyVisitor + MovePtr>(v: V) -> MovePtrAdaptor<V> { MovePtrAdaptor { inner: v } diff --git a/src/libstd/repr.rs b/src/libstd/repr.rs index 4feb1ca1910..d03621eb60d 100644 --- a/src/libstd/repr.rs +++ b/src/libstd/repr.rs @@ -98,10 +98,10 @@ enum VariantState { } pub struct ReprVisitor<'self> { - ptr: *c_void, - ptr_stk: ~[*c_void], - var_stk: ~[VariantState], - writer: &'self mut io::Writer + priv ptr: *c_void, + priv ptr_stk: ~[*c_void], + priv var_stk: ~[VariantState], + priv writer: &'self mut io::Writer } pub fn ReprVisitor<'a>(ptr: *c_void, diff --git a/src/libstd/rt/borrowck.rs b/src/libstd/rt/borrowck.rs index 3c2000c522c..4426a3eafe1 100644 --- a/src/libstd/rt/borrowck.rs +++ b/src/libstd/rt/borrowck.rs @@ -29,9 +29,9 @@ static ALL_BITS: uint = FROZEN_BIT | MUT_BIT; #[deriving(Eq)] pub struct BorrowRecord { - box: *mut raw::Box<()>, + priv box: *mut raw::Box<()>, file: *c_char, - line: size_t + priv line: size_t } fn try_take_task_borrow_list() -> Option<~[BorrowRecord]> { diff --git a/src/libstd/rt/comm.rs b/src/libstd/rt/comm.rs index 4eae8bdc9a8..6319fdead17 100644 --- a/src/libstd/rt/comm.rs +++ b/src/libstd/rt/comm.rs @@ -48,14 +48,14 @@ struct Packet<T> { // A one-shot channel. pub struct ChanOne<T> { - void_packet: *mut Void, - suppress_finalize: bool + priv void_packet: *mut Void, + priv suppress_finalize: bool } /// A one-shot port. pub struct PortOne<T> { - void_packet: *mut Void, - suppress_finalize: bool + priv void_packet: *mut Void, + priv suppress_finalize: bool } pub fn oneshot<T: Send>() -> (PortOne<T>, ChanOne<T>) { @@ -1117,7 +1117,7 @@ mod test { let total = stress_factor() + 10; let mut rng = rand::rng(); do total.times { - let msgs = rng.gen_integer_range(0u, 10); + let msgs = rng.gen_range(0u, 10); let pipe_clone = pipe.clone(); let end_chan_clone = end_chan.clone(); do spawntask_random { diff --git a/src/libstd/rt/context.rs b/src/libstd/rt/context.rs index 7f7545ca230..b86dbfd6fb0 100644 --- a/src/libstd/rt/context.rs +++ b/src/libstd/rt/context.rs @@ -25,11 +25,11 @@ pub static RED_ZONE: uint = 20 * 1024; // then misalign the regs again. pub struct Context { /// The context entry point, saved here for later destruction - start: Option<~~fn()>, + priv start: Option<~~fn()>, /// Hold the registers while the task or scheduler is suspended - regs: ~Registers, + priv regs: ~Registers, /// Lower bound and upper bound for the stack - stack_bounds: Option<(uint, uint)>, + priv stack_bounds: Option<(uint, uint)>, } impl Context { @@ -391,36 +391,32 @@ pub unsafe fn record_sp_limit(limit: uint) { /// As with the setter, this function does not have a __morestack header and can /// therefore be called in a "we're out of stack" situation. #[inline(always)] -// NOTE: after the next snapshot, can remove the initialization before inline -// assembly due to an improvement in how it's handled, then this specific -// allow directive should get removed. -#[allow(dead_assignment)] pub unsafe fn get_sp_limit() -> uint { return target_get_sp_limit(); // x86-64 #[cfg(target_arch = "x86_64", target_os = "macos")] #[inline(always)] unsafe fn target_get_sp_limit() -> uint { - let mut limit: uint = 0; + let limit; asm!("movq $$0x60+90*8, %rsi movq %gs:(%rsi), $0" : "=r"(limit) :: "rsi" : "volatile"); return limit; } #[cfg(target_arch = "x86_64", target_os = "linux")] #[inline(always)] unsafe fn target_get_sp_limit() -> uint { - let mut limit: uint = 0; + let limit; asm!("movq %fs:112, $0" : "=r"(limit) ::: "volatile"); return limit; } #[cfg(target_arch = "x86_64", target_os = "win32")] #[inline(always)] unsafe fn target_get_sp_limit() -> uint { - let mut limit: uint = 0; + let limit; asm!("movq %gs:0x28, $0" : "=r"(limit) ::: "volatile"); return limit; } #[cfg(target_arch = "x86_64", target_os = "freebsd")] #[inline(always)] unsafe fn target_get_sp_limit() -> uint { - let mut limit: uint = 0; + let limit; asm!("movq %fs:24, $0" : "=r"(limit) ::: "volatile"); return limit; } @@ -428,7 +424,7 @@ pub unsafe fn get_sp_limit() -> uint { // x86 #[cfg(target_arch = "x86", target_os = "macos")] #[inline(always)] unsafe fn target_get_sp_limit() -> uint { - let mut limit: uint = 0; + let limit; asm!("movl $$0x48+90*4, %eax movl %gs:(%eax), $0" : "=r"(limit) :: "eax" : "volatile"); return limit; @@ -436,13 +432,13 @@ pub unsafe fn get_sp_limit() -> uint { #[cfg(target_arch = "x86", target_os = "linux")] #[cfg(target_arch = "x86", target_os = "freebsd")] #[inline(always)] unsafe fn target_get_sp_limit() -> uint { - let mut limit: uint = 0; + let limit; asm!("movl %gs:48, $0" : "=r"(limit) ::: "volatile"); return limit; } #[cfg(target_arch = "x86", target_os = "win32")] #[inline(always)] unsafe fn target_get_sp_limit() -> uint { - let mut limit: uint = 0; + let limit; asm!("movl %fs:0x14, $0" : "=r"(limit) ::: "volatile"); return limit; } diff --git a/src/libstd/rt/crate_map.rs b/src/libstd/rt/crate_map.rs index d33e1af90f8..dd71426938d 100644 --- a/src/libstd/rt/crate_map.rs +++ b/src/libstd/rt/crate_map.rs @@ -26,9 +26,9 @@ pub struct ModEntry<'self> { } pub struct CrateMap<'self> { - version: i32, - entries: &'self [ModEntry<'self>], - children: &'self [&'self CrateMap<'self>] + priv version: i32, + priv entries: &'self [ModEntry<'self>], + priv children: &'self [&'self CrateMap<'self>] } #[cfg(not(windows))] diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index e25b03be361..a43bcd8142e 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -362,8 +362,8 @@ impl Seek for FileWriter { /// For this reason, it is best to use the access-constrained wrappers that are /// exposed via `FileInfo.open_reader()` and `FileInfo.open_writer()`. pub struct FileStream { - fd: ~RtioFileStream, - last_nread: int, + priv fd: ~RtioFileStream, + priv last_nread: int, } /// a `std::rt::io::Reader` trait impl for file I/O. diff --git a/src/libstd/rt/io/flate.rs b/src/libstd/rt/io/flate.rs index 7c72ce6ba89..8a5aa171eb8 100644 --- a/src/libstd/rt/io/flate.rs +++ b/src/libstd/rt/io/flate.rs @@ -17,7 +17,7 @@ use super::*; /// A Writer decorator that compresses using the 'deflate' scheme pub struct DeflateWriter<W> { - inner_writer: W + priv inner_writer: W } impl<W: Writer> DeflateWriter<W> { @@ -56,7 +56,7 @@ impl<W: Writer> Decorator<W> for DeflateWriter<W> { /// A Reader decorator that decompresses using the 'deflate' scheme pub struct InflateReader<R> { - inner_reader: R + priv inner_reader: R } impl<R: Reader> InflateReader<R> { diff --git a/src/libstd/rt/io/mock.rs b/src/libstd/rt/io/mock.rs index c46e1372c64..44709c7b7b6 100644 --- a/src/libstd/rt/io/mock.rs +++ b/src/libstd/rt/io/mock.rs @@ -13,7 +13,7 @@ use rt::io::{Reader, Writer}; pub struct MockReader { read: ~fn(buf: &mut [u8]) -> Option<uint>, - eof: ~fn() -> bool + priv eof: ~fn() -> bool } impl MockReader { @@ -31,8 +31,8 @@ impl Reader for MockReader { } pub struct MockWriter { - write: ~fn(buf: &[u8]), - flush: ~fn() + priv write: ~fn(buf: &[u8]), + priv flush: ~fn() } impl MockWriter { diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index 97d44da765a..a80c1aab398 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -12,8 +12,8 @@ This module defines the Rust interface for synchronous I/O. It models byte-oriented input and output with the Reader and Writer traits. -Types that implement both `Reader` and `Writer` and called 'streams', -and automatically implement trait `Stream`. +Types that implement both `Reader` and `Writer` are called 'streams', +and automatically implement the `Stream` trait. Implementations are provided for common I/O streams like file, TCP, UDP, Unix domain sockets. Readers and Writers may be composed to add capabilities like string diff --git a/src/libstd/rt/kill.rs b/src/libstd/rt/kill.rs index 8029e3f6431..19f17ca966d 100644 --- a/src/libstd/rt/kill.rs +++ b/src/libstd/rt/kill.rs @@ -219,17 +219,17 @@ pub struct Death { // might kill it. This is optional so we can take it by-value at exit time. kill_handle: Option<KillHandle>, // Handle to a watching parent, if we have one, for exit code propagation. - watching_parent: Option<KillHandle>, + priv watching_parent: Option<KillHandle>, // Action to be done with the exit code. If set, also makes the task wait // until all its watched children exit before collecting the status. on_exit: Option<~fn(bool)>, // nesting level counter for task::unkillable calls (0 == killable). - unkillable: int, + priv unkillable: int, // nesting level counter for unstable::atomically calls (0 == can deschedule). - wont_sleep: int, + priv wont_sleep: int, // A "spare" handle to the kill flag inside the kill handle. Used during // blocking/waking as an optimization to avoid two xadds on the refcount. - spare_kill_flag: Option<KillFlagHandle>, + priv spare_kill_flag: Option<KillFlagHandle>, } impl Drop for KillFlag { diff --git a/src/libstd/rt/local_heap.rs b/src/libstd/rt/local_heap.rs index 262da9f3b8e..14df292343e 100644 --- a/src/libstd/rt/local_heap.rs +++ b/src/libstd/rt/local_heap.rs @@ -32,8 +32,8 @@ pub type OpaqueBox = c_void; pub type TypeDesc = c_void; pub struct LocalHeap { - memory_region: *MemoryRegion, - boxed_region: *BoxedRegion + priv memory_region: *MemoryRegion, + priv boxed_region: *BoxedRegion } impl LocalHeap { diff --git a/src/libstd/rt/rc.rs b/src/libstd/rt/rc.rs index 2ba00c3a2fb..2699dab6d38 100644 --- a/src/libstd/rt/rc.rs +++ b/src/libstd/rt/rc.rs @@ -24,7 +24,7 @@ use libc::c_void; use cast; pub struct RC<T> { - p: *c_void // ~(uint, T) + priv p: *c_void // ~(uint, T) } impl<T> RC<T> { diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index ca521c792dc..501def8b060 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -66,7 +66,7 @@ pub struct FileOpenConfig { /// Flags for file access mode (as per open(2)) flags: int, /// File creation mode, ignored unless O_CREAT is passed as part of flags - mode: int + priv mode: int } pub trait IoFactory { diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index 336d2518e43..ee163bab3c0 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -66,26 +66,26 @@ pub struct Scheduler { event_loop: ~EventLoopObject, /// The scheduler runs on a special task. When it is not running /// it is stored here instead of the work queue. - sched_task: Option<~Task>, + priv sched_task: Option<~Task>, /// An action performed after a context switch on behalf of the /// code running before the context switch - cleanup_job: Option<CleanupJob>, + priv cleanup_job: Option<CleanupJob>, /// Should this scheduler run any task, or only pinned tasks? run_anything: bool, /// If the scheduler shouldn't run some tasks, a friend to send /// them to. - friend_handle: Option<SchedHandle>, + priv friend_handle: Option<SchedHandle>, /// A fast XorShift rng for scheduler use rng: XorShiftRng, /// A toggleable idle callback - idle_callback: Option<~PausibleIdleCallback>, + priv idle_callback: Option<~PausibleIdleCallback>, /// A countdown that starts at a random value and is decremented /// every time a yield check is performed. When it hits 0 a task /// will yield. - yield_check_count: uint, + priv yield_check_count: uint, /// A flag to tell the scheduler loop it needs to do some stealing /// in order to introduce randomness as part of a yield - steal_for_yield: bool + priv steal_for_yield: bool } /// An indication of how hard to work on a given operation, the difference @@ -431,7 +431,7 @@ impl Scheduler { fn try_steals(&mut self) -> Option<~Task> { let work_queues = &mut self.work_queues; let len = work_queues.len(); - let start_index = self.rng.gen_integer_range(0, len); + let start_index = self.rng.gen_range(0, len); for index in range(0, len).map(|i| (i + start_index) % len) { match work_queues[index].steal() { Some(task) => { diff --git a/src/libstd/rt/stack.rs b/src/libstd/rt/stack.rs index fddee5882b9..55bd4b0732a 100644 --- a/src/libstd/rt/stack.rs +++ b/src/libstd/rt/stack.rs @@ -15,8 +15,8 @@ use ops::Drop; use libc::{c_uint, uintptr_t}; pub struct StackSegment { - buf: ~[u8], - valgrind_id: c_uint + priv buf: ~[u8], + priv valgrind_id: c_uint } impl StackSegment { diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index a6f9e11e40e..c4f352501a0 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -44,7 +44,7 @@ use send_str::SendStr; pub struct Task { heap: LocalHeap, - gc: GarbageCollector, + priv gc: GarbageCollector, storage: LocalStorage, logger: StdErrLogger, unwinder: Unwinder, @@ -69,7 +69,7 @@ pub struct Coroutine { /// The segment of stack on which the task is currently running or /// if the task is blocked, on which the task will resume /// execution. - current_stack_segment: StackSegment, + priv current_stack_segment: StackSegment, /// Always valid if the task is alive and not running. saved_context: Context } diff --git a/src/libstd/rt/thread.rs b/src/libstd/rt/thread.rs index e774b81da35..949d73ecc4f 100644 --- a/src/libstd/rt/thread.rs +++ b/src/libstd/rt/thread.rs @@ -18,9 +18,9 @@ use uint; type raw_thread = libc::c_void; pub struct Thread { - main: ~fn(), - raw_thread: *raw_thread, - joined: bool, + priv main: ~fn(), + priv raw_thread: *raw_thread, + priv joined: bool } impl Thread { diff --git a/src/libstd/rt/tube.rs b/src/libstd/rt/tube.rs index b8e535e4c7d..16fd3fa38ea 100644 --- a/src/libstd/rt/tube.rs +++ b/src/libstd/rt/tube.rs @@ -28,7 +28,7 @@ struct TubeState<T> { } pub struct Tube<T> { - p: RC<TubeState<T>> + priv p: RC<TubeState<T>> } impl<T> Tube<T> { diff --git a/src/libstd/rt/uv/addrinfo.rs b/src/libstd/rt/uv/addrinfo.rs index 83a7e64b139..f2abcd3aca7 100644 --- a/src/libstd/rt/uv/addrinfo.rs +++ b/src/libstd/rt/uv/addrinfo.rs @@ -25,7 +25,7 @@ type GetAddrInfoCallback = ~fn(GetAddrInfoRequest, &UvAddrInfo, Option<UvError>) pub struct GetAddrInfoRequest(*uvll::uv_getaddrinfo_t); pub struct RequestData { - getaddrinfo_cb: Option<GetAddrInfoCallback>, + priv getaddrinfo_cb: Option<GetAddrInfoCallback>, } impl GetAddrInfoRequest { diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index 3a6d858df79..5d64ca4d755 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -25,7 +25,7 @@ pub struct FsRequest(*uvll::uv_fs_t); impl Request for FsRequest {} pub struct RequestData { - complete_cb: Option<FsCallback> + priv complete_cb: Option<FsCallback> } impl FsRequest { diff --git a/src/libstd/rt/uv/mod.rs b/src/libstd/rt/uv/mod.rs index 67926b35a62..3a6a3acbc53 100644 --- a/src/libstd/rt/uv/mod.rs +++ b/src/libstd/rt/uv/mod.rs @@ -80,7 +80,7 @@ pub mod pipe; /// with dtors may not be destructured, but tuple structs can, /// but the results are not correct. pub struct Loop { - handle: *uvll::uv_loop_t + priv handle: *uvll::uv_loop_t } /// The trait implemented by uv 'watchers' (handles). Watchers are diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index c7e51b3485d..8dd0f8a6b10 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -180,7 +180,7 @@ fn socket_name<T, U: Watcher + NativeHandle<*T>>(sk: SocketNameKind, // Obviously an Event Loop is always home. pub struct UvEventLoop { - uvio: UvIoFactory + priv uvio: UvIoFactory } impl UvEventLoop { @@ -240,9 +240,9 @@ impl EventLoop for UvEventLoop { } pub struct UvPausibleIdleCallback { - watcher: IdleWatcher, - idle_flag: bool, - closed: bool + priv watcher: IdleWatcher, + priv idle_flag: bool, + priv closed: bool } impl UvPausibleIdleCallback { @@ -294,10 +294,10 @@ fn test_callback_run_once() { // The entire point of async is to call into a loop from other threads so it does not need to home. pub struct UvRemoteCallback { // The uv async handle for triggering the callback - async: AsyncWatcher, + priv async: AsyncWatcher, // A flag to tell the callback to exit, set from the dtor. This is // almost never contested - only in rare races with the dtor. - exit_flag: Exclusive<bool> + priv exit_flag: Exclusive<bool> } impl UvRemoteCallback { @@ -804,8 +804,8 @@ impl IoFactory for UvIoFactory { } pub struct UvTcpListener { - watcher : TcpWatcher, - home: SchedHandle, + priv watcher : TcpWatcher, + priv home: SchedHandle, } impl HomingIO for UvTcpListener { @@ -866,8 +866,8 @@ impl RtioTcpListener for UvTcpListener { } pub struct UvTcpAcceptor { - listener: UvTcpListener, - incoming: Tube<Result<~RtioTcpStreamObject, IoError>>, + priv listener: UvTcpListener, + priv incoming: Tube<Result<~RtioTcpStreamObject, IoError>>, } impl HomingIO for UvTcpAcceptor { @@ -991,7 +991,7 @@ fn write_stream(mut watcher: StreamWatcher, pub struct UvUnboundPipe { pipe: Pipe, - home: SchedHandle, + priv home: SchedHandle, } impl HomingIO for UvUnboundPipe { @@ -1043,8 +1043,8 @@ impl RtioPipe for UvPipeStream { } pub struct UvTcpStream { - watcher: TcpWatcher, - home: SchedHandle, + priv watcher: TcpWatcher, + priv home: SchedHandle, } impl HomingIO for UvTcpStream { @@ -1143,8 +1143,8 @@ impl RtioTcpStream for UvTcpStream { } pub struct UvUdpSocket { - watcher: UdpWatcher, - home: SchedHandle, + priv watcher: UdpWatcher, + priv home: SchedHandle, } impl HomingIO for UvUdpSocket { @@ -1353,8 +1353,8 @@ impl RtioUdpSocket for UvUdpSocket { } pub struct UvTimer { - watcher: timer::TimerWatcher, - home: SchedHandle, + priv watcher: timer::TimerWatcher, + priv home: SchedHandle, } impl HomingIO for UvTimer { @@ -1400,10 +1400,10 @@ impl RtioTimer for UvTimer { } pub struct UvFileStream { - loop_: Loop, - fd: c_int, - close_on_drop: bool, - home: SchedHandle + priv loop_: Loop, + priv fd: c_int, + priv close_on_drop: bool, + priv home: SchedHandle } impl HomingIO for UvFileStream { @@ -1533,11 +1533,11 @@ impl RtioFileStream for UvFileStream { } pub struct UvProcess { - process: process::Process, + priv process: process::Process, // Sadly, this structure must be created before we return it, so in that // brief interim the `home` is None. - home: Option<SchedHandle>, + priv home: Option<SchedHandle>, // All None until the process exits (exit_error may stay None) priv exit_status: Option<int>, diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index a80d5cbc1fb..96c5dd068d0 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -134,26 +134,26 @@ pub type uv_pipe_t = c_void; pub struct uv_timespec_t { tv_sec: libc::c_long, - tv_nsec: libc::c_long + priv tv_nsec: libc::c_long } pub struct uv_stat_t { - st_dev: libc::uint64_t, + priv st_dev: libc::uint64_t, st_mode: libc::uint64_t, - st_nlink: libc::uint64_t, - st_uid: libc::uint64_t, - st_gid: libc::uint64_t, - st_rdev: libc::uint64_t, - st_ino: libc::uint64_t, + priv st_nlink: libc::uint64_t, + priv st_uid: libc::uint64_t, + priv st_gid: libc::uint64_t, + priv st_rdev: libc::uint64_t, + priv st_ino: libc::uint64_t, st_size: libc::uint64_t, - st_blksize: libc::uint64_t, - st_blocks: libc::uint64_t, - st_flags: libc::uint64_t, - st_gen: libc::uint64_t, + priv st_blksize: libc::uint64_t, + priv st_blocks: libc::uint64_t, + priv st_flags: libc::uint64_t, + priv st_gen: libc::uint64_t, st_atim: uv_timespec_t, st_mtim: uv_timespec_t, st_ctim: uv_timespec_t, - st_birthtim: uv_timespec_t + priv st_birthtim: uv_timespec_t } impl uv_stat_t { @@ -231,37 +231,37 @@ pub type socklen_t = c_int; #[cfg(target_os = "android")] #[cfg(target_os = "linux")] pub struct addrinfo { - ai_flags: c_int, - ai_family: c_int, - ai_socktype: c_int, - ai_protocol: c_int, - ai_addrlen: socklen_t, + priv ai_flags: c_int, + priv ai_family: c_int, + priv ai_socktype: c_int, + priv ai_protocol: c_int, + priv ai_addrlen: socklen_t, ai_addr: *sockaddr, - ai_canonname: *char, + priv ai_canonname: *char, ai_next: *addrinfo } #[cfg(target_os = "macos")] #[cfg(target_os = "freebsd")] pub struct addrinfo { - ai_flags: c_int, - ai_family: c_int, - ai_socktype: c_int, - ai_protocol: c_int, - ai_addrlen: socklen_t, - ai_canonname: *char, + priv ai_flags: c_int, + priv ai_family: c_int, + priv ai_socktype: c_int, + priv ai_protocol: c_int, + priv ai_addrlen: socklen_t, + priv ai_canonname: *char, ai_addr: *sockaddr, ai_next: *addrinfo } #[cfg(windows)] pub struct addrinfo { - ai_flags: c_int, - ai_family: c_int, - ai_socktype: c_int, - ai_protocol: c_int, - ai_addrlen: size_t, - ai_canonname: *char, + priv ai_flags: c_int, + priv ai_family: c_int, + priv ai_socktype: c_int, + priv ai_protocol: c_int, + priv ai_addrlen: size_t, + priv ai_canonname: *char, ai_addr: *sockaddr, ai_next: *addrinfo } @@ -960,8 +960,8 @@ pub unsafe fn freeaddrinfo(ai: *addrinfo) { } pub struct uv_err_data { - err_name: ~str, - err_msg: ~str, + priv err_name: ~str, + priv err_msg: ~str, } extern { diff --git a/src/libstd/run.rs b/src/libstd/run.rs index 36e73a6dd51..c4cb8be2061 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -34,7 +34,6 @@ pub struct Process { /// Options that can be given when starting a Process. pub struct ProcessOptions<'self> { - /** * If this is None then the new process will have the same initial * environment as the parent process. @@ -99,7 +98,6 @@ impl <'self> ProcessOptions<'self> { /// The output of a finished process. pub struct ProcessOutput { - /// The status (exit code) of the process. status: int, diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 883934124a6..f134788942c 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -998,7 +998,6 @@ pub fn utf8_char_width(b: u8) -> uint { pub struct CharRange { /// Current `char` ch: char, - /// Index of the first byte of the next `char` next: uint } diff --git a/src/libstd/task/mod.rs b/src/libstd/task/mod.rs index 970a62b676f..30c99c62885 100644 --- a/src/libstd/task/mod.rs +++ b/src/libstd/task/mod.rs @@ -108,7 +108,7 @@ pub enum SchedMode { * */ pub struct SchedOpts { - mode: SchedMode, + priv mode: SchedMode, } /** @@ -144,11 +144,11 @@ pub struct SchedOpts { * scheduler other tasks will be impeded or even blocked indefinitely. */ pub struct TaskOpts { - linked: bool, - supervised: bool, - watched: bool, - indestructible: bool, - notify_chan: Option<Chan<TaskResult>>, + priv linked: bool, + priv supervised: bool, + priv watched: bool, + priv indestructible: bool, + priv notify_chan: Option<Chan<TaskResult>>, name: Option<SendStr>, sched: SchedOpts, stack_size: Option<uint> @@ -170,9 +170,9 @@ pub struct TaskOpts { // FIXME (#3724): Replace the 'consumed' bit with move mode on self pub struct TaskBuilder { opts: TaskOpts, - gen_body: Option<~fn(v: ~fn()) -> ~fn()>, - can_not_copy: Option<util::NonCopyable>, - consumed: bool, + priv gen_body: Option<~fn(v: ~fn()) -> ~fn()>, + priv can_not_copy: Option<util::NonCopyable>, + priv consumed: bool, } /** diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index 7cf0f04c7e9..dec13eded39 100644 --- a/src/libstd/task/spawn.rs +++ b/src/libstd/task/spawn.rs @@ -308,10 +308,10 @@ fn each_ancestor(list: &mut AncestorList, // One of these per task. pub struct Taskgroup { // List of tasks with whose fates this one's is intertwined. - tasks: TaskGroupArc, // 'none' means the group has failed. + priv tasks: TaskGroupArc, // 'none' means the group has failed. // Lists of tasks who will kill us if they fail, but whom we won't kill. - ancestors: AncestorList, - notifier: Option<AutoNotify>, + priv ancestors: AncestorList, + priv notifier: Option<AutoNotify>, } impl Drop for Taskgroup { diff --git a/src/libstd/unstable/intrinsics.rs b/src/libstd/unstable/intrinsics.rs index 68fdfd73013..ee44bf4d996 100644 --- a/src/libstd/unstable/intrinsics.rs +++ b/src/libstd/unstable/intrinsics.rs @@ -49,23 +49,23 @@ pub struct TyDesc { align: uint, // Called on a copy of a value of type `T` *after* memcpy - take_glue: GlueFn, + priv take_glue: GlueFn, // Called when a value of type `T` is no longer needed drop_glue: GlueFn, // Called by drop glue when a value of type `T` can be freed - free_glue: GlueFn, + priv free_glue: GlueFn, // Called by reflection visitor to visit a value of type `T` - visit_glue: GlueFn, + priv visit_glue: GlueFn, // If T represents a box pointer (`@U` or `~U`), then // `borrow_offset` is the amount that the pointer must be adjusted // to find the payload. This is always derivable from the type // `U`, but in the case of `@Trait` or `~Trait` objects, the type // `U` is unknown. - borrow_offset: uint, + priv borrow_offset: uint, // Name corresponding to the type name: &'static str diff --git a/src/libstd/unstable/raw.rs b/src/libstd/unstable/raw.rs index ac0e83df7ef..b5d7cc47fdc 100644 --- a/src/libstd/unstable/raw.rs +++ b/src/libstd/unstable/raw.rs @@ -15,7 +15,7 @@ use unstable::intrinsics::TyDesc; pub struct Box<T> { ref_count: uint, type_desc: *TyDesc, - prev: *Box<T>, + priv prev: *Box<T>, next: *Box<T>, data: T } diff --git a/src/libstd/unstable/sync.rs b/src/libstd/unstable/sync.rs index 4c6ad469d8c..9d15dd031e0 100644 --- a/src/libstd/unstable/sync.rs +++ b/src/libstd/unstable/sync.rs @@ -304,7 +304,7 @@ pub unsafe fn atomically<U>(f: &fn() -> U) -> U { type rust_little_lock = *libc::c_void; pub struct LittleLock { - l: rust_little_lock, + priv l: rust_little_lock, } impl Drop for LittleLock { @@ -353,7 +353,7 @@ struct ExData<T> { * need to block or deschedule while accessing shared state, use extra::sync::RWArc. */ pub struct Exclusive<T> { - x: UnsafeArc<ExData<T>> + priv x: UnsafeArc<ExData<T>> } impl<T:Send> Clone for Exclusive<T> { |
