From 8ba058552b61484248fc295dfbbe2e18a9d49e48 Mon Sep 17 00:00:00 2001 From: Fenrir Date: Fri, 1 Dec 2017 21:57:34 -0700 Subject: [PATCH] Patch `std` to be compatible with Rust nightly-2017-12-01 This only fixes things enough so that the project compiles again. More standard library changes from upstream Rust will be pulled in later. --- ctr-std/src/collections/hash/map.rs | 175 ++++++++++++++-- ctr-std/src/collections/hash/set.rs | 64 ++++-- ctr-std/src/collections/hash/table.rs | 52 ++--- ctr-std/src/lib.rs | 14 -- ctr-std/src/panic.rs | 1 + ctr-std/src/path.rs | 1 - ctr-std/src/rand/mod.rs | 286 -------------------------- ctr-std/src/rand/reader.rs | 108 ---------- ctr-std/src/sync/once.rs | 2 +- ctr-std/src/sys/unix/mod.rs | 2 + ctr-std/src/sys/unix/rand.rs | 65 +++--- 11 files changed, 262 insertions(+), 508 deletions(-) delete mode 100644 ctr-std/src/rand/mod.rs delete mode 100644 ctr-std/src/rand/reader.rs diff --git a/ctr-std/src/collections/hash/map.rs b/ctr-std/src/collections/hash/map.rs index 746e180..7a79a47 100644 --- a/ctr-std/src/collections/hash/map.rs +++ b/ctr-std/src/collections/hash/map.rs @@ -20,8 +20,8 @@ use hash::{Hash, Hasher, BuildHasher, SipHasher13}; use iter::{FromIterator, FusedIterator}; use mem::{self, replace}; use ops::{Deref, Index, InPlace, Place, Placer}; -use rand::{self, Rng}; use ptr; +use sys; use super::table::{self, Bucket, EmptyBucket, FullBucket, FullBucketMut, RawTable, SafeHash}; use super::table::BucketState::{Empty, Full}; @@ -203,7 +203,7 @@ const DISPLACEMENT_THRESHOLD: usize = 128; // so we round that up to 128. // // At a load factor of α, the odds of finding the target bucket after exactly n -// unsuccesful probes[1] are +// unsuccessful probes[1] are // // Pr_α{displacement = n} = // (1 - α) / α * ∑_{k≥1} e^(-kα) * (kα)^(k+n) / (k + n)! * (1 - kα / (k + n + 1)) @@ -419,7 +419,7 @@ fn search_hashed(table: M, hash: SafeHash, mut is_match: F) -> Inter Empty(bucket) => { // Found a hole! return InternalEntry::Vacant { - hash: hash, + hash, elem: NoElem(bucket, displacement), }; } @@ -433,7 +433,7 @@ fn search_hashed(table: M, hash: SafeHash, mut is_match: F) -> Inter // We can finish the search early if we hit any bucket // with a lower distance to initial bucket than we've probed. return InternalEntry::Vacant { - hash: hash, + hash, elem: NeqElem(full, probe_displacement), }; } @@ -588,6 +588,9 @@ impl HashMap impl HashMap { /// Creates an empty `HashMap`. /// + /// The hash map is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// /// # Examples /// /// ``` @@ -646,7 +649,7 @@ impl HashMap #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_hasher(hash_builder: S) -> HashMap { HashMap { - hash_builder: hash_builder, + hash_builder, resize_policy: DefaultResizePolicy::new(), table: RawTable::new(0), } @@ -679,8 +682,8 @@ impl HashMap let resize_policy = DefaultResizePolicy::new(); let raw_cap = resize_policy.raw_capacity(capacity); HashMap { - hash_builder: hash_builder, - resize_policy: resize_policy, + hash_builder, + resize_policy, table: RawTable::new(raw_cap), } } @@ -688,6 +691,17 @@ impl HashMap /// Returns a reference to the map's [`BuildHasher`]. /// /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::RandomState; + /// + /// let hasher = RandomState::new(); + /// let map: HashMap = HashMap::with_hasher(hasher); + /// let hasher: &RandomState = map.hasher(); + /// ``` #[stable(feature = "hashmap_public_hasher", since = "1.9.0")] pub fn hasher(&self) -> &S { &self.hash_builder @@ -1099,6 +1113,7 @@ impl HashMap /// assert_eq!(map.get(&2), None); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn get(&self, k: &Q) -> Option<&V> where K: Borrow, Q: Hash + Eq @@ -1347,7 +1362,7 @@ pub struct Iter<'a, K: 'a, V: 'a> { inner: table::Iter<'a, K, V>, } -// FIXME(#19839) Remove in favor of `#[derive(Clone)]` +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> Clone for Iter<'a, K, V> { fn clone(&self) -> Iter<'a, K, V> { @@ -1400,7 +1415,7 @@ pub struct Keys<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, } -// FIXME(#19839) Remove in favor of `#[derive(Clone)]` +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> Clone for Keys<'a, K, V> { fn clone(&self) -> Keys<'a, K, V> { @@ -1429,7 +1444,7 @@ pub struct Values<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, } -// FIXME(#19839) Remove in favor of `#[derive(Clone)]` +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> Clone for Values<'a, K, V> { fn clone(&self) -> Values<'a, K, V> { @@ -1496,14 +1511,14 @@ impl<'a, K, V> InternalEntry> { InternalEntry::Occupied { elem } => { Some(Occupied(OccupiedEntry { key: Some(key), - elem: elem, + elem, })) } InternalEntry::Vacant { hash, elem } => { Some(Vacant(VacantEntry { - hash: hash, - key: key, - elem: elem, + hash, + key, + elem, })) } InternalEntry::TableIsEmpty => None, @@ -1618,7 +1633,7 @@ impl<'a, K, V, S> IntoIterator for &'a mut HashMap type Item = (&'a K, &'a mut V); type IntoIter = IterMut<'a, K, V>; - fn into_iter(mut self) -> IterMut<'a, K, V> { + fn into_iter(self) -> IterMut<'a, K, V> { self.iter_mut() } } @@ -1999,6 +2014,68 @@ impl<'a, K, V> Entry<'a, K, V> { Vacant(ref entry) => entry.key(), } } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// #![feature(entry_and_modify)] + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[unstable(feature = "entry_and_modify", issue = "44733")] + pub fn and_modify(self, mut f: F) -> Self + where F: FnMut(&mut V) + { + match self { + Occupied(mut entry) => { + f(entry.get_mut()); + Occupied(entry) + }, + Vacant(entry) => Vacant(entry), + } + } + +} + +impl<'a, K, V: Default> Entry<'a, K, V> { + #[unstable(feature = "entry_or_default", issue = "44324")] + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// #![feature(entry_or_default)] + /// # fn main() { + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, Option> = HashMap::new(); + /// map.entry("poneyland").or_default(); + /// + /// assert_eq!(map["poneyland"], None); + /// # } + /// ``` + pub fn or_default(self) -> &'a mut V { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(Default::default()), + } + } + } impl<'a, K, V> OccupiedEntry<'a, K, V> { @@ -2161,6 +2238,68 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { fn take_key(&mut self) -> Option { self.key.take() } + + /// Replaces the entry, returning the old key and value. The new key in the hash map will be + /// the key used to create this entry. + /// + /// # Examples + /// + /// ``` + /// #![feature(map_entry_replace)] + /// use std::collections::hash_map::{Entry, HashMap}; + /// use std::rc::Rc; + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(Rc::new("Stringthing".to_string()), 15); + /// + /// let my_key = Rc::new("Stringthing".to_string()); + /// + /// if let Entry::Occupied(entry) = map.entry(my_key) { + /// // Also replace the key with a handle to our other key. + /// let (old_key, old_value): (Rc, u32) = entry.replace_entry(16); + /// } + /// + /// ``` + #[unstable(feature = "map_entry_replace", issue = "44286")] + pub fn replace_entry(mut self, value: V) -> (K, V) { + let (old_key, old_value) = self.elem.read_mut(); + + let old_key = mem::replace(old_key, self.key.unwrap()); + let old_value = mem::replace(old_value, value); + + (old_key, old_value) + } + + /// Replaces the key in the hash map with the key used to create this entry. + /// + /// # Examples + /// + /// ``` + /// #![feature(map_entry_replace)] + /// use std::collections::hash_map::{Entry, HashMap}; + /// use std::rc::Rc; + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// let mut known_strings: Vec> = Vec::new(); + /// + /// // Initialise known strings, run program, etc. + /// + /// reclaim_memory(&mut map, &known_strings); + /// + /// fn reclaim_memory(map: &mut HashMap, u32>, known_strings: &[Rc] ) { + /// for s in known_strings { + /// if let Entry::Occupied(entry) = map.entry(s.clone()) { + /// // Replaces the entry's key with our version of it in `known_strings`. + /// entry.replace_key(); + /// } + /// } + /// } + /// ``` + #[unstable(feature = "map_entry_replace", issue = "44286")] + pub fn replace_key(mut self) -> K { + let (old_key, _) = self.elem.read_mut(); + mem::replace(old_key, self.key.unwrap()) + } } impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { @@ -2354,9 +2493,7 @@ impl RandomState { // increment one of the seeds on every RandomState creation, giving // every corresponding HashMap a different iteration order. thread_local!(static KEYS: Cell<(u64, u64)> = { - let r = rand::OsRng::new(); - let mut r = r.expect("failed to create an OS RNG"); - Cell::new((r.gen(), r.gen())) + Cell::new(sys::hashmap_random_keys()) }); KEYS.with(|keys| { @@ -2448,6 +2585,7 @@ impl super::Recover for HashMap { type Key = K; + #[inline] fn get(&self, key: &Q) -> Option<&K> { self.search(key).into_occupied_bucket().map(|bucket| bucket.into_refs().0) } @@ -2460,6 +2598,7 @@ impl super::Recover for HashMap self.search_mut(key).into_occupied_bucket().map(|bucket| pop_internal(bucket).0) } + #[inline] fn replace(&mut self, key: K) -> Option { self.reserve(1); diff --git a/ctr-std/src/collections/hash/set.rs b/ctr-std/src/collections/hash/set.rs index d80df5f..51698ce 100644 --- a/ctr-std/src/collections/hash/set.rs +++ b/ctr-std/src/collections/hash/set.rs @@ -123,13 +123,16 @@ pub struct HashSet { } impl HashSet { - /// Creates an empty HashSet. + /// Creates an empty `HashSet`. + /// + /// The hash set is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. /// /// # Examples /// /// ``` /// use std::collections::HashSet; - /// let mut set: HashSet = HashSet::new(); + /// let set: HashSet = HashSet::new(); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -146,7 +149,8 @@ impl HashSet { /// /// ``` /// use std::collections::HashSet; - /// let mut set: HashSet = HashSet::with_capacity(10); + /// let set: HashSet = HashSet::with_capacity(10); + /// assert!(set.capacity() >= 10); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -215,6 +219,17 @@ impl HashSet /// Returns a reference to the set's [`BuildHasher`]. /// /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// use std::collections::hash_map::RandomState; + /// + /// let hasher = RandomState::new(); + /// let set: HashSet = HashSet::with_hasher(hasher); + /// let hasher: &RandomState = set.hasher(); + /// ``` #[stable(feature = "hashmap_public_hasher", since = "1.9.0")] pub fn hasher(&self) -> &S { self.map.hasher() @@ -249,6 +264,7 @@ impl HashSet /// use std::collections::HashSet; /// let mut set: HashSet = HashSet::new(); /// set.reserve(10); + /// assert!(set.capacity() >= 10); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve(&mut self, additional: usize) { @@ -312,19 +328,19 @@ impl HashSet /// println!("{}", x); // Print 1 /// } /// - /// let diff: HashSet<_> = a.difference(&b).cloned().collect(); - /// assert_eq!(diff, [1].iter().cloned().collect()); + /// let diff: HashSet<_> = a.difference(&b).collect(); + /// assert_eq!(diff, [1].iter().collect()); /// /// // Note that difference is not symmetric, /// // and `b - a` means something else: - /// let diff: HashSet<_> = b.difference(&a).cloned().collect(); - /// assert_eq!(diff, [4].iter().cloned().collect()); + /// let diff: HashSet<_> = b.difference(&a).collect(); + /// assert_eq!(diff, [4].iter().collect()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn difference<'a>(&'a self, other: &'a HashSet) -> Difference<'a, T, S> { Difference { iter: self.iter(), - other: other, + other, } } @@ -343,11 +359,11 @@ impl HashSet /// println!("{}", x); /// } /// - /// let diff1: HashSet<_> = a.symmetric_difference(&b).cloned().collect(); - /// let diff2: HashSet<_> = b.symmetric_difference(&a).cloned().collect(); + /// let diff1: HashSet<_> = a.symmetric_difference(&b).collect(); + /// let diff2: HashSet<_> = b.symmetric_difference(&a).collect(); /// /// assert_eq!(diff1, diff2); - /// assert_eq!(diff1, [1, 4].iter().cloned().collect()); + /// assert_eq!(diff1, [1, 4].iter().collect()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn symmetric_difference<'a>(&'a self, @@ -371,14 +387,14 @@ impl HashSet /// println!("{}", x); /// } /// - /// let intersection: HashSet<_> = a.intersection(&b).cloned().collect(); - /// assert_eq!(intersection, [2, 3].iter().cloned().collect()); + /// let intersection: HashSet<_> = a.intersection(&b).collect(); + /// assert_eq!(intersection, [2, 3].iter().collect()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn intersection<'a>(&'a self, other: &'a HashSet) -> Intersection<'a, T, S> { Intersection { iter: self.iter(), - other: other, + other, } } @@ -397,8 +413,8 @@ impl HashSet /// println!("{}", x); /// } /// - /// let union: HashSet<_> = a.union(&b).cloned().collect(); - /// assert_eq!(union, [1, 2, 3, 4].iter().cloned().collect()); + /// let union: HashSet<_> = a.union(&b).collect(); + /// assert_eq!(union, [1, 2, 3, 4].iter().collect()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn union<'a>(&'a self, other: &'a HashSet) -> Union<'a, T, S> { @@ -440,6 +456,22 @@ impl HashSet } /// Clears the set, returning all elements in an iterator. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// assert!(!set.is_empty()); + /// + /// // print 1, 2, 3 in an arbitrary order + /// for i in set.drain() { + /// println!("{}", i); + /// } + /// + /// assert!(set.is_empty()); + /// ``` #[inline] #[stable(feature = "drain", since = "1.6.0")] pub fn drain(&mut self) -> Drain { diff --git a/ctr-std/src/collections/hash/table.rs b/ctr-std/src/collections/hash/table.rs index 3844690..7e623a0 100644 --- a/ctr-std/src/collections/hash/table.rs +++ b/ctr-std/src/collections/hash/table.rs @@ -353,14 +353,14 @@ impl>> Bucket { let ib_index = ib_index & table.capacity_mask; Bucket { raw: table.raw_bucket_at(ib_index), - table: table, + table, } } pub fn first(table: M) -> Bucket { Bucket { raw: table.raw_bucket_at(0), - table: table, + table, } } @@ -455,7 +455,7 @@ impl>> EmptyBucket { match self.next().peek() { Full(bucket) => { Ok(GapThenFull { - gap: gap, + gap, full: bucket, }) } @@ -563,7 +563,7 @@ impl<'t, K, V> FullBucket> { /// /// This works similarly to `put`, building an `EmptyBucket` out of the /// taken bucket. - pub fn take(mut self) -> (EmptyBucket>, K, V) { + pub fn take(self) -> (EmptyBucket>, K, V) { self.table.size -= 1; unsafe { @@ -717,26 +717,25 @@ fn calculate_offsets(hashes_size: usize, (pairs_offset, end_of_pairs, oflo) } -// Returns a tuple of (minimum required malloc alignment, hash_offset, +// Returns a tuple of (minimum required malloc alignment, // array_size), from the start of a mallocated array. fn calculate_allocation(hash_size: usize, hash_align: usize, pairs_size: usize, pairs_align: usize) - -> (usize, usize, usize, bool) { - let hash_offset = 0; + -> (usize, usize, bool) { let (_, end_of_pairs, oflo) = calculate_offsets(hash_size, pairs_size, pairs_align); let align = cmp::max(hash_align, pairs_align); - (align, hash_offset, end_of_pairs, oflo) + (align, end_of_pairs, oflo) } #[test] fn test_offset_calculation() { - assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 0, 144, false)); - assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 0, 5, false)); - assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 0, 20, false)); + assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 144, false)); + assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 5, false)); + assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 20, false)); assert_eq!(calculate_offsets(128, 15, 4), (128, 143, false)); assert_eq!(calculate_offsets(3, 2, 4), (4, 6, false)); assert_eq!(calculate_offsets(6, 12, 4), (8, 20, false)); @@ -768,10 +767,10 @@ impl RawTable { // This is great in theory, but in practice getting the alignment // right is a little subtle. Therefore, calculating offsets has been // factored out into a different function. - let (alignment, hash_offset, size, oflo) = calculate_allocation(hashes_size, - align_of::(), - pairs_size, - align_of::<(K, V)>()); + let (alignment, size, oflo) = calculate_allocation(hashes_size, + align_of::(), + pairs_size, + align_of::<(K, V)>()); assert!(!oflo, "capacity overflow"); // One check for overflow that covers calculation and rounding of size. @@ -784,7 +783,7 @@ impl RawTable { let buffer = Heap.alloc(Layout::from_size_align(size, alignment).unwrap()) .unwrap_or_else(|e| Heap.oom(e)); - let hashes = buffer.offset(hash_offset as isize) as *mut HashUint; + let hashes = buffer as *mut HashUint; RawTable { capacity_mask: capacity.wrapping_sub(1), @@ -860,8 +859,8 @@ impl RawTable { // Replace the marker regardless of lifetime bounds on parameters. IntoIter { iter: RawBuckets { - raw: raw, - elems_left: elems_left, + raw, + elems_left, marker: marker::PhantomData, }, table: self, @@ -873,8 +872,8 @@ impl RawTable { // Replace the marker regardless of lifetime bounds on parameters. Drain { iter: RawBuckets { - raw: raw, - elems_left: elems_left, + raw, + elems_left, marker: marker::PhantomData, }, table: Shared::from(self), @@ -925,7 +924,7 @@ struct RawBuckets<'a, K, V> { marker: marker::PhantomData<&'a ()>, } -// FIXME(#19839) Remove in favor of `#[derive(Clone)]` +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` impl<'a, K, V> Clone for RawBuckets<'a, K, V> { fn clone(&self) -> RawBuckets<'a, K, V> { RawBuckets { @@ -976,7 +975,7 @@ pub struct Iter<'a, K: 'a, V: 'a> { unsafe impl<'a, K: Sync, V: Sync> Sync for Iter<'a, K, V> {} unsafe impl<'a, K: Sync, V: Sync> Send for Iter<'a, K, V> {} -// FIXME(#19839) Remove in favor of `#[derive(Clone)]` +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` impl<'a, K, V> Clone for Iter<'a, K, V> { fn clone(&self) -> Iter<'a, K, V> { Iter { @@ -1157,6 +1156,7 @@ impl Clone for RawTable { } new_ht.size = self.size(); + new_ht.set_tag(self.tag()); new_ht } @@ -1183,10 +1183,10 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { let hashes_size = self.capacity() * size_of::(); let pairs_size = self.capacity() * size_of::<(K, V)>(); - let (align, _, size, oflo) = calculate_allocation(hashes_size, - align_of::(), - pairs_size, - align_of::<(K, V)>()); + let (align, size, oflo) = calculate_allocation(hashes_size, + align_of::(), + pairs_size, + align_of::<(K, V)>()); debug_assert!(!oflo, "should be impossible"); diff --git a/ctr-std/src/lib.rs b/ctr-std/src/lib.rs index 28ab259..4c08fe2 100644 --- a/ctr-std/src/lib.rs +++ b/ctr-std/src/lib.rs @@ -64,8 +64,6 @@ use prelude::v1::*; debug_assert_ne, unreachable, unimplemented, write, writeln, try)] extern crate core as __core; -#[allow(deprecated)] extern crate rand as core_rand; - #[macro_use] #[macro_reexport(vec, format)] extern crate alloc; @@ -184,20 +182,8 @@ mod sys; // Private support modules mod panicking; -mod rand; mod memchr; // The runtime entry point and a few unstable public functions used by the // compiler pub mod rt; - -// Some external utilities of the standard library rely on randomness (aka -// rustc_back::TempDir and tests) and need a way to get at the OS rng we've got -// here. This module is not at all intended for stabilization as-is, however, -// but it may be stabilized long-term. As a result we're exposing a hidden, -// unstable module so we can get our build working. -#[doc(hidden)] -#[unstable(feature = "rand", issue = "0")] -pub mod __rand { - pub use rand::{thread_rng, ThreadRng, Rng}; -} diff --git a/ctr-std/src/panic.rs b/ctr-std/src/panic.rs index 58356bc..e73e0a6 100644 --- a/ctr-std/src/panic.rs +++ b/ctr-std/src/panic.rs @@ -11,6 +11,7 @@ //! Panic support in the standard library #![stable(feature = "std_panic", since = "1.9.0")] +#![allow(auto_impl)] use any::Any; use cell::UnsafeCell; diff --git a/ctr-std/src/path.rs b/ctr-std/src/path.rs index d13baea..2435efd 100644 --- a/ctr-std/src/path.rs +++ b/ctr-std/src/path.rs @@ -106,7 +106,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use ascii::*; use borrow::{Borrow, Cow}; use cmp; use error::Error; diff --git a/ctr-std/src/rand/mod.rs b/ctr-std/src/rand/mod.rs deleted file mode 100644 index b853e83..0000000 --- a/ctr-std/src/rand/mod.rs +++ /dev/null @@ -1,286 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Utilities for random number generation -//! -//! The key functions are `random()` and `Rng::gen()`. These are polymorphic -//! and so can be used to generate any type that implements `Rand`. Type inference -//! means that often a simple call to `rand::random()` or `rng.gen()` will -//! suffice, but sometimes an annotation is required, e.g. `rand::random::()`. -//! -//! See the `distributions` submodule for sampling random numbers from -//! distributions like normal and exponential. -//! -//! # Thread-local RNG -//! -//! There is built-in support for a RNG associated with each thread stored -//! in thread-local storage. This RNG can be accessed via `thread_rng`, or -//! used implicitly via `random`. This RNG is normally randomly seeded -//! 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 an entropy source for cryptographic purposes -//! must use `OsRng`, which reads randomness from the source that the operating -//! system provides (e.g. `/dev/urandom` on Unixes or `CryptGenRandom()` on Windows). -//! The other random number generators provided by this module are not suitable -//! for such purposes. -//! -//! *Note*: many Unix systems provide `/dev/random` as well as `/dev/urandom`. -//! This module uses `/dev/urandom` for the following reasons: -//! -//! - On Linux, `/dev/random` may block if entropy pool is empty; `/dev/urandom` will not block. -//! This does not mean that `/dev/random` provides better output than -//! `/dev/urandom`; the kernel internally runs a cryptographically secure pseudorandom -//! number generator (CSPRNG) based on entropy pool for random number generation, -//! so the "quality" of `/dev/random` is not better than `/dev/urandom` in most cases. -//! However, this means that `/dev/urandom` can yield somewhat predictable randomness -//! if the entropy pool is very small, such as immediately after first booting. -//! Linux 3.17 added the `getrandom(2)` system call which solves the issue: it blocks if entropy -//! pool is not initialized yet, but it does not block once initialized. -//! `getrandom(2)` was based on `getentropy(2)`, an existing system call in OpenBSD. -//! `OsRng` tries to use `getrandom(2)` if available, and use `/dev/urandom` fallback if not. -//! If an application does not have `getrandom` and likely to be run soon after first booting, -//! or on a system with very few entropy sources, one should consider using `/dev/random` via -//! `ReaderRng`. -//! - On some systems (e.g. FreeBSD, OpenBSD and Mac OS X) there is no difference -//! between the two sources. (Also note that, on some systems e.g. FreeBSD, both `/dev/random` -//! and `/dev/urandom` may block once if the CSPRNG has not seeded yet.) - -#![unstable(feature = "rand", issue = "0")] - -use cell::RefCell; -use fmt; -use io; -use mem; -use rc::Rc; -use sys; - -#[cfg(target_pointer_width = "32")] -use core_rand::IsaacRng as IsaacWordRng; -#[cfg(target_pointer_width = "64")] -use core_rand::Isaac64Rng as IsaacWordRng; - -pub use core_rand::{Rand, Rng, SeedableRng}; -pub use core_rand::{XorShiftRng, IsaacRng, Isaac64Rng}; -pub use core_rand::reseeding; - -pub mod reader; - -/// The standard RNG. This is designed to be efficient on the current -/// platform. -#[derive(Copy, Clone)] -pub struct StdRng { - rng: IsaacWordRng, -} - -impl StdRng { - /// Create a randomly seeded instance of `StdRng`. - /// - /// This is a very expensive operation as it has to read - /// randomness from the operating system and use this in an - /// expensive seeding operation. If one is only generating a small - /// number of random numbers, or doesn't need the utmost speed for - /// generating each number, `thread_rng` and/or `random` may be more - /// appropriate. - /// - /// Reading the randomness from the OS may fail, and any error is - /// propagated via the `io::Result` return value. - pub fn new() -> io::Result { - OsRng::new().map(|mut r| StdRng { rng: r.gen() }) - } -} - -impl Rng for StdRng { - #[inline] - fn next_u32(&mut self) -> u32 { - self.rng.next_u32() - } - - #[inline] - fn next_u64(&mut self) -> u64 { - self.rng.next_u64() - } -} - -impl<'a> SeedableRng<&'a [usize]> for StdRng { - fn reseed(&mut self, seed: &'a [usize]) { - // the internal RNG can just be seeded from the above - // randomness. - self.rng.reseed(unsafe {mem::transmute(seed)}) - } - - fn from_seed(seed: &'a [usize]) -> StdRng { - StdRng { rng: SeedableRng::from_seed(unsafe {mem::transmute(seed)}) } - } -} - -/// Controls how the thread-local RNG is reseeded. -struct ThreadRngReseeder; - -impl reseeding::Reseeder for ThreadRngReseeder { - fn reseed(&mut self, rng: &mut StdRng) { - *rng = match StdRng::new() { - Ok(r) => r, - Err(e) => panic!("could not reseed thread_rng: {}", e) - } - } -} -const THREAD_RNG_RESEED_THRESHOLD: usize = 32_768; -type ThreadRngInner = reseeding::ReseedingRng; - -/// The thread-local RNG. -#[derive(Clone)] -pub struct ThreadRng { - rng: Rc>, -} - -impl fmt::Debug for ThreadRng { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("ThreadRng { .. }") - } -} - -/// Retrieve the lazily-initialized thread-local random number -/// generator, seeded by the system. Intended to be used in method -/// chaining style, e.g. `thread_rng().gen::()`. -/// -/// The RNG provided will reseed itself from the operating system -/// after generating a certain amount of randomness. -/// -/// The internal RNG used is platform and architecture dependent, even -/// if the operating system random number generator is rigged to give -/// the same sequence always. If absolute consistency is required, -/// explicitly select an RNG, e.g. `IsaacRng` or `Isaac64Rng`. -pub fn thread_rng() -> ThreadRng { - // used to make space in TLS for a random number generator - thread_local!(static THREAD_RNG_KEY: Rc> = { - let r = match StdRng::new() { - Ok(r) => r, - Err(e) => panic!("could not initialize thread_rng: {}", e) - }; - let rng = reseeding::ReseedingRng::new(r, - THREAD_RNG_RESEED_THRESHOLD, - ThreadRngReseeder); - Rc::new(RefCell::new(rng)) - }); - - ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) } -} - -impl Rng for ThreadRng { - fn next_u32(&mut self) -> u32 { - self.rng.borrow_mut().next_u32() - } - - fn next_u64(&mut self) -> u64 { - self.rng.borrow_mut().next_u64() - } - - #[inline] - fn fill_bytes(&mut self, bytes: &mut [u8]) { - self.rng.borrow_mut().fill_bytes(bytes) - } -} - -/// A random number generator that retrieves randomness straight from -/// the operating system. Platform sources: -/// -/// - Unix-like systems (Linux, Android, Mac OSX): read directly from -/// `/dev/urandom`, or from `getrandom(2)` system call if available. -/// - Windows: calls `CryptGenRandom`, using the default cryptographic -/// service provider with the `PROV_RSA_FULL` type. -/// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed. -/// - OpenBSD: uses the `getentropy(2)` system call. -/// -/// This does not block. -pub struct OsRng(sys::rand::OsRng); - -impl OsRng { - /// Create a new `OsRng`. - pub fn new() -> io::Result { - sys::rand::OsRng::new().map(OsRng) - } -} - -impl Rng for OsRng { - #[inline] - fn next_u32(&mut self) -> u32 { - self.0.next_u32() - } - - #[inline] - fn next_u64(&mut self) -> u64 { - self.0.next_u64() - } - - #[inline] - fn fill_bytes(&mut self, bytes: &mut [u8]) { - self.0.fill_bytes(bytes) - } -} - - -#[cfg(test)] -mod tests { - use sync::mpsc::channel; - use rand::Rng; - use super::OsRng; - use thread; - - #[test] - fn test_os_rng() { - let mut r = OsRng::new().unwrap(); - - r.next_u32(); - r.next_u64(); - - let mut v = [0; 1000]; - r.fill_bytes(&mut v); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn test_os_rng_tasks() { - - let mut txs = vec![]; - for _ in 0..20 { - let (tx, rx) = channel(); - txs.push(tx); - - thread::spawn(move|| { - // wait until all the threads are ready to go. - rx.recv().unwrap(); - - // deschedule to attempt to interleave things as much - // as possible (XXX: is this a good test?) - let mut r = OsRng::new().unwrap(); - thread::yield_now(); - let mut v = [0; 1000]; - - for _ in 0..100 { - r.next_u32(); - thread::yield_now(); - r.next_u64(); - thread::yield_now(); - r.fill_bytes(&mut v); - thread::yield_now(); - } - }); - } - - // start all the threads - for tx in &txs { - tx.send(()).unwrap(); - } - } -} diff --git a/ctr-std/src/rand/reader.rs b/ctr-std/src/rand/reader.rs deleted file mode 100644 index 08bc809..0000000 --- a/ctr-std/src/rand/reader.rs +++ /dev/null @@ -1,108 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A wrapper around any Read to treat it as an RNG. - -#![allow(dead_code)] - -use io::prelude::*; -use rand::Rng; - -/// An RNG that reads random bytes straight from a `Read`. This will -/// work best with an infinite reader, but this is not required. -/// -/// # Panics -/// -/// It will panic if it there is insufficient data to fulfill a request. -pub struct ReaderRng { - reader: R -} - -impl ReaderRng { - /// Create a new `ReaderRng` from a `Read`. - pub fn new(r: R) -> ReaderRng { - ReaderRng { - reader: r - } - } -} - -impl Rng for ReaderRng { - fn next_u32(&mut self) -> u32 { - // This is designed for speed: reading a LE integer on a LE - // platform just involves blitting the bytes into the memory - // of the u32, similarly for BE on BE; avoiding byteswapping. - let mut bytes = [0; 4]; - self.fill_bytes(&mut bytes); - unsafe { *(bytes.as_ptr() as *const u32) } - } - fn next_u64(&mut self) -> u64 { - // see above for explanation. - let mut bytes = [0; 8]; - self.fill_bytes(&mut bytes); - unsafe { *(bytes.as_ptr() as *const u64) } - } - fn fill_bytes(&mut self, mut v: &mut [u8]) { - while !v.is_empty() { - let t = v; - match self.reader.read(t) { - Ok(0) => panic!("ReaderRng.fill_bytes: EOF reached"), - Ok(n) => v = t.split_at_mut(n).1, - Err(e) => panic!("ReaderRng.fill_bytes: {}", e), - } - } - } -} - -#[cfg(test)] -mod tests { - use super::ReaderRng; - use rand::Rng; - - #[test] - fn test_reader_rng_u64() { - // transmute from the target to avoid endianness concerns. - let v = &[0, 0, 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, 0, 3][..]; - let mut rng = ReaderRng::new(v); - - assert_eq!(rng.next_u64(), 1u64.to_be()); - assert_eq!(rng.next_u64(), 2u64.to_be()); - assert_eq!(rng.next_u64(), 3u64.to_be()); - } - #[test] - fn test_reader_rng_u32() { - let v = &[0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3][..]; - let mut rng = ReaderRng::new(v); - - assert_eq!(rng.next_u32(), 1u32.to_be()); - assert_eq!(rng.next_u32(), 2u32.to_be()); - assert_eq!(rng.next_u32(), 3u32.to_be()); - } - #[test] - fn test_reader_rng_fill_bytes() { - let v = [1, 2, 3, 4, 5, 6, 7, 8]; - let mut w = [0; 8]; - - let mut rng = ReaderRng::new(&v[..]); - rng.fill_bytes(&mut w); - - assert!(v == w); - } - - #[test] - #[should_panic] - fn test_reader_rng_insufficient_bytes() { - let mut rng = ReaderRng::new(&[][..]); - let mut v = [0; 3]; - rng.fill_bytes(&mut v); - } -} diff --git a/ctr-std/src/sync/once.rs b/ctr-std/src/sync/once.rs index 1e7394c..c449315 100644 --- a/ctr-std/src/sync/once.rs +++ b/ctr-std/src/sync/once.rs @@ -248,7 +248,7 @@ impl Once { #[cold] fn call_inner(&'static self, ignore_poisoning: bool, - mut init: &mut FnMut(bool)) { + init: &mut FnMut(bool)) { let mut state = self.state.load(Ordering::SeqCst); 'outer: loop { diff --git a/ctr-std/src/sys/unix/mod.rs b/ctr-std/src/sys/unix/mod.rs index cd583b5..c0e4eb4 100644 --- a/ctr-std/src/sys/unix/mod.rs +++ b/ctr-std/src/sys/unix/mod.rs @@ -13,6 +13,8 @@ use io::{self, ErrorKind}; use libc; +pub use self::rand::hashmap_random_keys; + pub mod condvar; pub mod ext; pub mod fast_thread_local; diff --git a/ctr-std/src/sys/unix/rand.rs b/ctr-std/src/sys/unix/rand.rs index 39c967a..4500c9d 100644 --- a/ctr-std/src/sys/unix/rand.rs +++ b/ctr-std/src/sys/unix/rand.rs @@ -8,47 +8,36 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use io::{self, Error, ErrorKind}; use mem; -use rand::Rng; - -use libctru::{sslcInit, sslcExit, sslcGenerateRandomData}; - -pub struct OsRng(()); - -impl OsRng { - pub fn new() -> io::Result { - unsafe { - let r = sslcInit(0); - if r < 0 { - Err(Error::new(ErrorKind::Other, "Unable to initialize the RNG")) - } else { - Ok(OsRng(())) - } - } - } -} - -impl Rng for OsRng { - fn next_u32(&mut self) -> u32 { - let mut v = [0; 4]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } - } - - fn next_u64(&mut self) -> u64 { - let mut v = [0; 8]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } - } - - fn fill_bytes(&mut self, v: &mut [u8]) { - unsafe { sslcGenerateRandomData(v.as_ptr() as _, v.len() as u32); } +use slice; + +pub fn hashmap_random_keys() -> (u64, u64) { + let mut v = (0, 0); + unsafe { + let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8, + mem::size_of_val(&v)); + imp::fill_bytes(view); } + return v } -impl Drop for OsRng { - fn drop(&mut self) { - unsafe { sslcExit() } +mod imp { + use libctru; + + pub fn fill_bytes(v: &mut [u8]) { + unsafe { + // Initializing and de-initializing the sslC subsystem every time + // we initialize a hashmap is pretty dumb, but I can't think of a + // better method at the moment. + // + // lazy_static won't work because + // destructors (for closing the subsystem on exit) won't run. + // + // Perhaps overriding __appInit() and __appExit() will work, + // but that's an experiment for another time. + libctru::sslcInit(0); + libctru::sslcGenerateRandomData(v.as_ptr() as _, v.len() as u32); + libctru::sslcExit(); + } } }