diff options
| author | Djzin <djzin@users.noreply.github.com> | 2017-05-27 14:31:47 +0100 |
|---|---|---|
| committer | Djzin <djzin@users.noreply.github.com> | 2017-05-27 14:31:47 +0100 |
| commit | 74751358e625878306aa193fed788e79aa53d4fa (patch) | |
| tree | 1ba9b336d1ddb45d9f688d69f5bd4ede028db622 /src/libstd | |
| parent | c6307a2fa55c3d62c06b85b349257a8194093442 (diff) | |
| parent | 3e7908f616745573a11ad7dfad245f12be0069da (diff) | |
| download | rust-74751358e625878306aa193fed788e79aa53d4fa.tar.gz rust-74751358e625878306aa193fed788e79aa53d4fa.zip | |
Merge remote-tracking branch 'upstream/master' into fast-swap
Diffstat (limited to 'src/libstd')
89 files changed, 4349 insertions, 2173 deletions
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 46511452a72..717892be2ab 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -23,6 +23,10 @@ compiler_builtins = { path = "../libcompiler_builtins" } std_unicode = { path = "../libstd_unicode" } unwind = { path = "../libunwind" } +[target.x86_64-apple-darwin.dependencies] +rustc_asan = { path = "../librustc_asan" } +rustc_tsan = { path = "../librustc_tsan" } + [target.x86_64-unknown-linux-gnu.dependencies] rustc_asan = { path = "../librustc_asan" } rustc_lsan = { path = "../librustc_lsan" } diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index af21d6d906e..4e3781ecafa 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -9,15 +9,28 @@ // except according to those terms. //! Operations on ASCII strings and characters. +//! +//! Most string operations in Rust act on UTF-8 strings. However, at times it +//! makes more sense to only consider the ASCII character set for a specific +//! operation. +//! +//! The [`AsciiExt`] trait provides methods that allow for character +//! operations that only act on the ASCII subset and leave non-ASCII characters +//! alone. +//! +//! The [`escape_default`] function provides an iterator over the bytes of an +//! escaped version of the character given. +//! +//! [`AsciiExt`]: trait.AsciiExt.html +//! [`escape_default`]: fn.escape_default.html #![stable(feature = "rust1", since = "1.0.0")] use fmt; -use mem; use ops::Range; use iter::FusedIterator; -/// Extension methods for ASCII-subset only operations on string slices. +/// Extension methods for ASCII-subset only operations. /// /// Be aware that operations on seemingly non-ASCII characters can sometimes /// have unexpected results. Consider this example: @@ -53,20 +66,22 @@ pub trait AsciiExt { /// use std::ascii::AsciiExt; /// /// let ascii = 'a'; - /// let utf8 = '❤'; + /// let non_ascii = '❤'; + /// let int_ascii = 97; /// /// assert!(ascii.is_ascii()); - /// assert!(!utf8.is_ascii()); + /// assert!(!non_ascii.is_ascii()); + /// assert!(int_ascii.is_ascii()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn is_ascii(&self) -> bool; - /// Makes a copy of the string in ASCII upper case. + /// Makes a copy of the value in its ASCII upper case equivalent. /// /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', /// but non-ASCII letters are unchanged. /// - /// To uppercase the string in-place, use [`make_ascii_uppercase`]. + /// To uppercase the value in-place, use [`make_ascii_uppercase`]. /// /// To uppercase ASCII characters in addition to non-ASCII characters, use /// [`str::to_uppercase`]. @@ -77,10 +92,12 @@ pub trait AsciiExt { /// use std::ascii::AsciiExt; /// /// let ascii = 'a'; - /// let utf8 = '❤'; + /// let non_ascii = '❤'; + /// let int_ascii = 97; /// /// assert_eq!('A', ascii.to_ascii_uppercase()); - /// assert_eq!('❤', utf8.to_ascii_uppercase()); + /// assert_eq!('❤', non_ascii.to_ascii_uppercase()); + /// assert_eq!(65, int_ascii.to_ascii_uppercase()); /// ``` /// /// [`make_ascii_uppercase`]: #tymethod.make_ascii_uppercase @@ -88,12 +105,12 @@ pub trait AsciiExt { #[stable(feature = "rust1", since = "1.0.0")] fn to_ascii_uppercase(&self) -> Self::Owned; - /// Makes a copy of the string in ASCII lower case. + /// Makes a copy of the value in its ASCII lower case equivalent. /// /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', /// but non-ASCII letters are unchanged. /// - /// To lowercase the string in-place, use [`make_ascii_lowercase`]. + /// To lowercase the value in-place, use [`make_ascii_lowercase`]. /// /// To lowercase ASCII characters in addition to non-ASCII characters, use /// [`str::to_lowercase`]. @@ -104,10 +121,12 @@ pub trait AsciiExt { /// use std::ascii::AsciiExt; /// /// let ascii = 'A'; - /// let utf8 = '❤'; + /// let non_ascii = '❤'; + /// let int_ascii = 65; /// /// assert_eq!('a', ascii.to_ascii_lowercase()); - /// assert_eq!('❤', utf8.to_ascii_lowercase()); + /// assert_eq!('❤', non_ascii.to_ascii_lowercase()); + /// assert_eq!(97, int_ascii.to_ascii_lowercase()); /// ``` /// /// [`make_ascii_lowercase`]: #tymethod.make_ascii_lowercase @@ -115,10 +134,10 @@ pub trait AsciiExt { #[stable(feature = "rust1", since = "1.0.0")] fn to_ascii_lowercase(&self) -> Self::Owned; - /// Checks that two strings are an ASCII case-insensitive match. + /// Checks that two values are an ASCII case-insensitive match. /// /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, - /// but without allocating and copying temporary strings. + /// but without allocating and copying temporaries. /// /// # Examples /// @@ -142,7 +161,7 @@ pub trait AsciiExt { /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', /// but non-ASCII letters are unchanged. /// - /// To return a new uppercased string without modifying the existing one, use + /// To return a new uppercased value without modifying the existing one, use /// [`to_ascii_uppercase`]. /// /// # Examples @@ -166,7 +185,7 @@ pub trait AsciiExt { /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', /// but non-ASCII letters are unchanged. /// - /// To return a new lowercased string without modifying the existing one, use + /// To return a new lowercased value without modifying the existing one, use /// [`to_ascii_lowercase`]. /// /// # Examples @@ -579,12 +598,12 @@ impl AsciiExt for str { } fn make_ascii_uppercase(&mut self) { - let me: &mut [u8] = unsafe { mem::transmute(self) }; + let me = unsafe { self.as_bytes_mut() }; me.make_ascii_uppercase() } fn make_ascii_lowercase(&mut self) { - let me: &mut [u8] = unsafe { mem::transmute(self) }; + let me = unsafe { self.as_bytes_mut() }; me.make_ascii_lowercase() } @@ -928,8 +947,12 @@ impl AsciiExt for char { } } -/// An iterator over the escaped version of a byte, constructed via -/// `std::ascii::escape_default`. +/// An iterator over the escaped version of a byte. +/// +/// This `struct` is created by the [`escape_default`] function. See its +/// documentation for more. +/// +/// [`escape_default`]: fn.escape_default.html #[stable(feature = "rust1", since = "1.0.0")] pub struct EscapeDefault { range: Range<usize>, @@ -960,6 +983,38 @@ pub struct EscapeDefault { /// /// assert_eq!(b'\\', escaped.next().unwrap()); /// assert_eq!(b't', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'\r'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'r', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'\n'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'n', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'\''); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'\'', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'"'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'"', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'\\'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'\x9d'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'x', escaped.next().unwrap()); +/// assert_eq!(b'9', escaped.next().unwrap()); +/// assert_eq!(b'd', escaped.next().unwrap()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn escape_default(c: u8) -> EscapeDefault { diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 9fb83ad7598..f84662c3f86 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -43,11 +43,16 @@ fn main() { println!("cargo:rustc-link-lib=pthread"); } else if target.contains("apple-darwin") { println!("cargo:rustc-link-lib=System"); + + // res_init and friends require -lresolv on macOS/iOS. + // See #41582 and http://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html + println!("cargo:rustc-link-lib=resolv"); } else if target.contains("apple-ios") { println!("cargo:rustc-link-lib=System"); println!("cargo:rustc-link-lib=objc"); println!("cargo:rustc-link-lib=framework=Security"); println!("cargo:rustc-link-lib=framework=Foundation"); + println!("cargo:rustc-link-lib=resolv"); } else if target.contains("windows") { println!("cargo:rustc-link-lib=advapi32"); println!("cargo:rustc-link-lib=ws2_32"); diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index f9b0ec479d7..8c4cbb66b45 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -19,8 +19,9 @@ use fmt::{self, Debug}; use hash::{Hash, Hasher, BuildHasher, SipHasher13}; use iter::{FromIterator, FusedIterator}; use mem::{self, replace}; -use ops::{Deref, Index}; +use ops::{Deref, Index, InPlace, Place, Placer}; use rand::{self, Rng}; +use ptr; use super::table::{self, Bucket, EmptyBucket, FullBucket, FullBucketMut, RawTable, SafeHash}; use super::table::BucketState::{Empty, Full}; @@ -214,15 +215,14 @@ const DISPLACEMENT_THRESHOLD: usize = 128; // 1. Alfredo Viola (2005). Distributional analysis of Robin Hood linear probing // hashing with buckets. -/// A hash map implementation which uses linear probing with Robin Hood bucket -/// stealing. +/// A hash map implemented with linear probing and Robin Hood bucket stealing. /// /// By default, `HashMap` uses a hashing algorithm selected to provide /// resistance against HashDoS attacks. The algorithm is randomly seeded, and a /// reasonable best-effort is made to generate this seed from a high quality, /// secure source of randomness provided by the host without blocking the -/// program. Because of this, the randomness of the seed is dependant on the -/// quality of the system's random number generator at the time it is created. +/// program. Because of this, the randomness of the seed depends on the output +/// quality of the system's random number generator when the seed is created. /// In particular, seeds generated when the system's entropy pool is abnormally /// low such as during system boot may be of a lower quality. /// @@ -234,9 +234,8 @@ const DISPLACEMENT_THRESHOLD: usize = 128; /// attacks such as HashDoS. /// /// The hashing algorithm can be replaced on a per-`HashMap` basis using the -/// [`HashMap::default`], [`HashMap::with_hasher`], and -/// [`HashMap::with_capacity_and_hasher`] methods. Many alternative algorithms -/// are available on crates.io, such as the [`fnv`] crate. +/// [`default`], [`with_hasher`], and [`with_capacity_and_hasher`] methods. Many +/// alternative algorithms are available on crates.io, such as the [`fnv`] crate. /// /// It is required that the keys implement the [`Eq`] and [`Hash`] traits, although /// this can frequently be achieved by using `#[derive(PartialEq, Eq, Hash)]`. @@ -338,9 +337,9 @@ const DISPLACEMENT_THRESHOLD: usize = 128; /// [`PartialEq`]: ../../std/cmp/trait.PartialEq.html /// [`RefCell`]: ../../std/cell/struct.RefCell.html /// [`Cell`]: ../../std/cell/struct.Cell.html -/// [`HashMap::default`]: #method.default -/// [`HashMap::with_hasher`]: #method.with_hasher -/// [`HashMap::with_capacity_and_hasher`]: #method.with_capacity_and_hasher +/// [`default`]: #method.default +/// [`with_hasher`]: #method.with_hasher +/// [`with_capacity_and_hasher`]: #method.with_capacity_and_hasher /// [`fnv`]: https://crates.io/crates/fnv /// /// ``` @@ -372,7 +371,7 @@ const DISPLACEMENT_THRESHOLD: usize = 128; /// } /// ``` /// -/// A HashMap with fixed list of elements can be initialized from an array: +/// A `HashMap` with fixed list of elements can be initialized from an array: /// /// ``` /// use std::collections::HashMap; @@ -471,7 +470,7 @@ fn pop_internal<K, V>(starting_bucket: FullBucketMut<K, V>) } // Now we've done all our shifting. Return the value we grabbed earlier. - (retkey, retval, gap.into_bucket().into_table()) + (retkey, retval, gap.into_table()) } /// Perform robin hood bucket stealing at the given `bucket`. You must @@ -483,15 +482,15 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>, mut hash: SafeHash, mut key: K, mut val: V) - -> &'a mut V { - let start_index = bucket.index(); + -> FullBucketMut<'a, K, V> { let size = bucket.table().size(); - // Save the *starting point*. - let mut bucket = bucket.stash(); + let raw_capacity = bucket.table().capacity(); // There can be at most `size - dib` buckets to displace, because // in the worst case, there are `size` elements and we already are // `displacement` buckets away from the initial one. - let idx_end = start_index + size - bucket.displacement(); + let idx_end = (bucket.index() + size - bucket.displacement()) % raw_capacity; + // Save the *starting point*. + let mut bucket = bucket.stash(); loop { let (old_hash, old_key, old_val) = bucket.replace(hash, key, val); @@ -515,7 +514,7 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>, // bucket, which is a FullBucket on top of a // FullBucketMut, into just one FullBucketMut. The "table" // refers to the inner FullBucketMut in this context. - return bucket.into_table().into_mut_refs().1; + return bucket.into_table(); } Full(bucket) => bucket, }; @@ -567,11 +566,8 @@ impl<K, V, S> HashMap<K, V, S> // The caller should ensure that invariants by Robin Hood Hashing hold // and that there's space in the underlying table. fn insert_hashed_ordered(&mut self, hash: SafeHash, k: K, v: V) { - let raw_cap = self.raw_capacity(); let mut buckets = Bucket::new(&mut self.table, hash); - // note that buckets.index() keeps increasing - // even if the pointer wraps back to the first bucket. - let limit_bucket = buckets.index() + raw_cap; + let start_index = buckets.index(); loop { // We don't need to compare hashes for value swap. @@ -584,7 +580,7 @@ impl<K, V, S> HashMap<K, V, S> Full(b) => b.into_bucket(), }; buckets.next(); - debug_assert!(buckets.index() < limit_bucket); + debug_assert!(buckets.index() != start_index); } } } @@ -656,12 +652,13 @@ impl<K, V, S> HashMap<K, V, S> } } - /// Creates an empty `HashMap` with the specified capacity, using `hasher` + /// Creates an empty `HashMap` with the specified capacity, using `hash_builder` /// to hash the keys. /// /// The hash map will be able to hold at least `capacity` elements without /// reallocating. If `capacity` is 0, the hash map will not allocate. - /// Warning: `hasher` is normally randomly generated, and + /// + /// Warning: `hash_builder` is normally randomly generated, and /// is designed to allow HashMaps to be resistant to attacks that /// cause many collisions and very poor performance. Setting it /// manually using this function can expose a DoS attack vector. @@ -688,7 +685,9 @@ impl<K, V, S> HashMap<K, V, S> } } - /// Returns a reference to the map's hasher. + /// Returns a reference to the map's [`BuildHasher`]. + /// + /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html #[stable(feature = "hashmap_public_hasher", since = "1.9.0")] pub fn hasher(&self) -> &S { &self.hash_builder @@ -851,7 +850,7 @@ impl<K, V, S> HashMap<K, V, S> } /// An iterator visiting all keys in arbitrary order. - /// Iterator element type is `&'a K`. + /// The iterator element type is `&'a K`. /// /// # Examples /// @@ -873,7 +872,7 @@ impl<K, V, S> HashMap<K, V, S> } /// An iterator visiting all values in arbitrary order. - /// Iterator element type is `&'a V`. + /// The iterator element type is `&'a V`. /// /// # Examples /// @@ -895,7 +894,7 @@ impl<K, V, S> HashMap<K, V, S> } /// An iterator visiting all values mutably in arbitrary order. - /// Iterator element type is `&'a mut V`. + /// The iterator element type is `&'a mut V`. /// /// # Examples /// @@ -922,7 +921,7 @@ impl<K, V, S> HashMap<K, V, S> } /// An iterator visiting all key-value pairs in arbitrary order. - /// Iterator element type is `(&'a K, &'a V)`. + /// The iterator element type is `(&'a K, &'a V)`. /// /// # Examples /// @@ -945,7 +944,7 @@ impl<K, V, S> HashMap<K, V, S> /// An iterator visiting all key-value pairs in arbitrary order, /// with mutable references to the values. - /// Iterator element type is `(&'a K, &'a mut V)`. + /// The iterator element type is `(&'a K, &'a mut V)`. /// /// # Examples /// @@ -1232,35 +1231,35 @@ impl<K, V, S> HashMap<K, V, S> /// # Examples /// /// ``` - /// #![feature(retain_hash_collection)] /// use std::collections::HashMap; /// /// let mut map: HashMap<isize, isize> = (0..8).map(|x|(x, x*10)).collect(); /// map.retain(|&k, _| k % 2 == 0); /// assert_eq!(map.len(), 4); /// ``` - #[unstable(feature = "retain_hash_collection", issue = "36648")] + #[stable(feature = "retain_hash_collection", since = "1.18.0")] pub fn retain<F>(&mut self, mut f: F) where F: FnMut(&K, &mut V) -> bool { - if self.table.capacity() == 0 || self.table.size() == 0 { + if self.table.size() == 0 { return; } + let mut elems_left = self.table.size(); let mut bucket = Bucket::head_bucket(&mut self.table); bucket.prev(); - let tail = bucket.index(); - loop { + let start_index = bucket.index(); + while elems_left != 0 { bucket = match bucket.peek() { Full(mut full) => { + elems_left -= 1; let should_remove = { let (k, v) = full.read_mut(); !f(k, v) }; if should_remove { - let prev_idx = full.index(); let prev_raw = full.raw(); let (_, _, t) = pop_internal(full); - Bucket::new_from(prev_raw, prev_idx, t) + Bucket::new_from(prev_raw, t) } else { full.into_bucket() } @@ -1270,9 +1269,7 @@ impl<K, V, S> HashMap<K, V, S> } }; bucket.prev(); // reverse iteration - if bucket.index() == tail { - break; - } + debug_assert!(elems_left == 0 || bucket.index() != start_index); } } } @@ -1336,7 +1333,13 @@ impl<'a, K, Q: ?Sized, V, S> Index<&'a Q> for HashMap<K, V, S> } } -/// HashMap iterator. +/// An iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`iter`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.HashMap.html#method.iter +/// [`HashMap`]: struct.HashMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a, V: 'a> { inner: table::Iter<'a, K, V>, @@ -1359,19 +1362,37 @@ impl<'a, K: Debug, V: Debug> fmt::Debug for Iter<'a, K, V> { } } -/// HashMap mutable values iterator. +/// A mutable iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: struct.HashMap.html#method.iter_mut +/// [`HashMap`]: struct.HashMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, K: 'a, V: 'a> { inner: table::IterMut<'a, K, V>, } -/// HashMap move iterator. +/// An owning iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashMap`][`HashMap`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`into_iter`]: struct.HashMap.html#method.into_iter +/// [`HashMap`]: struct.HashMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter<K, V> { pub(super) inner: table::IntoIter<K, V>, } -/// HashMap keys iterator. +/// An iterator over the keys of a `HashMap`. +/// +/// This `struct` is created by the [`keys`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`keys`]: struct.HashMap.html#method.keys +/// [`HashMap`]: struct.HashMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Keys<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, @@ -1394,7 +1415,13 @@ impl<'a, K: Debug, V: Debug> fmt::Debug for Keys<'a, K, V> { } } -/// HashMap values iterator. +/// An iterator over the values of a `HashMap`. +/// +/// This `struct` is created by the [`values`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`values`]: struct.HashMap.html#method.values +/// [`HashMap`]: struct.HashMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Values<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, @@ -1417,13 +1444,25 @@ impl<'a, K: Debug, V: Debug> fmt::Debug for Values<'a, K, V> { } } -/// HashMap drain iterator. +/// A draining iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`drain`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`drain`]: struct.HashMap.html#method.drain +/// [`HashMap`]: struct.HashMap.html #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, K: 'a, V: 'a> { pub(super) inner: table::Drain<'a, K, V>, } -/// Mutable HashMap values iterator. +/// A mutable iterator over the values of a `HashMap`. +/// +/// This `struct` is created by the [`values_mut`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`values_mut`]: struct.HashMap.html#method.values_mut +/// [`HashMap`]: struct.HashMap.html #[stable(feature = "map_values_mut", since = "1.10.0")] pub struct ValuesMut<'a, K: 'a, V: 'a> { inner: IterMut<'a, K, V>, @@ -1470,19 +1509,20 @@ impl<'a, K, V> InternalEntry<K, V, &'a mut RawTable<K, V>> { } } -/// A view into a single location in a map, which may be vacant or occupied. -/// This enum is constructed from the [`entry`] method on [`HashMap`]. +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashMap`]. /// /// [`HashMap`]: struct.HashMap.html /// [`entry`]: struct.HashMap.html#method.entry #[stable(feature = "rust1", since = "1.0.0")] pub enum Entry<'a, K: 'a, V: 'a> { - /// An occupied Entry. + /// An occupied entry. #[stable(feature = "rust1", since = "1.0.0")] Occupied(#[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V>), - /// A vacant Entry. + /// A vacant entry. #[stable(feature = "rust1", since = "1.0.0")] Vacant(#[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V>), @@ -1506,7 +1546,7 @@ impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for Entry<'a, K, V> { } } -/// A view into a single occupied location in a HashMap. +/// A view into an occupied entry in a `HashMap`. /// It is part of the [`Entry`] enum. /// /// [`Entry`]: enum.Entry.html @@ -1526,7 +1566,7 @@ impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for OccupiedEntry<'a, K, V> { } } -/// A view into a single empty location in a HashMap. +/// A view into a vacant entry in a `HashMap`. /// It is part of the [`Entry`] enum. /// /// [`Entry`]: enum.Entry.html @@ -1818,6 +1858,80 @@ impl<'a, K, V> fmt::Debug for Drain<'a, K, V> } } +/// A place for insertion to a `Entry`. +/// +/// See [`HashMap::entry`](struct.HashMap.html#method.entry) for details. +#[must_use = "places do nothing unless written to with `<-` syntax"] +#[unstable(feature = "collection_placement", + reason = "struct name and placement protocol is subject to change", + issue = "30172")] +pub struct EntryPlace<'a, K: 'a, V: 'a> { + bucket: FullBucketMut<'a, K, V>, +} + +#[unstable(feature = "collection_placement", + reason = "struct name and placement protocol is subject to change", + issue = "30172")] +impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for EntryPlace<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("EntryPlace") + .field("key", self.bucket.read().0) + .field("value", self.bucket.read().1) + .finish() + } +} + +#[unstable(feature = "collection_placement", + reason = "struct name and placement protocol is subject to change", + issue = "30172")] +impl<'a, K, V> Drop for EntryPlace<'a, K, V> { + fn drop(&mut self) { + // Inplacement insertion failed. Only key need to drop. + // The value is failed to insert into map. + unsafe { self.bucket.remove_key() }; + } +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, K, V> Placer<V> for Entry<'a, K, V> { + type Place = EntryPlace<'a, K, V>; + + fn make_place(self) -> EntryPlace<'a, K, V> { + let b = match self { + Occupied(mut o) => { + unsafe { ptr::drop_in_place(o.elem.read_mut().1); } + o.elem + } + Vacant(v) => { + unsafe { v.insert_key() } + } + }; + EntryPlace { bucket: b } + } +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, K, V> Place<V> for EntryPlace<'a, K, V> { + fn pointer(&mut self) -> *mut V { + self.bucket.read_mut().1 + } +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, K, V> InPlace<V> for EntryPlace<'a, K, V> { + type Owner = (); + + unsafe fn finalize(self) { + mem::forget(self); + } +} + impl<'a, K, V> Entry<'a, K, V> { #[stable(feature = "rust1", since = "1.0.0")] /// Ensures a value is in the entry by inserting the default if empty, and returns @@ -1902,13 +2016,6 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { self.elem.read().0 } - /// Deprecated, renamed to `remove_entry` - #[unstable(feature = "map_entry_recover_keys", issue = "34285")] - #[rustc_deprecated(since = "1.12.0", reason = "renamed to `remove_entry`")] - pub fn remove_pair(self) -> (K, V) { - self.remove_entry() - } - /// Take the ownership of the key and value from the map. /// /// # Examples @@ -2108,7 +2215,7 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(self, value: V) -> &'a mut V { - match self.elem { + let b = match self.elem { NeqElem(mut bucket, disp) => { if disp >= DISPLACEMENT_THRESHOLD { bucket.table_mut().set_tag(true); @@ -2119,7 +2226,28 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { if disp >= DISPLACEMENT_THRESHOLD { bucket.table_mut().set_tag(true); } - bucket.put(self.hash, self.key, value).into_mut_refs().1 + bucket.put(self.hash, self.key, value) + }, + }; + b.into_mut_refs().1 + } + + // Only used for InPlacement insert. Avoid unnecessary value copy. + // The value remains uninitialized. + unsafe fn insert_key(self) -> FullBucketMut<'a, K, V> { + match self.elem { + NeqElem(mut bucket, disp) => { + if disp >= DISPLACEMENT_THRESHOLD { + bucket.table_mut().set_tag(true); + } + let uninit = mem::uninitialized(); + robin_hood(bucket, disp, self.hash, self.key, uninit) + }, + NoElem(mut bucket, disp) => { + if disp >= DISPLACEMENT_THRESHOLD { + bucket.table_mut().set_tag(true); + } + bucket.put_key(self.hash, self.key) }, } } @@ -2274,10 +2402,9 @@ impl DefaultHasher { #[stable(feature = "hashmap_default_hasher", since = "1.13.0")] impl Default for DefaultHasher { - /// Creates a new `DefaultHasher` using [`DefaultHasher::new`]. See - /// [`DefaultHasher::new`] documentation for more information. + /// Creates a new `DefaultHasher` using [`new`]. See its documentation for more. /// - /// [`DefaultHasher::new`]: #method.new + /// [`new`]: #method.new fn default() -> DefaultHasher { DefaultHasher::new() } @@ -2392,6 +2519,7 @@ mod test_map { use super::RandomState; use cell::RefCell; use rand::{thread_rng, Rng}; + use panic; #[test] fn test_zero_capacities() { @@ -3265,4 +3393,57 @@ mod test_map { } panic!("Adaptive early resize failed"); } + + #[test] + fn test_placement_in() { + let mut map = HashMap::new(); + map.extend((0..10).map(|i| (i, i))); + + map.entry(100) <- 100; + assert_eq!(map[&100], 100); + + map.entry(0) <- 10; + assert_eq!(map[&0], 10); + + assert_eq!(map.len(), 11); + } + + #[test] + fn test_placement_panic() { + let mut map = HashMap::new(); + map.extend((0..10).map(|i| (i, i))); + + fn mkpanic() -> usize { panic!() } + + // modify existing key + // when panic happens, previous key is removed. + let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { map.entry(0) <- mkpanic(); })); + assert_eq!(map.len(), 9); + assert!(!map.contains_key(&0)); + + // add new key + let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { map.entry(100) <- mkpanic(); })); + assert_eq!(map.len(), 9); + assert!(!map.contains_key(&100)); + } + + #[test] + fn test_placement_drop() { + // correctly drop + struct TestV<'a>(&'a mut bool); + impl<'a> Drop for TestV<'a> { + fn drop(&mut self) { + if !*self.0 { panic!("value double drop!"); } // no double drop + *self.0 = false; + } + } + + fn makepanic<'a>() -> TestV<'a> { panic!() } + + let mut can_drop = true; + let mut hm = HashMap::new(); + hm.insert(0, TestV(&mut can_drop)); + let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { hm.entry(0) <- makepanic(); })); + assert_eq!(hm.len(), 0); + } } diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index ac0d15472c1..d80df5f18b6 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -24,11 +24,10 @@ use super::map::{self, HashMap, Keys, RandomState}; // for `bucket.val` in the case of HashSet. I suppose we would need HKT // to get rid of it properly. -/// An implementation of a hash set using the underlying representation of a -/// HashMap where the value is (). +/// A hash set implemented as a `HashMap` where the value is `()`. /// -/// As with the `HashMap` type, a `HashSet` requires that the elements -/// implement the `Eq` and `Hash` traits. This can frequently be achieved by +/// As with the [`HashMap`] type, a `HashSet` requires that the elements +/// implement the [`Eq`] and [`Hash`] traits. This can frequently be achieved by /// using `#[derive(PartialEq, Eq, Hash)]`. If you implement these yourself, /// it is important that the following property holds: /// @@ -40,9 +39,9 @@ use super::map::{self, HashMap, Keys, RandomState}; /// /// /// It is a logic error for an item to be modified in such a way that the -/// item's hash, as determined by the `Hash` trait, or its equality, as -/// determined by the `Eq` trait, changes while it is in the set. This is -/// normally only possible through `Cell`, `RefCell`, global state, I/O, or +/// item's hash, as determined by the [`Hash`] trait, or its equality, as +/// determined by the [`Eq`] trait, changes while it is in the set. This is +/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or /// unsafe code. /// /// # Examples @@ -75,8 +74,8 @@ use super::map::{self, HashMap, Keys, RandomState}; /// ``` /// /// The easiest way to use `HashSet` with a custom type is to derive -/// `Eq` and `Hash`. We must also derive `PartialEq`, this will in the -/// future be implied by `Eq`. +/// [`Eq`] and [`Hash`]. We must also derive [`PartialEq`], this will in the +/// future be implied by [`Eq`]. /// /// ``` /// use std::collections::HashSet; @@ -99,7 +98,7 @@ use super::map::{self, HashMap, Keys, RandomState}; /// } /// ``` /// -/// HashSet with fixed list of elements can be initialized from an array: +/// A `HashSet` with fixed list of elements can be initialized from an array: /// /// ``` /// use std::collections::HashSet; @@ -110,8 +109,13 @@ use super::map::{self, HashMap, Keys, RandomState}; /// // use the values stored in the set /// } /// ``` - - +/// +/// [`Cell`]: ../../std/cell/struct.Cell.html +/// [`Eq`]: ../../std/cmp/trait.Eq.html +/// [`Hash`]: ../../std/hash/trait.Hash.html +/// [`HashMap`]: struct.HashMap.html +/// [`PartialEq`]: ../../std/cmp/trait.PartialEq.html +/// [`RefCell`]: ../../std/cell/struct.RefCell.html #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct HashSet<T, S = RandomState> { @@ -181,7 +185,7 @@ impl<T, S> HashSet<T, S> HashSet { map: HashMap::with_hasher(hasher) } } - /// Creates an empty HashSet with with the specified capacity, using + /// Creates an empty `HashSet` with with the specified capacity, using /// `hasher` to hash the keys. /// /// The hash set will be able to hold at least `capacity` elements without @@ -208,7 +212,9 @@ impl<T, S> HashSet<T, S> HashSet { map: HashMap::with_capacity_and_hasher(capacity, hasher) } } - /// Returns a reference to the set's hasher. + /// Returns a reference to the set's [`BuildHasher`]. + /// + /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html #[stable(feature = "hashmap_public_hasher", since = "1.9.0")] pub fn hasher(&self) -> &S { self.map.hasher() @@ -271,7 +277,7 @@ impl<T, S> HashSet<T, S> } /// An iterator visiting all elements in arbitrary order. - /// Iterator element type is &'a T. + /// The iterator element type is `&'a T`. /// /// # Examples /// @@ -291,7 +297,7 @@ impl<T, S> HashSet<T, S> Iter { iter: self.map.keys() } } - /// Visit the values representing the difference, + /// Visits the values representing the difference, /// i.e. the values that are in `self` but not in `other`. /// /// # Examples @@ -322,7 +328,7 @@ impl<T, S> HashSet<T, S> } } - /// Visit the values representing the symmetric difference, + /// Visits the values representing the symmetric difference, /// i.e. the values that are in `self` or in `other` but not in both. /// /// # Examples @@ -350,7 +356,7 @@ impl<T, S> HashSet<T, S> SymmetricDifference { iter: self.difference(other).chain(other.difference(self)) } } - /// Visit the values representing the intersection, + /// Visits the values representing the intersection, /// i.e. the values that are both in `self` and `other`. /// /// # Examples @@ -376,7 +382,7 @@ impl<T, S> HashSet<T, S> } } - /// Visit the values representing the union, + /// Visits the values representing the union, /// i.e. all the values in `self` or `other`, without duplicates. /// /// # Examples @@ -460,7 +466,7 @@ impl<T, S> HashSet<T, S> /// Returns `true` if the set contains a value. /// /// The value may be any borrowed form of the set's value type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for /// the value type. /// /// # Examples @@ -472,6 +478,9 @@ impl<T, S> HashSet<T, S> /// assert_eq!(set.contains(&1), true); /// assert_eq!(set.contains(&4), false); /// ``` + /// + /// [`Eq`]: ../../std/cmp/trait.Eq.html + /// [`Hash`]: ../../std/hash/trait.Hash.html #[stable(feature = "rust1", since = "1.0.0")] pub fn contains<Q: ?Sized>(&self, value: &Q) -> bool where T: Borrow<Q>, @@ -483,8 +492,11 @@ impl<T, S> HashSet<T, S> /// Returns a reference to the value in the set, if any, that is equal to the given value. /// /// The value may be any borrowed form of the set's value type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for /// the value type. + /// + /// [`Eq`]: ../../std/cmp/trait.Eq.html + /// [`Hash`]: ../../std/hash/trait.Hash.html #[stable(feature = "set_recovery", since = "1.9.0")] pub fn get<Q: ?Sized>(&self, value: &Q) -> Option<&T> where T: Borrow<Q>, @@ -596,7 +608,7 @@ impl<T, S> HashSet<T, S> /// present in the set. /// /// The value may be any borrowed form of the set's value type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for /// the value type. /// /// # Examples @@ -610,6 +622,9 @@ impl<T, S> HashSet<T, S> /// assert_eq!(set.remove(&2), true); /// assert_eq!(set.remove(&2), false); /// ``` + /// + /// [`Eq`]: ../../std/cmp/trait.Eq.html + /// [`Hash`]: ../../std/hash/trait.Hash.html #[stable(feature = "rust1", since = "1.0.0")] pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> bool where T: Borrow<Q>, @@ -621,8 +636,11 @@ impl<T, S> HashSet<T, S> /// Removes and returns the value in the set, if any, that is equal to the given one. /// /// The value may be any borrowed form of the set's value type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for /// the value type. + /// + /// [`Eq`]: ../../std/cmp/trait.Eq.html + /// [`Hash`]: ../../std/hash/trait.Hash.html #[stable(feature = "set_recovery", since = "1.9.0")] pub fn take<Q: ?Sized>(&mut self, value: &Q) -> Option<T> where T: Borrow<Q>, @@ -638,7 +656,6 @@ impl<T, S> HashSet<T, S> /// # Examples /// /// ``` - /// #![feature(retain_hash_collection)] /// use std::collections::HashSet; /// /// let xs = [1,2,3,4,5,6]; @@ -646,7 +663,7 @@ impl<T, S> HashSet<T, S> /// set.retain(|&k| k % 2 == 0); /// assert_eq!(set.len(), 3); /// ``` - #[unstable(feature = "retain_hash_collection", issue = "36648")] + #[stable(feature = "retain_hash_collection", since = "1.18.0")] pub fn retain<F>(&mut self, mut f: F) where F: FnMut(&T) -> bool { @@ -856,25 +873,49 @@ impl<'a, 'b, T, S> Sub<&'b HashSet<T, S>> for &'a HashSet<T, S> } } -/// HashSet iterator +/// An iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`iter`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`iter`]: struct.HashSet.html#method.iter #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a> { iter: Keys<'a, K, ()>, } -/// HashSet move iterator +/// An owning iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashSet`][`HashSet`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`into_iter`]: struct.HashSet.html#method.into_iter #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter<K> { iter: map::IntoIter<K, ()>, } -/// HashSet drain iterator +/// A draining iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`drain`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`drain`]: struct.HashSet.html#method.drain #[stable(feature = "rust1", since = "1.0.0")] pub struct Drain<'a, K: 'a> { iter: map::Drain<'a, K, ()>, } -/// Intersection iterator +/// A lazy iterator producing elements in the intersection of `HashSet`s. +/// +/// This `struct` is created by the [`intersection`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`intersection`]: struct.HashSet.html#method.intersection #[stable(feature = "rust1", since = "1.0.0")] pub struct Intersection<'a, T: 'a, S: 'a> { // iterator of the first set @@ -883,7 +924,13 @@ pub struct Intersection<'a, T: 'a, S: 'a> { other: &'a HashSet<T, S>, } -/// Difference iterator +/// A lazy iterator producing elements in the difference of `HashSet`s. +/// +/// This `struct` is created by the [`difference`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`difference`]: struct.HashSet.html#method.difference #[stable(feature = "rust1", since = "1.0.0")] pub struct Difference<'a, T: 'a, S: 'a> { // iterator of the first set @@ -892,13 +939,25 @@ pub struct Difference<'a, T: 'a, S: 'a> { other: &'a HashSet<T, S>, } -/// Symmetric difference iterator. +/// A lazy iterator producing elements in the symmetric difference of `HashSet`s. +/// +/// This `struct` is created by the [`symmetric_difference`] method on +/// [`HashSet`]. See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`symmetric_difference`]: struct.HashSet.html#method.symmetric_difference #[stable(feature = "rust1", since = "1.0.0")] pub struct SymmetricDifference<'a, T: 'a, S: 'a> { iter: Chain<Difference<'a, T, S>, Difference<'a, T, S>>, } -/// Set union iterator. +/// A lazy iterator producing elements in the union of `HashSet`s. +/// +/// This `struct` is created by the [`union`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`union`]: struct.HashSet.html#method.union #[stable(feature = "rust1", since = "1.0.0")] pub struct Union<'a, T: 'a, S: 'a> { iter: Chain<Iter<'a, T>, Difference<'a, T, S>>, @@ -979,9 +1038,7 @@ impl<'a, K> FusedIterator for Iter<'a, K> {} #[stable(feature = "std_debug", since = "1.16.0")] impl<'a, K: fmt::Debug> fmt::Debug for Iter<'a, K> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.clone()) - .finish() + f.debug_list().entries(self.clone()).finish() } } @@ -1008,10 +1065,11 @@ impl<K> FusedIterator for IntoIter<K> {} #[stable(feature = "std_debug", since = "1.16.0")] impl<K: fmt::Debug> fmt::Debug for IntoIter<K> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let entries_iter = self.iter.inner.iter().map(|(k, _)| k); - f.debug_list() - .entries(entries_iter) - .finish() + let entries_iter = self.iter + .inner + .iter() + .map(|(k, _)| k); + f.debug_list().entries(entries_iter).finish() } } @@ -1038,10 +1096,11 @@ impl<'a, K> FusedIterator for Drain<'a, K> {} #[stable(feature = "std_debug", since = "1.16.0")] impl<'a, K: fmt::Debug> fmt::Debug for Drain<'a, K> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let entries_iter = self.iter.inner.iter().map(|(k, _)| k); - f.debug_list() - .entries(entries_iter) - .finish() + let entries_iter = self.iter + .inner + .iter() + .map(|(k, _)| k); + f.debug_list().entries(entries_iter).finish() } } @@ -1081,12 +1140,10 @@ impl<'a, T, S> Iterator for Intersection<'a, T, S> #[stable(feature = "std_debug", since = "1.16.0")] impl<'a, T, S> fmt::Debug for Intersection<'a, T, S> where T: fmt::Debug + Eq + Hash, - S: BuildHasher, + S: BuildHasher { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.clone()) - .finish() + f.debug_list().entries(self.clone()).finish() } } @@ -1140,12 +1197,10 @@ impl<'a, T, S> FusedIterator for Difference<'a, T, S> #[stable(feature = "std_debug", since = "1.16.0")] impl<'a, T, S> fmt::Debug for Difference<'a, T, S> where T: fmt::Debug + Eq + Hash, - S: BuildHasher, + S: BuildHasher { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.clone()) - .finish() + f.debug_list().entries(self.clone()).finish() } } @@ -1181,12 +1236,10 @@ impl<'a, T, S> FusedIterator for SymmetricDifference<'a, T, S> #[stable(feature = "std_debug", since = "1.16.0")] impl<'a, T, S> fmt::Debug for SymmetricDifference<'a, T, S> where T: fmt::Debug + Eq + Hash, - S: BuildHasher, + S: BuildHasher { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.clone()) - .finish() + f.debug_list().entries(self.clone()).finish() } } @@ -1207,12 +1260,10 @@ impl<'a, T, S> FusedIterator for Union<'a, T, S> #[stable(feature = "std_debug", since = "1.16.0")] impl<'a, T, S> fmt::Debug for Union<'a, T, S> where T: fmt::Debug + Eq + Hash, - S: BuildHasher, + S: BuildHasher { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(self.clone()) - .finish() + f.debug_list().entries(self.clone()).finish() } } @@ -1636,7 +1687,7 @@ mod test_set { #[test] fn test_retain() { - let xs = [1,2,3,4,5,6]; + let xs = [1, 2, 3, 4, 5, 6]; let mut set: HashSet<isize> = xs.iter().cloned().collect(); set.retain(|&k| k % 2 == 0); assert_eq!(set.len(), 3); diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 0e225b2964f..50c721db849 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -8,13 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::heap::{EMPTY, allocate, deallocate}; +use alloc::heap::{allocate, deallocate}; use cmp; use hash::{BuildHasher, Hash, Hasher}; -use intrinsics::needs_drop; use marker; -use mem::{align_of, size_of}; +use mem::{align_of, size_of, needs_drop}; use mem; use ops::{Deref, DerefMut}; use ptr::{self, Unique, Shared}; @@ -33,6 +32,7 @@ use self::BucketState::*; type HashUint = usize; const EMPTY_BUCKET: HashUint = 0; +const EMPTY: usize = 1; /// Special `Unique<HashUint>` that uses the lower bit of the pointer /// to expose a boolean tag. @@ -49,24 +49,25 @@ impl TaggedHashUintPtr { #[inline] fn set_tag(&mut self, value: bool) { - let usize_ptr = &*self.0 as *const *mut HashUint as *mut usize; + let mut usize_ptr = self.0.as_ptr() as usize; unsafe { if value { - *usize_ptr |= 1; + usize_ptr |= 1; } else { - *usize_ptr &= !1; + usize_ptr &= !1; } + self.0 = Unique::new(usize_ptr as *mut HashUint) } } #[inline] fn tag(&self) -> bool { - (*self.0 as usize) & 1 == 1 + (self.0.as_ptr() as usize) & 1 == 1 } #[inline] fn ptr(&self) -> *mut HashUint { - (*self.0 as usize & !1) as *mut HashUint + (self.0.as_ptr() as usize & !1) as *mut HashUint } } @@ -113,7 +114,7 @@ impl TaggedHashUintPtr { /// when the RawTable is created and is accessible with the `tag` and `set_tag` /// functions. pub struct RawTable<K, V> { - capacity: usize, + capacity_mask: usize, size: usize, hashes: TaggedHashUintPtr, @@ -125,10 +126,13 @@ pub struct RawTable<K, V> { unsafe impl<K: Send, V: Send> Send for RawTable<K, V> {} unsafe impl<K: Sync, V: Sync> Sync for RawTable<K, V> {} +// An unsafe view of a RawTable bucket +// Valid indexes are within [0..table_capacity) pub struct RawBucket<K, V> { - hash: *mut HashUint, + hash_start: *mut HashUint, // We use *const to ensure covariance with respect to K and V - pair: *const (K, V), + pair_start: *const (K, V), + idx: usize, _marker: marker::PhantomData<(K, V)>, } @@ -141,7 +145,6 @@ impl<K, V> Clone for RawBucket<K, V> { pub struct Bucket<K, V, M> { raw: RawBucket<K, V>, - idx: usize, table: M, } @@ -154,13 +157,11 @@ impl<K, V, M: Copy> Clone for Bucket<K, V, M> { pub struct EmptyBucket<K, V, M> { raw: RawBucket<K, V>, - idx: usize, table: M, } pub struct FullBucket<K, V, M> { raw: RawBucket<K, V>, - idx: usize, table: M, } @@ -232,13 +233,17 @@ fn can_alias_safehash_as_hash() { assert_eq!(size_of::<SafeHash>(), size_of::<HashUint>()) } +// RawBucket methods are unsafe as it's possible to +// make a RawBucket point to invalid memory using safe code. impl<K, V> RawBucket<K, V> { - unsafe fn offset(self, count: isize) -> RawBucket<K, V> { - RawBucket { - hash: self.hash.offset(count), - pair: self.pair.offset(count), - _marker: marker::PhantomData, - } + unsafe fn hash(&self) -> *mut HashUint { + self.hash_start.offset(self.idx as isize) + } + unsafe fn pair(&self) -> *mut (K, V) { + self.pair_start.offset(self.idx as isize) as *mut (K, V) + } + unsafe fn hash_pair(&self) -> (*mut HashUint, *mut (K, V)) { + (self.hash(), self.pair()) } } @@ -258,7 +263,7 @@ impl<K, V, M> FullBucket<K, V, M> { } /// Get the raw index. pub fn index(&self) -> usize { - self.idx + self.raw.idx } /// Get the raw bucket. pub fn raw(&self) -> RawBucket<K, V> { @@ -280,7 +285,7 @@ impl<K, V, M> EmptyBucket<K, V, M> { impl<K, V, M> Bucket<K, V, M> { /// Get the raw index. pub fn index(&self) -> usize { - self.idx + self.raw.idx } /// get the table. pub fn into_table(self) -> M { @@ -331,12 +336,11 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> Bucket<K, V, M> { Bucket::at_index(table, hash.inspect() as usize) } - pub fn new_from(r: RawBucket<K, V>, i: usize, t: M) + pub fn new_from(r: RawBucket<K, V>, t: M) -> Bucket<K, V, M> { Bucket { raw: r, - idx: i, table: t, } } @@ -346,18 +350,16 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> Bucket<K, V, M> { // This is an uncommon case though, so avoid it in release builds. debug_assert!(table.capacity() > 0, "Table should have capacity at this point"); - let ib_index = ib_index & (table.capacity() - 1); + let ib_index = ib_index & table.capacity_mask; Bucket { - raw: unsafe { table.first_bucket_raw().offset(ib_index as isize) }, - idx: ib_index, + raw: table.raw_bucket_at(ib_index), table: table, } } pub fn first(table: M) -> Bucket<K, V, M> { Bucket { - raw: table.first_bucket_raw(), - idx: 0, + raw: table.raw_bucket_at(0), table: table, } } @@ -401,48 +403,30 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> Bucket<K, V, M> { /// the appropriate types to call most of the other functions in /// this module. pub fn peek(self) -> BucketState<K, V, M> { - match unsafe { *self.raw.hash } { + match unsafe { *self.raw.hash() } { EMPTY_BUCKET => { Empty(EmptyBucket { raw: self.raw, - idx: self.idx, table: self.table, }) } _ => { Full(FullBucket { raw: self.raw, - idx: self.idx, table: self.table, }) } } } - /// Modifies the bucket pointer in place to make it point to the next slot. + /// Modifies the bucket in place to make it point to the next slot. pub fn next(&mut self) { - self.idx += 1; - let range = self.table.capacity(); - // This code is branchless thanks to a conditional move. - let dist = if self.idx & (range - 1) == 0 { - 1 - range as isize - } else { - 1 - }; - unsafe { - self.raw = self.raw.offset(dist); - } + self.raw.idx = self.raw.idx.wrapping_add(1) & self.table.capacity_mask; } - /// Modifies the bucket pointer in place to make it point to the previous slot. + /// Modifies the bucket in place to make it point to the previous slot. pub fn prev(&mut self) { - let range = self.table.capacity(); - let new_idx = self.idx.wrapping_sub(1) & (range - 1); - let dist = (new_idx as isize).wrapping_sub(self.idx as isize); - self.idx = new_idx; - unsafe { - self.raw = self.raw.offset(dist); - } + self.raw.idx = self.raw.idx.wrapping_sub(1) & self.table.capacity_mask; } } @@ -458,7 +442,6 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> EmptyBucket<K, V, M> { pub fn into_bucket(self) -> Bucket<K, V, M> { Bucket { raw: self.raw, - idx: self.idx, table: self.table, } } @@ -466,7 +449,6 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> EmptyBucket<K, V, M> { pub fn gap_peek(self) -> Result<GapThenFull<K, V, M>, Bucket<K, V, M>> { let gap = EmptyBucket { raw: self.raw, - idx: self.idx, table: (), }; @@ -494,15 +476,29 @@ impl<K, V, M> EmptyBucket<K, V, M> /// Use `make_hash` to construct a `SafeHash` to pass to this function. pub fn put(mut self, hash: SafeHash, key: K, value: V) -> FullBucket<K, V, M> { unsafe { - *self.raw.hash = hash.inspect(); - ptr::write(self.raw.pair as *mut (K, V), (key, value)); + *self.raw.hash() = hash.inspect(); + ptr::write(self.raw.pair(), (key, value)); self.table.borrow_table_mut().size += 1; } FullBucket { raw: self.raw, - idx: self.idx, + table: self.table, + } + } + + /// Puts given key, remain value uninitialized. + /// It is only used for inplacement insertion. + pub unsafe fn put_key(mut self, hash: SafeHash, key: K) -> FullBucket<K, V, M> { + *self.raw.hash() = hash.inspect(); + let pair_ptr = self.raw.pair(); + ptr::write(&mut (*pair_ptr).0, key); + + self.table.borrow_table_mut().size += 1; + + FullBucket { + raw: self.raw, table: self.table, } } @@ -520,7 +516,6 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> FullBucket<K, V, M> { pub fn into_bucket(self) -> Bucket<K, V, M> { Bucket { raw: self.raw, - idx: self.idx, table: self.table, } } @@ -530,7 +525,6 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> FullBucket<K, V, M> { pub fn stash(self) -> FullBucket<K, V, Self> { FullBucket { raw: self.raw, - idx: self.idx, table: self, } } @@ -544,17 +538,20 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> FullBucket<K, V, M> { // Calculates the distance one has to travel when going from // `hash mod capacity` onwards to `idx mod capacity`, wrapping around // if the destination is not reached before the end of the table. - (self.idx.wrapping_sub(self.hash().inspect() as usize)) & (self.table.capacity() - 1) + (self.raw.idx.wrapping_sub(self.hash().inspect() as usize)) & self.table.capacity_mask } #[inline] pub fn hash(&self) -> SafeHash { - unsafe { SafeHash { hash: *self.raw.hash } } + unsafe { SafeHash { hash: *self.raw.hash() } } } /// Gets references to the key and value at a given index. pub fn read(&self) -> (&K, &V) { - unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) } + unsafe { + let pair_ptr = self.raw.pair(); + (&(*pair_ptr).0, &(*pair_ptr).1) + } } } @@ -570,17 +567,27 @@ impl<'t, K, V> FullBucket<K, V, &'t mut RawTable<K, V>> { self.table.size -= 1; unsafe { - *self.raw.hash = EMPTY_BUCKET; - let (k, v) = ptr::read(self.raw.pair); + *self.raw.hash() = EMPTY_BUCKET; + let (k, v) = ptr::read(self.raw.pair()); (EmptyBucket { raw: self.raw, - idx: self.idx, table: self.table, }, k, v) } } + + /// Remove this bucket's `key` from the hashtable. + /// Only used for inplacement insertion. + /// NOTE: `Value` is uninitialized when this function is called, don't try to drop the `Value`. + pub unsafe fn remove_key(&mut self) { + self.table.size -= 1; + + *self.raw.hash() = EMPTY_BUCKET; + let pair_ptr = self.raw.pair(); + ptr::drop_in_place(&mut (*pair_ptr).0); // only drop key + } } // This use of `Put` is misleading and restrictive, but safe and sufficient for our use cases @@ -590,8 +597,8 @@ impl<K, V, M> FullBucket<K, V, M> { pub fn replace(&mut self, h: SafeHash, k: K, v: V) -> (SafeHash, K, V) { unsafe { - let old_hash = ptr::replace(self.raw.hash as *mut SafeHash, h); - let (old_key, old_val) = ptr::replace(self.raw.pair as *mut (K, V), (k, v)); + let old_hash = ptr::replace(self.raw.hash() as *mut SafeHash, h); + let (old_key, old_val) = ptr::replace(self.raw.pair(), (k, v)); (old_hash, old_key, old_val) } @@ -603,8 +610,10 @@ impl<K, V, M> FullBucket<K, V, M> { /// Gets mutable references to the key and value at a given index. pub fn read_mut(&mut self) -> (&mut K, &mut V) { - let pair_mut = self.raw.pair as *mut (K, V); - unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) } + unsafe { + let pair_ptr = self.raw.pair(); + (&mut (*pair_ptr).0, &mut (*pair_ptr).1) + } } } @@ -617,7 +626,10 @@ impl<'t, K, V, M> FullBucket<K, V, M> /// in exchange for this, the returned references have a longer lifetime /// than the references returned by `read()`. pub fn into_refs(self) -> (&'t K, &'t V) { - unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) } + unsafe { + let pair_ptr = self.raw.pair(); + (&(*pair_ptr).0, &(*pair_ptr).1) + } } } @@ -627,8 +639,10 @@ impl<'t, K, V, M> FullBucket<K, V, M> /// This works similarly to `into_refs`, exchanging a bucket state /// for mutable references into the table. pub fn into_mut_refs(self) -> (&'t mut K, &'t mut V) { - let pair_mut = self.raw.pair as *mut (K, V); - unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) } + unsafe { + let pair_ptr = self.raw.pair(); + (&mut (*pair_ptr).0, &mut (*pair_ptr).1) + } } } @@ -640,22 +654,23 @@ impl<K, V, M> GapThenFull<K, V, M> &self.full } - pub fn into_bucket(self) -> Bucket<K, V, M> { - self.full.into_bucket() + pub fn into_table(self) -> M { + self.full.into_table() } pub fn shift(mut self) -> Result<GapThenFull<K, V, M>, Bucket<K, V, M>> { unsafe { - *self.gap.raw.hash = mem::replace(&mut *self.full.raw.hash, EMPTY_BUCKET); - ptr::copy_nonoverlapping(self.full.raw.pair, self.gap.raw.pair as *mut (K, V), 1); + let (gap_hash, gap_pair) = self.gap.raw.hash_pair(); + let (full_hash, full_pair) = self.full.raw.hash_pair(); + *gap_hash = mem::replace(&mut *full_hash, EMPTY_BUCKET); + ptr::copy_nonoverlapping(full_pair, gap_pair, 1); } - let FullBucket { raw: prev_raw, idx: prev_idx, .. } = self.full; + let FullBucket { raw: prev_raw, .. } = self.full; match self.full.next().peek() { Full(bucket) => { self.gap.raw = prev_raw; - self.gap.idx = prev_idx; self.full = bucket; @@ -734,7 +749,7 @@ impl<K, V> RawTable<K, V> { if capacity == 0 { return RawTable { size: 0, - capacity: 0, + capacity_mask: capacity.wrapping_sub(1), hashes: TaggedHashUintPtr::new(EMPTY as *mut HashUint), marker: marker::PhantomData, }; @@ -774,25 +789,27 @@ impl<K, V> RawTable<K, V> { let hashes = buffer.offset(hash_offset as isize) as *mut HashUint; RawTable { - capacity: capacity, + capacity_mask: capacity.wrapping_sub(1), size: 0, hashes: TaggedHashUintPtr::new(hashes), marker: marker::PhantomData, } } - fn first_bucket_raw(&self) -> RawBucket<K, V> { - let hashes_size = self.capacity * size_of::<HashUint>(); - let pairs_size = self.capacity * size_of::<(K, V)>(); + fn raw_bucket_at(&self, index: usize) -> RawBucket<K, V> { + let hashes_size = self.capacity() * size_of::<HashUint>(); + let pairs_size = self.capacity() * size_of::<(K, V)>(); - let buffer = self.hashes.ptr() as *mut u8; let (pairs_offset, _, oflo) = calculate_offsets(hashes_size, pairs_size, align_of::<(K, V)>()); debug_assert!(!oflo, "capacity overflow"); + + let buffer = self.hashes.ptr() as *mut u8; unsafe { RawBucket { - hash: self.hashes.ptr(), - pair: buffer.offset(pairs_offset as isize) as *const _, + hash_start: buffer as *mut HashUint, + pair_start: buffer.offset(pairs_offset as isize) as *const (K, V), + idx: index, _marker: marker::PhantomData, } } @@ -810,7 +827,7 @@ impl<K, V> RawTable<K, V> { /// The hashtable's capacity, similar to a vector's. pub fn capacity(&self) -> usize { - self.capacity + self.capacity_mask.wrapping_add(1) } /// The number of elements ever `put` in the hashtable, minus the number @@ -821,8 +838,8 @@ impl<K, V> RawTable<K, V> { fn raw_buckets(&self) -> RawBuckets<K, V> { RawBuckets { - raw: self.first_bucket_raw(), - hashes_end: unsafe { self.hashes.ptr().offset(self.capacity as isize) }, + raw: self.raw_bucket_at(0), + elems_left: self.size, marker: marker::PhantomData, } } @@ -830,25 +847,23 @@ impl<K, V> RawTable<K, V> { pub fn iter(&self) -> Iter<K, V> { Iter { iter: self.raw_buckets(), - elems_left: self.size(), } } pub fn iter_mut(&mut self) -> IterMut<K, V> { IterMut { iter: self.raw_buckets(), - elems_left: self.size(), _marker: marker::PhantomData, } } pub fn into_iter(self) -> IntoIter<K, V> { - let RawBuckets { raw, hashes_end, .. } = self.raw_buckets(); + let RawBuckets { raw, elems_left, .. } = self.raw_buckets(); // Replace the marker regardless of lifetime bounds on parameters. IntoIter { iter: RawBuckets { raw: raw, - hashes_end: hashes_end, + elems_left: elems_left, marker: marker::PhantomData, }, table: self, @@ -856,12 +871,12 @@ impl<K, V> RawTable<K, V> { } pub fn drain(&mut self) -> Drain<K, V> { - let RawBuckets { raw, hashes_end, .. } = self.raw_buckets(); + let RawBuckets { raw, elems_left, .. } = self.raw_buckets(); // Replace the marker regardless of lifetime bounds on parameters. Drain { iter: RawBuckets { raw: raw, - hashes_end: hashes_end, + elems_left: elems_left, marker: marker::PhantomData, }, table: unsafe { Shared::new(self) }, @@ -869,15 +884,21 @@ impl<K, V> RawTable<K, V> { } } - /// Returns an iterator that copies out each entry. Used while the table - /// is being dropped. - unsafe fn rev_move_buckets(&mut self) -> RevMoveBuckets<K, V> { - let raw_bucket = self.first_bucket_raw(); - RevMoveBuckets { - raw: raw_bucket.offset(self.capacity as isize), - hashes_end: raw_bucket.hash, - elems_left: self.size, - marker: marker::PhantomData, + /// Drops buckets in reverse order. It leaves the table in an inconsistent + /// state and should only be used for dropping the table's remaining + /// entries. It's used in the implementation of Drop. + unsafe fn rev_drop_buckets(&mut self) { + // initialize the raw bucket past the end of the table + let mut raw = self.raw_bucket_at(self.capacity()); + let mut elems_left = self.size; + + while elems_left != 0 { + raw.idx -= 1; + + if *raw.hash() != EMPTY_BUCKET { + elems_left -= 1; + ptr::drop_in_place(raw.pair()); + } } } @@ -896,7 +917,7 @@ impl<K, V> RawTable<K, V> { /// this interface is safe, it's not used outside this module. struct RawBuckets<'a, K, V> { raw: RawBucket<K, V>, - hashes_end: *mut HashUint, + elems_left: usize, // Strictly speaking, this should be &'a (K,V), but that would // require that K:'a, and we often use RawBuckets<'static...> for @@ -911,7 +932,7 @@ impl<'a, K, V> Clone for RawBuckets<'a, K, V> { fn clone(&self) -> RawBuckets<'a, K, V> { RawBuckets { raw: self.raw, - hashes_end: self.hashes_end, + elems_left: self.elems_left, marker: marker::PhantomData, } } @@ -922,62 +943,36 @@ impl<'a, K, V> Iterator for RawBuckets<'a, K, V> { type Item = RawBucket<K, V>; fn next(&mut self) -> Option<RawBucket<K, V>> { - while self.raw.hash != self.hashes_end { - unsafe { - // We are swapping out the pointer to a bucket and replacing - // it with the pointer to the next one. - let prev = ptr::replace(&mut self.raw, self.raw.offset(1)); - if *prev.hash != EMPTY_BUCKET { - return Some(prev); - } - } - } - - None - } -} - -/// An iterator that moves out buckets in reverse order. It leaves the table -/// in an inconsistent state and should only be used for dropping -/// the table's remaining entries. It's used in the implementation of Drop. -struct RevMoveBuckets<'a, K, V> { - raw: RawBucket<K, V>, - hashes_end: *mut HashUint, - elems_left: usize, - - // As above, `&'a (K,V)` would seem better, but we often use - // 'static for the lifetime, and this is not a publicly exposed - // type. - marker: marker::PhantomData<&'a ()>, -} - -impl<'a, K, V> Iterator for RevMoveBuckets<'a, K, V> { - type Item = (K, V); - - fn next(&mut self) -> Option<(K, V)> { if self.elems_left == 0 { return None; } loop { - debug_assert!(self.raw.hash != self.hashes_end); - unsafe { - self.raw = self.raw.offset(-1); - - if *self.raw.hash != EMPTY_BUCKET { + let item = self.raw; + self.raw.idx += 1; + if *item.hash() != EMPTY_BUCKET { self.elems_left -= 1; - return Some(ptr::read(self.raw.pair)); + return Some(item); } } } } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.elems_left, Some(self.elems_left)) + } +} + +impl<'a, K, V> ExactSizeIterator for RawBuckets<'a, K, V> { + fn len(&self) -> usize { + self.elems_left + } } /// Iterator over shared references to entries in a table. pub struct Iter<'a, K: 'a, V: 'a> { iter: RawBuckets<'a, K, V>, - elems_left: usize, } unsafe impl<'a, K: Sync, V: Sync> Sync for Iter<'a, K, V> {} @@ -988,16 +983,13 @@ impl<'a, K, V> Clone for Iter<'a, K, V> { fn clone(&self) -> Iter<'a, K, V> { Iter { iter: self.iter.clone(), - elems_left: self.elems_left, } } } - /// Iterator over mutable references to entries in a table. pub struct IterMut<'a, K: 'a, V: 'a> { iter: RawBuckets<'a, K, V>, - elems_left: usize, // To ensure invariance with respect to V _marker: marker::PhantomData<&'a mut V>, } @@ -1011,7 +1003,6 @@ impl<'a, K: 'a, V: 'a> IterMut<'a, K, V> { pub fn iter(&self) -> Iter<K, V> { Iter { iter: self.iter.clone(), - elems_left: self.elems_left, } } } @@ -1029,7 +1020,6 @@ impl<K, V> IntoIter<K, V> { pub fn iter(&self) -> Iter<K, V> { Iter { iter: self.iter.clone(), - elems_left: self.table.size, } } } @@ -1046,11 +1036,8 @@ unsafe impl<'a, K: Send, V: Send> Send for Drain<'a, K, V> {} impl<'a, K, V> Drain<'a, K, V> { pub fn iter(&self) -> Iter<K, V> { - unsafe { - Iter { - iter: self.iter.clone(), - elems_left: (**self.table).size, - } + Iter { + iter: self.iter.clone(), } } } @@ -1059,19 +1046,20 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> { type Item = (&'a K, &'a V); fn next(&mut self) -> Option<(&'a K, &'a V)> { - self.iter.next().map(|bucket| { - self.elems_left -= 1; - unsafe { (&(*bucket.pair).0, &(*bucket.pair).1) } + self.iter.next().map(|raw| unsafe { + let pair_ptr = raw.pair(); + (&(*pair_ptr).0, &(*pair_ptr).1) }) } fn size_hint(&self) -> (usize, Option<usize>) { - (self.elems_left, Some(self.elems_left)) + self.iter.size_hint() } } + impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> { fn len(&self) -> usize { - self.elems_left + self.iter.len() } } @@ -1079,20 +1067,20 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> { type Item = (&'a K, &'a mut V); fn next(&mut self) -> Option<(&'a K, &'a mut V)> { - self.iter.next().map(|bucket| { - self.elems_left -= 1; - let pair_mut = bucket.pair as *mut (K, V); - unsafe { (&(*pair_mut).0, &mut (*pair_mut).1) } + self.iter.next().map(|raw| unsafe { + let pair_ptr = raw.pair(); + (&(*pair_ptr).0, &mut (*pair_ptr).1) }) } fn size_hint(&self) -> (usize, Option<usize>) { - (self.elems_left, Some(self.elems_left)) + self.iter.size_hint() } } + impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> { fn len(&self) -> usize { - self.elems_left + self.iter.len() } } @@ -1100,23 +1088,23 @@ impl<K, V> Iterator for IntoIter<K, V> { type Item = (SafeHash, K, V); fn next(&mut self) -> Option<(SafeHash, K, V)> { - self.iter.next().map(|bucket| { + self.iter.next().map(|raw| { self.table.size -= 1; unsafe { - let (k, v) = ptr::read(bucket.pair); - (SafeHash { hash: *bucket.hash }, k, v) + let (k, v) = ptr::read(raw.pair()); + (SafeHash { hash: *raw.hash() }, k, v) } }) } fn size_hint(&self) -> (usize, Option<usize>) { - let size = self.table.size(); - (size, Some(size)) + self.iter.size_hint() } } + impl<K, V> ExactSizeIterator for IntoIter<K, V> { fn len(&self) -> usize { - self.table.size() + self.iter().len() } } @@ -1125,23 +1113,23 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> { #[inline] fn next(&mut self) -> Option<(SafeHash, K, V)> { - self.iter.next().map(|bucket| { + self.iter.next().map(|raw| { unsafe { - (**self.table).size -= 1; - let (k, v) = ptr::read(bucket.pair); - (SafeHash { hash: ptr::replace(bucket.hash, EMPTY_BUCKET) }, k, v) + self.table.as_mut().size -= 1; + let (k, v) = ptr::read(raw.pair()); + (SafeHash { hash: ptr::replace(&mut *raw.hash(), EMPTY_BUCKET) }, k, v) } }) } fn size_hint(&self) -> (usize, Option<usize>) { - let size = unsafe { (**self.table).size() }; - (size, Some(size)) + self.iter.size_hint() } } + impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { fn len(&self) -> usize { - unsafe { (**self.table).size() } + self.iter.len() } } @@ -1154,30 +1142,21 @@ impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> { impl<K: Clone, V: Clone> Clone for RawTable<K, V> { fn clone(&self) -> RawTable<K, V> { unsafe { - let mut new_ht = RawTable::new_uninitialized(self.capacity()); - - { - let cap = self.capacity(); - let mut new_buckets = Bucket::first(&mut new_ht); - let mut buckets = Bucket::first(self); - while buckets.index() != cap { - match buckets.peek() { - Full(full) => { - let (h, k, v) = { - let (k, v) = full.read(); - (full.hash(), k.clone(), v.clone()) - }; - *new_buckets.raw.hash = h.inspect(); - ptr::write(new_buckets.raw.pair as *mut (K, V), (k, v)); - } - Empty(..) => { - *new_buckets.raw.hash = EMPTY_BUCKET; - } - } - new_buckets.next(); - buckets.next(); + let cap = self.capacity(); + let mut new_ht = RawTable::new_uninitialized(cap); + + let mut new_buckets = new_ht.raw_bucket_at(0); + let mut buckets = self.raw_bucket_at(0); + while buckets.idx < cap { + *new_buckets.hash() = *buckets.hash(); + if *new_buckets.hash() != EMPTY_BUCKET { + let pair_ptr = buckets.pair(); + let kv = ((*pair_ptr).0.clone(), (*pair_ptr).1.clone()); + ptr::write(new_buckets.pair(), kv); } - }; + buckets.idx += 1; + new_buckets.idx += 1; + } new_ht.size = self.size(); @@ -1188,7 +1167,7 @@ impl<K: Clone, V: Clone> Clone for RawTable<K, V> { unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> { fn drop(&mut self) { - if self.capacity == 0 { + if self.capacity() == 0 { return; } @@ -1200,12 +1179,12 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> { unsafe { if needs_drop::<(K, V)>() { // avoid linear runtime for types that don't need drop - for _ in self.rev_move_buckets() {} + self.rev_drop_buckets(); } } - let hashes_size = self.capacity * size_of::<HashUint>(); - let pairs_size = self.capacity * size_of::<(K, V)>(); + let hashes_size = self.capacity() * size_of::<HashUint>(); + let pairs_size = self.capacity() * size_of::<(K, V)>(); let (align, _, size, oflo) = calculate_allocation(hashes_size, align_of::<HashUint>(), pairs_size, diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 8884d0688b8..506bf717337 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -157,29 +157,29 @@ //! information to do this itself. Therefore, it is up to us programmers to give //! it hints. //! -//! Any `with_capacity()` constructor will instruct the collection to allocate +//! Any `with_capacity` constructor will instruct the collection to allocate //! enough space for the specified number of elements. Ideally this will be for //! exactly that many elements, but some implementation details may prevent //! this. [`Vec`] and [`VecDeque`] can be relied on to allocate exactly the -//! requested amount, though. Use `with_capacity()` when you know exactly how many +//! requested amount, though. Use `with_capacity` when you know exactly how many //! elements will be inserted, or at least have a reasonable upper-bound on that //! number. //! -//! When anticipating a large influx of elements, the `reserve()` family of +//! When anticipating a large influx of elements, the `reserve` family of //! methods can be used to hint to the collection how much room it should make -//! for the coming items. As with `with_capacity()`, the precise behavior of +//! for the coming items. As with `with_capacity`, the precise behavior of //! these methods will be specific to the collection of interest. //! //! For optimal performance, collections will generally avoid shrinking //! themselves. If you believe that a collection will not soon contain any more -//! elements, or just really need the memory, the `shrink_to_fit()` method prompts +//! elements, or just really need the memory, the `shrink_to_fit` method prompts //! the collection to shrink the backing array to the minimum size capable of //! holding its elements. //! //! Finally, if ever you're interested in what the actual capacity of the -//! collection is, most collections provide a `capacity()` method to query this +//! collection is, most collections provide a `capacity` method to query this //! information on demand. This can be useful for debugging purposes, or for -//! use with the `reserve()` methods. +//! use with the `reserve` methods. //! //! ## Iterators //! @@ -194,11 +194,11 @@ //! //! All of the standard collections provide several iterators for performing //! bulk manipulation of their contents. The three primary iterators almost -//! every collection should provide are `iter()`, `iter_mut()`, and `into_iter()`. +//! every collection should provide are `iter`, `iter_mut`, and `into_iter`. //! Some of these are not provided on collections where it would be unsound or //! unreasonable to provide them. //! -//! `iter()` provides an iterator of immutable references to all the contents of a +//! `iter` provides an iterator of immutable references to all the contents of a //! collection in the most "natural" order. For sequence collections like [`Vec`], //! this means the items will be yielded in increasing order of index starting //! at 0. For ordered collections like [`BTreeMap`], this means that the items @@ -214,8 +214,8 @@ //! } //! ``` //! -//! `iter_mut()` provides an iterator of *mutable* references in the same order as -//! `iter()`. This is great for mutating all the contents of the collection. +//! `iter_mut` provides an iterator of *mutable* references in the same order as +//! `iter`. This is great for mutating all the contents of the collection. //! //! ``` //! let mut vec = vec![1, 2, 3, 4]; @@ -224,12 +224,12 @@ //! } //! ``` //! -//! `into_iter()` transforms the actual collection into an iterator over its +//! `into_iter` transforms the actual collection into an iterator over its //! contents by-value. This is great when the collection itself is no longer -//! needed, and the values are needed elsewhere. Using `extend()` with `into_iter()` +//! needed, and the values are needed elsewhere. Using `extend` with `into_iter` //! is the main way that contents of one collection are moved into another. -//! `extend()` automatically calls `into_iter()`, and takes any `T: `[`IntoIterator`]. -//! Calling `collect()` on an iterator itself is also a great way to convert one +//! `extend` automatically calls `into_iter`, and takes any `T: `[`IntoIterator`]. +//! Calling `collect` on an iterator itself is also a great way to convert one //! collection into another. Both of these methods should internally use the //! capacity management tools discussed in the previous section to do this as //! efficiently as possible. @@ -248,9 +248,9 @@ //! ``` //! //! Iterators also provide a series of *adapter* methods for performing common -//! threads to sequences. Among the adapters are functional favorites like `map()`, -//! `fold()`, `skip()` and `take()`. Of particular interest to collections is the -//! `rev()` adapter, that reverses any iterator that supports this operation. Most +//! threads to sequences. Among the adapters are functional favorites like `map`, +//! `fold`, `skip` and `take`. Of particular interest to collections is the +//! `rev` adapter, that reverses any iterator that supports this operation. Most //! collections provide reversible iterators as the way to iterate over them in //! reverse order. //! @@ -263,27 +263,27 @@ //! //! Several other collection methods also return iterators to yield a sequence //! of results but avoid allocating an entire collection to store the result in. -//! This provides maximum flexibility as `collect()` or `extend()` can be called to +//! This provides maximum flexibility as `collect` or `extend` can be called to //! "pipe" the sequence into any collection if desired. Otherwise, the sequence //! can be looped over with a `for` loop. The iterator can also be discarded //! after partial use, preventing the computation of the unused items. //! //! ## Entries //! -//! The `entry()` API is intended to provide an efficient mechanism for +//! The `entry` API is intended to provide an efficient mechanism for //! manipulating the contents of a map conditionally on the presence of a key or //! not. The primary motivating use case for this is to provide efficient //! accumulator maps. For instance, if one wishes to maintain a count of the //! number of times each key has been seen, they will have to perform some //! conditional logic on whether this is the first time the key has been seen or -//! not. Normally, this would require a `find()` followed by an `insert()`, +//! not. Normally, this would require a `find` followed by an `insert`, //! effectively duplicating the search effort on each insertion. //! //! When a user calls `map.entry(&key)`, the map will search for the key and //! then yield a variant of the `Entry` enum. //! //! If a `Vacant(entry)` is yielded, then the key *was not* found. In this case -//! the only valid operation is to `insert()` a value into the entry. When this is +//! the only valid operation is to `insert` a value into the entry. When this is //! done, the vacant entry is consumed and converted into a mutable reference to //! the value that was inserted. This allows for further manipulation of the //! value beyond the lifetime of the search itself. This is useful if complex @@ -291,14 +291,14 @@ //! just inserted. //! //! If an `Occupied(entry)` is yielded, then the key *was* found. In this case, -//! the user has several options: they can `get()`, `insert()` or `remove()` the +//! the user has several options: they can `get`, `insert` or `remove` the //! value of the occupied entry. Additionally, they can convert the occupied //! entry into a mutable reference to its value, providing symmetry to the -//! vacant `insert()` case. +//! vacant `insert` case. //! //! ### Examples //! -//! Here are the two primary ways in which `entry()` is used. First, a simple +//! Here are the two primary ways in which `entry` is used. First, a simple //! example where the logic performed on the values is trivial. //! //! #### Counting the number of times each character in a string occurs @@ -322,7 +322,7 @@ //! ``` //! //! When the logic to be performed on the value is more complex, we may simply -//! use the `entry()` API to ensure that the value is initialized and perform the +//! use the `entry` API to ensure that the value is initialized and perform the //! logic afterwards. //! //! #### Tracking the inebriation of customers at a bar @@ -360,7 +360,7 @@ //! //! # Insert and complex keys //! -//! If we have a more complex key, calls to `insert()` will +//! If we have a more complex key, calls to `insert` will //! not update the value of the key. For example: //! //! ``` @@ -442,16 +442,14 @@ mod hash; #[stable(feature = "rust1", since = "1.0.0")] pub mod hash_map { - //! A hash map implementation which uses linear probing with Robin - //! Hood bucket stealing. + //! A hash map implemented with linear probing and Robin Hood bucket stealing. #[stable(feature = "rust1", since = "1.0.0")] pub use super::hash::map::*; } #[stable(feature = "rust1", since = "1.0.0")] pub mod hash_set { - //! An implementation of a hash set using the underlying representation of a - //! HashMap where the value is (). + //! A hash set implemented as a `HashMap` where the value is `()`. #[stable(feature = "rust1", since = "1.0.0")] pub use super::hash::set::*; } diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 64eb52e28bc..27b40793ff6 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -13,6 +13,13 @@ //! This module contains functions to inspect various aspects such as //! environment variables, process arguments, the current directory, and various //! other important directories. +//! +//! There are several functions and structs in this module that have a +//! counterpart ending in `os`. Those ending in `os` will return an [`OsString`] +//! and those without will be returning a [`String`]. +//! +//! [`OsString`]: ../../std/ffi/struct.OsString.html +//! [`String`]: ../string/struct.String.html #![stable(feature = "env", since = "1.0.0")] @@ -43,16 +50,19 @@ use sys::os as os_imp; /// use std::env; /// /// // We assume that we are in a valid directory. -/// let p = env::current_dir().unwrap(); -/// println!("The current directory is {}", p.display()); +/// let path = env::current_dir().unwrap(); +/// println!("The current directory is {}", path.display()); /// ``` #[stable(feature = "env", since = "1.0.0")] pub fn current_dir() -> io::Result<PathBuf> { os_imp::getcwd() } -/// Changes the current working directory to the specified path, returning -/// whether the change was completed successfully or not. +/// Changes the current working directory to the specified path. +/// +/// Returns an [`Err`] if the operation fails. +/// +/// [`Err`]: ../../std/result/enum.Result.html#method.err /// /// # Examples /// @@ -65,13 +75,14 @@ pub fn current_dir() -> io::Result<PathBuf> { /// println!("Successfully changed working directory to {}!", root.display()); /// ``` #[stable(feature = "env", since = "1.0.0")] -pub fn set_current_dir<P: AsRef<Path>>(p: P) -> io::Result<()> { - os_imp::chdir(p.as_ref()) +pub fn set_current_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { + os_imp::chdir(path.as_ref()) } /// An iterator over a snapshot of the environment variables of this process. /// -/// This structure is created through the [`std::env::vars`] function. +/// This structure is created by the [`std::env::vars`] function. See its +/// documentation for more. /// /// [`std::env::vars`]: fn.vars.html #[stable(feature = "env", since = "1.0.0")] @@ -79,7 +90,8 @@ pub struct Vars { inner: VarsOs } /// An iterator over a snapshot of the environment variables of this process. /// -/// This structure is created through the [`std::env::vars_os`] function. +/// This structure is created by the [`std::env::vars_os`] function. See +/// its documentation for more. /// /// [`std::env::vars_os`]: fn.vars_os.html #[stable(feature = "env", since = "1.0.0")] @@ -173,12 +185,10 @@ impl fmt::Debug for VarsOs { /// Fetches the environment variable `key` from the current process. /// -/// The returned result is [`Ok(s)`] if the environment variable is present and is -/// valid unicode. If the environment variable is not present, or it is not -/// valid unicode, then [`Err`] will be returned. +/// # Errors /// -/// [`Ok(s)`]: ../result/enum.Result.html#variant.Ok -/// [`Err`]: ../result/enum.Result.html#variant.Err +/// * Environment variable is not present +/// * Environment variable is not valid unicode /// /// # Examples /// @@ -199,7 +209,7 @@ pub fn var<K: AsRef<OsStr>>(key: K) -> Result<String, VarError> { fn _var(key: &OsStr) -> Result<String, VarError> { match var_os(key) { Some(s) => s.into_string().map_err(VarError::NotUnicode), - None => Err(VarError::NotPresent) + None => Err(VarError::NotPresent), } } @@ -230,7 +240,8 @@ fn _var_os(key: &OsStr) -> Option<OsString> { }) } -/// Possible errors from the [`env::var`] function. +/// The error type for operations interacting with environment variables. +/// Possibly returned from the [`env::var`] function. /// /// [`env::var`]: fn.var.html #[derive(Debug, PartialEq, Eq, Clone)] @@ -353,10 +364,13 @@ fn _remove_var(k: &OsStr) { }) } -/// An iterator over `PathBuf` instances for parsing an environment variable -/// according to platform-specific conventions. +/// An iterator that splits an environment variable into paths according to +/// platform-specific conventions. +/// +/// This structure is created by the [`std::env::split_paths`] function See its +/// documentation for more. /// -/// This structure is returned from `std::env::split_paths`. +/// [`std::env::split_paths`]: fn.split_paths.html #[stable(feature = "env", since = "1.0.0")] pub struct SplitPaths<'a> { inner: os_imp::SplitPaths<'a> } @@ -399,8 +413,10 @@ impl<'a> fmt::Debug for SplitPaths<'a> { } } -/// Error type returned from `std::env::join_paths` when paths fail to be -/// joined. +/// The error type for operations on the `PATH` variable. Possibly returned from +/// the [`env::join_paths`] function. +/// +/// [`env::join_paths`]: fn.join_paths.html #[derive(Debug)] #[stable(feature = "env", since = "1.0.0")] pub struct JoinPathsError { @@ -410,7 +426,7 @@ pub struct JoinPathsError { /// Joins a collection of [`Path`]s appropriately for the `PATH` /// environment variable. /// -/// Returns an [`OsString`] on success. +/// # Errors /// /// Returns an [`Err`][err] (containing an error message) if one of the input /// [`Path`]s contains an invalid character for constructing the `PATH` @@ -490,12 +506,16 @@ pub fn home_dir() -> Option<PathBuf> { /// Returns the path of a temporary directory. /// -/// On Unix, returns the value of the `TMPDIR` environment variable if it is +/// # Unix +/// +/// Returns the value of the `TMPDIR` environment variable if it is /// set, otherwise for non-Android it returns `/tmp`. If Android, since there /// is no global temporary folder (it is usually allocated per-app), it returns /// `/data/local/tmp`. /// -/// On Windows, returns the value of, in order, the `TMP`, `TEMP`, +/// # Windows +/// +/// Returns the value of, in order, the `TMP`, `TEMP`, /// `USERPROFILE` environment variable if any are set and not the empty /// string. Otherwise, `temp_dir` returns the path of the Windows directory. /// This behavior is identical to that of [`GetTempPath`][msdn], which this @@ -680,7 +700,7 @@ impl ExactSizeIterator for Args { fn is_empty(&self) -> bool { self.inner.is_empty() } } -#[stable(feature = "env_iterators", since = "1.11.0")] +#[stable(feature = "env_iterators", since = "1.12.0")] impl DoubleEndedIterator for Args { fn next_back(&mut self) -> Option<String> { self.inner.next_back().map(|s| s.into_string().unwrap()) @@ -707,7 +727,7 @@ impl ExactSizeIterator for ArgsOs { fn is_empty(&self) -> bool { self.inner.is_empty() } } -#[stable(feature = "env_iterators", since = "1.11.0")] +#[stable(feature = "env_iterators", since = "1.12.0")] impl DoubleEndedIterator for ArgsOs { fn next_back(&mut self) -> Option<OsString> { self.inner.next_back() } } diff --git a/src/libstd/error.rs b/src/libstd/error.rs index e115263d2eb..f56e3a5d780 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -193,7 +193,7 @@ impl From<String> for Box<Error + Send + Sync> { } } -#[stable(feature = "string_box_error", since = "1.7.0")] +#[stable(feature = "string_box_error", since = "1.6.0")] impl From<String> for Box<Error> { fn from(str_err: String) -> Box<Error> { let err1: Box<Error + Send + Sync> = From::from(str_err); @@ -209,13 +209,18 @@ impl<'a, 'b> From<&'b str> for Box<Error + Send + Sync + 'a> { } } -#[stable(feature = "string_box_error", since = "1.7.0")] +#[stable(feature = "string_box_error", since = "1.6.0")] impl<'a> From<&'a str> for Box<Error> { fn from(err: &'a str) -> Box<Error> { From::from(String::from(err)) } } +#[unstable(feature = "never_type_impls", issue = "35121")] +impl Error for ! { + fn description(&self) -> &str { *self } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Error for str::ParseBoolError { fn description(&self) -> &str { "failed to parse bool" } @@ -277,7 +282,7 @@ impl Error for char::DecodeUtf16Error { } } -#[stable(feature = "box_error", since = "1.7.0")] +#[stable(feature = "box_error", since = "1.8.0")] impl<T: Error> Error for Box<T> { fn description(&self) -> &str { Error::description(&**self) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 544f4f9ddbe..4abad7e24f8 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -8,7 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The 32-bit floating point type. +//! This module provides constants which are specific to the implementation +//! of the `f32` floating point data type. Mathematically significant +//! numbers are provided in the `consts` sub-module. //! //! *[See also the `f32` primitive type](../primitive.f32.html).* @@ -20,8 +22,6 @@ use core::num; #[cfg(not(test))] use intrinsics; #[cfg(not(test))] -use libc::c_int; -#[cfg(not(test))] use num::FpCategory; @@ -71,8 +71,6 @@ mod cmath { pub fn atan2f(a: c_float, b: c_float) -> c_float; pub fn atanf(n: c_float) -> c_float; pub fn coshf(n: c_float) -> c_float; - pub fn frexpf(n: c_float, value: &mut c_int) -> c_float; - pub fn ldexpf(x: c_float, n: c_int) -> c_float; pub fn sinhf(n: c_float) -> c_float; pub fn tanf(n: c_float) -> c_float; pub fn tanhf(n: c_float) -> c_float; @@ -82,7 +80,7 @@ mod cmath { pub use self::shims::*; #[cfg(target_env = "msvc")] mod shims { - use libc::{c_float, c_int}; + use libc::c_float; #[inline] pub unsafe fn acosf(n: c_float) -> c_float { @@ -110,20 +108,6 @@ mod cmath { } #[inline] - #[allow(deprecated)] - pub unsafe fn frexpf(x: c_float, value: &mut c_int) -> c_float { - let (a, b) = f64::frexp(x as f64); - *value = b as c_int; - a as c_float - } - - #[inline] - #[allow(deprecated)] - pub unsafe fn ldexpf(x: c_float, n: c_int) -> c_float { - f64::ldexp(x as f64, n as isize) as c_float - } - - #[inline] pub unsafe fn sinhf(n: c_float) -> c_float { f64::sinh(n as f64) as c_float } @@ -242,40 +226,6 @@ impl f32 { #[inline] pub fn classify(self) -> FpCategory { num::Float::classify(self) } - /// Returns the mantissa, base 2 exponent, and sign as integers, respectively. - /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`. - /// The floating point encoding is documented in the [Reference][floating-point]. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// use std::f32; - /// - /// let num = 2.0f32; - /// - /// // (8388608, -22, 1) - /// let (mantissa, exponent, sign) = num.integer_decode(); - /// let sign_f = sign as f32; - /// let mantissa_f = mantissa as f32; - /// let exponent_f = num.powf(exponent as f32); - /// - /// // 1 * 8388608 * 2^(-22) == 2 - /// let abs_difference = (sign_f * mantissa_f * exponent_f - num).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - /// [floating-point]: ../reference/types.html#machine-types - #[unstable(feature = "float_extras", reason = "signature is undecided", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - #[allow(deprecated)] - pub fn integer_decode(self) -> (u64, i16, i8) { - num::Float::integer_decode(self) - } - /// Returns the largest integer less than or equal to a number. /// /// ``` @@ -710,89 +660,6 @@ impl f32 { #[inline] pub fn to_radians(self) -> f32 { num::Float::to_radians(self) } - /// Constructs a floating point number of `x*2^exp`. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// use std::f32; - /// // 3*2^2 - 12 == 0 - /// let abs_difference = (f32::ldexp(3.0, 2) - 12.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[unstable(feature = "float_extras", - reason = "pending integer conventions", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn ldexp(x: f32, exp: isize) -> f32 { - unsafe { cmath::ldexpf(x, exp as c_int) } - } - - /// Breaks the number into a normalized fraction and a base-2 exponent, - /// satisfying: - /// - /// * `self = x * 2^exp` - /// * `0.5 <= abs(x) < 1.0` - /// - /// ``` - /// #![feature(float_extras)] - /// - /// use std::f32; - /// - /// let x = 4.0f32; - /// - /// // (1/2)*2^3 -> 1 * 8/2 -> 4.0 - /// let f = x.frexp(); - /// let abs_difference_0 = (f.0 - 0.5).abs(); - /// let abs_difference_1 = (f.1 as f32 - 3.0).abs(); - /// - /// assert!(abs_difference_0 <= f32::EPSILON); - /// assert!(abs_difference_1 <= f32::EPSILON); - /// ``` - #[unstable(feature = "float_extras", - reason = "pending integer conventions", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn frexp(self) -> (f32, isize) { - unsafe { - let mut exp = 0; - let x = cmath::frexpf(self, &mut exp); - (x, exp as isize) - } - } - - /// Returns the next representable floating-point value in the direction of - /// `other`. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// use std::f32; - /// - /// let x = 1.0f32; - /// - /// let abs_diff = (x.next_after(2.0) - 1.00000011920928955078125_f32).abs(); - /// - /// assert!(abs_diff <= f32::EPSILON); - /// ``` - #[unstable(feature = "float_extras", - reason = "unsure about its place in the world", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn next_after(self, other: f32) -> f32 { - unsafe { cmath::nextafterf(self, other) } - } - /// Returns the maximum of the two numbers. /// /// ``` @@ -1224,6 +1091,68 @@ impl f32 { pub fn atanh(self) -> f32 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } + + /// Raw transmutation to `u32`. + /// + /// Converts the `f32` into its raw memory representation, + /// similar to the `transmute` function. + /// + /// Note that this function is distinct from casting. + /// + /// # Examples + /// + /// ``` + /// #![feature(float_bits_conv)] + /// assert_ne!((1f32).to_bits(), 1f32 as u32); // to_bits() is not casting! + /// assert_eq!((12.5f32).to_bits(), 0x41480000); + /// + /// ``` + #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "40470")] + #[inline] + pub fn to_bits(self) -> u32 { + unsafe { ::mem::transmute(self) } + } + + /// Raw transmutation from `u32`. + /// + /// Converts the given `u32` containing the float's raw memory + /// representation into the `f32` type, similar to the + /// `transmute` function. + /// + /// There is only one difference to a bare `transmute`: + /// Due to the implications onto Rust's safety promises being + /// uncertain, if the representation of a signaling NaN "sNaN" float + /// is passed to the function, the implementation is allowed to + /// return a quiet NaN instead. + /// + /// Note that this function is distinct from casting. + /// + /// # Examples + /// + /// ``` + /// #![feature(float_bits_conv)] + /// use std::f32; + /// let v = f32::from_bits(0x41480000); + /// let difference = (v - 12.5).abs(); + /// assert!(difference <= 1e-5); + /// // Example for a signaling NaN value: + /// let snan = 0x7F800001; + /// assert_ne!(f32::from_bits(snan).to_bits(), snan); + /// ``` + #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "40470")] + #[inline] + pub fn from_bits(mut v: u32) -> Self { + const EXP_MASK: u32 = 0x7F800000; + const QNAN_MASK: u32 = 0x00400000; + const FRACT_MASK: u32 = 0x007FFFFF; + if v & EXP_MASK == EXP_MASK && v & FRACT_MASK != 0 { + // If we have a NaN value, we + // convert signaling NaN values to quiet NaN + // by setting the the highest bit of the fraction + v |= QNAN_MASK; + } + unsafe { ::mem::transmute(v) } + } } #[cfg(test)] @@ -1399,23 +1328,6 @@ mod tests { } #[test] - #[allow(deprecated)] - fn test_integer_decode() { - assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1)); - assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1)); - assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1)); - assert_eq!(0f32.integer_decode(), (0, -150, 1)); - assert_eq!((-0f32).integer_decode(), (0, -150, -1)); - assert_eq!(INFINITY.integer_decode(), (8388608, 105, 1)); - assert_eq!(NEG_INFINITY.integer_decode(), (8388608, 105, -1)); - - // Ignore the "sign" (quiet / signalling flag) of NAN. - // It can vary between runtime operations and LLVM folding. - let (nan_m, nan_e, _nan_s) = NAN.integer_decode(); - assert_eq!((nan_m, nan_e), (12582912, 105)); - } - - #[test] fn test_floor() { assert_approx_eq!(1.0f32.floor(), 1.0f32); assert_approx_eq!(1.3f32.floor(), 1.0f32); @@ -1727,58 +1639,6 @@ mod tests { } #[test] - #[allow(deprecated)] - fn test_ldexp() { - let f1 = 2.0f32.powi(-123); - let f2 = 2.0f32.powi(-111); - let f3 = 1.75 * 2.0f32.powi(-12); - assert_eq!(f32::ldexp(1f32, -123), f1); - assert_eq!(f32::ldexp(1f32, -111), f2); - assert_eq!(f32::ldexp(1.75f32, -12), f3); - - assert_eq!(f32::ldexp(0f32, -123), 0f32); - assert_eq!(f32::ldexp(-0f32, -123), -0f32); - - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(f32::ldexp(inf, -123), inf); - assert_eq!(f32::ldexp(neg_inf, -123), neg_inf); - assert!(f32::ldexp(nan, -123).is_nan()); - } - - #[test] - #[allow(deprecated)] - fn test_frexp() { - let f1 = 2.0f32.powi(-123); - let f2 = 2.0f32.powi(-111); - let f3 = 1.75 * 2.0f32.powi(-123); - let (x1, exp1) = f1.frexp(); - let (x2, exp2) = f2.frexp(); - let (x3, exp3) = f3.frexp(); - assert_eq!((x1, exp1), (0.5f32, -122)); - assert_eq!((x2, exp2), (0.5f32, -110)); - assert_eq!((x3, exp3), (0.875f32, -122)); - assert_eq!(f32::ldexp(x1, exp1), f1); - assert_eq!(f32::ldexp(x2, exp2), f2); - assert_eq!(f32::ldexp(x3, exp3), f3); - - assert_eq!(0f32.frexp(), (0f32, 0)); - assert_eq!((-0f32).frexp(), (-0f32, 0)); - } - - #[test] #[cfg_attr(windows, ignore)] // FIXME #8755 - #[allow(deprecated)] - fn test_frexp_nowin() { - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(match inf.frexp() { (x, _) => x }, inf); - assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf); - assert!(match nan.frexp() { (x, _) => x.is_nan() }) - } - - #[test] fn test_asinh() { assert_eq!(0.0f32.asinh(), 0.0f32); assert_eq!((-0.0f32).asinh(), -0.0f32); @@ -1868,4 +1728,31 @@ mod tests { assert_approx_eq!(ln_2, 2f32.ln()); assert_approx_eq!(ln_10, 10f32.ln()); } + + #[test] + fn test_float_bits_conv() { + assert_eq!((1f32).to_bits(), 0x3f800000); + assert_eq!((12.5f32).to_bits(), 0x41480000); + assert_eq!((1337f32).to_bits(), 0x44a72000); + assert_eq!((-14.25f32).to_bits(), 0xc1640000); + assert_approx_eq!(f32::from_bits(0x3f800000), 1.0); + assert_approx_eq!(f32::from_bits(0x41480000), 12.5); + assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0); + assert_approx_eq!(f32::from_bits(0xc1640000), -14.25); + } + #[test] + fn test_snan_masking() { + let snan: u32 = 0x7F801337; + const PAYLOAD_MASK: u32 = 0x003FFFFF; + const QNAN_MASK: u32 = 0x00400000; + let nan_masked_fl = f32::from_bits(snan); + let nan_masked = nan_masked_fl.to_bits(); + // Ensure that signaling NaNs don't stay the same + assert_ne!(nan_masked, snan); + // Ensure that we have a quiet NaN + assert_ne!(nan_masked & QNAN_MASK, 0); + assert!(nan_masked_fl.is_nan()); + // Ensure the payload wasn't touched during conversion + assert_eq!(nan_masked & PAYLOAD_MASK, snan & PAYLOAD_MASK); + } } diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index dd4bc253bed..82e3903eec7 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -8,7 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The 64-bit floating point type. +//! This module provides constants which are specific to the implementation +//! of the `f64` floating point data type. Mathematically significant +//! numbers are provided in the `consts` sub-module. //! //! *[See also the `f64` primitive type](../primitive.f64.html).* @@ -20,8 +22,6 @@ use core::num; #[cfg(not(test))] use intrinsics; #[cfg(not(test))] -use libc::c_int; -#[cfg(not(test))] use num::FpCategory; #[stable(feature = "rust1", since = "1.0.0")] @@ -186,36 +186,6 @@ impl f64 { #[inline] pub fn classify(self) -> FpCategory { num::Float::classify(self) } - /// Returns the mantissa, base 2 exponent, and sign as integers, respectively. - /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`. - /// The floating point encoding is documented in the [Reference][floating-point]. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// let num = 2.0f64; - /// - /// // (8388608, -22, 1) - /// let (mantissa, exponent, sign) = num.integer_decode(); - /// let sign_f = sign as f64; - /// let mantissa_f = mantissa as f64; - /// let exponent_f = num.powf(exponent as f64); - /// - /// // 1 * 8388608 * 2^(-22) == 2 - /// let abs_difference = (sign_f * mantissa_f * exponent_f - num).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - /// [floating-point]: ../reference/types.html#machine-types - #[unstable(feature = "float_extras", reason = "signature is undecided", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - #[allow(deprecated)] - pub fn integer_decode(self) -> (u64, i16, i8) { num::Float::integer_decode(self) } - /// Returns the largest integer less than or equal to a number. /// /// ``` @@ -604,84 +574,6 @@ impl f64 { #[inline] pub fn to_radians(self) -> f64 { num::Float::to_radians(self) } - /// Constructs a floating point number of `x*2^exp`. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// // 3*2^2 - 12 == 0 - /// let abs_difference = (f64::ldexp(3.0, 2) - 12.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[unstable(feature = "float_extras", - reason = "pending integer conventions", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn ldexp(x: f64, exp: isize) -> f64 { - unsafe { cmath::ldexp(x, exp as c_int) } - } - - /// Breaks the number into a normalized fraction and a base-2 exponent, - /// satisfying: - /// - /// * `self = x * 2^exp` - /// * `0.5 <= abs(x) < 1.0` - /// - /// ``` - /// #![feature(float_extras)] - /// - /// let x = 4.0_f64; - /// - /// // (1/2)*2^3 -> 1 * 8/2 -> 4.0 - /// let f = x.frexp(); - /// let abs_difference_0 = (f.0 - 0.5).abs(); - /// let abs_difference_1 = (f.1 as f64 - 3.0).abs(); - /// - /// assert!(abs_difference_0 < 1e-10); - /// assert!(abs_difference_1 < 1e-10); - /// ``` - #[unstable(feature = "float_extras", - reason = "pending integer conventions", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn frexp(self) -> (f64, isize) { - unsafe { - let mut exp = 0; - let x = cmath::frexp(self, &mut exp); - (x, exp as isize) - } - } - - /// Returns the next representable floating-point value in the direction of - /// `other`. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// let x = 1.0f64; - /// - /// let abs_diff = (x.next_after(2.0) - 1.0000000000000002220446049250313_f64).abs(); - /// - /// assert!(abs_diff < 1e-10); - /// ``` - #[unstable(feature = "float_extras", - reason = "unsure about its place in the world", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn next_after(self, other: f64) -> f64 { - unsafe { cmath::nextafter(self, other) } - } - /// Returns the maximum of the two numbers. /// /// ``` @@ -1116,6 +1008,68 @@ impl f64 { } } } + + /// Raw transmutation to `u64`. + /// + /// Converts the `f64` into its raw memory representation, + /// similar to the `transmute` function. + /// + /// Note that this function is distinct from casting. + /// + /// # Examples + /// + /// ``` + /// #![feature(float_bits_conv)] + /// assert!((1f64).to_bits() != 1f64 as u64); // to_bits() is not casting! + /// assert_eq!((12.5f64).to_bits(), 0x4029000000000000); + /// + /// ``` + #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "40470")] + #[inline] + pub fn to_bits(self) -> u64 { + unsafe { ::mem::transmute(self) } + } + + /// Raw transmutation from `u64`. + /// + /// Converts the given `u64` containing the float's raw memory + /// representation into the `f64` type, similar to the + /// `transmute` function. + /// + /// There is only one difference to a bare `transmute`: + /// Due to the implications onto Rust's safety promises being + /// uncertain, if the representation of a signaling NaN "sNaN" float + /// is passed to the function, the implementation is allowed to + /// return a quiet NaN instead. + /// + /// Note that this function is distinct from casting. + /// + /// # Examples + /// + /// ``` + /// #![feature(float_bits_conv)] + /// use std::f64; + /// let v = f64::from_bits(0x4029000000000000); + /// let difference = (v - 12.5).abs(); + /// assert!(difference <= 1e-5); + /// // Example for a signaling NaN value: + /// let snan = 0x7FF0000000000001; + /// assert_ne!(f64::from_bits(snan).to_bits(), snan); + /// ``` + #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "40470")] + #[inline] + pub fn from_bits(mut v: u64) -> Self { + const EXP_MASK: u64 = 0x7FF0000000000000; + const QNAN_MASK: u64 = 0x0001000000000000; + const FRACT_MASK: u64 = 0x000FFFFFFFFFFFFF; + if v & EXP_MASK == EXP_MASK && v & FRACT_MASK != 0 { + // If we have a NaN value, we + // convert signaling NaN values to quiet NaN + // by setting the the highest bit of the fraction + v |= QNAN_MASK; + } + unsafe { ::mem::transmute(v) } + } } #[cfg(test)] @@ -1290,23 +1244,6 @@ mod tests { } #[test] - #[allow(deprecated)] - fn test_integer_decode() { - assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1)); - assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1)); - assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1)); - assert_eq!(0f64.integer_decode(), (0, -1075, 1)); - assert_eq!((-0f64).integer_decode(), (0, -1075, -1)); - assert_eq!(INFINITY.integer_decode(), (4503599627370496, 972, 1)); - assert_eq!(NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1)); - - // Ignore the "sign" (quiet / signalling flag) of NAN. - // It can vary between runtime operations and LLVM folding. - let (nan_m, nan_e, _nan_s) = NAN.integer_decode(); - assert_eq!((nan_m, nan_e), (6755399441055744, 972)); - } - - #[test] fn test_floor() { assert_approx_eq!(1.0f64.floor(), 1.0f64); assert_approx_eq!(1.3f64.floor(), 1.0f64); @@ -1618,58 +1555,6 @@ mod tests { } #[test] - #[allow(deprecated)] - fn test_ldexp() { - let f1 = 2.0f64.powi(-123); - let f2 = 2.0f64.powi(-111); - let f3 = 1.75 * 2.0f64.powi(-12); - assert_eq!(f64::ldexp(1f64, -123), f1); - assert_eq!(f64::ldexp(1f64, -111), f2); - assert_eq!(f64::ldexp(1.75f64, -12), f3); - - assert_eq!(f64::ldexp(0f64, -123), 0f64); - assert_eq!(f64::ldexp(-0f64, -123), -0f64); - - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - let nan: f64 = NAN; - assert_eq!(f64::ldexp(inf, -123), inf); - assert_eq!(f64::ldexp(neg_inf, -123), neg_inf); - assert!(f64::ldexp(nan, -123).is_nan()); - } - - #[test] - #[allow(deprecated)] - fn test_frexp() { - let f1 = 2.0f64.powi(-123); - let f2 = 2.0f64.powi(-111); - let f3 = 1.75 * 2.0f64.powi(-123); - let (x1, exp1) = f1.frexp(); - let (x2, exp2) = f2.frexp(); - let (x3, exp3) = f3.frexp(); - assert_eq!((x1, exp1), (0.5f64, -122)); - assert_eq!((x2, exp2), (0.5f64, -110)); - assert_eq!((x3, exp3), (0.875f64, -122)); - assert_eq!(f64::ldexp(x1, exp1), f1); - assert_eq!(f64::ldexp(x2, exp2), f2); - assert_eq!(f64::ldexp(x3, exp3), f3); - - assert_eq!(0f64.frexp(), (0f64, 0)); - assert_eq!((-0f64).frexp(), (-0f64, 0)); - } - - #[test] #[cfg_attr(windows, ignore)] // FIXME #8755 - #[allow(deprecated)] - fn test_frexp_nowin() { - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - let nan: f64 = NAN; - assert_eq!(match inf.frexp() { (x, _) => x }, inf); - assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf); - assert!(match nan.frexp() { (x, _) => x.is_nan() }) - } - - #[test] fn test_asinh() { assert_eq!(0.0f64.asinh(), 0.0f64); assert_eq!((-0.0f64).asinh(), -0.0f64); @@ -1753,4 +1638,16 @@ mod tests { assert_approx_eq!(ln_2, 2f64.ln()); assert_approx_eq!(ln_10, 10f64.ln()); } + + #[test] + fn test_float_bits_conv() { + assert_eq!((1f64).to_bits(), 0x3ff0000000000000); + assert_eq!((12.5f64).to_bits(), 0x4029000000000000); + assert_eq!((1337f64).to_bits(), 0x4094e40000000000); + assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000); + assert_approx_eq!(f64::from_bits(0x3ff0000000000000), 1.0); + assert_approx_eq!(f64::from_bits(0x4029000000000000), 12.5); + assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0); + assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25); + } } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index bfb0aa6e1a1..1167c39dba8 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -23,19 +23,19 @@ use ptr; use slice; use str::{self, Utf8Error}; -/// A type representing an owned C-compatible string +/// A type representing an owned C-compatible string. /// /// This type serves the primary purpose of being able to safely generate a /// C-compatible string from a Rust byte slice or vector. An instance of this /// type is a static guarantee that the underlying bytes contain no interior 0 /// bytes and the final byte is 0. /// -/// A `CString` is created from either a byte slice or a byte vector. After -/// being created, a `CString` predominately inherits all of its methods from -/// the `Deref` implementation to `[c_char]`. Note that the underlying array -/// is represented as an array of `c_char` as opposed to `u8`. A `u8` slice -/// can be obtained with the `as_bytes` method. Slices produced from a `CString` -/// do *not* contain the trailing nul terminator unless otherwise specified. +/// A `CString` is created from either a byte slice or a byte vector. A [`u8`] +/// slice can be obtained with the `as_bytes` method. Slices produced from a +/// `CString` do *not* contain the trailing nul terminator unless otherwise +/// specified. +/// +/// [`u8`]: ../primitive.u8.html /// /// # Examples /// @@ -83,12 +83,14 @@ pub struct CString { /// /// Note that this structure is **not** `repr(C)` and is not recommended to be /// placed in the signatures of FFI functions. Instead safe wrappers of FFI -/// functions may leverage the unsafe `from_ptr` constructor to provide a safe +/// functions may leverage the unsafe [`from_ptr`] constructor to provide a safe /// interface to other consumers. /// +/// [`from_ptr`]: #method.from_ptr +/// /// # Examples /// -/// Inspecting a foreign C string +/// Inspecting a foreign C string: /// /// ```no_run /// use std::ffi::CStr; @@ -102,7 +104,7 @@ pub struct CString { /// } /// ``` /// -/// Passing a Rust-originating C string +/// Passing a Rust-originating C string: /// /// ```no_run /// use std::ffi::{CString, CStr}; @@ -118,7 +120,9 @@ pub struct CString { /// work(&s); /// ``` /// -/// Converting a foreign C string into a Rust `String` +/// Converting a foreign C string into a Rust [`String`]: +/// +/// [`String`]: ../string/struct.String.html /// /// ```no_run /// use std::ffi::CStr; @@ -144,14 +148,18 @@ pub struct CStr { inner: [c_char] } -/// An error returned from `CString::new` to indicate that a nul byte was found +/// An error returned from [`CString::new`] to indicate that a nul byte was found /// in the vector provided. +/// +/// [`CString::new`]: struct.CString.html#method.new #[derive(Clone, PartialEq, Eq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct NulError(usize, Vec<u8>); -/// An error returned from `CStr::from_bytes_with_nul` to indicate that a nul +/// An error returned from [`CStr::from_bytes_with_nul`] to indicate that a nul /// byte was found too early in the slice provided or one wasn't found at all. +/// +/// [`CStr::from_bytes_with_nul`]: struct.CStr.html#method.from_bytes_with_nul #[derive(Clone, PartialEq, Eq, Debug)] #[stable(feature = "cstr_from_bytes", since = "1.10.0")] pub struct FromBytesWithNulError { @@ -177,8 +185,10 @@ impl FromBytesWithNulError { } } -/// An error returned from `CString::into_string` to indicate that a UTF-8 error +/// An error returned from [`CString::into_string`] to indicate that a UTF-8 error /// was encountered during the conversion. +/// +/// [`CString::into_string`]: struct.CString.html#method.into_string #[derive(Clone, PartialEq, Eq, Debug)] #[stable(feature = "cstring_into", since = "1.7.0")] pub struct IntoStringError { @@ -226,10 +236,12 @@ impl CString { /// Creates a C-compatible string from a byte vector without checking for /// interior 0 bytes. /// - /// This method is equivalent to `new` except that no runtime assertion + /// This method is equivalent to [`new`] except that no runtime assertion /// is made that `v` contains no 0 bytes, and it requires an actual /// byte vector, not anything that can be converted to one with Into. /// + /// [`new`]: #method.new + /// /// # Examples /// /// ``` @@ -254,9 +266,11 @@ impl CString { /// # Safety /// /// This should only ever be called with a pointer that was earlier - /// obtained by calling `into_raw` on a `CString`. Other usage (e.g. trying to take + /// obtained by calling [`into_raw`] on a `CString`. Other usage (e.g. trying to take /// ownership of a string that was allocated by foreign code) is likely to lead /// to undefined behavior or allocator corruption. + /// + /// [`into_raw`]: #method.into_raw #[stable(feature = "cstr_memory", since = "1.4.0")] pub unsafe fn from_raw(ptr: *mut c_char) -> CString { let len = libc::strlen(ptr) + 1; // Including the NUL byte @@ -267,19 +281,23 @@ impl CString { /// Transfers ownership of the string to a C caller. /// /// The pointer must be returned to Rust and reconstituted using - /// `from_raw` to be properly deallocated. Specifically, one + /// [`from_raw`] to be properly deallocated. Specifically, one /// should *not* use the standard C `free` function to deallocate /// this string. /// - /// Failure to call `from_raw` will lead to a memory leak. + /// Failure to call [`from_raw`] will lead to a memory leak. + /// + /// [`from_raw`]: #method.from_raw #[stable(feature = "cstr_memory", since = "1.4.0")] pub fn into_raw(self) -> *mut c_char { Box::into_raw(self.into_inner()) as *mut c_char } - /// Converts the `CString` into a `String` if it contains valid Unicode data. + /// Converts the `CString` into a [`String`] if it contains valid Unicode data. /// /// On failure, ownership of the original `CString` is returned. + /// + /// [`String`]: ../string/struct.String.html #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_string(self) -> Result<String, IntoStringError> { String::from_utf8(self.into_bytes()) @@ -301,8 +319,10 @@ impl CString { vec } - /// Equivalent to the `into_bytes` function except that the returned vector + /// Equivalent to the [`into_bytes`] function except that the returned vector /// includes the trailing nul byte. + /// + /// [`into_bytes`]: #method.into_bytes #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_bytes_with_nul(self) -> Vec<u8> { self.into_inner().into_vec() @@ -317,20 +337,34 @@ impl CString { &self.inner[..self.inner.len() - 1] } - /// Equivalent to the `as_bytes` function except that the returned slice + /// Equivalent to the [`as_bytes`] function except that the returned slice /// includes the trailing nul byte. + /// + /// [`as_bytes`]: #method.as_bytes #[stable(feature = "rust1", since = "1.0.0")] pub fn as_bytes_with_nul(&self) -> &[u8] { &self.inner } - /// Converts this `CString` into a boxed `CStr`. - #[unstable(feature = "into_boxed_c_str", issue = "0")] + /// Extracts a [`CStr`] slice containing the entire string. + /// + /// [`CStr`]: struct.CStr.html + #[unstable(feature = "as_c_str", issue = "40380")] + pub fn as_c_str(&self) -> &CStr { + &*self + } + + /// Converts this `CString` into a boxed [`CStr`]. + /// + /// [`CStr`]: struct.CStr.html + #[unstable(feature = "into_boxed_c_str", issue = "40380")] pub fn into_boxed_c_str(self) -> Box<CStr> { unsafe { mem::transmute(self.into_inner()) } } - // Bypass "move out of struct which implements `Drop` trait" restriction. + // Bypass "move out of struct which implements [`Drop`] trait" restriction. + /// + /// [`Drop`]: ../ops/trait.Drop.html fn into_inner(self) -> Box<[u8]> { unsafe { let result = ptr::read(&self.inner); @@ -356,7 +390,7 @@ impl ops::Deref for CString { type Target = CStr; fn deref(&self) -> &CStr { - unsafe { mem::transmute(self.as_bytes_with_nul()) } + unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) } } } @@ -415,6 +449,20 @@ impl<'a> From<&'a CStr> for Box<CStr> { } } +#[stable(feature = "c_string_from_box", since = "1.18.0")] +impl From<Box<CStr>> for CString { + fn from(s: Box<CStr>) -> CString { + s.into_c_string() + } +} + +#[stable(feature = "box_from_c_string", since = "1.18.0")] +impl Into<Box<CStr>> for CString { + fn into(self) -> Box<CStr> { + self.into_boxed_c_str() + } +} + #[stable(feature = "default_box_extra", since = "1.17.0")] impl Default for Box<CStr> { fn default() -> Box<CStr> { @@ -425,7 +473,9 @@ impl Default for Box<CStr> { impl NulError { /// Returns the position of the nul byte in the slice that was provided to - /// `CString::new`. + /// [`CString::new`]. + /// + /// [`CString::new`]: struct.CString.html#method.new /// /// # Examples /// @@ -500,8 +550,10 @@ impl fmt::Display for FromBytesWithNulError { } impl IntoStringError { - /// Consumes this error, returning original `CString` which generated the + /// Consumes this error, returning original [`CString`] which generated the /// error. + /// + /// [`CString`]: struct.CString.html #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_cstring(self) -> CString { self.inner @@ -539,9 +591,9 @@ impl CStr { /// allows inspection and interoperation of non-owned C strings. This method /// is unsafe for a number of reasons: /// - /// * There is no guarantee to the validity of `ptr` + /// * There is no guarantee to the validity of `ptr`. /// * The returned lifetime is not guaranteed to be the actual lifetime of - /// `ptr` + /// `ptr`. /// * There is no guarantee that the memory pointed to by `ptr` contains a /// valid nul terminator byte at the end of the string. /// @@ -569,7 +621,8 @@ impl CStr { #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr { let len = libc::strlen(ptr); - mem::transmute(slice::from_raw_parts(ptr, len as usize + 1)) + let ptr = ptr as *const u8; + CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1)) } /// Creates a C string wrapper from a byte slice. @@ -684,26 +737,30 @@ impl CStr { /// Converts this C string to a byte slice containing the trailing 0 byte. /// - /// This function is the equivalent of `to_bytes` except that it will retain + /// This function is the equivalent of [`to_bytes`] except that it will retain /// the trailing nul instead of chopping it off. /// /// > **Note**: This method is currently implemented as a 0-cost cast, but /// > it is planned to alter its definition in the future to perform the /// > length calculation whenever this method is called. + /// + /// [`to_bytes`]: #method.to_bytes #[stable(feature = "rust1", since = "1.0.0")] pub fn to_bytes_with_nul(&self) -> &[u8] { unsafe { mem::transmute(&self.inner) } } - /// Yields a `&str` slice if the `CStr` contains valid UTF-8. + /// Yields a [`&str`] slice if the `CStr` contains valid UTF-8. /// /// This function will calculate the length of this string and check for - /// UTF-8 validity, and then return the `&str` if it's valid. + /// UTF-8 validity, and then return the [`&str`] if it's valid. /// /// > **Note**: This method is currently implemented to check for validity /// > after a 0-cost cast, but it is planned to alter its definition in the /// > future to perform the length calculation in addition to the UTF-8 /// > check whenever this method is called. + /// + /// [`&str`]: ../primitive.str.html #[stable(feature = "cstr_to_str", since = "1.4.0")] pub fn to_str(&self) -> Result<&str, str::Utf8Error> { // NB: When CStr is changed to perform the length check in .to_bytes() @@ -713,21 +770,33 @@ impl CStr { str::from_utf8(self.to_bytes()) } - /// Converts a `CStr` into a `Cow<str>`. + /// Converts a `CStr` into a [`Cow`]`<`[`str`]`>`. /// /// This function will calculate the length of this string (which normally /// requires a linear amount of work to be done) and then return the - /// resulting slice as a `Cow<str>`, replacing any invalid UTF-8 sequences + /// resulting slice as a [`Cow`]`<`[`str`]`>`, replacing any invalid UTF-8 sequences /// with `U+FFFD REPLACEMENT CHARACTER`. /// /// > **Note**: This method is currently implemented to check for validity /// > after a 0-cost cast, but it is planned to alter its definition in the /// > future to perform the length calculation in addition to the UTF-8 /// > check whenever this method is called. + /// + /// [`Cow`]: ../borrow/enum.Cow.html + /// [`str`]: ../primitive.str.html #[stable(feature = "cstr_to_str", since = "1.4.0")] pub fn to_string_lossy(&self) -> Cow<str> { String::from_utf8_lossy(self.to_bytes()) } + + /// Converts a [`Box`]`<CStr>` into a [`CString`] without copying or allocating. + /// + /// [`Box`]: ../boxed/struct.Box.html + /// [`CString`]: struct.CString.html + #[unstable(feature = "into_boxed_c_str", issue = "40380")] + pub fn into_c_string(self: Box<CStr>) -> CString { + unsafe { mem::transmute(self) } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -922,12 +991,11 @@ mod tests { fn into_boxed() { let orig: &[u8] = b"Hello, world!\0"; let cstr = CStr::from_bytes_with_nul(orig).unwrap(); - let cstring = cstr.to_owned(); - let box1: Box<CStr> = Box::from(cstr); - let box2 = cstring.into_boxed_c_str(); - assert_eq!(cstr, &*box1); - assert_eq!(box1, box2); - assert_eq!(&*box2, cstr); + let boxed: Box<CStr> = Box::from(cstr); + let cstring = cstr.to_owned().into_boxed_c_str().into_c_string(); + assert_eq!(cstr, &*boxed); + assert_eq!(&*boxed, &*cstring); + assert_eq!(&*cstring, cstr); } #[test] diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 41bdd9c51d4..a5a1b5e5f09 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -188,6 +188,16 @@ impl OsString { /// in the given `OsString`. /// /// The collection may reserve more space to avoid frequent reallocations. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// + /// let mut s = OsString::new(); + /// s.reserve(10); + /// assert!(s.capacity() >= 10); + /// ``` #[stable(feature = "osstring_simple_functions", since = "1.9.0")] pub fn reserve(&mut self, additional: usize) { self.inner.reserve(additional) @@ -200,19 +210,59 @@ impl OsString { /// Note that the allocator may give the collection more space than it /// requests. Therefore capacity can not be relied upon to be precisely /// minimal. Prefer reserve if future insertions are expected. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// + /// let mut s = OsString::new(); + /// s.reserve_exact(10); + /// assert!(s.capacity() >= 10); + /// ``` #[stable(feature = "osstring_simple_functions", since = "1.9.0")] pub fn reserve_exact(&mut self, additional: usize) { self.inner.reserve_exact(additional) } /// Shrinks the capacity of the `OsString` to match its length. + /// + /// # Examples + /// + /// ``` + /// #![feature(osstring_shrink_to_fit)] + /// + /// use std::ffi::OsString; + /// + /// let mut s = OsString::from("foo"); + /// + /// s.reserve(100); + /// assert!(s.capacity() >= 100); + /// + /// s.shrink_to_fit(); + /// assert_eq!(3, s.capacity()); + /// ``` #[unstable(feature = "osstring_shrink_to_fit", issue = "40421")] pub fn shrink_to_fit(&mut self) { self.inner.shrink_to_fit() } - /// Converts this `OsString` into a boxed `OsStr`. - #[unstable(feature = "into_boxed_os_str", issue = "0")] + /// Converts this `OsString` into a boxed [`OsStr`]. + /// + /// [`OsStr`]: struct.OsStr.html + /// + /// # Examples + /// + /// ``` + /// #![feature(into_boxed_os_str)] + /// + /// use std::ffi::{OsString, OsStr}; + /// + /// let s = OsString::from("hello"); + /// + /// let b: Box<OsStr> = s.into_boxed_os_str(); + /// ``` + #[unstable(feature = "into_boxed_os_str", issue = "40380")] pub fn into_boxed_os_str(self) -> Box<OsStr> { unsafe { mem::transmute(self.inner.into_box()) } } @@ -398,6 +448,16 @@ impl OsStr { /// Copies the slice into an owned [`OsString`]. /// /// [`OsString`]: struct.OsString.html + /// + /// # Examples + /// + /// ``` + /// use std::ffi::{OsStr, OsString}; + /// + /// let os_str = OsStr::new("foo"); + /// let os_string = os_str.to_os_string(); + /// assert_eq!(os_string, OsString::from("foo")); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_os_string(&self) -> OsString { OsString { inner: self.inner.to_owned() } @@ -424,12 +484,13 @@ impl OsStr { /// Returns the length of this `OsStr`. /// /// Note that this does **not** return the number of bytes in this string - /// as, for example, OS strings on Windows are encoded as a list of `u16` + /// as, for example, OS strings on Windows are encoded as a list of [`u16`] /// rather than a list of bytes. This number is simply useful for passing to /// other methods like [`OsString::with_capacity`] to avoid reallocations. /// /// See `OsStr` introduction for more information about encoding. /// + /// [`u16`]: ../primitive.u16.html /// [`OsString::with_capacity`]: struct.OsString.html#method.with_capacity /// /// # Examples @@ -448,6 +509,16 @@ impl OsStr { self.inner.inner.len() } + /// Converts a [`Box`]`<OsStr>` into an [`OsString`] without copying or allocating. + /// + /// [`Box`]: ../boxed/struct.Box.html + /// [`OsString`]: struct.OsString.html + #[unstable(feature = "into_boxed_os_str", issue = "40380")] + pub fn into_os_string(self: Box<OsStr>) -> OsString { + let inner: Box<Slice> = unsafe { mem::transmute(self) }; + OsString { inner: Buf::from_box(inner) } + } + /// Gets the underlying byte representation. /// /// Note: it is *crucial* that this API is private, to avoid @@ -464,6 +535,20 @@ impl<'a> From<&'a OsStr> for Box<OsStr> { } } +#[stable(feature = "os_string_from_box", since = "1.18.0")] +impl From<Box<OsStr>> for OsString { + fn from(boxed: Box<OsStr>) -> OsString { + boxed.into_os_string() + } +} + +#[stable(feature = "box_from_os_string", since = "1.18.0")] +impl Into<Box<OsStr>> for OsString { + fn into(self) -> Box<OsStr> { + self.into_boxed_os_str() + } +} + #[stable(feature = "box_default_extra", since = "1.17.0")] impl Default for Box<OsStr> { fn default() -> Box<OsStr> { @@ -598,7 +683,13 @@ impl Borrow<OsStr> for OsString { #[stable(feature = "rust1", since = "1.0.0")] impl ToOwned for OsStr { type Owned = OsString; - fn to_owned(&self) -> OsString { self.to_os_string() } + fn to_owned(&self) -> OsString { + self.to_os_string() + } + fn clone_into(&self, target: &mut OsString) { + target.clear(); + target.push(self); + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -772,12 +863,11 @@ mod tests { fn into_boxed() { let orig = "Hello, world!"; let os_str = OsStr::new(orig); - let os_string = os_str.to_owned(); - let box1: Box<OsStr> = Box::from(os_str); - let box2 = os_string.into_boxed_os_str(); - assert_eq!(os_str, &*box1); - assert_eq!(box1, box2); - assert_eq!(&*box2, os_str); + let boxed: Box<OsStr> = Box::from(os_str); + let os_string = os_str.to_owned().into_boxed_os_str().into_os_string(); + assert_eq!(os_str, &*boxed); + assert_eq!(&*boxed, &*os_string); + assert_eq!(&*os_string, os_str); } #[test] @@ -785,4 +875,14 @@ mod tests { let boxed = <Box<OsStr>>::default(); assert!(boxed.is_empty()); } + + #[test] + fn test_os_str_clone_into() { + let mut os_string = OsString::with_capacity(123); + os_string.push("hello"); + let os_str = OsStr::new("bonjour"); + os_str.clone_into(&mut os_string); + assert_eq!(os_str, os_string); + assert!(os_string.capacity() >= 123); + } } diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index e5562d05f10..69843199348 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -142,14 +142,14 @@ pub struct DirEntry(fs_imp::DirEntry); /// [`File::open`]: struct.File.html#method.open /// [`File::create`]: struct.File.html#method.create /// -/// Generally speaking, when using `OpenOptions`, you'll first call [`new()`], -/// then chain calls to methods to set each option, then call [`open()`], +/// Generally speaking, when using `OpenOptions`, you'll first call [`new`], +/// then chain calls to methods to set each option, then call [`open`], /// passing the path of the file you're trying to open. This will give you a /// [`io::Result`][result] with a [`File`][file] inside that you can further /// operate on. /// -/// [`new()`]: struct.OpenOptions.html#method.new -/// [`open()`]: struct.OpenOptions.html#method.open +/// [`new`]: struct.OpenOptions.html#method.new +/// [`open`]: struct.OpenOptions.html#method.open /// [result]: ../io/type.Result.html /// [file]: struct.File.html /// @@ -1176,6 +1176,7 @@ impl AsInner<fs_imp::DirEntry> for DirEntry { /// This function currently corresponds to the `unlink` function on Unix /// and the `DeleteFile` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1212,6 +1213,7 @@ pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> { /// This function currently corresponds to the `stat` function on Unix /// and the `GetFileAttributesEx` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1245,6 +1247,7 @@ pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> { /// This function currently corresponds to the `lstat` function on Unix /// and the `GetFileAttributesEx` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1287,6 +1290,7 @@ pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> { /// on Windows, `from` can be anything, but `to` must *not* be a directory. /// /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1330,6 +1334,7 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> /// `O_CLOEXEC` is set for returned file descriptors. /// On Windows, this function currently corresponds to `CopyFileEx`. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1366,6 +1371,7 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> { /// This function currently corresponds to the `link` function on Unix /// and the `CreateHardLink` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1424,6 +1430,7 @@ pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<( /// and the `CreateFile` function with `FILE_FLAG_OPEN_REPARSE_POINT` and /// `FILE_FLAG_BACKUP_SEMANTICS` flags on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1457,6 +1464,7 @@ pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { /// This function currently corresponds to the `realpath` function on Unix /// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1489,6 +1497,7 @@ pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { /// This function currently corresponds to the `mkdir` function on Unix /// and the `CreateDirectory` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1522,6 +1531,7 @@ pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { /// This function currently corresponds to the `mkdir` function on Unix /// and the `CreateDirectory` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1534,6 +1544,12 @@ pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { /// error conditions for when a directory is being created (after it is /// determined to not exist) are outlined by `fs::create_dir`. /// +/// Notable exception is made for situations where any of the directories +/// specified in the `path` could not be created as it was being created concurrently. +/// Such cases are considered success. In other words: calling `create_dir_all` +/// concurrently from multiple threads or processes is guaranteed to not fail +/// due to race itself. +/// /// # Examples /// /// ``` @@ -1556,6 +1572,7 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> { /// This function currently corresponds to the `rmdir` function on Unix /// and the `RemoveDirectory` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1593,6 +1610,7 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { /// and the `FindFirstFile`, `GetFileAttributesEx`, `DeleteFile`, and `RemoveDirectory` functions /// on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1627,6 +1645,7 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> { /// This function currently corresponds to the `opendir` function on Unix /// and the `FindFirstFile` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1673,6 +1692,7 @@ pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> { /// This function currently corresponds to the `chmod` function on Unix /// and the `SetFileAttributes` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1720,9 +1740,9 @@ impl DirBuilder { } } - /// Indicate that directories create should be created recursively, creating - /// all parent directories if they do not exist with the same security and - /// permissions settings. + /// Indicates that directories should be created recursively, creating all + /// parent directories. Parents that do not exist are created with the same + /// security and permissions settings. /// /// This option defaults to `false`. /// @@ -1743,6 +1763,9 @@ impl DirBuilder { /// Create the specified directory with the options configured in this /// builder. /// + /// It is considered an error if the directory already exists unless + /// recursive mode is enabled. + /// /// # Examples /// /// ```no_run @@ -1769,11 +1792,25 @@ impl DirBuilder { } fn create_dir_all(&self, path: &Path) -> io::Result<()> { - if path == Path::new("") || path.is_dir() { return Ok(()) } - if let Some(p) = path.parent() { - self.create_dir_all(p)? + if path == Path::new("") { + return Ok(()) + } + + match self.inner.mkdir(path) { + Ok(()) => return Ok(()), + Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} + Err(_) if path.is_dir() => return Ok(()), + Err(e) => return Err(e), + } + match path.parent() { + Some(p) => try!(self.create_dir_all(p)), + None => return Err(io::Error::new(io::ErrorKind::Other, "failed to create whole tree")), + } + match self.inner.mkdir(path) { + Ok(()) => Ok(()), + Err(_) if path.is_dir() => Ok(()), + Err(e) => Err(e), } - self.inner.mkdir(path) } } @@ -1793,6 +1830,7 @@ mod tests { use rand::{StdRng, Rng}; use str; use sys_common::io::test::{TempDir, tmpdir}; + use thread; #[cfg(windows)] use os::windows::fs::{symlink_dir, symlink_file}; @@ -2261,11 +2299,42 @@ mod tests { } #[test] + fn concurrent_recursive_mkdir() { + for _ in 0..100 { + let dir = tmpdir(); + let mut dir = dir.join("a"); + for _ in 0..40 { + dir = dir.join("a"); + } + let mut join = vec!(); + for _ in 0..8 { + let dir = dir.clone(); + join.push(thread::spawn(move || { + check!(fs::create_dir_all(&dir)); + })) + } + + // No `Display` on result of `join()` + join.drain(..).map(|join| join.join().unwrap()).count(); + } + } + + #[test] fn recursive_mkdir_slash() { check!(fs::create_dir_all(&Path::new("/"))); } #[test] + fn recursive_mkdir_dot() { + check!(fs::create_dir_all(&Path::new("."))); + } + + #[test] + fn recursive_mkdir_empty() { + check!(fs::create_dir_all(&Path::new(""))); + } + + #[test] fn recursive_rmdir() { let tmpdir = tmpdir(); let d1 = tmpdir.join("d1"); @@ -2343,7 +2412,7 @@ mod tests { let tmpdir = tmpdir(); let unicode = tmpdir.path(); - let unicode = unicode.join(&format!("test-각丁ー再见")); + let unicode = unicode.join("test-각丁ー再见"); check!(fs::create_dir(&unicode)); assert!(unicode.exists()); assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists()); diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index f98a3a87b01..3b82412716e 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -21,12 +21,12 @@ use memchr; /// The `BufReader` struct adds buffering to any reader. /// /// It can be excessively inefficient to work directly with a [`Read`] instance. -/// For example, every call to [`read`] on [`TcpStream`] results in a system call. -/// A `BufReader` performs large, infrequent reads on the underlying [`Read`] -/// and maintains an in-memory buffer of the results. +/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`] +/// results in a system call. A `BufReader` performs large, infrequent reads on +/// the underlying [`Read`] and maintains an in-memory buffer of the results. /// /// [`Read`]: ../../std/io/trait.Read.html -/// [`read`]: ../../std/net/struct.TcpStream.html#method.read +/// [`TcpStream::read`]: ../../std/net/struct.TcpStream.html#method.read /// [`TcpStream`]: ../../std/net/struct.TcpStream.html /// /// # Examples @@ -261,9 +261,10 @@ impl<R: Seek> Seek for BufReader<R> { /// Wraps a writer and buffers its output. /// /// It can be excessively inefficient to work directly with something that -/// implements [`Write`]. For example, every call to [`write`] on [`TcpStream`] -/// results in a system call. A `BufWriter` keeps an in-memory buffer of data -/// and writes it to an underlying writer in large, infrequent batches. +/// implements [`Write`]. For example, every call to +/// [`write`][`Tcpstream::write`] on [`TcpStream`] results in a system call. A +/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying +/// writer in large, infrequent batches. /// /// The buffer will be written out when the writer is dropped. /// @@ -303,7 +304,7 @@ impl<R: Seek> Seek for BufReader<R> { /// the `stream` is dropped. /// /// [`Write`]: ../../std/io/trait.Write.html -/// [`write`]: ../../std/net/struct.TcpStream.html#method.write +/// [`Tcpstream::write`]: ../../std/net/struct.TcpStream.html#method.write /// [`TcpStream`]: ../../std/net/struct.TcpStream.html #[stable(feature = "rust1", since = "1.0.0")] pub struct BufWriter<W: Write> { diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 60767ea4786..53347eb14db 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -89,6 +89,10 @@ pub struct Cursor<T> { impl<T> Cursor<T> { /// Creates a new cursor wrapping the provided underlying I/O object. /// + /// Cursor initial position is `0` even if underlying object (e. + /// g. `Vec`) is not empty. So writing to cursor starts with + /// overwriting `Vec` content, not with appending to it. + /// /// # Examples /// /// ``` diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index 6d4da2e6a88..fb67eaf3c63 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -140,13 +140,13 @@ pub enum ErrorKind { #[stable(feature = "rust1", since = "1.0.0")] TimedOut, /// An error returned when an operation could not be completed because a - /// call to [`write()`] returned [`Ok(0)`]. + /// call to [`write`] returned [`Ok(0)`]. /// /// This typically means that an operation could only succeed if it wrote a /// particular number of bytes but only a smaller number of bytes could be /// written. /// - /// [`write()`]: ../../std/io/trait.Write.html#tymethod.write + /// [`write`]: ../../std/io/trait.Write.html#tymethod.write /// [`Ok(0)`]: ../../std/io/type.Result.html #[stable(feature = "rust1", since = "1.0.0")] WriteZero, diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 58788cdcd4c..c872a8e5261 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -21,7 +21,8 @@ //! of other types, and you can implement them for your types too. As such, //! you'll see a few different types of I/O throughout the documentation in //! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec<T>`]s. For -//! example, [`Read`] adds a [`read()`] method, which we can use on `File`s: +//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on +//! `File`s: //! //! ``` //! use std::io; @@ -106,7 +107,7 @@ //! ``` //! //! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call -//! to [`write()`]: +//! to [`write`][`Write::write`]: //! //! ``` //! use std::io; @@ -145,6 +146,18 @@ //! # } //! ``` //! +//! Note that you cannot use the `?` operator in functions that do not return +//! a `Result<T, E>` (e.g. `main`). Instead, you can call `.unwrap()` or `match` +//! on the return value to catch any possible errors: +//! +//! ``` +//! use std::io; +//! +//! let mut input = String::new(); +//! +//! io::stdin().read_line(&mut input).unwrap(); +//! ``` +//! //! And a very common source of output is standard output: //! //! ``` @@ -157,7 +170,7 @@ //! # } //! ``` //! -//! Of course, using [`io::stdout()`] directly is less common than something like +//! Of course, using [`io::stdout`] directly is less common than something like //! [`println!`]. //! //! ## Iterator types @@ -245,13 +258,13 @@ //! [`Vec<T>`]: ../vec/struct.Vec.html //! [`BufReader`]: struct.BufReader.html //! [`BufWriter`]: struct.BufWriter.html -//! [`write()`]: trait.Write.html#tymethod.write -//! [`io::stdout()`]: fn.stdout.html +//! [`Write::write`]: trait.Write.html#tymethod.write +//! [`io::stdout`]: fn.stdout.html //! [`println!`]: ../macro.println.html //! [`Lines`]: struct.Lines.html //! [`io::Result`]: type.Result.html //! [`?` operator]: ../../book/syntax-index.html -//! [`read()`]: trait.Read.html#tymethod.read +//! [`Read::read`]: trait.Read.html#tymethod.read #![stable(feature = "rust1", since = "1.0.0")] @@ -274,9 +287,11 @@ pub use self::error::{Result, Error, ErrorKind}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::util::{copy, sink, Sink, empty, Empty, repeat, Repeat}; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::stdio::{stdin, stdout, stderr, _print, Stdin, Stdout, Stderr}; +pub use self::stdio::{stdin, stdout, stderr, Stdin, Stdout, Stderr}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::stdio::{StdoutLock, StderrLock, StdinLock}; +#[unstable(feature = "print_internals", issue = "0")] +pub use self::stdio::{_print, _eprint}; #[unstable(feature = "libstd_io_internals", issue = "0")] #[doc(no_inline, hidden)] pub use self::stdio::{set_panic, set_print}; @@ -453,6 +468,9 @@ pub trait Read { /// variant will be returned. If an error is returned then it must be /// guaranteed that no bytes were read. /// + /// An error of the `ErrorKind::Interrupted` kind is non-fatal and the read + /// operation should be retried if there is nothing else to do. + /// /// # Examples /// /// [`File`][file]s implement `Read`: @@ -468,7 +486,7 @@ pub trait Read { /// let mut f = File::open("foo.txt")?; /// let mut buffer = [0; 10]; /// - /// // read 10 bytes + /// // read up to 10 bytes /// f.read(&mut buffer[..])?; /// # Ok(()) /// # } @@ -530,7 +548,7 @@ pub trait Read { /// If the data in this stream is *not* valid UTF-8 then an error is /// returned and `buf` is unchanged. /// - /// See [`read_to_end()`][readtoend] for other error semantics. + /// See [`read_to_end`][readtoend] for other error semantics. /// /// [readtoend]: #method.read_to_end /// @@ -815,12 +833,12 @@ pub trait Read { /// /// Implementors of the `Write` trait are sometimes called 'writers'. /// -/// Writers are defined by two required methods, [`write()`] and [`flush()`]: +/// Writers are defined by two required methods, [`write`] and [`flush`]: /// -/// * The [`write()`] method will attempt to write some data into the object, +/// * The [`write`] method will attempt to write some data into the object, /// returning how many bytes were successfully written. /// -/// * The [`flush()`] method is useful for adaptors and explicit buffers +/// * The [`flush`] method is useful for adaptors and explicit buffers /// themselves for ensuring that all buffered data has been pushed out to the /// 'true sink'. /// @@ -828,8 +846,8 @@ pub trait Read { /// throughout [`std::io`] take and provide types which implement the `Write` /// trait. /// -/// [`write()`]: #tymethod.write -/// [`flush()`]: #tymethod.flush +/// [`write`]: #tymethod.write +/// [`flush`]: #tymethod.flush /// [`std::io`]: index.html /// /// # Examples @@ -872,6 +890,9 @@ pub trait Write { /// It is **not** considered an error if the entire buffer could not be /// written to this writer. /// + /// An error of the `ErrorKind::Interrupted` kind is non-fatal and the + /// write operation should be retried if there is nothing else to do. + /// /// # Examples /// /// ``` @@ -881,6 +902,7 @@ pub trait Write { /// # fn foo() -> std::io::Result<()> { /// let mut buffer = File::create("foo.txt")?; /// + /// // Writes some prefix of the byte string, not necessarily all of it. /// buffer.write(b"some bytes")?; /// # Ok(()) /// # } @@ -916,14 +938,17 @@ pub trait Write { /// Attempts to write an entire buffer into this write. /// - /// This method will continuously call `write` while there is more data to - /// write. This method will not return until the entire buffer has been - /// successfully written or an error occurs. The first error generated from - /// this method will be returned. + /// This method will continuously call `write` until there is no more data + /// to be written or an error of non-`ErrorKind::Interrupted` kind is + /// returned. This method will not return until the entire buffer has been + /// successfully written or such an error occurs. The first error that is + /// not of `ErrorKind::Interrupted` kind generated from this method will be + /// returned. /// /// # Errors /// - /// This function will return the first error that `write` returns. + /// This function will return the first error of + /// non-`ErrorKind::Interrupted` kind that `write` returns. /// /// # Examples /// @@ -1159,7 +1184,7 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>) /// /// For example, reading line-by-line is inefficient without using a buffer, so /// if you want to read by line, you'll need `BufRead`, which includes a -/// [`read_line()`] method as well as a [`lines()`] iterator. +/// [`read_line`] method as well as a [`lines`] iterator. /// /// # Examples /// @@ -1183,8 +1208,8 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>) /// /// [`BufReader`]: struct.BufReader.html /// [`File`]: ../fs/struct.File.html -/// [`read_line()`]: #method.read_line -/// [`lines()`]: #method.lines +/// [`read_line`]: #method.read_line +/// [`lines`]: #method.lines /// [`Read`]: trait.Read.html /// /// ``` @@ -1209,13 +1234,13 @@ pub trait BufRead: Read { /// Fills the internal buffer of this object, returning the buffer contents. /// /// This function is a lower-level call. It needs to be paired with the - /// [`consume()`] method to function properly. When calling this + /// [`consume`] method to function properly. When calling this /// method, none of the contents will be "read" in the sense that later - /// calling `read` may return the same contents. As such, [`consume()`] must + /// calling `read` may return the same contents. As such, [`consume`] must /// be called with the number of bytes that are consumed from this buffer to /// ensure that the bytes are never returned twice. /// - /// [`consume()`]: #tymethod.consume + /// [`consume`]: #tymethod.consume /// /// An empty buffer returned indicates that the stream has reached EOF. /// @@ -1256,21 +1281,21 @@ pub trait BufRead: Read { /// so they should no longer be returned in calls to `read`. /// /// This function is a lower-level call. It needs to be paired with the - /// [`fill_buf()`] method to function properly. This function does + /// [`fill_buf`] method to function properly. This function does /// not perform any I/O, it simply informs this object that some amount of - /// its buffer, returned from [`fill_buf()`], has been consumed and should + /// its buffer, returned from [`fill_buf`], has been consumed and should /// no longer be returned. As such, this function may do odd things if - /// [`fill_buf()`] isn't called before calling it. + /// [`fill_buf`] isn't called before calling it. /// /// The `amt` must be `<=` the number of bytes in the buffer returned by - /// [`fill_buf()`]. + /// [`fill_buf`]. /// /// # Examples /// - /// Since `consume()` is meant to be used with [`fill_buf()`], + /// Since `consume()` is meant to be used with [`fill_buf`], /// that method's example includes an example of `consume()`. /// - /// [`fill_buf()`]: #tymethod.fill_buf + /// [`fill_buf`]: #tymethod.fill_buf #[stable(feature = "rust1", since = "1.0.0")] fn consume(&mut self, amt: usize); @@ -1285,33 +1310,47 @@ pub trait BufRead: Read { /// # Errors /// /// This function will ignore all instances of [`ErrorKind::Interrupted`] and - /// will otherwise return any errors returned by [`fill_buf()`]. + /// will otherwise return any errors returned by [`fill_buf`]. /// /// If an I/O error is encountered then all bytes read so far will be /// present in `buf` and its length will have been adjusted appropriately. /// - /// # Examples - /// - /// A locked standard input implements `BufRead`. In this example, we'll - /// read from standard input until we see an `a` byte. - /// - /// [`fill_buf()`]: #tymethod.fill_buf + /// [`fill_buf`]: #tymethod.fill_buf /// [`ErrorKind::Interrupted`]: enum.ErrorKind.html#variant.Interrupted /// - /// ``` - /// use std::io; - /// use std::io::prelude::*; + /// # Examples /// - /// fn foo() -> io::Result<()> { - /// let stdin = io::stdin(); - /// let mut stdin = stdin.lock(); - /// let mut buffer = Vec::new(); + /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In + /// this example, we use [`Cursor`] to read all the bytes in a byte slice + /// in hyphen delimited segments: /// - /// stdin.read_until(b'a', &mut buffer)?; + /// [`Cursor`]: struct.Cursor.html /// - /// println!("{:?}", buffer); - /// # Ok(()) - /// # } + /// ``` + /// use std::io::{self, BufRead}; + /// + /// let mut cursor = io::Cursor::new(b"lorem-ipsum"); + /// let mut buf = vec![]; + /// + /// // cursor is at 'l' + /// let num_bytes = cursor.read_until(b'-', &mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 6); + /// assert_eq!(buf, b"lorem-"); + /// buf.clear(); + /// + /// // cursor is at 'i' + /// let num_bytes = cursor.read_until(b'-', &mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 5); + /// assert_eq!(buf, b"ipsum"); + /// buf.clear(); + /// + /// // cursor is at EOF + /// let num_bytes = cursor.read_until(b'-', &mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 0); + /// assert_eq!(buf, b""); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<usize> { @@ -1330,35 +1369,43 @@ pub trait BufRead: Read { /// /// # Errors /// - /// This function has the same error semantics as [`read_until()`] and will + /// This function has the same error semantics as [`read_until`] and will /// also return an error if the read bytes are not valid UTF-8. If an I/O /// error is encountered then `buf` may contain some bytes already read in /// the event that all data read so far was valid UTF-8. /// /// # Examples /// - /// A locked standard input implements `BufRead`. In this example, we'll - /// read all of the lines from standard input. If we were to do this in - /// an actual project, the [`lines()`] method would be easier, of - /// course. + /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In + /// this example, we use [`Cursor`] to read all the lines in a byte slice: /// - /// [`lines()`]: #method.lines - /// [`read_until()`]: #method.read_until + /// [`Cursor`]: struct.Cursor.html /// /// ``` - /// use std::io; - /// use std::io::prelude::*; - /// - /// let stdin = io::stdin(); - /// let mut stdin = stdin.lock(); - /// let mut buffer = String::new(); - /// - /// while stdin.read_line(&mut buffer).unwrap() > 0 { - /// // work with buffer - /// println!("{:?}", buffer); - /// - /// buffer.clear(); - /// } + /// use std::io::{self, BufRead}; + /// + /// let mut cursor = io::Cursor::new(b"foo\nbar"); + /// let mut buf = String::new(); + /// + /// // cursor is at 'f' + /// let num_bytes = cursor.read_line(&mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 4); + /// assert_eq!(buf, "foo\n"); + /// buf.clear(); + /// + /// // cursor is at 'b' + /// let num_bytes = cursor.read_line(&mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 3); + /// assert_eq!(buf, "bar"); + /// buf.clear(); + /// + /// // cursor is at EOF + /// let num_bytes = cursor.read_line(&mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 0); + /// assert_eq!(buf, ""); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn read_line(&mut self, buf: &mut String) -> Result<usize> { @@ -1375,27 +1422,31 @@ pub trait BufRead: Read { /// [`io::Result`]`<`[`Vec<u8>`]`>`. Each vector returned will *not* have /// the delimiter byte at the end. /// - /// This function will yield errors whenever [`read_until()`] would have + /// This function will yield errors whenever [`read_until`] would have /// also yielded an error. /// + /// [`io::Result`]: type.Result.html + /// [`Vec<u8>`]: ../vec/struct.Vec.html + /// [`read_until`]: #method.read_until + /// /// # Examples /// - /// A locked standard input implements `BufRead`. In this example, we'll - /// read some input from standard input, splitting on commas. + /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In + /// this example, we use [`Cursor`] to iterate over all hyphen delimited + /// segments in a byte slice /// - /// [`io::Result`]: type.Result.html - /// [`Vec<u8>`]: ../vec/struct.Vec.html - /// [`read_until()`]: #method.read_until + /// [`Cursor`]: struct.Cursor.html /// /// ``` - /// use std::io; - /// use std::io::prelude::*; + /// use std::io::{self, BufRead}; /// - /// let stdin = io::stdin(); + /// let cursor = io::Cursor::new(b"lorem-ipsum-dolor"); /// - /// for content in stdin.lock().split(b',') { - /// println!("{:?}", content.unwrap()); - /// } + /// let mut split_iter = cursor.split(b'-').map(|l| l.unwrap()); + /// assert_eq!(split_iter.next(), Some(b"lorem".to_vec())); + /// assert_eq!(split_iter.next(), Some(b"ipsum".to_vec())); + /// assert_eq!(split_iter.next(), Some(b"dolor".to_vec())); + /// assert_eq!(split_iter.next(), None); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn split(self, byte: u8) -> Split<Self> where Self: Sized { @@ -1413,24 +1464,29 @@ pub trait BufRead: Read { /// /// # Examples /// - /// A locked standard input implements `BufRead`: + /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In + /// this example, we use [`Cursor`] to iterate over all the lines in a byte + /// slice. + /// + /// [`Cursor`]: struct.Cursor.html /// /// ``` - /// use std::io; - /// use std::io::prelude::*; + /// use std::io::{self, BufRead}; /// - /// let stdin = io::stdin(); + /// let cursor = io::Cursor::new(b"lorem\nipsum\r\ndolor"); /// - /// for line in stdin.lock().lines() { - /// println!("{}", line.unwrap()); - /// } + /// let mut lines_iter = cursor.lines().map(|l| l.unwrap()); + /// assert_eq!(lines_iter.next(), Some(String::from("lorem"))); + /// assert_eq!(lines_iter.next(), Some(String::from("ipsum"))); + /// assert_eq!(lines_iter.next(), Some(String::from("dolor"))); + /// assert_eq!(lines_iter.next(), None); /// ``` /// /// # Errors /// - /// Each line of the iterator has the same error semantics as [`BufRead::read_line()`]. + /// Each line of the iterator has the same error semantics as [`BufRead::read_line`]. /// - /// [`BufRead::read_line()`]: trait.BufRead.html#method.read_line + /// [`BufRead::read_line`]: trait.BufRead.html#method.read_line #[stable(feature = "rust1", since = "1.0.0")] fn lines(self) -> Lines<Self> where Self: Sized { Lines { buf: self } @@ -1439,10 +1495,10 @@ pub trait BufRead: Read { /// Adaptor to chain together two readers. /// -/// This struct is generally created by calling [`chain()`] on a reader. -/// Please see the documentation of [`chain()`] for more details. +/// This struct is generally created by calling [`chain`] on a reader. +/// Please see the documentation of [`chain`] for more details. /// -/// [`chain()`]: trait.Read.html#method.chain +/// [`chain`]: trait.Read.html#method.chain #[stable(feature = "rust1", since = "1.0.0")] pub struct Chain<T, U> { first: T, @@ -1450,6 +1506,87 @@ pub struct Chain<T, U> { done_first: bool, } +impl<T, U> Chain<T, U> { + /// Consumes the `Chain`, returning the wrapped readers. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_io_inner_methods)] + /// + /// # use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut foo_file = File::open("foo.txt")?; + /// let mut bar_file = File::open("bar.txt")?; + /// + /// let chain = foo_file.chain(bar_file); + /// let (foo_file, bar_file) = chain.into_inner(); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "more_io_inner_methods", issue="41519")] + pub fn into_inner(self) -> (T, U) { + (self.first, self.second) + } + + /// Gets references to the underlying readers in this `Chain`. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_io_inner_methods)] + /// + /// # use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut foo_file = File::open("foo.txt")?; + /// let mut bar_file = File::open("bar.txt")?; + /// + /// let chain = foo_file.chain(bar_file); + /// let (foo_file, bar_file) = chain.get_ref(); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "more_io_inner_methods", issue="41519")] + pub fn get_ref(&self) -> (&T, &U) { + (&self.first, &self.second) + } + + /// Gets mutable references to the underlying readers in this `Chain`. + /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying readers as doing so may corrupt the internal state of this + /// `Chain`. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_io_inner_methods)] + /// + /// # use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut foo_file = File::open("foo.txt")?; + /// let mut bar_file = File::open("bar.txt")?; + /// + /// let mut chain = foo_file.chain(bar_file); + /// let (foo_file, bar_file) = chain.get_mut(); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "more_io_inner_methods", issue="41519")] + pub fn get_mut(&mut self) -> (&mut T, &mut U) { + (&mut self.first, &mut self.second) + } +} + #[stable(feature = "std_debug", since = "1.16.0")] impl<T: fmt::Debug, U: fmt::Debug> fmt::Debug for Chain<T, U> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1496,10 +1633,10 @@ impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> { /// Reader adaptor which limits the bytes read from an underlying reader. /// -/// This struct is generally created by calling [`take()`] on a reader. -/// Please see the documentation of [`take()`] for more details. +/// This struct is generally created by calling [`take`] on a reader. +/// Please see the documentation of [`take`] for more details. /// -/// [`take()`]: trait.Read.html#method.take +/// [`take`]: trait.Read.html#method.take #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Take<T> { @@ -1562,6 +1699,64 @@ impl<T> Take<T> { pub fn into_inner(self) -> T { self.inner } + + /// Gets a reference to the underlying reader. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_io_inner_methods)] + /// + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut file = File::open("foo.txt")?; + /// + /// let mut buffer = [0; 5]; + /// let mut handle = file.take(5); + /// handle.read(&mut buffer)?; + /// + /// let file = handle.get_ref(); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "more_io_inner_methods", issue="41519")] + pub fn get_ref(&self) -> &T { + &self.inner + } + + /// Gets a mutable reference to the underlying reader. + /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying reader as doing so may corrupt the internal limit of this + /// `Take`. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_io_inner_methods)] + /// + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut file = File::open("foo.txt")?; + /// + /// let mut buffer = [0; 5]; + /// let mut handle = file.take(5); + /// handle.read(&mut buffer)?; + /// + /// let file = handle.get_mut(); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "more_io_inner_methods", issue="41519")] + pub fn get_mut(&mut self) -> &mut T { + &mut self.inner + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1614,10 +1809,10 @@ fn read_one_byte(reader: &mut Read) -> Option<Result<u8>> { /// An iterator over `u8` values of a reader. /// -/// This struct is generally created by calling [`bytes()`] on a reader. -/// Please see the documentation of [`bytes()`] for more details. +/// This struct is generally created by calling [`bytes`] on a reader. +/// Please see the documentation of [`bytes`] for more details. /// -/// [`bytes()`]: trait.Read.html#method.bytes +/// [`bytes`]: trait.Read.html#method.bytes #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Bytes<R> { @@ -1635,7 +1830,7 @@ impl<R: Read> Iterator for Bytes<R> { /// An iterator over the `char`s of a reader. /// -/// This struct is generally created by calling [`chars()`][chars] on a reader. +/// This struct is generally created by calling [`chars`][chars] on a reader. /// Please see the documentation of `chars()` for more details. /// /// [chars]: trait.Read.html#method.chars @@ -1726,7 +1921,7 @@ impl fmt::Display for CharsError { /// An iterator over the contents of an instance of `BufRead` split on a /// particular byte. /// -/// This struct is generally created by calling [`split()`][split] on a +/// This struct is generally created by calling [`split`][split] on a /// `BufRead`. Please see the documentation of `split()` for more details. /// /// [split]: trait.BufRead.html#method.split @@ -1758,7 +1953,7 @@ impl<B: BufRead> Iterator for Split<B> { /// An iterator over the lines of an instance of `BufRead`. /// -/// This struct is generally created by calling [`lines()`][lines] on a +/// This struct is generally created by calling [`lines`][lines] on a /// `BufRead`. Please see the documentation of `lines()` for more details. /// /// [lines]: trait.BufRead.html#method.lines diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index e16e8019b5f..a8b0bf0071a 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -17,7 +17,7 @@ use io::{self, BufReader, LineWriter}; use sync::{Arc, Mutex, MutexGuard}; use sys::stdio; use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; -use thread::LocalKeyState; +use thread::{LocalKey, LocalKeyState}; /// Stdout used by print! and println! macros thread_local! { @@ -332,11 +332,11 @@ impl<'a> fmt::Debug for StdinLock<'a> { /// /// Each handle shares a global buffer of data to be written to the standard /// output stream. Access is also synchronized via a lock and explicit control -/// over locking is available via the [`lock()`] method. +/// over locking is available via the [`lock`] method. /// /// Created by the [`io::stdout`] method. /// -/// [`lock()`]: #method.lock +/// [`lock`]: #method.lock /// [`io::stdout`]: fn.stdout.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Stdout { @@ -659,41 +659,56 @@ pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> { }) } -#[unstable(feature = "print", - reason = "implementation detail which may disappear or be replaced at any time", - issue = "0")] -#[doc(hidden)] -pub fn _print(args: fmt::Arguments) { - // As an implementation of the `println!` macro, we want to try our best to - // not panic wherever possible and get the output somewhere. There are - // currently two possible vectors for panics we take care of here: - // - // 1. If the TLS key for the local stdout has been destroyed, accessing it - // would cause a panic. Note that we just lump in the uninitialized case - // here for convenience, we're not trying to avoid a panic. - // 2. If the local stdout is currently in use (e.g. we're in the middle of - // already printing) then accessing again would cause a panic. - // - // If, however, the actual I/O causes an error, we do indeed panic. - let result = match LOCAL_STDOUT.state() { +/// Write `args` to output stream `local_s` if possible, `global_s` +/// otherwise. `label` identifies the stream in a panic message. +/// +/// This function is used to print error messages, so it takes extra +/// care to avoid causing a panic when `local_stream` is unusable. +/// For instance, if the TLS key for the local stream is uninitialized +/// or already destroyed, or if the local stream is locked by another +/// thread, it will just fall back to the global stream. +/// +/// However, if the actual I/O causes an error, this function does panic. +fn print_to<T>(args: fmt::Arguments, + local_s: &'static LocalKey<RefCell<Option<Box<Write+Send>>>>, + global_s: fn() -> T, + label: &str) where T: Write { + let result = match local_s.state() { LocalKeyState::Uninitialized | - LocalKeyState::Destroyed => stdout().write_fmt(args), + LocalKeyState::Destroyed => global_s().write_fmt(args), LocalKeyState::Valid => { - LOCAL_STDOUT.with(|s| { + local_s.with(|s| { if let Ok(mut borrowed) = s.try_borrow_mut() { if let Some(w) = borrowed.as_mut() { return w.write_fmt(args); } } - stdout().write_fmt(args) + global_s().write_fmt(args) }) } }; if let Err(e) = result { - panic!("failed printing to stdout: {}", e); + panic!("failed printing to {}: {}", label, e); } } +#[unstable(feature = "print_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "0")] +#[doc(hidden)] +pub fn _print(args: fmt::Arguments) { + print_to(args, &LOCAL_STDOUT, stdout, "stdout"); +} + +#[unstable(feature = "print_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "0")] +#[doc(hidden)] +pub fn _eprint(args: fmt::Arguments) { + use panicking::LOCAL_STDERR; + print_to(args, &LOCAL_STDERR, stderr, "stderr"); +} + #[cfg(test)] mod tests { use thread; diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index 4163187488e..078f1ad3f6c 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -63,7 +63,7 @@ pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result< /// A reader which is always at EOF. /// -/// This struct is generally created by calling [`empty()`][empty]. Please see +/// This struct is generally created by calling [`empty`][empty]. Please see /// the documentation of `empty()` for more details. /// /// [empty]: fn.empty.html @@ -107,7 +107,7 @@ impl fmt::Debug for Empty { /// A reader which yields one byte over and over and over and over and over and... /// -/// This struct is generally created by calling [`repeat()`][repeat]. Please +/// This struct is generally created by calling [`repeat`][repeat]. Please /// see the documentation of `repeat()` for more details. /// /// [repeat]: fn.repeat.html @@ -150,7 +150,7 @@ impl fmt::Debug for Repeat { /// A writer which will move data into the void. /// -/// This struct is generally created by calling [`sink()`][sink]. Please +/// This struct is generally created by calling [`sink`][sink]. Please /// see the documentation of `sink()` for more details. /// /// [sink]: fn.sink.html diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 070690773b6..b0820d6f05a 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -21,7 +21,7 @@ //! contained an `extern crate std;` import at the [crate root]. Therefore the //! standard library can be accessed in [`use`] statements through the path //! `std`, as in [`use std::env`], or in expressions through the absolute path -//! `::std`, as in [`::std::env::args()`]. +//! `::std`, as in [`::std::env::args`]. //! //! # How to read this documentation //! @@ -94,6 +94,17 @@ //! compiler - but they are documented here the same). Like the prelude, the //! standard macros are imported by default into all crates. //! +//! # Contributing changes to the documentation +//! +//! Check out the rust contribution guidelines [here]( +//! https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md). +//! The source for this documentation can be found on [Github](https://github.com/rust-lang). +//! To contribute changes, make sure you read the guidelines first, then submit +//! pull-requests for your suggested changes. +//! +//! Contributions are appreciated! If you see a part of the docs that can be +//! improved, submit a PR, or chat with us first on irc.mozilla.org #rust-docs. +//! //! # A Tour of The Rust Standard Library //! //! The rest of this crate documentation is dedicated to pointing out notable @@ -156,7 +167,7 @@ //! [TCP]: net/struct.TcpStream.html //! [The Rust Prelude]: prelude/index.html //! [UDP]: net/struct.UdpSocket.html -//! [`::std::env::args()`]: env/fn.args.html +//! [`::std::env::args`]: env/fn.args.html //! [`Arc`]: sync/struct.Arc.html //! [owned slice]: boxed/index.html //! [`Cell`]: cell/struct.Cell.html @@ -174,7 +185,7 @@ //! [slice]: primitive.slice.html //! [`atomic`]: sync/atomic/index.html //! [`collections`]: collections/index.html -//! [`for`]: ../book/loops.html#for +//! [`for`]: ../book/first-edition/loops.html#for //! [`format!`]: macro.format.html //! [`fs`]: fs/index.html //! [`io`]: io/index.html @@ -189,14 +200,14 @@ //! [`sync`]: sync/index.html //! [`thread`]: thread/index.html //! [`use std::env`]: env/index.html -//! [`use`]: ../book/crates-and-modules.html#importing-modules-with-use -//! [crate root]: ../book/crates-and-modules.html#basic-terminology-crates-and-modules +//! [`use`]: ../book/first-edition/crates-and-modules.html#importing-modules-with-use +//! [crate root]: ../book/first-edition/crates-and-modules.html#basic-terminology-crates-and-modules //! [crates.io]: https://crates.io -//! [deref coercions]: ../book/deref-coercions.html +//! [deref coercions]: ../book/first-edition/deref-coercions.html //! [files]: fs/struct.File.html //! [multithreading]: thread/index.html //! [other]: #what-is-in-the-standard-library-documentation -//! [primitive types]: ../book/primitive-types.html +//! [primitive types]: ../book/first-edition/primitive-types.html #![crate_name = "std"] #![stable(feature = "rust1", since = "1.0.0")] @@ -237,7 +248,6 @@ #![feature(allow_internal_unstable)] #![feature(asm)] #![feature(associated_consts)] -#![feature(borrow_state)] #![feature(box_syntax)] #![feature(cfg_target_has_atomic)] #![feature(cfg_target_thread_local)] @@ -245,7 +255,6 @@ #![feature(char_escape_debug)] #![feature(char_internals)] #![feature(collections)] -#![feature(collections_bound)] #![feature(collections_range)] #![feature(compiler_builtins_lib)] #![feature(const_fn)] @@ -253,7 +262,6 @@ #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] -#![feature(float_extras)] #![feature(float_from_str_radix)] #![feature(fn_traits)] #![feature(fnbox)] @@ -273,6 +281,8 @@ #![feature(linkage)] #![feature(macro_reexport)] #![feature(needs_panic_runtime)] +#![feature(needs_drop)] +#![feature(never_type)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] #![feature(on_unimplemented)] @@ -281,8 +291,8 @@ #![feature(panic_unwind)] #![feature(peek)] #![feature(placement_in_syntax)] +#![feature(placement_new_protocol)] #![feature(prelude_import)] -#![feature(pub_restricted)] #![feature(rand)] #![feature(raw)] #![feature(repr_simd)] @@ -296,9 +306,11 @@ #![feature(stmt_expr_attributes)] #![feature(str_char)] #![feature(str_internals)] +#![feature(str_mut_extras)] #![feature(str_utf16)] #![feature(test, rustc_private)] #![feature(thread_local)] +#![feature(toowned_clone_into)] #![feature(try_from)] #![feature(unboxed_closures)] #![feature(unicode)] @@ -306,8 +318,8 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(vec_push_all)] -#![feature(zero_one)] #![cfg_attr(test, feature(update_panic_count))] +#![cfg_attr(test, feature(float_bits_conv))] // Explicitly import the prelude. The compiler uses this same unstable attribute // to import the prelude implicitly when building crates that depend on std. diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index a1f092621cb..df3fce0da76 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -68,6 +68,9 @@ macro_rules! panic { /// necessary to use `io::stdout().flush()` to ensure the output is emitted /// immediately. /// +/// Use `print!` only for the primary output of your program. Use +/// `eprint!` instead to print error and progress messages. +/// /// # Panics /// /// Panics if writing to `io::stdout()` fails. @@ -105,9 +108,12 @@ macro_rules! print { /// Use the `format!` syntax to write data to the standard output. /// See `std::fmt` for more information. /// +/// Use `println!` only for the primary output of your program. Use +/// `eprintln!` instead to print error and progress messages. +/// /// # Panics /// -/// Panics if writing to `io::stdout()` fails. +/// Panics if writing to `io::stdout` fails. /// /// # Examples /// @@ -124,6 +130,45 @@ macro_rules! println { ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); } +/// Macro for printing to the standard error. +/// +/// Equivalent to the `print!` macro, except that output goes to +/// `io::stderr` instead of `io::stdout`. See `print!` for +/// example usage. +/// +/// Use `eprint!` only for error and progress messages. Use `print!` +/// instead for the primary output of your program. +/// +/// # Panics +/// +/// Panics if writing to `io::stderr` fails. +#[macro_export] +#[stable(feature = "eprint", since = "1.19.0")] +#[allow_internal_unstable] +macro_rules! eprint { + ($($arg:tt)*) => ($crate::io::_eprint(format_args!($($arg)*))); +} + +/// Macro for printing to the standard error, with a newline. +/// +/// Equivalent to the `println!` macro, except that output goes to +/// `io::stderr` instead of `io::stdout`. See `println!` for +/// example usage. +/// +/// Use `eprintln!` only for error and progress messages. Use `println!` +/// instead for the primary output of your program. +/// +/// # Panics +/// +/// Panics if writing to `io::stderr` fails. +#[macro_export] +#[stable(feature = "eprint", since = "1.19.0")] +macro_rules! eprintln { + () => (eprint!("\n")); + ($fmt:expr) => (eprint!(concat!($fmt, "\n"))); + ($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*)); +} + /// A macro to select an event from a number of receivers. /// /// This macro is used to wait for the first event to occur on a number of diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 84c4acb8d92..36c06dc0b58 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -20,15 +20,31 @@ use vec; use iter; use slice; -/// Representation of a socket address for networking applications. +/// An internet socket address, either IPv4 or IPv6. /// -/// A socket address can either represent the IPv4 or IPv6 protocol and is -/// paired with at least a port number as well. Each protocol may have more -/// specific information about the address available to it as well. +/// Internet socket addresses consist of an [IP address], a 16-bit port number, as well +/// as possibly some version-dependent additional information. See [`SocketAddrV4`]'s and +/// [`SocketAddrV6`]'s respective documentation for more details. +/// +/// [IP address]: ../../std/net/enum.IpAddr.html +/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html +/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html +/// +/// # Examples +/// +/// ``` +/// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +/// +/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); +/// +/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket)); +/// assert_eq!(socket.port(), 8080); +/// assert_eq!(socket.is_ipv4(), true); +/// ``` #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum SocketAddr { - /// An IPv4 socket address which is a (ip, port) combination. + /// An IPv4 socket address. #[stable(feature = "rust1", since = "1.0.0")] V4(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV4), /// An IPv6 socket address. @@ -36,18 +52,63 @@ pub enum SocketAddr { V6(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV6), } -/// An IPv4 socket address which is a (ip, port) combination. +/// An IPv4 socket address. +/// +/// IPv4 socket addresses consist of an [IPv4 address] and a 16-bit port number, as +/// stated in [IETF RFC 793]. +/// +/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. +/// +/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 +/// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html +/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +/// +/// # Examples +/// +/// ``` +/// use std::net::{Ipv4Addr, SocketAddrV4}; +/// +/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); +/// +/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket)); +/// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1)); +/// assert_eq!(socket.port(), 8080); +/// ``` #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] pub struct SocketAddrV4 { inner: c::sockaddr_in } /// An IPv6 socket address. +/// +/// IPv6 socket addresses consist of an [Ipv6 address], a 16-bit port number, as well +/// as fields containing the traffic class, the flow label, and a scope identifier +/// (see [IETF RFC 2553, Section 3.3] for more details). +/// +/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. +/// +/// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 +/// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html +/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +/// +/// # Examples +/// +/// ``` +/// use std::net::{Ipv6Addr, SocketAddrV6}; +/// +/// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0); +/// +/// assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket)); +/// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)); +/// assert_eq!(socket.port(), 8080); +/// ``` #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] pub struct SocketAddrV6 { inner: c::sockaddr_in6 } impl SocketAddr { - /// Creates a new socket address from the (ip, port) pair. + /// Creates a new socket address from an [IP address] and a port number. + /// + /// [IP address]: ../../std/net/enum.IpAddr.html /// /// # Examples /// @@ -84,7 +145,7 @@ impl SocketAddr { } } - /// Change the IP address associated with this socket address. + /// Changes the IP address associated with this socket address. /// /// # Examples /// @@ -123,7 +184,7 @@ impl SocketAddr { } } - /// Change the port number associated with this socket address. + /// Changes the port number associated with this socket address. /// /// # Examples /// @@ -142,8 +203,13 @@ impl SocketAddr { } } - /// Returns true if the IP in this `SocketAddr` is a valid IPv4 address, - /// false if it's a valid IPv6 address. + /// Returns [`true`] if the [IP address] in this `SocketAddr` is an + /// [IPv4 address], and [`false`] otherwise. + /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// [IP address]: ../../std/net/enum.IpAddr.html + /// [IPv4 address]: ../../std/net/enum.IpAddr.html#variant.V4 /// /// # Examples /// @@ -164,8 +230,13 @@ impl SocketAddr { } } - /// Returns true if the IP in this `SocketAddr` is a valid IPv6 address, - /// false if it's a valid IPv4 address. + /// Returns [`true`] if the [IP address] in this `SocketAddr` is an + /// [IPv6 address], and [`false`] otherwise. + /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// [IP address]: ../../std/net/enum.IpAddr.html + /// [IPv6 address]: ../../std/net/enum.IpAddr.html#variant.V6 /// /// # Examples /// @@ -189,7 +260,9 @@ impl SocketAddr { } impl SocketAddrV4 { - /// Creates a new socket address from the (ip, port) pair. + /// Creates a new socket address from an [IPv4 address] and a port number. + /// + /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html /// /// # Examples /// @@ -227,7 +300,7 @@ impl SocketAddrV4 { } } - /// Change the IP address associated with this socket address. + /// Changes the IP address associated with this socket address. /// /// # Examples /// @@ -258,7 +331,7 @@ impl SocketAddrV4 { ntoh(self.inner.sin_port) } - /// Change the port number associated with this socket address. + /// Changes the port number associated with this socket address. /// /// # Examples /// @@ -276,8 +349,14 @@ impl SocketAddrV4 { } impl SocketAddrV6 { - /// Creates a new socket address from the ip/port/flowinfo/scope_id - /// components. + /// Creates a new socket address from an [IPv6 address], a 16-bit port number, + /// and the `flowinfo` and `scope_id` fields. + /// + /// For more information on the meaning and layout of the `flowinfo` and `scope_id` + /// parameters, see [IETF RFC 2553, Section 3.3]. + /// + /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 + /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html /// /// # Examples /// @@ -318,7 +397,7 @@ impl SocketAddrV6 { } } - /// Change the IP address associated with this socket address. + /// Changes the IP address associated with this socket address. /// /// # Examples /// @@ -349,7 +428,7 @@ impl SocketAddrV6 { ntoh(self.inner.sin6_port) } - /// Change the port number associated with this socket address. + /// Changes the port number associated with this socket address. /// /// # Examples /// @@ -365,8 +444,17 @@ impl SocketAddrV6 { self.inner.sin6_port = hton(new_port); } - /// Returns the flow information associated with this address, - /// corresponding to the `sin6_flowinfo` field in C. + /// Returns the flow information associated with this address. + /// + /// This information corresponds to the `sin6_flowinfo` field in C's `netinet/in.h`, + /// as specified in [IETF RFC 2553, Section 3.3]. + /// It combines information about the flow label and the traffic class as specified + /// in [IETF RFC 2460], respectively [Section 6] and [Section 7]. + /// + /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 + /// [IETF RFC 2460]: https://tools.ietf.org/html/rfc2460 + /// [Section 6]: https://tools.ietf.org/html/rfc2460#section-6 + /// [Section 7]: https://tools.ietf.org/html/rfc2460#section-7 /// /// # Examples /// @@ -381,7 +469,11 @@ impl SocketAddrV6 { self.inner.sin6_flowinfo } - /// Change the flow information associated with this socket address. + /// Changes the flow information associated with this socket address. + /// + /// See the [`flowinfo`] method's documentation for more details. + /// + /// [`flowinfo`]: #method.flowinfo /// /// # Examples /// @@ -397,8 +489,12 @@ impl SocketAddrV6 { self.inner.sin6_flowinfo = new_flowinfo; } - /// Returns the scope ID associated with this address, - /// corresponding to the `sin6_scope_id` field in C. + /// Returns the scope ID associated with this address. + /// + /// This information corresponds to the `sin6_scope_id` field in C's `netinet/in.h`, + /// as specified in [IETF RFC 2553, Section 3.3]. + /// + /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 /// /// # Examples /// @@ -415,6 +511,10 @@ impl SocketAddrV6 { /// Change the scope ID associated with this socket address. /// + /// See the [`scope_id`] method's documentation for more details. + /// + /// [`scope_id`]: #method.scope_id + /// /// # Examples /// /// ``` @@ -559,37 +659,51 @@ impl hash::Hash for SocketAddrV6 { } /// A trait for objects which can be converted or resolved to one or more -/// `SocketAddr` values. +/// [`SocketAddr`] values. /// /// This trait is used for generic address resolution when constructing network /// objects. By default it is implemented for the following types: /// -/// * `SocketAddr`, `SocketAddrV4`, `SocketAddrV6` - `to_socket_addrs` is -/// identity function. +/// * [`SocketAddr`]: [`to_socket_addrs`] is the identity function. /// -/// * `(IpvNAddr, u16)` - `to_socket_addrs` constructs `SocketAddr` trivially. +/// * [`SocketAddrV4`], [`SocketAddrV6`], `(`[`IpAddr`]`, `[`u16`]`)`, +/// `(`[`Ipv4Addr`]`, `[`u16`]`)`, `(`[`Ipv6Addr`]`, `[`u16`]`)`: +/// [`to_socket_addrs`] constructs a [`SocketAddr`] trivially. /// -/// * `(&str, u16)` - the string should be either a string representation of an -/// IP address expected by `FromStr` implementation for `IpvNAddr` or a host +/// * `(`[`&str`]`, `[`u16`]`)`: the string should be either a string representation +/// of an [`IpAddr`] address as expected by [`FromStr`] implementation or a host /// name. /// -/// * `&str` - the string should be either a string representation of a -/// `SocketAddr` as expected by its `FromStr` implementation or a string like -/// `<host_name>:<port>` pair where `<port>` is a `u16` value. +/// * [`&str`]: the string should be either a string representation of a +/// [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like +/// `<host_name>:<port>` pair where `<port>` is a [`u16`] value. /// -/// This trait allows constructing network objects like `TcpStream` or -/// `UdpSocket` easily with values of various types for the bind/connection +/// This trait allows constructing network objects like [`TcpStream`] or +/// [`UdpSocket`] easily with values of various types for the bind/connection /// address. It is needed because sometimes one type is more appropriate than /// the other: for simple uses a string like `"localhost:12345"` is much nicer -/// than manual construction of the corresponding `SocketAddr`, but sometimes -/// `SocketAddr` value is *the* main source of the address, and converting it to +/// than manual construction of the corresponding [`SocketAddr`], but sometimes +/// [`SocketAddr`] value is *the* main source of the address, and converting it to /// some other type (e.g. a string) just for it to be converted back to -/// `SocketAddr` in constructor methods is pointless. +/// [`SocketAddr`] in constructor methods is pointless. /// /// Addresses returned by the operating system that are not IP addresses are /// silently ignored. /// -/// Some examples: +/// [`FromStr`]: ../../std/str/trait.FromStr.html +/// [`IpAddr`]: ../../std/net/enum.IpAddr.html +/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html +/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html +/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html +/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html +/// [`&str`]: ../../std/primitive.str.html +/// [`TcpStream`]: ../../std/net/struct.TcpStream.html +/// [`to_socket_addrs`]: #tymethod.to_socket_addrs +/// [`UdpSocket`]: ../../std/net/struct.UdpSocket.html +/// [`u16`]: ../../std/primitive.u16.html +/// +/// # Examples /// /// ```no_run /// use std::net::{SocketAddrV4, TcpStream, UdpSocket, TcpListener, Ipv4Addr}; @@ -629,10 +743,6 @@ pub trait ToSocketAddrs { /// /// Note that this function may block the current thread while resolution is /// performed. - /// - /// # Errors - /// - /// Any errors encountered during resolution will be returned as an `Err`. #[stable(feature = "rust1", since = "1.0.0")] fn to_socket_addrs(&self) -> io::Result<Self::Iter>; } diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 5d6e8d319d7..1e5368896af 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -21,44 +21,100 @@ use net::{hton, ntoh}; use sys::net::netc as c; use sys_common::{AsInner, FromInner}; -/// An IP address, either an IPv4 or IPv6 address. +/// An IP address, either IPv4 or IPv6. /// -/// # Examples +/// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their +/// respective documentation for more details. /// -/// Constructing an IPv4 address: +/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html +/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html /// -/// ``` -/// use std::net::{IpAddr, Ipv4Addr}; +/// # Examples /// -/// IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); /// ``` +/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// -/// Constructing an IPv6 address: +/// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); +/// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); /// -/// ``` -/// use std::net::{IpAddr, Ipv6Addr}; +/// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4)); +/// assert_eq!("::1".parse(), Ok(localhost_v6)); /// -/// IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); +/// assert_eq!(localhost_v4.is_ipv6(), false); +/// assert_eq!(localhost_v4.is_ipv4(), true); /// ``` #[stable(feature = "ip_addr", since = "1.7.0")] #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)] pub enum IpAddr { - /// Representation of an IPv4 address. + /// An IPv4 address. #[stable(feature = "ip_addr", since = "1.7.0")] V4(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv4Addr), - /// Representation of an IPv6 address. + /// An IPv6 address. #[stable(feature = "ip_addr", since = "1.7.0")] V6(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv6Addr), } -/// Representation of an IPv4 address. +/// An IPv4 address. +/// +/// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791]. +/// They are usually represented as four octets. +/// +/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. +/// +/// [IETF RFC 791]: https://tools.ietf.org/html/rfc791 +/// [`IpAddr`]: ../../std/net/enum.IpAddr.html +/// +/// # Textual representation +/// +/// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal +/// notation, divided by `.` (this is called "dot-decimal notation"). +/// +/// [`FromStr`]: ../../std/str/trait.FromStr.html +/// +/// # Examples +/// +/// ``` +/// use std::net::Ipv4Addr; +/// +/// let localhost = Ipv4Addr::new(127, 0, 0, 1); +/// assert_eq!("127.0.0.1".parse(), Ok(localhost)); +/// assert_eq!(localhost.is_loopback(), true); +/// ``` #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Ipv4Addr { inner: c::in_addr, } -/// Representation of an IPv6 address. +/// An IPv6 address. +/// +/// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291]. +/// They are usually represented as eight 16-bit segments. +/// +/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. +/// +/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 +/// [`IpAddr`]: ../../std/net/enum.IpAddr.html +/// +/// # Textual representation +/// +/// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent +/// an IPv6 address in text, but in general, each segments is written in hexadecimal +/// notation, and segments are separated by `:`. For more information, see +/// [IETF RFC 5952]. +/// +/// [`FromStr`]: ../../std/str/trait.FromStr.html +/// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952 +/// +/// # Examples +/// +/// ``` +/// use std::net::Ipv6Addr; +/// +/// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); +/// assert_eq!("::1".parse(), Ok(localhost)); +/// assert_eq!(localhost.is_loopback(), true); +/// ``` #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Ipv6Addr { @@ -78,10 +134,14 @@ pub enum Ipv6MulticastScope { } impl IpAddr { - /// Returns true for the special 'unspecified' address ([IPv4], [IPv6]). + /// Returns [`true`] for the special 'unspecified' address. + /// + /// See the documentation for [`Ipv4Addr::is_unspecified`][IPv4] and + /// [`Ipv6Addr::is_unspecified`][IPv6] for more details. /// /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_unspecified /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_unspecified + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -99,10 +159,14 @@ impl IpAddr { } } - /// Returns true if this is a loopback address ([IPv4], [IPv6]). + /// Returns [`true`] if this is a loopback address. + /// + /// See the documentation for [`Ipv4Addr::is_loopback`][IPv4] and + /// [`Ipv6Addr::is_loopback`][IPv6] for more details. /// /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_loopback /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_loopback + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -120,10 +184,14 @@ impl IpAddr { } } - /// Returns true if the address appears to be globally routable ([IPv4], [IPv6]). + /// Returns [`true`] if the address appears to be globally routable. + /// + /// See the documentation for [`Ipv4Addr::is_global`][IPv4] and + /// [`Ipv6Addr::is_global`][IPv6] for more details. /// /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_global /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_global + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -145,10 +213,14 @@ impl IpAddr { } } - /// Returns true if this is a multicast address ([IPv4], [IPv6]). + /// Returns [`true`] if this is a multicast address. + /// + /// See the documentation for [`Ipv4Addr::is_multicast`][IPv4] and + /// [`Ipv6Addr::is_multicast`][IPv6] for more details. /// /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_multicast /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_multicast + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -166,10 +238,14 @@ impl IpAddr { } } - /// Returns true if this address is in a range designated for documentation ([IPv4], [IPv6]). + /// Returns [`true`] if this address is in a range designated for documentation. + /// + /// See the documentation for [`Ipv4Addr::is_documentation`][IPv4] and + /// [`Ipv6Addr::is_documentation`][IPv6] for more details. /// /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_documentation /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_documentation + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -191,7 +267,11 @@ impl IpAddr { } } - /// Returns true if this address is a valid IPv4 address, false if it's a valid IPv6 address. + /// Returns [`true`] if this address is an [IPv4 address], and [`false`] otherwise. + /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// [IPv4 address]: #variant.V4 /// /// # Examples /// @@ -212,7 +292,11 @@ impl IpAddr { } } - /// Returns true if this address is a valid IPv6 address, false if it's a valid IPv4 address. + /// Returns [`true`] if this address is an [IPv6 address], and [`false`] otherwise. + /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// [IPv6 address]: #variant.V6 /// /// # Examples /// @@ -274,12 +358,13 @@ impl Ipv4Addr { [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8] } - /// Returns true for the special 'unspecified' address (0.0.0.0). + /// Returns [`true`] for the special 'unspecified' address (0.0.0.0). /// /// This property is defined in _UNIX Network Programming, Second Edition_, /// W. Richard Stevens, p. 891; see also [ip7]. /// /// [ip7]: http://man7.org/linux/man-pages/man7/ip.7.html + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -294,11 +379,12 @@ impl Ipv4Addr { self.inner.s_addr == 0 } - /// Returns true if this is a loopback address (127.0.0.0/8). + /// Returns [`true`] if this is a loopback address (127.0.0.0/8). /// - /// This property is defined by [RFC 1122]. + /// This property is defined by [IETF RFC 1122]. /// - /// [RFC 1122]: https://tools.ietf.org/html/rfc1122 + /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -313,15 +399,16 @@ impl Ipv4Addr { self.octets()[0] == 127 } - /// Returns true if this is a private address. + /// Returns [`true`] if this is a private address. /// - /// The private address ranges are defined in [RFC 1918] and include: + /// The private address ranges are defined in [IETF RFC 1918] and include: /// /// - 10.0.0.0/8 /// - 172.16.0.0/12 /// - 192.168.0.0/16 /// - /// [RFC 1918]: https://tools.ietf.org/html/rfc1918 + /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -346,11 +433,12 @@ impl Ipv4Addr { } } - /// Returns true if the address is link-local (169.254.0.0/16). + /// Returns [`true`] if the address is link-local (169.254.0.0/16). /// - /// This property is defined by [RFC 3927]. + /// This property is defined by [IETF RFC 3927]. /// - /// [RFC 3927]: https://tools.ietf.org/html/rfc3927 + /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -366,7 +454,7 @@ impl Ipv4Addr { self.octets()[0] == 169 && self.octets()[1] == 254 } - /// Returns true if the address appears to be globally routable. + /// Returns [`true`] if the address appears to be globally routable. /// See [iana-ipv4-special-registry][ipv4-sr]. /// /// The following return false: @@ -379,6 +467,7 @@ impl Ipv4Addr { /// - the unspecified address (0.0.0.0) /// /// [ipv4-sr]: http://goo.gl/RaZ7lg + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -400,12 +489,13 @@ impl Ipv4Addr { !self.is_broadcast() && !self.is_documentation() && !self.is_unspecified() } - /// Returns true if this is a multicast address (224.0.0.0/4). + /// Returns [`true`] if this is a multicast address (224.0.0.0/4). /// /// Multicast addresses have a most significant octet between 224 and 239, - /// and is defined by [RFC 5771]. + /// and is defined by [IETF RFC 5771]. /// - /// [RFC 5771]: https://tools.ietf.org/html/rfc5771 + /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -421,11 +511,12 @@ impl Ipv4Addr { self.octets()[0] >= 224 && self.octets()[0] <= 239 } - /// Returns true if this is a broadcast address (255.255.255.255). + /// Returns [`true`] if this is a broadcast address (255.255.255.255). /// - /// A broadcast address has all octets set to 255 as defined in [RFC 919]. + /// A broadcast address has all octets set to 255 as defined in [IETF RFC 919]. /// - /// [RFC 919]: https://tools.ietf.org/html/rfc919 + /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -441,15 +532,16 @@ impl Ipv4Addr { self.octets()[2] == 255 && self.octets()[3] == 255 } - /// Returns true if this address is in a range designated for documentation. + /// Returns [`true`] if this address is in a range designated for documentation. /// - /// This is defined in [RFC 5737]: + /// This is defined in [IETF RFC 5737]: /// /// - 192.0.2.0/24 (TEST-NET-1) /// - 198.51.100.0/24 (TEST-NET-2) /// - 203.0.113.0/24 (TEST-NET-3) /// - /// [RFC 5737]: https://tools.ietf.org/html/rfc5737 + /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -471,10 +563,12 @@ impl Ipv4Addr { } } - /// Converts this address to an IPv4-compatible IPv6 address. + /// Converts this address to an IPv4-compatible [IPv6 address]. /// /// a.b.c.d becomes ::a.b.c.d /// + /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html + /// /// # Examples /// /// ``` @@ -490,10 +584,12 @@ impl Ipv4Addr { ((self.octets()[2] as u16) << 8) | self.octets()[3] as u16) } - /// Converts this address to an IPv4-mapped IPv6 address. + /// Converts this address to an IPv4-mapped [IPv6 address]. /// /// a.b.c.d becomes ::ffff:a.b.c.d /// + /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html + /// /// # Examples /// /// ``` @@ -561,7 +657,7 @@ impl PartialEq for Ipv4Addr { } } -#[stable(feature = "ip_cmp", since = "1.15.0")] +#[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialEq<Ipv4Addr> for IpAddr { fn eq(&self, other: &Ipv4Addr) -> bool { match *self { @@ -571,7 +667,7 @@ impl PartialEq<Ipv4Addr> for IpAddr { } } -#[stable(feature = "ip_cmp", since = "1.15.0")] +#[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialEq<IpAddr> for Ipv4Addr { fn eq(&self, other: &IpAddr) -> bool { match *other { @@ -598,7 +694,7 @@ impl PartialOrd for Ipv4Addr { } } -#[stable(feature = "ip_cmp", since = "1.15.0")] +#[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialOrd<Ipv4Addr> for IpAddr { fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> { match *self { @@ -608,7 +704,7 @@ impl PartialOrd<Ipv4Addr> for IpAddr { } } -#[stable(feature = "ip_cmp", since = "1.15.0")] +#[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialOrd<IpAddr> for Ipv4Addr { fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> { match *other { @@ -636,6 +732,7 @@ impl FromInner<c::in_addr> for Ipv4Addr { #[stable(feature = "ip_u32", since = "1.1.0")] impl From<Ipv4Addr> for u32 { + /// It performs the conversion in network order (big-endian). fn from(ip: Ipv4Addr) -> u32 { let ip = ip.octets(); ((ip[0] as u32) << 24) + ((ip[1] as u32) << 16) + ((ip[2] as u32) << 8) + (ip[3] as u32) @@ -644,6 +741,7 @@ impl From<Ipv4Addr> for u32 { #[stable(feature = "ip_u32", since = "1.1.0")] impl From<u32> for Ipv4Addr { + /// It performs the conversion in network order (big-endian). fn from(ip: u32) -> Ipv4Addr { Ipv4Addr::new((ip >> 24) as u8, (ip >> 16) as u8, (ip >> 8) as u8, ip as u8) } @@ -715,11 +813,12 @@ impl Ipv6Addr { ] } - /// Returns true for the special 'unspecified' address (::). + /// Returns [`true`] for the special 'unspecified' address (::). /// - /// This property is defined in [RFC 4291]. + /// This property is defined in [IETF RFC 4291]. /// - /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -734,11 +833,12 @@ impl Ipv6Addr { self.segments() == [0, 0, 0, 0, 0, 0, 0, 0] } - /// Returns true if this is a loopback address (::1). + /// Returns [`true`] if this is a loopback address (::1). /// - /// This property is defined in [RFC 4291]. + /// This property is defined in [IETF RFC 4291]. /// - /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -753,14 +853,17 @@ impl Ipv6Addr { self.segments() == [0, 0, 0, 0, 0, 0, 0, 1] } - /// Returns true if the address appears to be globally routable. + /// Returns [`true`] if the address appears to be globally routable. /// - /// The following return false: + /// The following return [`false`]: /// /// - the loopback address /// - link-local, site-local, and unique local unicast addresses /// - interface-, link-, realm-, admin- and site-local multicast addresses /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// /// # Examples /// /// ``` @@ -782,11 +885,12 @@ impl Ipv6Addr { } } - /// Returns true if this is a unique local address (fc00::/7). + /// Returns [`true`] if this is a unique local address (fc00::/7). /// - /// This property is defined in [RFC 4193]. + /// This property is defined in [IETF RFC 4193]. /// - /// [RFC 4193]: https://tools.ietf.org/html/rfc4193 + /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -805,11 +909,12 @@ impl Ipv6Addr { (self.segments()[0] & 0xfe00) == 0xfc00 } - /// Returns true if the address is unicast and link-local (fe80::/10). + /// Returns [`true`] if the address is unicast and link-local (fe80::/10). /// - /// This property is defined in [RFC 4291]. + /// This property is defined in [IETF RFC 4291]. /// - /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -828,9 +933,11 @@ impl Ipv6Addr { (self.segments()[0] & 0xffc0) == 0xfe80 } - /// Returns true if this is a deprecated unicast site-local address + /// Returns [`true`] if this is a deprecated unicast site-local address /// (fec0::/10). /// + /// [`true`]: ../../std/primitive.bool.html + /// /// # Examples /// /// ``` @@ -848,12 +955,13 @@ impl Ipv6Addr { (self.segments()[0] & 0xffc0) == 0xfec0 } - /// Returns true if this is an address reserved for documentation + /// Returns [`true`] if this is an address reserved for documentation /// (2001:db8::/32). /// - /// This property is defined in [RFC 3849]. + /// This property is defined in [IETF RFC 3849]. /// - /// [RFC 3849]: https://tools.ietf.org/html/rfc3849 + /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -872,7 +980,7 @@ impl Ipv6Addr { (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) } - /// Returns true if the address is a globally routable unicast address. + /// Returns [`true`] if the address is a globally routable unicast address. /// /// The following return false: /// @@ -883,6 +991,8 @@ impl Ipv6Addr { /// - the unspecified address /// - the address range reserved for documentation /// + /// [`true`]: ../../std/primitive.bool.html + /// /// # Examples /// /// ``` @@ -935,11 +1045,13 @@ impl Ipv6Addr { } } - /// Returns true if this is a multicast address (ff00::/8). + /// Returns [`true`] if this is a multicast address (ff00::/8). + /// + /// This property is defined by [IETF RFC 4291]. /// - /// This property is defined by [RFC 4291]. + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [`true`]: ../../std/primitive.bool.html /// - /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 /// # Examples /// /// ``` @@ -953,11 +1065,16 @@ impl Ipv6Addr { (self.segments()[0] & 0xff00) == 0xff00 } - /// Converts this address to an IPv4 address. Returns None if this address is + /// Converts this address to an [IPv4 address]. Returns [`None`] if this address is /// neither IPv4-compatible or IPv4-mapped. /// /// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d /// + /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// /// ``` /// use std::net::{Ipv4Addr, Ipv6Addr}; /// @@ -1083,7 +1200,7 @@ impl PartialEq for Ipv6Addr { } } -#[stable(feature = "ip_cmp", since = "1.15.0")] +#[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialEq<IpAddr> for Ipv6Addr { fn eq(&self, other: &IpAddr) -> bool { match *other { @@ -1093,7 +1210,7 @@ impl PartialEq<IpAddr> for Ipv6Addr { } } -#[stable(feature = "ip_cmp", since = "1.15.0")] +#[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialEq<Ipv6Addr> for IpAddr { fn eq(&self, other: &Ipv6Addr) -> bool { match *self { @@ -1120,7 +1237,7 @@ impl PartialOrd for Ipv6Addr { } } -#[stable(feature = "ip_cmp", since = "1.15.0")] +#[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialOrd<Ipv6Addr> for IpAddr { fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> { match *self { @@ -1130,7 +1247,7 @@ impl PartialOrd<Ipv6Addr> for IpAddr { } } -#[stable(feature = "ip_cmp", since = "1.15.0")] +#[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialOrd<IpAddr> for Ipv6Addr { fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> { match *other { @@ -1185,7 +1302,7 @@ impl From<[u8; 16]> for Ipv6Addr { } } -#[stable(feature = "ipv6_from_segments", since = "1.15.0")] +#[stable(feature = "ipv6_from_segments", since = "1.16.0")] impl From<[u16; 8]> for Ipv6Addr { fn from(segments: [u16; 8]) -> Ipv6Addr { let [a, b, c, d, e, f, g, h] = segments; diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index b0d2e3e4687..9fcb93e2032 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -9,6 +9,32 @@ // except according to those terms. //! Networking primitives for TCP/UDP communication. +//! +//! This module provides networking functionality for the Transmission Control and User +//! Datagram Protocols, as well as types for IP and socket addresses. +//! +//! # Organization +//! +//! * [`TcpListener`] and [`TcpStream`] provide functionality for communication over TCP +//! * [`UdpSocket`] provides functionality for communication over UDP +//! * [`IpAddr`] represents IP addresses of either IPv4 or IPv6; [`Ipv4Addr`] and +//! [`Ipv6Addr`] are respectively IPv4 and IPv6 addresses +//! * [`SocketAddr`] represents socket addresses of either IPv4 or IPv6; [`SocketAddrV4`] +//! and [`SocketAddrV6`] are respectively IPv4 and IPv6 socket addresses +//! * [`ToSocketAddrs`] is a trait that used for generic address resolution when interacting +//! with networking objects like [`TcpListener`], [`TcpStream`] or [`UdpSocket`] +//! * Other types are return or parameter types for various methods in this module +//! +//! [`IpAddr`]: ../../std/net/enum.IpAddr.html +//! [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html +//! [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html +//! [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +//! [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html +//! [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html +//! [`TcpListener`]: ../../std/net/struct.TcpListener.html +//! [`TcpStream`]: ../../std/net/struct.TcpStream.html +//! [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html +//! [`UdpSocket`]: ../../std/net/struct.UdpSocket.html #![stable(feature = "rust1", since = "1.0.0")] @@ -43,17 +69,30 @@ mod test; #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Shutdown { - /// Indicates that the reading portion of this stream/socket should be shut - /// down. All currently blocked and future reads will return `Ok(0)`. + /// The reading portion of the [`TcpStream`] should be shut down. + /// + /// All currently blocked and future [reads] will return [`Ok(0)`]. + /// + /// [`TcpStream`]: ../../std/net/struct.TcpStream.html + /// [reads]: ../../std/io/trait.Read.html + /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok #[stable(feature = "rust1", since = "1.0.0")] Read, - /// Indicates that the writing portion of this stream/socket should be shut - /// down. All currently blocked and future writes will return an error. + /// The writing portion of the [`TcpStream`] should be shut down. + /// + /// All currently blocked and future [writes] will return an error. + /// + /// [`TcpStream`]: ../../std/net/struct.TcpStream.html + /// [writes]: ../../std/io/trait.Write.html #[stable(feature = "rust1", since = "1.0.0")] Write, - /// Shut down both the reading and writing portions of this stream. + /// Both the reading and the writing portions of the [`TcpStream`] should be shut down. + /// + /// See [`Shutdown::Read`] and [`Shutdown::Write`] for more information. /// - /// See `Shutdown::Read` and `Shutdown::Write` for more information. + /// [`TcpStream`]: ../../std/net/struct.TcpStream.html + /// [`Shutdown::Read`]: #variant.Read + /// [`Shutdown::Write`]: #variant.Write #[stable(feature = "rust1", since = "1.0.0")] Both, } diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs index d86711c10ac..7d7c67ff3f9 100644 --- a/src/libstd/net/parser.rs +++ b/src/libstd/net/parser.rs @@ -368,7 +368,19 @@ impl FromStr for SocketAddr { } } -/// An error returned when parsing an IP address or a socket address. +/// An error which can be returned when parsing an IP address or a socket address. +/// +/// This error is used as the error type for the [`FromStr`] implementation for +/// [`IpAddr`], [`Ipv4Addr`], [`Ipv6Addr`], [`SocketAddr`], [`SocketAddrV4`], and +/// [`SocketAddrV6`]. +/// +/// [`FromStr`]: ../../std/str/trait.FromStr.html +/// [`IpAddr`]: ../../std/net/enum.IpAddr.html +/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html +/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html +/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html +/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug, Clone, PartialEq, Eq)] pub struct AddrParseError(()); diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 9bead22ef7f..c1493c9c6f4 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -17,10 +17,25 @@ use sys_common::net as net_imp; use sys_common::{AsInner, FromInner, IntoInner}; use time::Duration; -/// A structure which represents a TCP stream between a local socket and a -/// remote socket. +/// A TCP stream between a local and a remote socket. /// -/// The socket will be closed when the value is dropped. +/// After creating a `TcpStream` by either [`connect`]ing to a remote host or +/// [`accept`]ing a connection on a [`TcpListener`], data can be transmitted +/// by [reading] and [writing] to it. +/// +/// The connection will be closed when the value is dropped. The reading and writing +/// portions of the connection can also be shut down individually with the [`shutdown`] +/// method. +/// +/// The Transmission Control Protocol is specified in [IETF RFC 793]. +/// +/// [`accept`]: ../../std/net/struct.TcpListener.html#method.accept +/// [`connect`]: #method.connect +/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 +/// [reading]: ../../std/io/trait.Read.html +/// [`shutdown`]: #method.shutdown +/// [`TcpListener`]: ../../std/net/struct.TcpListener.html +/// [writing]: ../../std/io/trait.Write.html /// /// # Examples /// @@ -39,42 +54,53 @@ use time::Duration; #[stable(feature = "rust1", since = "1.0.0")] pub struct TcpStream(net_imp::TcpStream); -/// A structure representing a socket server. +/// A TCP socket server, listening for connections. +/// +/// After creating a `TcpListener` by [`bind`]ing it to a socket address, it listens +/// for incoming TCP connections. These can be accepted by calling [`accept`] or by +/// iterating over the [`Incoming`] iterator returned by [`incoming`][`TcpListener::incoming`]. +/// +/// The socket will be closed when the value is dropped. +/// +/// The Transmission Control Protocol is specified in [IETF RFC 793]. +/// +/// [`accept`]: #method.accept +/// [`bind`]: #method.bind +/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 +/// [`Incoming`]: ../../std/net/struct.Incoming.html +/// [`TcpListener::incoming`]: #method.incoming /// /// # Examples /// -/// ```no_run +/// ``` +/// # use std::io; /// use std::net::{TcpListener, TcpStream}; /// -/// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); -/// /// fn handle_client(stream: TcpStream) { /// // ... /// } /// +/// # fn process() -> io::Result<()> { +/// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); +/// /// // accept connections and process them serially /// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// handle_client(stream); -/// } -/// Err(e) => { /* connection failed */ } -/// } +/// handle_client(stream?); /// } +/// # Ok(()) +/// # } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct TcpListener(net_imp::TcpListener); -/// An infinite iterator over the connections from a `TcpListener`. -/// -/// This iterator will infinitely yield [`Some`] of the accepted connections. It -/// is equivalent to calling `accept` in a loop. +/// An iterator that infinitely [`accept`]s connections on a [`TcpListener`]. /// /// This `struct` is created by the [`incoming`] method on [`TcpListener`]. +/// See its documentation for more. /// -/// [`Some`]: ../../std/option/enum.Option.html#variant.Some -/// [`incoming`]: struct.TcpListener.html#method.incoming -/// [`TcpListener`]: struct.TcpListener.html +/// [`accept`]: ../../std/net/struct.TcpListener.html#method.accept +/// [`incoming`]: ../../std/net/struct.TcpListener.html#method.incoming +/// [`TcpListener`]: ../../std/net/struct.TcpListener.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Incoming<'a> { listener: &'a TcpListener } @@ -83,11 +109,15 @@ impl TcpStream { /// Opens a TCP connection to a remote host. /// /// `addr` is an address of the remote host. Anything which implements - /// `ToSocketAddrs` trait can be supplied for the address; see this trait + /// [`ToSocketAddrs`] trait can be supplied for the address; see this trait /// documentation for concrete examples. - /// In case `ToSocketAddrs::to_socket_addrs()` returns more than one entry, + /// In case [`ToSocketAddrs::to_socket_addrs()`] returns more than one entry, /// then the first valid and reachable address is used. /// + /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html + /// [`ToSocketAddrs::to_socket_addrs()`]: + /// ../../std/net/trait.ToSocketAddrs.html#tymethod.to_socket_addrs + /// /// # Examples /// /// ```no_run @@ -146,6 +176,13 @@ impl TcpStream { /// /// [`Shutdown`]: ../../std/net/enum.Shutdown.html /// + /// # Platform-specific behavior + /// + /// Calling this function multiple times may result in different behavior, + /// depending on the operating system. On Linux, the second call will + /// return `Ok(())`, but on macOS, it will return `ErrorKind::NotConnected`. + /// This may change in the future. + /// /// # Examples /// /// ```no_run @@ -183,7 +220,7 @@ impl TcpStream { /// Sets the read timeout to the timeout specified. /// - /// If the value specified is [`None`], then [`read()`] calls will block + /// If the value specified is [`None`], then [`read`] calls will block /// indefinitely. It is an error to pass the zero `Duration` to this /// method. /// @@ -194,7 +231,7 @@ impl TcpStream { /// error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`read()`]: ../../std/io/trait.Read.html#tymethod.read + /// [`read`]: ../../std/io/trait.Read.html#tymethod.read /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut /// @@ -214,7 +251,7 @@ impl TcpStream { /// Sets the write timeout to the timeout specified. /// - /// If the value specified is [`None`], then [`write()`] calls will block + /// If the value specified is [`None`], then [`write`] calls will block /// indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// @@ -225,7 +262,7 @@ impl TcpStream { /// an error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`write()`]: ../../std/io/trait.Write.html#tymethod.write + /// [`write`]: ../../std/io/trait.Write.html#tymethod.write /// [`Duration`]: ../../std/time/struct.Duration.html /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut @@ -246,14 +283,14 @@ impl TcpStream { /// Returns the read timeout of this socket. /// - /// If the timeout is [`None`], then [`read()`] calls will block indefinitely. + /// If the timeout is [`None`], then [`read`] calls will block indefinitely. /// /// # Note /// /// Some platforms do not provide access to the current timeout. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`read()`]: ../../std/io/trait.Read.html#tymethod.read + /// [`read`]: ../../std/io/trait.Read.html#tymethod.read /// /// # Examples /// @@ -272,14 +309,14 @@ impl TcpStream { /// Returns the write timeout of this socket. /// - /// If the timeout is [`None`], then [`write()`] calls will block indefinitely. + /// If the timeout is [`None`], then [`write`] calls will block indefinitely. /// /// # Note /// /// Some platforms do not provide access to the current timeout. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`write()`]: ../../std/io/trait.Write.html#tymethod.write + /// [`write`]: ../../std/io/trait.Write.html#tymethod.write /// /// # Examples /// @@ -306,7 +343,6 @@ impl TcpStream { /// # Examples /// /// ```no_run - /// #![feature(peek)] /// use std::net::TcpStream; /// /// let stream = TcpStream::connect("127.0.0.1:8000") @@ -314,7 +350,7 @@ impl TcpStream { /// let mut buf = [0; 10]; /// let len = stream.peek(&mut buf).expect("peek failed"); /// ``` - #[unstable(feature = "peek", issue = "38980")] + #[stable(feature = "peek", since = "1.18.0")] pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { self.0.peek(buf) } @@ -494,11 +530,14 @@ impl TcpListener { /// /// Binding with a port number of 0 will request that the OS assigns a port /// to this listener. The port allocated can be queried via the - /// `local_addr` method. + /// [`local_addr`] method. /// - /// The address type can be any implementor of `ToSocketAddrs` trait. See + /// The address type can be any implementor of [`ToSocketAddrs`] trait. See /// its documentation for concrete examples. /// + /// [`local_addr`]: #method.local_addr + /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html + /// /// # Examples /// /// ```no_run @@ -529,10 +568,12 @@ impl TcpListener { /// Creates a new independently owned handle to the underlying socket. /// - /// The returned `TcpListener` is a reference to the same socket that this + /// The returned [`TcpListener`] is a reference to the same socket that this /// object references. Both handles can be used to accept incoming /// connections and options set on one listener will affect the other. /// + /// [`TcpListener`]: ../../std/net/struct.TcpListener.html + /// /// # Examples /// /// ```no_run @@ -549,9 +590,11 @@ impl TcpListener { /// Accept a new incoming connection from this listener. /// /// This function will block the calling thread until a new TCP connection - /// is established. When established, the corresponding `TcpStream` and the + /// is established. When established, the corresponding [`TcpStream`] and the /// remote peer's address will be returned. /// + /// [`TcpStream`]: ../../std/net/struct.TcpStream.html + /// /// # Examples /// /// ```no_run @@ -572,10 +615,12 @@ impl TcpListener { /// listener. /// /// The returned iterator will never return [`None`] and will also not yield - /// the peer's [`SocketAddr`] structure. + /// the peer's [`SocketAddr`] structure. Iterating over it is equivalent to + /// calling [`accept`] in a loop. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html + /// [`accept`]: #method.accept /// /// # Examples /// @@ -618,7 +663,7 @@ impl TcpListener { /// Gets the value of the `IP_TTL` option for this socket. /// - /// For more information about this option, see [`set_ttl()`][link]. + /// For more information about this option, see [`set_ttl`][link]. /// /// [link]: #method.set_ttl /// diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index f452c75d389..80151dc2b44 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -15,11 +15,29 @@ use sys_common::net as net_imp; use sys_common::{AsInner, FromInner, IntoInner}; use time::Duration; -/// A User Datagram Protocol socket. +/// A UDP socket. /// -/// This is an implementation of a bound UDP socket. This supports both IPv4 and -/// IPv6 addresses, and there is no corresponding notion of a server because UDP -/// is a datagram protocol. +/// After creating a `UdpSocket` by [`bind`]ing it to a socket address, data can be +/// [sent to] and [received from] any other socket address. +/// +/// Although UDP is a connectionless protocol, this implementation provides an interface +/// to set an address where data should be sent and received from. After setting a remote +/// address with [`connect`], data can be sent to and received from that address with +/// [`send`] and [`recv`]. +/// +/// As stated in the User Datagram Protocol's specification in [IETF RFC 768], UDP is +/// an unordered, unreliable protocol; refer to [`TcpListener`] and [`TcpStream`] for TCP +/// primitives. +/// +/// [`bind`]: #method.bind +/// [`connect`]: #method.connect +/// [IETF RFC 768]: https://tools.ietf.org/html/rfc768 +/// [`recv`]: #method.recv +/// [received from]: #method.recv_from +/// [`send`]: #method.send +/// [sent to]: #method.send_to +/// [`TcpListener`]: ../../std/net/struct.TcpListener.html +/// [`TcpStream`]: ../../std/net/struct.TcpStream.html /// /// # Examples /// @@ -94,7 +112,6 @@ impl UdpSocket { /// # Examples /// /// ```no_run - /// #![feature(peek)] /// use std::net::UdpSocket; /// /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); @@ -102,7 +119,7 @@ impl UdpSocket { /// let (number_of_bytes, src_addr) = socket.peek_from(&mut buf) /// .expect("Didn't receive data"); /// ``` - #[unstable(feature = "peek", issue = "38980")] + #[stable(feature = "peek", since = "1.18.0")] pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { self.0.peek_from(buf) } @@ -175,7 +192,7 @@ impl UdpSocket { /// Sets the read timeout to the timeout specified. /// - /// If the value specified is [`None`], then [`read()`] calls will block + /// If the value specified is [`None`], then [`read`] calls will block /// indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// @@ -186,7 +203,7 @@ impl UdpSocket { /// error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`read()`]: ../../std/io/trait.Read.html#tymethod.read + /// [`read`]: ../../std/io/trait.Read.html#tymethod.read /// [`Duration`]: ../../std/time/struct.Duration.html /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut @@ -206,7 +223,7 @@ impl UdpSocket { /// Sets the write timeout to the timeout specified. /// - /// If the value specified is [`None`], then [`write()`] calls will block + /// If the value specified is [`None`], then [`write`] calls will block /// indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// @@ -217,7 +234,7 @@ impl UdpSocket { /// an error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`write()`]: ../../std/io/trait.Write.html#tymethod.write + /// [`write`]: ../../std/io/trait.Write.html#tymethod.write /// [`Duration`]: ../../std/time/struct.Duration.html /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut @@ -237,10 +254,10 @@ impl UdpSocket { /// Returns the read timeout of this socket. /// - /// If the timeout is [`None`], then [`read()`] calls will block indefinitely. + /// If the timeout is [`None`], then [`read`] calls will block indefinitely. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`read()`]: ../../std/io/trait.Read.html#tymethod.read + /// [`read`]: ../../std/io/trait.Read.html#tymethod.read /// /// # Examples /// @@ -258,10 +275,10 @@ impl UdpSocket { /// Returns the write timeout of this socket. /// - /// If the timeout is [`None`], then [`write()`] calls will block indefinitely. + /// If the timeout is [`None`], then [`write`] calls will block indefinitely. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`write()`]: ../../std/io/trait.Write.html#tymethod.write + /// [`write`]: ../../std/io/trait.Write.html#tymethod.write /// /// # Examples /// @@ -560,10 +577,10 @@ impl UdpSocket { /// Sends data on the socket to the remote address to which it is connected. /// - /// The [`connect()`] method will connect this socket to a remote address. This + /// The [`connect`] method will connect this socket to a remote address. This /// method will fail if the socket is not connected. /// - /// [`connect()`]: #method.connect + /// [`connect`]: #method.connect /// /// # Examples /// @@ -582,9 +599,11 @@ impl UdpSocket { /// Receives data on the socket from the remote address to which it is /// connected. /// - /// The `connect` method will connect this socket to a remote address. This + /// The [`connect`] method will connect this socket to a remote address. This /// method will fail if the socket is not connected. /// + /// [`connect`]: #method.connect + /// /// # Examples /// /// ```no_run @@ -618,7 +637,6 @@ impl UdpSocket { /// # Examples /// /// ```no_run - /// #![feature(peek)] /// use std::net::UdpSocket; /// /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); @@ -629,7 +647,7 @@ impl UdpSocket { /// Err(e) => println!("peek function failed: {:?}", e), /// } /// ``` - #[unstable(feature = "peek", issue = "38980")] + #[stable(feature = "peek", since = "1.18.0")] pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { self.0.peek(buf) } diff --git a/src/libstd/num.rs b/src/libstd/num.rs index 5f83d077a13..ff89887ac92 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -17,9 +17,6 @@ #![allow(missing_docs)] #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -pub use core::num::{Zero, One}; -#[stable(feature = "rust1", since = "1.0.0")] pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::Wrapping; diff --git a/src/libstd/os/android/raw.rs b/src/libstd/os/android/raw.rs index 5e473a933a6..60ad8fcc54c 100644 --- a/src/libstd/os/android/raw.rs +++ b/src/libstd/os/android/raw.rs @@ -165,3 +165,66 @@ mod arch { } } +#[cfg(target_arch = "x86_64")] +mod arch { + use os::raw::{c_uint, c_long, c_ulong}; + use os::unix::raw::{uid_t, gid_t}; + + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type dev_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type mode_t = u32; + + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type blkcnt_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type blksize_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type ino_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type nlink_t = u32; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type off_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type time_t = i64; + + #[repr(C)] + #[derive(Clone)] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub struct stat { + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_dev: dev_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ino: ino_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_nlink: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mode: c_uint, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_uid: uid_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gid: gid_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_rdev: dev_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_size: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blksize: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blocks: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime_nsec: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime_nsec: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime_nsec: c_ulong, + __unused: [c_long; 3], + } +} + diff --git a/src/libstd/os/linux/fs.rs b/src/libstd/os/linux/fs.rs index 11c41816cec..7ebda5ed744 100644 --- a/src/libstd/os/linux/fs.rs +++ b/src/libstd/os/linux/fs.rs @@ -34,36 +34,55 @@ pub trait MetadataExt { #[allow(deprecated)] fn as_raw_stat(&self) -> &raw::stat; + /// Returns the device ID on which this file resides. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_dev(&self) -> u64; + /// Returns the inode number. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_ino(&self) -> u64; + /// Returns the file type and mode. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_mode(&self) -> u32; + /// Returns the number of hard links to file. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_nlink(&self) -> u64; + /// Returns the user ID of the file owner. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_uid(&self) -> u32; + /// Returns the group ID of the file owner. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_gid(&self) -> u32; + /// Returns the device ID that this file represents. Only relevant for special file. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_rdev(&self) -> u64; + /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes. + /// + /// The size of a symbolic link is the length of the pathname it contains, + /// without a terminating null byte. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_size(&self) -> u64; + /// Returns the last access time. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_atime(&self) -> i64; + /// Returns the last access time, nano seconds part. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_atime_nsec(&self) -> i64; + /// Returns the last modification time. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_mtime(&self) -> i64; + /// Returns the last modification time, nano seconds part. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_mtime_nsec(&self) -> i64; + /// Returns the last status change time. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_ctime(&self) -> i64; + /// Returns the last status change time, nano seconds part. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_ctime_nsec(&self) -> i64; + /// Returns the "preferred" blocksize for efficient filesystem I/O. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_blksize(&self) -> u64; + /// Returns the number of blocks allocated to the file, 512-byte units. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_blocks(&self) -> u64; } diff --git a/src/libstd/os/macos/mod.rs b/src/libstd/os/macos/mod.rs index 4e995358fd8..c9406f73100 100644 --- a/src/libstd/os/macos/mod.rs +++ b/src/libstd/os/macos/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! MacOS-specific definitions +//! macOS-specific definitions #![stable(feature = "raw_ext", since = "1.1.0")] diff --git a/src/libstd/os/macos/raw.rs b/src/libstd/os/macos/raw.rs index 8f9b29462c4..8ffddf638b1 100644 --- a/src/libstd/os/macos/raw.rs +++ b/src/libstd/os/macos/raw.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! MacOS-specific raw type definitions +//! macOS-specific raw type definitions #![stable(feature = "raw_ext", since = "1.1.0")] #![rustc_deprecated(since = "1.8.0", diff --git a/src/libstd/os/raw.rs b/src/libstd/os/raw.rs index 68d4ca90019..c34491941d6 100644 --- a/src/libstd/os/raw.rs +++ b/src/libstd/os/raw.rs @@ -14,22 +14,24 @@ use fmt; -#[cfg(any(target_os = "android", - target_os = "emscripten", +#[cfg(any(target_os = "emscripten", all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc", target_arch = "powerpc64", target_arch = "s390x")), + all(target_os = "android", any(target_arch = "aarch64", + target_arch = "arm")), all(target_os = "fuchsia", target_arch = "aarch64")))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8; -#[cfg(not(any(target_os = "android", - target_os = "emscripten", +#[cfg(not(any(target_os = "emscripten", all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc", target_arch = "powerpc64", target_arch = "s390x")), + all(target_os = "android", any(target_arch = "aarch64", + target_arch = "arm")), all(target_os = "fuchsia", target_arch = "aarch64"))))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8; #[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8; diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 3b5a1cffc7a..6f46a73698f 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -160,10 +160,10 @@ pub fn take_hook() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> { /// A struct providing information about a panic. /// -/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook()`] +/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`] /// function. /// -/// [`set_hook()`]: ../../std/panic/fn.set_hook.html +/// [`set_hook`]: ../../std/panic/fn.set_hook.html /// /// # Examples /// @@ -237,9 +237,9 @@ impl<'a> PanicInfo<'a> { /// A struct containing information about the location of a panic. /// -/// This structure is created by the [`location()`] method of [`PanicInfo`]. +/// This structure is created by the [`location`] method of [`PanicInfo`]. /// -/// [`location()`]: ../../std/panic/struct.PanicInfo.html#method.location +/// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location /// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html /// /// # Examples diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 245a6d945b5..e128a4164d7 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -15,6 +15,13 @@ //! around [`OsString`] and [`OsStr`] respectively, meaning that they work directly //! on strings according to the local platform's path syntax. //! +//! Paths can be parsed into [`Component`]s by iterating over the structure +//! returned by the [`components`] method on [`Path`]. [`Component`]s roughly +//! correspond to the substrings between path separators (`/` or `\`). You can +//! reconstruct an equivalent path from components with the [`push`] method on +//! [`PathBuf`]; note that the paths may differ syntactically by the +//! normalization described in the documentation for the [`components`] method. +//! //! ## Simple usage //! //! Path manipulation includes both parsing components from slices and building @@ -44,69 +51,26 @@ //! ``` //! use std::path::PathBuf; //! +//! // This way works... //! let mut path = PathBuf::from("c:\\"); +//! //! path.push("windows"); //! path.push("system32"); -//! path.set_extension("dll"); -//! ``` -//! -//! ## Path components and normalization -//! -//! The path APIs are built around the notion of "components", which roughly -//! correspond to the substrings between path separators (`/` and, on Windows, -//! `\`). The APIs for path parsing are largely specified in terms of the path's -//! components, so it's important to clearly understand how those are -//! determined. -//! -//! A path can always be reconstructed into an *equivalent* path by -//! putting together its components via `push`. Syntactically, the -//! paths may differ by the normalization described below. -//! -//! ### Component types -//! -//! Components come in several types: //! -//! * Normal components are the default: standard references to files or -//! directories. The path `a/b` has two normal components, `a` and `b`. -//! -//! * Current directory components represent the `.` character. For example, -//! `./a` has a current directory component and a normal component `a`. -//! -//! * The root directory component represents a separator that designates -//! starting from root. For example, `/a/b` has a root directory component -//! followed by normal components `a` and `b`. -//! -//! On Windows, an additional component type comes into play: -//! -//! * Prefix components, of which there is a large variety. For example, `C:` -//! and `\\server\share` are prefixes. The path `C:windows` has a prefix -//! component `C:` and a normal component `windows`; the path `C:\windows` has a -//! prefix component `C:`, a root directory component, and a normal component -//! `windows`. -//! -//! ### Normalization -//! -//! Aside from splitting on the separator(s), there is a small amount of -//! "normalization": -//! -//! * Repeated separators are ignored: `a/b` and `a//b` both have components `a` -//! and `b`. -//! -//! * Occurrences of `.` are normalized away, *except* if they are at -//! the beginning of the path (in which case they are often meaningful -//! in terms of path searching). So, for example, `a/./b`, `a/b/`, -//! `/a/b/.` and `a/b` all have components `a` and `b`, but `./a/b` -//! has a leading current directory component. +//! path.set_extension("dll"); //! -//! No other normalization takes place by default. In particular, -//! `a/c` and `a/b/../c` are distinct, to account for the possibility -//! that `b` is a symbolic link (so its parent isn't `a`). Further -//! normalization is possible to build on top of the components APIs, -//! and will be included in this library in the near future. +//! // ... but push is best used if you don't know everything up +//! // front. If you do, this way is better: +//! let path: PathBuf = ["c:\\", "windows", "system32.dll"].iter().collect(); +//! ``` //! +//! [`Component`]: ../../std/path/enum.Component.html +//! [`components`]: ../../std/path/struct.Path.html#method.components //! [`PathBuf`]: ../../std/path/struct.PathBuf.html //! [`Path`]: ../../std/path/struct.Path.html +//! [`push`]: ../../std/path/struct.PathBuf.html#method.push //! [`String`]: ../../std/string/struct.String.html +//! //! [`str`]: ../../std/primitive.str.html //! [`OsString`]: ../../std/ffi/struct.OsString.html //! [`OsStr`]: ../../std/ffi/struct.OsStr.html @@ -143,36 +107,81 @@ use sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix}; // Windows Prefixes //////////////////////////////////////////////////////////////////////////////// -/// Path prefixes (Windows only). +/// Windows path prefixes, e.g. `C:` or `\\server\share`. +/// +/// Windows uses a variety of path prefix styles, including references to drive +/// volumes (like `C:`), network shared folders (like `\\server\share`), and +/// others. In addition, some path prefixes are "verbatim" (i.e. prefixed with +/// `\\?\`), in which case `/` is *not* treated as a separator and essentially +/// no normalization is performed. +/// +/// # Examples /// -/// Windows uses a variety of path styles, including references to drive -/// volumes (like `C:`), network shared folders (like `\\server\share`) and -/// others. In addition, some path prefixes are "verbatim", in which case -/// `/` is *not* treated as a separator and essentially no normalization is -/// performed. +/// ``` +/// use std::path::{Component, Path, Prefix}; +/// use std::path::Prefix::*; +/// use std::ffi::OsStr; +/// +/// fn get_path_prefix(s: &str) -> Prefix { +/// let path = Path::new(s); +/// match path.components().next().unwrap() { +/// Component::Prefix(prefix_component) => prefix_component.kind(), +/// _ => panic!(), +/// } +/// } +/// +/// # if cfg!(windows) { +/// assert_eq!(Verbatim(OsStr::new("pictures")), +/// get_path_prefix(r"\\?\pictures\kittens")); +/// assert_eq!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")), +/// get_path_prefix(r"\\?\UNC\server\share")); +/// assert_eq!(VerbatimDisk('C' as u8), get_path_prefix(r"\\?\c:\")); +/// assert_eq!(DeviceNS(OsStr::new("BrainInterface")), +/// get_path_prefix(r"\\.\BrainInterface")); +/// assert_eq!(UNC(OsStr::new("server"), OsStr::new("share")), +/// get_path_prefix(r"\\server\share")); +/// assert_eq!(Disk('C' as u8), get_path_prefix(r"C:\Users\Rust\Pictures\Ferris")); +/// # } +/// ``` #[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Prefix<'a> { - /// Prefix `\\?\`, together with the given component immediately following it. + /// Verbatim prefix, e.g. `\\?\cat_pics`. + /// + /// Verbatim prefixes consist of `\\?\` immediately followed by the given + /// component. #[stable(feature = "rust1", since = "1.0.0")] Verbatim(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), - /// Prefix `\\?\UNC\`, with the "server" and "share" components following it. + /// Verbatim prefix using Windows' _**U**niform **N**aming **C**onvention_, + /// e.g. `\\?\UNC\server\share`. + /// + /// Verbatim UNC prefixes consist of `\\?\UNC\` immediately followed by the + /// server's hostname and a share name. #[stable(feature = "rust1", since = "1.0.0")] VerbatimUNC( #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, ), - /// Prefix like `\\?\C:\`, for the given drive letter + /// Verbatim disk prefix, e.g. `\\?\C:\`. + /// + /// Verbatim disk prefixes consist of `\\?\` immediately followed by the + /// drive letter and `:\`. #[stable(feature = "rust1", since = "1.0.0")] VerbatimDisk(#[stable(feature = "rust1", since = "1.0.0")] u8), - /// Prefix `\\.\`, together with the given component immediately following it. + /// Device namespace prefix, e.g. `\\.\COM42`. + /// + /// Device namespace prefixes consist of `\\.\` immediately followed by the + /// device name. #[stable(feature = "rust1", since = "1.0.0")] DeviceNS(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), - /// Prefix `\\server\share`, with the given "server" and "share" components. + /// Prefix using Windows' _**U**niform **N**aming **C**onvention_, e.g. + /// `\\server\share`. + /// + /// UNC prefixes consist of the server's hostname and a share name. #[stable(feature = "rust1", since = "1.0.0")] UNC( #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, @@ -217,6 +226,20 @@ impl<'a> Prefix<'a> { } /// Determines if the prefix is verbatim, i.e. begins with `\\?\`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Prefix::*; + /// use std::ffi::OsStr; + /// + /// assert!(Verbatim(OsStr::new("pictures")).is_verbatim()); + /// assert!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")).is_verbatim()); + /// assert!(VerbatimDisk('C' as u8).is_verbatim()); + /// assert!(!DeviceNS(OsStr::new("BrainInterface")).is_verbatim()); + /// assert!(!UNC(OsStr::new("server"), OsStr::new("share")).is_verbatim()); + /// assert!(!Disk('C' as u8).is_verbatim()); + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_verbatim(&self) -> bool { @@ -356,9 +379,42 @@ enum State { Done = 3, } -/// A Windows path prefix, e.g. `C:` or `\\server\share`. +/// A structure wrapping a Windows path prefix as well as its unparsed string +/// representation. +/// +/// In addition to the parsed [`Prefix`] information returned by [`kind`], +/// `PrefixComponent` also holds the raw and unparsed [`OsStr`] slice, +/// returned by [`as_os_str`]. +/// +/// Instances of this `struct` can be obtained by matching against the +/// [`Prefix` variant] on [`Component`]. /// /// Does not occur on Unix. +/// +/// # Examples +/// +/// ``` +/// # if cfg!(windows) { +/// use std::path::{Component, Path, Prefix}; +/// use std::ffi::OsStr; +/// +/// let path = Path::new(r"c:\you\later\"); +/// match path.components().next().unwrap() { +/// Component::Prefix(prefix_component) => { +/// assert_eq!(Prefix::Disk('C' as u8), prefix_component.kind()); +/// assert_eq!(OsStr::new("c:"), prefix_component.as_os_str()); +/// } +/// _ => unreachable!(), +/// } +/// # } +/// ``` +/// +/// [`as_os_str`]: #method.as_os_str +/// [`Component`]: enum.Component.html +/// [`kind`]: #method.kind +/// [`OsStr`]: ../../std/ffi/struct.OsStr.html +/// [`Prefix` variant]: enum.Component.html#variant.Prefix +/// [`Prefix`]: enum.Prefix.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone, Eq, Debug)] pub struct PrefixComponent<'a> { @@ -370,13 +426,20 @@ pub struct PrefixComponent<'a> { } impl<'a> PrefixComponent<'a> { - /// The parsed prefix data. + /// Returns the parsed prefix data. + /// + /// See [`Prefix`]'s documentation for more information on the different + /// kinds of prefixes. + /// + /// [`Prefix`]: enum.Prefix.html #[stable(feature = "rust1", since = "1.0.0")] pub fn kind(&self) -> Prefix<'a> { self.parsed } - /// The raw `OsStr` slice for this prefix. + /// Returns the raw [`OsStr`] slice for this prefix. + /// + /// [`OsStr`]: ../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(&self) -> &'a OsStr { self.raw @@ -413,11 +476,11 @@ impl<'a> Hash for PrefixComponent<'a> { /// A single component of a path. /// -/// See the module documentation for an in-depth explanation of components and -/// their role in the API. +/// A `Component` roughtly corresponds to a substring between path separators +/// (`/` or `\`). /// -/// This `enum` is created from iterating over the [`path::Components`] -/// `struct`. +/// This `enum` is created by iterating over [`Components`], which in turn is +/// created by the [`components`][`Path::components`] method on [`Path`]. /// /// # Examples /// @@ -434,37 +497,49 @@ impl<'a> Hash for PrefixComponent<'a> { /// ]); /// ``` /// -/// [`path::Components`]: struct.Components.html +/// [`Components`]: struct.Components.html +/// [`Path`]: struct.Path.html +/// [`Path::components`]: struct.Path.html#method.components #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Component<'a> { /// A Windows path prefix, e.g. `C:` or `\\server\share`. /// + /// There is a large variety of prefix types, see [`Prefix`]'s documentation + /// for more. + /// /// Does not occur on Unix. + /// + /// [`Prefix`]: enum.Prefix.html #[stable(feature = "rust1", since = "1.0.0")] Prefix( #[stable(feature = "rust1", since = "1.0.0")] PrefixComponent<'a> ), - /// The root directory component, appears after any prefix and before anything else + /// The root directory component, appears after any prefix and before anything else. + /// + /// It represents a separator that designates that a path starts from root. #[stable(feature = "rust1", since = "1.0.0")] RootDir, - /// A reference to the current directory, i.e. `.` + /// A reference to the current directory, i.e. `.`. #[stable(feature = "rust1", since = "1.0.0")] CurDir, - /// A reference to the parent directory, i.e. `..` + /// A reference to the parent directory, i.e. `..`. #[stable(feature = "rust1", since = "1.0.0")] ParentDir, - /// A normal component, i.e. `a` and `b` in `a/b` + /// A normal component, e.g. `a` and `b` in `a/b`. + /// + /// This variant is the most common one, it represents references to files + /// or directories. #[stable(feature = "rust1", since = "1.0.0")] Normal(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), } impl<'a> Component<'a> { - /// Extracts the underlying `OsStr` slice. + /// Extracts the underlying [`OsStr`] slice. /// /// # Examples /// @@ -475,6 +550,8 @@ impl<'a> Component<'a> { /// let components: Vec<_> = path.components().map(|comp| comp.as_os_str()).collect(); /// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]); /// ``` + /// + /// [`OsStr`]: ../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(self) -> &'a OsStr { match self { @@ -494,12 +571,10 @@ impl<'a> AsRef<OsStr> for Component<'a> { } } -/// The core iterator giving the components of a path. +/// An interator over the [`Component`]s of a [`Path`]. /// -/// See the module documentation for an in-depth explanation of components and -/// their role in the API. -/// -/// This `struct` is created by the [`path::Path::components`] method. +/// This `struct` is created by the [`components`] method on [`Path`]. +/// See its documentation for more. /// /// # Examples /// @@ -513,7 +588,9 @@ impl<'a> AsRef<OsStr> for Component<'a> { /// } /// ``` /// -/// [`path::Path::components`]: struct.Path.html#method.components +/// [`Component`]: enum.Component.html +/// [`components`]: struct.Path.html#method.components +/// [`Path`]: struct.Path.html #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Components<'a> { @@ -534,9 +611,15 @@ pub struct Components<'a> { back: State, } -/// An iterator over the components of a path, as [`OsStr`] slices. +/// An iterator over the [`Component`]s of a [`Path`], as [`OsStr`] slices. /// +/// This `struct` is created by the [`iter`] method on [`Path`]. +/// See its documentation for more. +/// +/// [`Component`]: enum.Component.html +/// [`iter`]: struct.Path.html#method.iter /// [`OsStr`]: ../../std/ffi/struct.OsStr.html +/// [`Path`]: struct.Path.html #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a> { @@ -762,6 +845,18 @@ impl<'a> fmt::Debug for Iter<'a> { impl<'a> Iter<'a> { /// Extracts a slice corresponding to the portion of the path remaining for iteration. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let mut iter = Path::new("/tmp/foo/bar.txt").iter(); + /// iter.next(); + /// iter.next(); + /// + /// assert_eq!(Path::new("foo/bar.txt"), iter.as_path()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn as_path(&self) -> &'a Path { self.inner.as_path() @@ -949,14 +1044,40 @@ impl<'a> cmp::Ord for Components<'a> { /// /// # Examples /// +/// You can use [`push`] to build up a `PathBuf` from +/// components: +/// /// ``` /// use std::path::PathBuf; /// -/// let mut path = PathBuf::from("c:\\"); +/// let mut path = PathBuf::new(); +/// +/// path.push(r"C:\"); /// path.push("windows"); /// path.push("system32"); +/// /// path.set_extension("dll"); /// ``` +/// +/// However, [`push`] is best used for dynamic situations. This is a better way +/// to do this when you know all of the components ahead of time: +/// +/// ``` +/// use std::path::PathBuf; +/// +/// let path: PathBuf = [r"C:\", "windows", "system32.dll"].iter().collect(); +/// ``` +/// +/// We can still do better than this! Since these are all strings, we can use +/// `From::from`: +/// +/// ``` +/// use std::path::PathBuf; +/// +/// let path = PathBuf::from(r"C:\windows\system32.dll"); +/// ``` +/// +/// Which method works best depends on what kind of situation you're in. #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct PathBuf { @@ -1065,13 +1186,14 @@ impl PathBuf { self.inner.push(path); } - /// Truncate `self` to [`self.parent()`]. + /// Truncate `self` to [`self.parent`]. /// - /// Returns false and does nothing if [`self.file_name()`] is `None`. + /// Returns `false` and does nothing if [`self.file_name`] is [`None`]. /// Otherwise, returns `true`. /// - /// [`self.parent()`]: struct.PathBuf.html#method.parent - /// [`self.file_name()`]: struct.PathBuf.html#method.file_name + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`self.parent`]: struct.PathBuf.html#method.parent + /// [`self.file_name`]: struct.PathBuf.html#method.file_name /// /// # Examples /// @@ -1096,13 +1218,18 @@ impl PathBuf { } } - /// Updates [`self.file_name()`] to `file_name`. + /// Updates [`self.file_name`] to `file_name`. /// - /// If [`self.file_name()`] was [`None`], this is equivalent to pushing + /// If [`self.file_name`] was [`None`], this is equivalent to pushing /// `file_name`. /// - /// [`self.file_name()`]: struct.PathBuf.html#method.file_name + /// Otherwise it is equivalent to calling [`pop`] and then pushing + /// `file_name`. The new path will be a sibling of the original path. + /// (That is, it will have the same parent.) + /// + /// [`self.file_name`]: struct.PathBuf.html#method.file_name /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`pop`]: struct.PathBuf.html#method.pop /// /// # Examples /// @@ -1130,15 +1257,16 @@ impl PathBuf { self.push(file_name); } - /// Updates [`self.extension()`] to `extension`. + /// Updates [`self.extension`] to `extension`. /// - /// If [`self.file_name()`] is `None`, does nothing and returns `false`. + /// Returns `false` and does nothing if [`self.file_name`] is [`None`], + /// returns `true` and updates the extension otherwise. /// - /// Otherwise, returns `true`; if [`self.extension()`] is [`None`], the - /// extension is added; otherwise it is replaced. + /// If [`self.extension`] is [`None`], the extension is added; otherwise + /// it is replaced. /// - /// [`self.file_name()`]: struct.PathBuf.html#method.file_name - /// [`self.extension()`]: struct.PathBuf.html#method.extension + /// [`self.file_name`]: struct.PathBuf.html#method.file_name + /// [`self.extension`]: struct.PathBuf.html#method.extension /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Examples @@ -1195,8 +1323,11 @@ impl PathBuf { self.inner } - /// Converts this `PathBuf` into a boxed `Path`. - #[unstable(feature = "into_boxed_path", issue = "0")] + /// Converts this `PathBuf` into a [boxed][`Box`] [`Path`]. + /// + /// [`Box`]: ../../std/boxed/struct.Box.html + /// [`Path`]: struct.Path.html + #[unstable(feature = "into_boxed_path", issue = "40380")] pub fn into_boxed_path(self) -> Box<Path> { unsafe { mem::transmute(self.inner.into_boxed_os_str()) } } @@ -1210,11 +1341,17 @@ impl<'a> From<&'a Path> for Box<Path> { } } -#[stable(feature = "box_default_extra", since = "1.17.0")] -impl Default for Box<Path> { - fn default() -> Box<Path> { - let boxed: Box<OsStr> = Default::default(); - unsafe { mem::transmute(boxed) } +#[stable(feature = "path_buf_from_box", since = "1.18.0")] +impl From<Box<Path>> for PathBuf { + fn from(boxed: Box<Path>) -> PathBuf { + boxed.into_path_buf() + } +} + +#[stable(feature = "box_from_path_buf", since = "1.18.0")] +impl Into<Box<Path>> for PathBuf { + fn into(self) -> Box<Path> { + self.into_boxed_path() } } @@ -1287,7 +1424,7 @@ impl Borrow<Path> for PathBuf { } } -#[stable(feature = "default_for_pathbuf", since = "1.16.0")] +#[stable(feature = "default_for_pathbuf", since = "1.17.0")] impl Default for PathBuf { fn default() -> Self { PathBuf::new() @@ -1316,6 +1453,9 @@ impl ToOwned for Path { fn to_owned(&self) -> PathBuf { self.to_path_buf() } + fn clone_into(&self, target: &mut PathBuf) { + self.inner.clone_into(&mut target.inner); + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1396,10 +1536,14 @@ pub struct Path { inner: OsStr, } -/// An error returned from the [`Path::strip_prefix`] method indicating that the -/// prefix was not found in `self`. +/// An error returned from [`Path::strip_prefix`][`strip_prefix`] if the prefix +/// was not found. +/// +/// This `struct` is created by the [`strip_prefix`] method on [`Path`]. +/// See its documentation for more. /// -/// [`Path::strip_prefix`]: struct.Path.html#method.strip_prefix +/// [`strip_prefix`]: struct.Path.html#method.strip_prefix +/// [`Path`]: struct.Path.html #[derive(Debug, Clone, PartialEq, Eq)] #[stable(since = "1.7.0", feature = "strip_prefix")] pub struct StripPrefixError(()); @@ -1415,7 +1559,7 @@ impl Path { os_str_as_u8_slice(&self.inner) } - /// Directly wrap a string slice as a `Path` slice. + /// Directly wraps a string slice as a `Path` slice. /// /// This is a cost-free conversion. /// @@ -1495,7 +1639,7 @@ impl Path { /// assert_eq!(path.to_string_lossy(), "foo.txt"); /// ``` /// - /// Had `os_str` contained invalid unicode, the `to_string_lossy` call might + /// Had `path` contained invalid unicode, the `to_string_lossy` call might /// have returned `"fo�.txt"`. #[stable(feature = "rust1", since = "1.0.0")] pub fn to_string_lossy(&self) -> Cow<str> { @@ -1519,10 +1663,11 @@ impl Path { PathBuf::from(self.inner.to_os_string()) } - /// A path is *absolute* if it is independent of the current directory. + /// Returns `true` if the `Path` is absolute, i.e. if it is independent of + /// the current directory. /// /// * On Unix, a path is absolute if it starts with the root, so - /// `is_absolute` and `has_root` are equivalent. + /// `is_absolute` and [`has_root`] are equivalent. /// /// * On Windows, a path is absolute if it has a prefix and starts with the /// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not. @@ -1534,6 +1679,8 @@ impl Path { /// /// assert!(!Path::new("foo.txt").is_absolute()); /// ``` + /// + /// [`has_root`]: #method.has_root #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] pub fn is_absolute(&self) -> bool { @@ -1541,7 +1688,9 @@ impl Path { self.has_root() && (cfg!(unix) || cfg!(target_os = "redox") || self.prefix().is_some()) } - /// A path is *relative* if it is not absolute. + /// Return `false` if the `Path` is relative, i.e. not absolute. + /// + /// See [`is_absolute`]'s documentation for more details. /// /// # Examples /// @@ -1550,6 +1699,8 @@ impl Path { /// /// assert!(Path::new("foo.txt").is_relative()); /// ``` + /// + /// [`is_absolute`]: #method.is_absolute #[stable(feature = "rust1", since = "1.0.0")] pub fn is_relative(&self) -> bool { !self.is_absolute() @@ -1559,7 +1710,7 @@ impl Path { self.components().prefix } - /// A path has a root if the body of the path begins with the directory separator. + /// Returns `true` if the `Path` has a root. /// /// * On Unix, a path has a root if it begins with `/`. /// @@ -1580,7 +1731,7 @@ impl Path { self.components().has_root() } - /// The path without its final component, if any. + /// Returns the `Path` without its final component, if there is one. /// /// Returns [`None`] if the path terminates in a root or prefix. /// @@ -1613,9 +1764,12 @@ impl Path { }) } - /// The final component of the path, if it is a normal file. + /// Returns the final component of the `Path`, if there is one. + /// + /// If the path is a normal file, this is the file name. If it's the path of a directory, this + /// is the directory name. /// - /// If the path terminates in `..`, `file_name` will return [`None`]. + /// Returns [`None`] If the path terminates in `..`. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None /// @@ -1625,21 +1779,12 @@ impl Path { /// use std::path::Path; /// use std::ffi::OsStr; /// - /// let path = Path::new("foo.txt"); - /// let os_str = OsStr::new("foo.txt"); - /// - /// assert_eq!(Some(os_str), path.file_name()); - /// ``` - /// - /// # Other examples - /// - /// ``` - /// use std::path::Path; - /// use std::ffi::OsStr; - /// + /// assert_eq!(Some(OsStr::new("bin")), Path::new("/usr/bin/").file_name()); + /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("tmp/foo.txt").file_name()); /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.").file_name()); /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.//").file_name()); /// assert_eq!(None, Path::new("foo.txt/..").file_name()); + /// assert_eq!(None, Path::new("/").file_name()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn file_name(&self) -> Option<&OsStr> { @@ -1733,9 +1878,9 @@ impl Path { iter_after(self.components().rev(), child.components().rev()).is_some() } - /// Extracts the stem (non-extension) portion of [`self.file_name()`]. + /// Extracts the stem (non-extension) portion of [`self.file_name`]. /// - /// [`self.file_name()`]: struct.Path.html#method.file_name + /// [`self.file_name`]: struct.Path.html#method.file_name /// /// The stem is: /// @@ -1760,7 +1905,7 @@ impl Path { self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.or(after)) } - /// Extracts the extension of [`self.file_name()`], if possible. + /// Extracts the extension of [`self.file_name`], if possible. /// /// The extension is: /// @@ -1769,7 +1914,7 @@ impl Path { /// * [`None`], if the file name begins with `.` and has no other `.`s within; /// * Otherwise, the portion of the file name after the final `.` /// - /// [`self.file_name()`]: struct.Path.html#method.file_name + /// [`self.file_name`]: struct.Path.html#method.file_name /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Examples @@ -1825,6 +1970,9 @@ impl Path { /// /// let path = Path::new("/tmp/foo.txt"); /// assert_eq!(path.with_file_name("bar.txt"), PathBuf::from("/tmp/bar.txt")); + /// + /// let path = Path::new("/tmp"); + /// assert_eq!(path.with_file_name("var"), PathBuf::from("/var")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf { @@ -1863,7 +2011,21 @@ impl Path { buf } - /// Produce an iterator over the components of the path. + /// Produces an iterator over the [`Component`]s of the path. + /// + /// When parsing the path, there is a small amount of normalization: + /// + /// * Repeated separators are ignored, so `a/b` and `a//b` both have + /// `a` and `b` as components. + /// + /// * Occurentces of `.` are normalized away, exept if they are at the + /// beginning of the path. For example, `a/./b`, `a/b/`, `a/b/.` and + /// `a/b` all have `a` and `b` as components, but `./a/b` starts with + /// an additional [`CurDir`] component. + /// + /// Note that no other normalization takes place; in particular, `a/c` + /// and `a/b/../c` are distinct, to account for the possibility that `b` + /// is a symbolic link (so its parent isn't `a`). /// /// # Examples /// @@ -1878,6 +2040,9 @@ impl Path { /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("foo.txt")))); /// assert_eq!(components.next(), None) /// ``` + /// + /// [`Component`]: enum.Component.html + /// [`CurDir`]: enum.Component.html#variant.CurDir #[stable(feature = "rust1", since = "1.0.0")] pub fn components(&self) -> Components { let prefix = parse_prefix(self.as_os_str()); @@ -1890,8 +2055,13 @@ impl Path { } } - /// Produce an iterator over the path's components viewed as [`OsStr`] slices. + /// Produces an iterator over the path's components viewed as [`OsStr`] + /// slices. + /// + /// For more information about the particulars of how the path is separated + /// into components, see [`components`]. /// + /// [`components`]: #method.components /// [`OsStr`]: ../ffi/struct.OsStr.html /// /// # Examples @@ -1930,7 +2100,7 @@ impl Path { Display { path: self } } - /// Query the file system to get information about a file, directory, etc. + /// Queries the file system to get information about a file, directory, etc. /// /// This function will traverse symbolic links to query information about the /// destination file. @@ -1953,7 +2123,7 @@ impl Path { fs::metadata(self) } - /// Query the metadata about a file without following symlinks. + /// Queries the metadata about a file without following symlinks. /// /// This is an alias to [`fs::symlink_metadata`]. /// @@ -2089,6 +2259,17 @@ impl Path { pub fn is_dir(&self) -> bool { fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false) } + + /// Converts a [`Box<Path>`][`Box`] into a [`PathBuf`] without copying or + /// allocating. + /// + /// [`Box`]: ../../std/boxed/struct.Box.html + /// [`PathBuf`]: struct.PathBuf.html + #[unstable(feature = "into_boxed_path", issue = "40380")] + pub fn into_path_buf(self: Box<Path>) -> PathBuf { + let inner: Box<OsStr> = unsafe { mem::transmute(self) }; + PathBuf { inner: OsString::from(inner) } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -2105,7 +2286,26 @@ impl fmt::Debug for Path { } } -/// Helper struct for safely printing paths with `format!()` and `{}` +/// Helper struct for safely printing paths with [`format!`] and `{}`. +/// +/// A [`Path`] might contain non-Unicode data. This `struct` implements the +/// [`Display`] trait in a way that mitigates that. It is created by the +/// [`display`][`Path::display`] method on [`Path`]. +/// +/// # Examples +/// +/// ``` +/// use std::path::Path; +/// +/// let path = Path::new("/tmp/foo.rs"); +/// +/// println!("{}", path.display()); +/// ``` +/// +/// [`Display`]: ../../std/fmt/trait.Display.html +/// [`format!`]: ../../std/macro.format.html +/// [`Path`]: struct.Path.html +/// [`Path::display`]: struct.Path.html#method.display #[stable(feature = "rust1", since = "1.0.0")] pub struct Display<'a> { path: &'a Path, @@ -3703,17 +3903,19 @@ mod tests { fn into_boxed() { let orig: &str = "some/sort/of/path"; let path = Path::new(orig); - let path_buf = path.to_owned(); - let box1: Box<Path> = Box::from(path); - let box2 = path_buf.into_boxed_path(); - assert_eq!(path, &*box1); - assert_eq!(box1, box2); - assert_eq!(&*box2, path); + let boxed: Box<Path> = Box::from(path); + let path_buf = path.to_owned().into_boxed_path().into_path_buf(); + assert_eq!(path, &*boxed); + assert_eq!(&*boxed, &*path_buf); + assert_eq!(&*path_buf, path); } #[test] - fn boxed_default() { - let boxed = <Box<Path>>::default(); - assert!(boxed.as_os_str().is_empty()); + fn test_clone_into() { + let mut path_buf = PathBuf::from("supercalifragilisticexpialidocious"); + let path = Path::new("short"); + path.clone_into(&mut path_buf); + assert_eq!(path, path_buf); + assert!(path_buf.into_os_string().capacity() >= 15); } } diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs index f4cd319f064..86e661d7948 100644 --- a/src/libstd/prelude/mod.rs +++ b/src/libstd/prelude/mod.rs @@ -56,14 +56,14 @@ //! traits indicate fundamental properties of types. //! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}. Various //! operations for both destructors and overloading `()`. -//! * [`std::mem`]::[`drop`], a convenience function for explicitly dropping a -//! value. +//! * [`std::mem`]::[`drop`][`mem::drop`], a convenience function for explicitly +//! dropping a value. //! * [`std::boxed`]::[`Box`], a way to allocate values on the heap. //! * [`std::borrow`]::[`ToOwned`], The conversion trait that defines -//! [`to_owned()`], the generic method for creating an owned type from a +//! [`to_owned`], the generic method for creating an owned type from a //! borrowed type. -//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines [`clone()`], -//! the method for producing a copy of a value. +//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines +//! [`clone`][`Clone::clone`], the method for producing a copy of a value. //! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }. The //! comparison traits, which implement the comparison operators and are often //! seen in trait bounds. @@ -117,8 +117,8 @@ //! [`ToOwned`]: ../borrow/trait.ToOwned.html //! [`ToString`]: ../string/trait.ToString.html //! [`Vec`]: ../vec/struct.Vec.html -//! [`clone()`]: ../clone/trait.Clone.html#tymethod.clone -//! [`drop`]: ../mem/fn.drop.html +//! [`Clone::clone`]: ../clone/trait.Clone.html#tymethod.clone +//! [`mem::drop`]: ../mem/fn.drop.html //! [`std::borrow`]: ../borrow/index.html //! [`std::boxed`]: ../boxed/index.html //! [`std::clone`]: ../clone/index.html @@ -135,7 +135,7 @@ //! [`std::slice`]: ../slice/index.html //! [`std::string`]: ../string/index.html //! [`std::vec`]: ../vec/index.html -//! [`to_owned()`]: ../borrow/trait.ToOwned.html#tymethod.to_owned +//! [`to_owned`]: ../borrow/trait.ToOwned.html#tymethod.to_owned //! [book-closures]: ../../book/closures.html //! [book-dtor]: ../../book/drop.html //! [book-enums]: ../../book/enums.html diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 11197db98a3..61ff8daddf0 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -29,7 +29,7 @@ /// ``` /// /// [`assert!`]: macro.assert.html -/// [`if`]: ../book/if.html +/// [`if`]: ../book/first-edition/if.html /// [`BitAnd`]: ops/trait.BitAnd.html /// [`BitOr`]: ops/trait.BitOr.html /// [`Not`]: ops/trait.Not.html @@ -183,9 +183,9 @@ mod prim_unit { } /// Working with raw pointers in Rust is uncommon, /// typically limited to a few patterns. /// -/// Use the `null` function to create null pointers, and the `is_null` method +/// Use the [`null`] function to create null pointers, and the [`is_null`] method /// of the `*const T` type to check for null. The `*const T` type also defines -/// the `offset` method, for pointer math. +/// the [`offset`] method, for pointer math. /// /// # Common ways to create raw pointers /// @@ -213,7 +213,7 @@ mod prim_unit { } /// /// ## 2. Consume a box (`Box<T>`). /// -/// The `into_raw` function consumes a box and returns +/// The [`into_raw`] function consumes a box and returns /// the raw pointer. It doesn't destroy `T` or deallocate any memory. /// /// ``` @@ -227,7 +227,7 @@ mod prim_unit { } /// } /// ``` /// -/// Note that here the call to `drop` is for clarity - it indicates +/// Note that here the call to [`drop`] is for clarity - it indicates /// that we are done with the given value and it should be destroyed. /// /// ## 3. Get it from C. @@ -255,6 +255,11 @@ mod prim_unit { } /// /// *[See also the `std::ptr` module](ptr/index.html).* /// +/// [`null`]: ../std/ptr/fn.null.html +/// [`is_null`]: ../std/primitive.pointer.html#method.is_null +/// [`offset`]: ../std/primitive.pointer.html#method.offset +/// [`into_raw`]: ../std/boxed/struct.Box.html#method.into_raw +/// [`drop`]: ../std/mem/fn.drop.html #[stable(feature = "rust1", since = "1.0.0")] mod prim_pointer { } @@ -272,7 +277,7 @@ mod prim_pointer { } /// Arrays of sizes from 0 to 32 (inclusive) implement the following traits if /// the element type allows it: /// -/// - [`Clone`][clone] (only if `T: [Copy][copy]`) +/// - [`Clone`][clone] (only if `T: `[`Copy`][copy]) /// - [`Debug`][debug] /// - [`IntoIterator`][intoiterator] (implemented for `&[T; N]` and `&mut [T; N]`) /// - [`PartialEq`][partialeq], [`PartialOrd`][partialord], [`Eq`][eq], [`Ord`][ord] @@ -401,7 +406,7 @@ mod prim_slice { } /// /// This documentation describes a number of methods and trait implementations /// on the `str` type. For technical reasons, there is additional, separate -/// documentation in [the `std::str` module](str/index.html) as well. +/// documentation in the [`std::str`](str/index.html) module as well. /// /// # Examples /// @@ -420,7 +425,7 @@ mod prim_slice { } /// # Representation /// /// A `&str` is made up of two components: a pointer to some bytes, and a -/// length. You can look at these with the [`.as_ptr()`] and [`len()`] methods: +/// length. You can look at these with the [`as_ptr`] and [`len`] methods: /// /// ``` /// use std::slice; @@ -447,11 +452,11 @@ mod prim_slice { } /// assert_eq!(s, Ok(story)); /// ``` /// -/// [`.as_ptr()`]: #method.as_ptr -/// [`len()`]: #method.len +/// [`as_ptr`]: #method.as_ptr +/// [`len`]: #method.len /// /// Note: This example shows the internals of `&str`. `unsafe` should not be -/// used to get a string slice under normal circumstances. Use `.as_slice()` +/// used to get a string slice under normal circumstances. Use `as_slice` /// instead. #[stable(feature = "rust1", since = "1.0.0")] mod prim_str { } @@ -490,7 +495,7 @@ mod prim_str { } /// assert_eq!(tuple.2, 'c'); /// ``` /// -/// For more about tuples, see [the book](../book/primitive-types.html#tuples). +/// For more about tuples, see [the book](../book/first-edition/primitive-types.html#tuples). /// /// # Trait implementations /// diff --git a/src/libstd/process.rs b/src/libstd/process.rs index f846ef3e69e..da64704efba 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -73,6 +73,15 @@ use sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; /// spawning process and can itself be constructed using a builder-style /// interface. /// +/// There is no implementation of [`Drop`] for child processes, +/// so if you do not ensure the `Child` has exited then it will continue to +/// run, even after the `Child` handle to the child process has gone out of +/// scope. +/// +/// Calling [`wait`](#method.wait) (or other functions that wrap around it) will make +/// the parent process wait until the child has actually exited before +/// continuing. +/// /// # Examples /// /// ```should_panic @@ -89,17 +98,6 @@ use sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; /// assert!(ecode.success()); /// ``` /// -/// # Note -/// -/// Take note that there is no implementation of [`Drop`] for child processes, -/// so if you do not ensure the `Child` has exited then it will continue to -/// run, even after the `Child` handle to the child process has gone out of -/// scope. -/// -/// Calling [`wait`][`wait`] (or other functions that wrap around it) will make -/// the parent process wait until the child has actually exited before -/// continuing. -/// /// [`Command`]: struct.Command.html /// [`Drop`]: ../../core/ops/trait.Drop.html /// [`wait`]: #method.wait @@ -150,8 +148,9 @@ impl fmt::Debug for Child { } } -/// A handle to a child process's stdin. This struct is used in the [`stdin`] -/// field on [`Child`]. +/// A handle to a child process's stdin. +/// +/// This struct is used in the [`stdin`] field on [`Child`]. /// /// [`Child`]: struct.Child.html /// [`stdin`]: struct.Child.html#structfield.stdin @@ -192,8 +191,9 @@ impl fmt::Debug for ChildStdin { } } -/// A handle to a child process's stdout. This struct is used in the [`stdout`] -/// field on [`Child`]. +/// A handle to a child process's stdout. +/// +/// This struct is used in the [`stdout`] field on [`Child`]. /// /// [`Child`]: struct.Child.html /// [`stdout`]: struct.Child.html#structfield.stdout @@ -233,8 +233,9 @@ impl fmt::Debug for ChildStdout { } } -/// A handle to a child process's stderr. This struct is used in the [`stderr`] -/// field on [`Child`]. +/// A handle to a child process's stderr. +/// +/// This struct is used in the [`stderr`] field on [`Child`]. /// /// [`Child`]: struct.Child.html /// [`stderr`]: struct.Child.html#structfield.stderr @@ -343,6 +344,23 @@ impl Command { /// Add an argument to pass to the program. /// + /// Only one argument can be passed per use. So instead of: + /// + /// ```ignore + /// .arg("-C /path/to/repo") + /// ``` + /// + /// usage would be: + /// + /// ```ignore + /// .arg("-C") + /// .arg("/path/to/repo") + /// ``` + /// + /// To pass multiple arguments see [`args`]. + /// + /// [`args`]: #method.args + /// /// # Examples /// /// Basic usage: @@ -364,6 +382,10 @@ impl Command { /// Add multiple arguments to pass to the program. /// + /// To pass a single argument see [`arg`]. + /// + /// [`arg`]: #method.arg + /// /// # Examples /// /// Basic usage: @@ -416,7 +438,10 @@ impl Command { /// # Examples /// /// Basic usage: + /// /// ```no_run + /// #![feature(command_envs)] + /// /// use std::process::{Command, Stdio}; /// use std::env; /// use std::collections::HashMap; @@ -729,6 +754,13 @@ impl fmt::Debug for Stdio { } /// Describes the result of a process after it has terminated. +/// +/// This `struct` is used to represent the exit status of a child process. +/// Child processes are created via the [`Command`] struct and their exit +/// status is exposed through the [`status`] method. +/// +/// [`Command`]: struct.Command.html +/// [`status`]: struct.Command.html#method.status #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "process", since = "1.0.0")] pub struct ExitStatus(imp::ExitStatus); @@ -763,6 +795,22 @@ impl ExitStatus { /// On Unix, this will return `None` if the process was terminated /// by a signal; `std::os::unix` provides an extension trait for /// extracting the signal and other details from the `ExitStatus`. + /// + /// # Examples + /// + /// ```no_run + /// use std::process::Command; + /// + /// let status = Command::new("mkdir") + /// .arg("projects") + /// .status() + /// .expect("failed to execute mkdir"); + /// + /// match status.code() { + /// Some(code) => println!("Exited with status code: {}", code), + /// None => println!("Process terminated by signal") + /// } + /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn code(&self) -> Option<i32> { self.0.code() @@ -880,8 +928,6 @@ impl Child { /// Basic usage: /// /// ```no_run - /// #![feature(process_try_wait)] - /// /// use std::process::Command; /// /// let mut child = Command::new("ls").spawn().unwrap(); @@ -896,7 +942,7 @@ impl Child { /// Err(e) => println!("error attempting to wait: {}", e), /// } /// ``` - #[unstable(feature = "process_try_wait", issue = "38903")] + #[stable(feature = "process_try_wait", since = "1.18.0")] pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> { Ok(self.handle.try_wait()?.map(ExitStatus)) } @@ -1012,7 +1058,7 @@ impl Child { /// ```no_run /// use std::process; /// -/// process::exit(0x0f00); +/// process::exit(0x0100); /// ``` /// /// [platform-specific behavior]: #platform-specific-behavior @@ -1032,7 +1078,42 @@ pub fn exit(code: i32) -> ! { /// will be run. If a clean shutdown is needed it is recommended to only call /// this function at a known point where there are no more destructors left /// to run. -#[unstable(feature = "process_abort", issue = "37838")] +/// +/// # Examples +/// +/// ```no_run +/// use std::process; +/// +/// fn main() { +/// println!("aborting"); +/// +/// process::abort(); +/// +/// // execution never gets here +/// } +/// ``` +/// +/// The [`abort`] function terminates the process, so the destructor will not +/// get run on the example below: +/// +/// ```no_run +/// use std::process; +/// +/// struct HasDrop; +/// +/// impl Drop for HasDrop { +/// fn drop(&mut self) { +/// println!("This will never be printed!"); +/// } +/// } +/// +/// fn main() { +/// let _x = HasDrop; +/// process::abort(); +/// // the destructor implemented for HasDrop will never get run +/// } +/// ``` +#[stable(feature = "process_abort", since = "1.17.0")] pub fn abort() -> ! { unsafe { ::sys::abort_internal() }; } diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index b853e83de5d..4f33d726398 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -52,7 +52,7 @@ //! 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 +//! - On some systems (e.g. FreeBSD, OpenBSD and macOS) 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.) @@ -195,7 +195,7 @@ impl Rng for ThreadRng { /// A random number generator that retrieves randomness straight from /// the operating system. Platform sources: /// -/// - Unix-like systems (Linux, Android, Mac OSX): read directly from +/// - Unix-like systems (Linux, Android, macOS): 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. diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index 78d5aa597ba..06fd838ea06 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -29,13 +29,14 @@ pub use panicking::{begin_panic, begin_panic_fmt, update_panic_count}; #[cfg(not(test))] #[lang = "start"] -fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { - use mem; +fn lang_start(main: fn(), argc: isize, argv: *const *const u8) -> isize { use panic; use sys; use sys_common; - use sys_common::thread_info::{self, NewThread}; + use sys_common::thread_info; use thread::Thread; + #[cfg(not(feature = "backtrace"))] + use mem; sys::init(); @@ -47,13 +48,18 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { // created. Note that this isn't necessary in general for new threads, // but we just do this to name the main thread and to give it correct // info about the stack bounds. - let thread: Thread = NewThread::new(Some("main".to_owned())); + let thread = Thread::new(Some("main".to_owned())); thread_info::set(main_guard, thread); // Store our args if necessary in a squirreled away location sys::args::init(argc, argv); // Let's run some code! + #[cfg(feature = "backtrace")] + let res = panic::catch_unwind(|| { + ::sys_common::backtrace::__rust_begin_short_backtrace(main) + }); + #[cfg(not(feature = "backtrace"))] let res = panic::catch_unwind(mem::transmute::<_, fn()>(main)); sys_common::cleanup(); res.is_err() diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs index f15e7ff8916..a7b01e49d2b 100644 --- a/src/libstd/sync/barrier.rs +++ b/src/libstd/sync/barrier.rs @@ -50,12 +50,11 @@ struct BarrierState { generation_id: usize, } -/// A result returned from wait. +/// A `BarrierWaitResult` is returned by [`wait`] when all threads in the [`Barrier`] +/// have rendezvoused. /// -/// Currently this opaque structure only has one method, [`.is_leader()`]. Only -/// one thread will receive a result that will return `true` from this function. -/// -/// [`.is_leader()`]: #method.is_leader +/// [`wait`]: struct.Barrier.html#method.wait +/// [`Barrier`]: struct.Barrier.html /// /// # Examples /// diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 68c7e88f67f..c120a3045e4 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -150,7 +150,7 @@ impl Condvar { /// /// This function will atomically unlock the mutex specified (represented by /// `guard`) and block the current thread. This means that any calls - /// to [`notify_one()`] or [`notify_all()`] which happen logically after the + /// to [`notify_one`] or [`notify_all`] which happen logically after the /// mutex is unlocked are candidates to wake this thread up. When this /// function call returns, the lock specified will have been re-acquired. /// @@ -167,16 +167,16 @@ impl Condvar { /// /// # Panics /// - /// This function will [`panic!()`] if it is used with more than one mutex + /// This function will [`panic!`] if it is used with more than one mutex /// over time. Each condition variable is dynamically bound to exactly one /// mutex to ensure defined behavior across platforms. If this functionality /// is not desired, then unsafe primitives in `sys` are provided. /// - /// [`notify_one()`]: #method.notify_one - /// [`notify_all()`]: #method.notify_all + /// [`notify_one`]: #method.notify_one + /// [`notify_all`]: #method.notify_all /// [poisoning]: ../sync/struct.Mutex.html#poisoning /// [`Mutex`]: ../sync/struct.Mutex.html - /// [`panic!()`]: ../../std/macro.panic.html + /// [`panic!`]: ../../std/macro.panic.html /// /// # Examples /// @@ -359,11 +359,11 @@ impl Condvar { /// be woken up from its call to [`wait`] or [`wait_timeout`]. Calls to /// `notify_one` are not buffered in any way. /// - /// To wake up all threads, see [`notify_all()`]. + /// To wake up all threads, see [`notify_all`]. /// /// [`wait`]: #method.wait /// [`wait_timeout`]: #method.wait_timeout - /// [`notify_all()`]: #method.notify_all + /// [`notify_all`]: #method.notify_all /// /// # Examples /// @@ -401,9 +401,9 @@ impl Condvar { /// variable are awoken. Calls to `notify_all()` are not buffered in any /// way. /// - /// To wake up only one thread, see [`notify_one()`]. + /// To wake up only one thread, see [`notify_one`]. /// - /// [`notify_one()`]: #method.notify_one + /// [`notify_one`]: #method.notify_one /// /// # Examples /// @@ -461,7 +461,7 @@ impl fmt::Debug for Condvar { } } -#[stable(feature = "condvar_default", since = "1.9.0")] +#[stable(feature = "condvar_default", since = "1.10.0")] impl Default for Condvar { /// Creates a `Condvar` which is ready to be waited on and notified. fn default() -> Condvar { diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index aeeab170dea..69507cada2b 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -13,40 +13,50 @@ //! This module provides message-based communication over channels, concretely //! defined among three types: //! -//! * `Sender` -//! * `SyncSender` -//! * `Receiver` +//! * [`Sender`] +//! * [`SyncSender`] +//! * [`Receiver`] //! -//! A `Sender` or `SyncSender` is used to send data to a `Receiver`. Both +//! A [`Sender`] or [`SyncSender`] is used to send data to a [`Receiver`]. Both //! senders are clone-able (multi-producer) such that many threads can send //! simultaneously to one receiver (single-consumer). //! //! These channels come in two flavors: //! -//! 1. An asynchronous, infinitely buffered channel. The `channel()` function +//! 1. An asynchronous, infinitely buffered channel. The [`channel`] function //! will return a `(Sender, Receiver)` tuple where all sends will be //! **asynchronous** (they never block). The channel conceptually has an //! infinite buffer. //! -//! 2. A synchronous, bounded channel. The `sync_channel()` function will return -//! a `(SyncSender, Receiver)` tuple where the storage for pending messages -//! is a pre-allocated buffer of a fixed size. All sends will be +//! 2. A synchronous, bounded channel. The [`sync_channel`] function will +//! return a `(SyncSender, Receiver)` tuple where the storage for pending +//! messages is a pre-allocated buffer of a fixed size. All sends will be //! **synchronous** by blocking until there is buffer space available. Note -//! that a bound of 0 is allowed, causing the channel to become a -//! "rendezvous" channel where each sender atomically hands off a message to -//! a receiver. +//! that a bound of 0 is allowed, causing the channel to become a "rendezvous" +//! channel where each sender atomically hands off a message to a receiver. +//! +//! [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html +//! [`SyncSender`]: ../../../std/sync/mpsc/struct.SyncSender.html +//! [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html +//! [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send +//! [`channel`]: ../../../std/sync/mpsc/fn.channel.html +//! [`sync_channel`]: ../../../std/sync/mpsc/fn.sync_channel.html //! //! ## Disconnection //! -//! The send and receive operations on channels will all return a `Result` +//! The send and receive operations on channels will all return a [`Result`] //! indicating whether the operation succeeded or not. An unsuccessful operation //! is normally indicative of the other half of a channel having "hung up" by //! being dropped in its corresponding thread. //! //! Once half of a channel has been deallocated, most operations can no longer -//! continue to make progress, so `Err` will be returned. Many applications will -//! continue to `unwrap()` the results returned from this module, instigating a -//! propagation of failure among threads if one unexpectedly dies. +//! continue to make progress, so [`Err`] will be returned. Many applications +//! will continue to [`unwrap`] the results returned from this module, +//! instigating a propagation of failure among threads if one unexpectedly dies. +//! +//! [`Result`]: ../../../std/result/enum.Result.html +//! [`Err`]: ../../../std/result/enum.Result.html#variant.Err +//! [`unwrap`]: ../../../std/result/enum.Result.html#method.unwrap //! //! # Examples //! @@ -287,8 +297,34 @@ mod sync; mod mpsc_queue; mod spsc_queue; -/// The receiving-half of Rust's channel type. This half can only be owned by -/// one thread +/// The receiving half of Rust's [`channel`][] (or [`sync_channel`]) type. +/// This half can only be owned by one thread. +/// +/// Messages sent to the channel can be retrieved using [`recv`]. +/// +/// [`channel`]: fn.channel.html +/// [`sync_channel`]: fn.sync_channel.html +/// [`recv`]: struct.Receiver.html#method.recv +/// +/// # Examples +/// +/// ```rust +/// use std::sync::mpsc::channel; +/// use std::thread; +/// use std::time::Duration; +/// +/// let (send, recv) = channel(); +/// +/// thread::spawn(move || { +/// send.send("Hello world!").unwrap(); +/// thread::sleep(Duration::from_secs(2)); // block for two seconds +/// send.send("Delayed for 2 seconds").unwrap(); +/// }); +/// +/// println!("{}", recv.recv().unwrap()); // Received immediately +/// println!("Waiting..."); +/// println!("{}", recv.recv().unwrap()); // Received after 2 seconds +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Receiver<T> { inner: UnsafeCell<Flavor<T>>, @@ -302,38 +338,153 @@ unsafe impl<T: Send> Send for Receiver<T> { } #[stable(feature = "rust1", since = "1.0.0")] impl<T> !Sync for Receiver<T> { } -/// An iterator over messages on a receiver, this iterator will block -/// whenever `next` is called, waiting for a new message, and `None` will be -/// returned when the corresponding channel has hung up. +/// An iterator over messages on a [`Receiver`], created by [`iter`]. +/// +/// This iterator will block whenever [`next`] is called, +/// waiting for a new message, and [`None`] will be returned +/// when the corresponding channel has hung up. +/// +/// [`iter`]: struct.Receiver.html#method.iter +/// [`Receiver`]: struct.Receiver.html +/// [`next`]: ../../../std/iter/trait.Iterator.html#tymethod.next +/// [`None`]: ../../../std/option/enum.Option.html#variant.None +/// +/// # Examples +/// +/// ```rust +/// use std::sync::mpsc::channel; +/// use std::thread; +/// +/// let (send, recv) = channel(); +/// +/// thread::spawn(move || { +/// send.send(1u8).unwrap(); +/// send.send(2u8).unwrap(); +/// send.send(3u8).unwrap(); +/// }); +/// +/// for x in recv.iter() { +/// println!("Got: {}", x); +/// } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Iter<'a, T: 'a> { rx: &'a Receiver<T> } -/// An iterator that attempts to yield all pending values for a receiver. -/// `None` will be returned when there are no pending values remaining or +/// An iterator that attempts to yield all pending values for a [`Receiver`], +/// created by [`try_iter`]. +/// +/// [`None`] will be returned when there are no pending values remaining or /// if the corresponding channel has hung up. /// -/// This Iterator will never block the caller in order to wait for data to -/// become available. Instead, it will return `None`. +/// This iterator will never block the caller in order to wait for data to +/// become available. Instead, it will return [`None`]. +/// +/// [`Receiver`]: struct.Receiver.html +/// [`try_iter`]: struct.Receiver.html#method.try_iter +/// [`None`]: ../../../std/option/enum.Option.html#variant.None +/// +/// # Examples +/// +/// ```rust +/// use std::sync::mpsc::channel; +/// use std::thread; +/// use std::time::Duration; +/// +/// let (sender, receiver) = channel(); +/// +/// // Nothing is in the buffer yet +/// assert!(receiver.try_iter().next().is_none()); +/// println!("Nothing in the buffer..."); +/// +/// thread::spawn(move || { +/// sender.send(1).unwrap(); +/// sender.send(2).unwrap(); +/// sender.send(3).unwrap(); +/// }); +/// +/// println!("Going to sleep..."); +/// thread::sleep(Duration::from_secs(2)); // block for two seconds +/// +/// for x in receiver.try_iter() { +/// println!("Got: {}", x); +/// } +/// ``` #[stable(feature = "receiver_try_iter", since = "1.15.0")] #[derive(Debug)] pub struct TryIter<'a, T: 'a> { rx: &'a Receiver<T> } -/// An owning iterator over messages on a receiver, this iterator will block -/// whenever `next` is called, waiting for a new message, and `None` will be -/// returned when the corresponding channel has hung up. +/// An owning iterator over messages on a [`Receiver`], +/// created by **Receiver::into_iter**. +/// +/// This iterator will block whenever [`next`] +/// is called, waiting for a new message, and [`None`] will be +/// returned if the corresponding channel has hung up. +/// +/// [`Receiver`]: struct.Receiver.html +/// [`next`]: ../../../std/iter/trait.Iterator.html#tymethod.next +/// [`None`]: ../../../std/option/enum.Option.html#variant.None +/// +/// # Examples +/// +/// ```rust +/// use std::sync::mpsc::channel; +/// use std::thread; +/// +/// let (send, recv) = channel(); +/// +/// thread::spawn(move || { +/// send.send(1u8).unwrap(); +/// send.send(2u8).unwrap(); +/// send.send(3u8).unwrap(); +/// }); +/// +/// for x in recv.into_iter() { +/// println!("Got: {}", x); +/// } +/// ``` #[stable(feature = "receiver_into_iter", since = "1.1.0")] #[derive(Debug)] pub struct IntoIter<T> { rx: Receiver<T> } -/// The sending-half of Rust's asynchronous channel type. This half can only be +/// The sending-half of Rust's asynchronous [`channel`] type. This half can only be /// owned by one thread, but it can be cloned to send to other threads. +/// +/// Messages can be sent through this channel with [`send`]. +/// +/// [`channel`]: fn.channel.html +/// [`send`]: struct.Sender.html#method.send +/// +/// # Examples +/// +/// ```rust +/// use std::sync::mpsc::channel; +/// use std::thread; +/// +/// let (sender, receiver) = channel(); +/// let sender2 = sender.clone(); +/// +/// // First thread owns sender +/// thread::spawn(move || { +/// sender.send(1).unwrap(); +/// }); +/// +/// // Second thread owns sender2 +/// thread::spawn(move || { +/// sender2.send(2).unwrap(); +/// }); +/// +/// let msg = receiver.recv().unwrap(); +/// let msg2 = receiver.recv().unwrap(); +/// +/// assert_eq!(3, msg + msg2); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Sender<T> { inner: UnsafeCell<Flavor<T>>, @@ -347,8 +498,55 @@ unsafe impl<T: Send> Send for Sender<T> { } #[stable(feature = "rust1", since = "1.0.0")] impl<T> !Sync for Sender<T> { } -/// The sending-half of Rust's synchronous channel type. This half can only be -/// owned by one thread, but it can be cloned to send to other threads. +/// The sending-half of Rust's synchronous [`sync_channel`] type. +/// This half can only be owned by one thread, but it can be cloned +/// to send to other threads. +/// +/// Messages can be sent through this channel with [`send`] or [`try_send`]. +/// +/// [`send`] will block if there is no space in the internal buffer. +/// +/// [`sync_channel`]: fn.sync_channel.html +/// [`send`]: struct.SyncSender.html#method.send +/// [`try_send`]: struct.SyncSender.html#method.try_send +/// +/// # Examples +/// +/// ```rust +/// use std::sync::mpsc::sync_channel; +/// use std::thread; +/// +/// // Create a sync_channel with buffer size 2 +/// let (sync_sender, receiver) = sync_channel(2); +/// let sync_sender2 = sync_sender.clone(); +/// +/// // First thread owns sync_sender +/// thread::spawn(move || { +/// sync_sender.send(1).unwrap(); +/// sync_sender.send(2).unwrap(); +/// }); +/// +/// // Second thread owns sync_sender2 +/// thread::spawn(move || { +/// sync_sender2.send(3).unwrap(); +/// // thread will now block since the buffer is full +/// println!("Thread unblocked!"); +/// }); +/// +/// let mut msg; +/// +/// msg = receiver.recv().unwrap(); +/// println!("message {} received", msg); +/// +/// // "Thread unblocked!" will be printed now +/// +/// msg = receiver.recv().unwrap(); +/// println!("message {} received", msg); +/// +/// msg = receiver.recv().unwrap(); +/// +/// println!("message {} received", msg); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct SyncSender<T> { inner: Arc<sync::Packet<T>>, @@ -360,70 +558,97 @@ unsafe impl<T: Send> Send for SyncSender<T> {} #[stable(feature = "rust1", since = "1.0.0")] impl<T> !Sync for SyncSender<T> {} -/// An error returned from the `send` function on channels. +/// An error returned from the [`Sender::send`] or [`SyncSender::send`] +/// function on **channel**s. /// -/// A `send` operation can only fail if the receiving end of a channel is +/// A **send** operation can only fail if the receiving end of a channel is /// disconnected, implying that the data could never be received. The error /// contains the data being sent as a payload so it can be recovered. +/// +/// [`Sender::send`]: struct.Sender.html#method.send +/// [`SyncSender::send`]: struct.SyncSender.html#method.send #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, Clone, Copy)] pub struct SendError<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T); -/// An error returned from the `recv` function on a `Receiver`. +/// An error returned from the [`recv`] function on a [`Receiver`]. +/// +/// The [`recv`] operation can only fail if the sending half of a +/// [`channel`][`channel`] (or [`sync_channel`]) is disconnected, implying that no further +/// messages will ever be received. /// -/// The `recv` operation can only fail if the sending half of a channel is -/// disconnected, implying that no further messages will ever be received. +/// [`recv`]: struct.Receiver.html#method.recv +/// [`Receiver`]: struct.Receiver.html +/// [`channel`]: fn.channel.html +/// [`sync_channel`]: fn.sync_channel.html #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RecvError; -/// This enumeration is the list of the possible reasons that `try_recv` could -/// not return data when called. +/// This enumeration is the list of the possible reasons that [`try_recv`] could +/// not return data when called. This can occur with both a [`channel`] and +/// a [`sync_channel`]. +/// +/// [`try_recv`]: struct.Receiver.html#method.try_recv +/// [`channel`]: fn.channel.html +/// [`sync_channel`]: fn.sync_channel.html #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum TryRecvError { - /// This channel is currently empty, but the sender(s) have not yet + /// This **channel** is currently empty, but the **Sender**(s) have not yet /// disconnected, so data may yet become available. #[stable(feature = "rust1", since = "1.0.0")] Empty, - /// This channel's sending half has become disconnected, and there will - /// never be any more data received on this channel + /// The **channel**'s sending half has become disconnected, and there will + /// never be any more data received on it. #[stable(feature = "rust1", since = "1.0.0")] Disconnected, } -/// This enumeration is the list of possible errors that `recv_timeout` could -/// not return data when called. +/// This enumeration is the list of possible errors that made [`recv_timeout`] +/// unable to return data when called. This can occur with both a [`channel`] and +/// a [`sync_channel`]. +/// +/// [`recv_timeout`]: struct.Receiver.html#method.recv_timeout +/// [`channel`]: fn.channel.html +/// [`sync_channel`]: fn.sync_channel.html #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] pub enum RecvTimeoutError { - /// This channel is currently empty, but the sender(s) have not yet + /// This **channel** is currently empty, but the **Sender**(s) have not yet /// disconnected, so data may yet become available. #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] Timeout, - /// This channel's sending half has become disconnected, and there will - /// never be any more data received on this channel + /// The **channel**'s sending half has become disconnected, and there will + /// never be any more data received on it. #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] Disconnected, } /// This enumeration is the list of the possible error outcomes for the -/// `SyncSender::try_send` method. +/// [`try_send`] method. +/// +/// [`try_send`]: struct.SyncSender.html#method.try_send #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, Clone, Copy)] pub enum TrySendError<T> { - /// The data could not be sent on the channel because it would require that + /// The data could not be sent on the [`sync_channel`] because it would require that /// the callee block to send the data. /// /// If this is a buffered channel, then the buffer is full at this time. If - /// this is not a buffered channel, then there is no receiver available to + /// this is not a buffered channel, then there is no [`Receiver`] available to /// acquire the data. + /// + /// [`sync_channel`]: fn.sync_channel.html + /// [`Receiver`]: struct.Receiver.html #[stable(feature = "rust1", since = "1.0.0")] Full(#[stable(feature = "rust1", since = "1.0.0")] T), - /// This channel's receiving half has disconnected, so the data could not be + /// This [`sync_channel`]'s receiving half has disconnected, so the data could not be /// sent. The data is returned back to the callee in this case. + /// + /// [`sync_channel`]: fn.sync_channel.html #[stable(feature = "rust1", since = "1.0.0")] Disconnected(#[stable(feature = "rust1", since = "1.0.0")] T), } @@ -457,15 +682,27 @@ impl<T> UnsafeFlavor<T> for Receiver<T> { } /// Creates a new asynchronous channel, returning the sender/receiver halves. -/// All data sent on the sender will become available on the receiver, and no -/// send will block the calling thread (this channel has an "infinite buffer"). +/// All data sent on the [`Sender`] will become available on the [`Receiver`] in +/// the same order as it was sent, and no [`send`] will block the calling thread +/// (this channel has an "infinite buffer", unlike [`sync_channel`], which will +/// block after its buffer limit is reached). [`recv`] will block until a message +/// is available. /// -/// If the [`Receiver`] is disconnected while trying to [`send()`] with the -/// [`Sender`], the [`send()`] method will return an error. +/// The [`Sender`] can be cloned to [`send`] to the same channel multiple times, but +/// only one [`Receiver`] is supported. /// -/// [`send()`]: ../../../std/sync/mpsc/struct.Sender.html#method.send -/// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html -/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html +/// If the [`Receiver`] is disconnected while trying to [`send`] with the +/// [`Sender`], the [`send`] method will return a [`SendError`]. Similarly, If the +/// [`Sender`] is disconnected while trying to [`recv`], the [`recv`] method will +/// return a [`RecvError`]. +/// +/// [`send`]: struct.Sender.html#method.send +/// [`recv`]: struct.Receiver.html#method.recv +/// [`Sender`]: struct.Sender.html +/// [`Receiver`]: struct.Receiver.html +/// [`sync_channel`]: fn.sync_channel.html +/// [`SendError`]: struct.SendError.html +/// [`RecvError`]: struct.RecvError.html /// /// # Examples /// @@ -473,20 +710,18 @@ impl<T> UnsafeFlavor<T> for Receiver<T> { /// use std::sync::mpsc::channel; /// use std::thread; /// -/// // tx is the sending half (tx for transmission), and rx is the receiving -/// // half (rx for receiving). -/// let (tx, rx) = channel(); +/// let (sender, receiver) = channel(); /// /// // Spawn off an expensive computation /// thread::spawn(move|| { /// # fn expensive_computation() {} -/// tx.send(expensive_computation()).unwrap(); +/// sender.send(expensive_computation()).unwrap(); /// }); /// /// // Do some useful work for awhile /// /// // Let's see what that answer was -/// println!("{:?}", rx.recv().unwrap()); +/// println!("{:?}", receiver.recv().unwrap()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn channel<T>() -> (Sender<T>, Receiver<T>) { @@ -495,24 +730,32 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) { } /// Creates a new synchronous, bounded channel. -/// -/// Like asynchronous channels, the [`Receiver`] will block until a message -/// becomes available. These channels differ greatly in the semantics of the -/// sender from asynchronous channels, however. +/// All data sent on the [`SyncSender`] will become available on the [`Receiver`] +/// in the same order as it was sent. Like asynchronous [`channel`]s, the +/// [`Receiver`] will block until a message becomes available. `sync_channel` +/// differs greatly in the semantics of the sender, however. /// /// This channel has an internal buffer on which messages will be queued. /// `bound` specifies the buffer size. When the internal buffer becomes full, /// future sends will *block* waiting for the buffer to open up. Note that a /// buffer size of 0 is valid, in which case this becomes "rendezvous channel" -/// where each [`send()`] will not return until a recv is paired with it. +/// where each [`send`] will not return until a [`recv`] is paired with it. +/// +/// The [`SyncSender`] can be cloned to [`send`] to the same channel multiple +/// times, but only one [`Receiver`] is supported. /// -/// Like asynchronous channels, if the [`Receiver`] is disconnected while -/// trying to [`send()`] with the [`SyncSender`], the [`send()`] method will -/// return an error. +/// Like asynchronous channels, if the [`Receiver`] is disconnected while trying +/// to [`send`] with the [`SyncSender`], the [`send`] method will return a +/// [`SendError`]. Similarly, If the [`SyncSender`] is disconnected while trying +/// to [`recv`], the [`recv`] method will return a [`RecvError`]. /// -/// [`send()`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send -/// [`SyncSender`]: ../../../std/sync/mpsc/struct.SyncSender.html -/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html +/// [`channel`]: fn.channel.html +/// [`send`]: struct.SyncSender.html#method.send +/// [`recv`]: struct.Receiver.html#method.recv +/// [`SyncSender`]: struct.SyncSender.html +/// [`Receiver`]: struct.Receiver.html +/// [`SendError`]: struct.SendError.html +/// [`RecvError`]: struct.RecvError.html /// /// # Examples /// @@ -520,18 +763,18 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) { /// use std::sync::mpsc::sync_channel; /// use std::thread; /// -/// let (tx, rx) = sync_channel(1); +/// let (sender, receiver) = sync_channel(1); /// /// // this returns immediately -/// tx.send(1).unwrap(); +/// sender.send(1).unwrap(); /// /// thread::spawn(move|| { /// // this will block until the previous message has been received -/// tx.send(2).unwrap(); +/// sender.send(2).unwrap(); /// }); /// -/// assert_eq!(rx.recv().unwrap(), 1); -/// assert_eq!(rx.recv().unwrap(), 2); +/// assert_eq!(receiver.recv().unwrap(), 1); +/// assert_eq!(receiver.recv().unwrap(), 2); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn sync_channel<T>(bound: usize) -> (SyncSender<T>, Receiver<T>) { @@ -556,10 +799,13 @@ impl<T> Sender<T> { /// A successful send occurs when it is determined that the other end of /// the channel has not hung up already. An unsuccessful send would be one /// where the corresponding receiver has already been deallocated. Note - /// that a return value of `Err` means that the data will never be - /// received, but a return value of `Ok` does *not* mean that the data + /// that a return value of [`Err`] means that the data will never be + /// received, but a return value of [`Ok`] does *not* mean that the data /// will be received. It is possible for the corresponding receiver to - /// hang up immediately after this function returns `Ok`. + /// hang up immediately after this function returns [`Ok`]. + /// + /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err + /// [`Ok`]: ../../../std/result/enum.Result.html#variant.Ok /// /// This method will never block the current thread. /// @@ -675,7 +921,7 @@ impl<T> Drop for Sender<T> { } } -#[stable(feature = "mpsc_debug", since = "1.7.0")] +#[stable(feature = "mpsc_debug", since = "1.8.0")] impl<T> fmt::Debug for Sender<T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Sender {{ .. }}") @@ -699,12 +945,37 @@ impl<T> SyncSender<T> { /// Note that a successful send does *not* guarantee that the receiver will /// ever see the data if there is a buffer on this channel. Items may be /// enqueued in the internal buffer for the receiver to receive at a later - /// time. If the buffer size is 0, however, it can be guaranteed that the - /// receiver has indeed received the data if this function returns success. + /// time. If the buffer size is 0, however, the channel becomes a rendezvous + /// channel and it guarantees that the receiver has indeed received + /// the data if this function returns success. /// - /// This function will never panic, but it may return `Err` if the - /// `Receiver` has disconnected and is no longer able to receive + /// This function will never panic, but it may return [`Err`] if the + /// [`Receiver`] has disconnected and is no longer able to receive /// information. + /// + /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err + /// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html + /// + /// # Examples + /// + /// ```rust + /// use std::sync::mpsc::sync_channel; + /// use std::thread; + /// + /// // Create a rendezvous sync_channel with buffer size 0 + /// let (sync_sender, receiver) = sync_channel(0); + /// + /// thread::spawn(move || { + /// println!("sending message..."); + /// sync_sender.send(1).unwrap(); + /// // Thread is now blocked until the message is received + /// + /// println!("...message received!"); + /// }); + /// + /// let msg = receiver.recv().unwrap(); + /// assert_eq!(1, msg); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn send(&self, t: T) -> Result<(), SendError<T>> { self.inner.send(t).map_err(SendError) @@ -712,13 +983,53 @@ impl<T> SyncSender<T> { /// Attempts to send a value on this channel without blocking. /// - /// This method differs from `send` by returning immediately if the + /// This method differs from [`send`] by returning immediately if the /// channel's buffer is full or no receiver is waiting to acquire some - /// data. Compared with `send`, this function has two failure cases + /// data. Compared with [`send`], this function has two failure cases /// instead of one (one for disconnection, one for a full buffer). /// - /// See `SyncSender::send` for notes about guarantees of whether the + /// See [`send`] for notes about guarantees of whether the /// receiver has received the data or not if this function is successful. + /// + /// [`send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send + /// + /// # Examples + /// + /// ```rust + /// use std::sync::mpsc::sync_channel; + /// use std::thread; + /// + /// // Create a sync_channel with buffer size 1 + /// let (sync_sender, receiver) = sync_channel(1); + /// let sync_sender2 = sync_sender.clone(); + /// + /// // First thread owns sync_sender + /// thread::spawn(move || { + /// sync_sender.send(1).unwrap(); + /// sync_sender.send(2).unwrap(); + /// // Thread blocked + /// }); + /// + /// // Second thread owns sync_sender2 + /// thread::spawn(move || { + /// // This will return an error and send + /// // no message if the buffer is full + /// sync_sender2.try_send(3).is_err(); + /// }); + /// + /// let mut msg; + /// msg = receiver.recv().unwrap(); + /// println!("message {} received", msg); + /// + /// msg = receiver.recv().unwrap(); + /// println!("message {} received", msg); + /// + /// // Third message may have never been sent + /// match receiver.try_recv() { + /// Ok(msg) => println!("message {} received", msg), + /// Err(_) => println!("the third message was never sent"), + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> { self.inner.try_send(t) @@ -740,7 +1051,7 @@ impl<T> Drop for SyncSender<T> { } } -#[stable(feature = "mpsc_debug", since = "1.7.0")] +#[stable(feature = "mpsc_debug", since = "1.8.0")] impl<T> fmt::Debug for SyncSender<T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "SyncSender {{ .. }}") @@ -756,7 +1067,7 @@ impl<T> Receiver<T> { Receiver { inner: UnsafeCell::new(inner) } } - /// Attempts to return a pending value on this receiver without blocking + /// Attempts to return a pending value on this receiver without blocking. /// /// This method will never block the caller in order to wait for data to /// become available. Instead, this will always return immediately with a @@ -764,6 +1075,21 @@ impl<T> Receiver<T> { /// /// This is useful for a flavor of "optimistic check" before deciding to /// block on a receiver. + /// + /// Compared with [`recv`], this function has two failure cases instead of one + /// (one for disconnection, one for an empty buffer). + /// + /// [`recv`]: struct.Receiver.html#method.recv + /// + /// # Examples + /// + /// ```rust + /// use std::sync::mpsc::{Receiver, channel}; + /// + /// let (_, receiver): (_, Receiver<i32>) = channel(); + /// + /// assert!(receiver.try_recv().is_err()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn try_recv(&self) -> Result<T, TryRecvError> { loop { @@ -819,15 +1145,19 @@ impl<T> Receiver<T> { /// /// This function will always block the current thread if there is no data /// available and it's possible for more data to be sent. Once a message is - /// sent to the corresponding `Sender`, then this receiver will wake up and - /// return that message. + /// sent to the corresponding [`Sender`][] (or [`SyncSender`]), then this + /// receiver will wake up and return that message. /// - /// If the corresponding `Sender` has disconnected, or it disconnects while - /// this call is blocking, this call will wake up and return `Err` to + /// If the corresponding [`Sender`] has disconnected, or it disconnects while + /// this call is blocking, this call will wake up and return [`Err`] to /// indicate that no more messages can ever be received on this channel. /// However, since channels are buffered, messages sent before the disconnect /// will still be properly received. /// + /// [`Sender`]: struct.Sender.html + /// [`SyncSender`]: struct.SyncSender.html + /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err + /// /// # Examples /// /// ``` @@ -907,15 +1237,19 @@ impl<T> Receiver<T> { /// /// This function will always block the current thread if there is no data /// available and it's possible for more data to be sent. Once a message is - /// sent to the corresponding `Sender`, then this receiver will wake up and - /// return that message. + /// sent to the corresponding [`Sender`][] (or [`SyncSender`]), then this + /// receiver will wake up and return that message. /// - /// If the corresponding `Sender` has disconnected, or it disconnects while - /// this call is blocking, this call will wake up and return `Err` to + /// If the corresponding [`Sender`] has disconnected, or it disconnects while + /// this call is blocking, this call will wake up and return [`Err`] to /// indicate that no more messages can ever be received on this channel. /// However, since channels are buffered, messages sent before the disconnect /// will still be properly received. /// + /// [`Sender`]: struct.Sender.html + /// [`SyncSender`]: struct.SyncSender.html + /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err + /// /// # Examples /// /// ```no_run @@ -993,7 +1327,29 @@ impl<T> Receiver<T> { } /// Returns an iterator that will block waiting for messages, but never - /// `panic!`. It will return `None` when the channel has hung up. + /// [`panic!`]. It will return [`None`] when the channel has hung up. + /// + /// [`panic!`]: ../../../std/macro.panic.html + /// [`None`]: ../../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ```rust + /// use std::sync::mpsc::channel; + /// use std::thread; + /// + /// let (send, recv) = channel(); + /// + /// thread::spawn(move || { + /// send.send(1u8).unwrap(); + /// send.send(2u8).unwrap(); + /// send.send(3u8).unwrap(); + /// }); + /// + /// for x in recv.iter() { + /// println!("Got: {}", x); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter<T> { Iter { rx: self } @@ -1001,8 +1357,37 @@ impl<T> Receiver<T> { /// Returns an iterator that will attempt to yield all pending values. /// It will return `None` if there are no more pending values or if the - /// channel has hung up. The iterator will never `panic!` or block the + /// channel has hung up. The iterator will never [`panic!`] or block the /// user by waiting for values. + /// + /// [`panic!`]: ../../../std/macro.panic.html + /// + /// # Examples + /// + /// ```rust + /// use std::sync::mpsc::channel; + /// use std::thread; + /// use std::time::Duration; + /// + /// let (sender, receiver) = channel(); + /// + /// // Nothing is in the buffer yet + /// assert!(receiver.try_iter().next().is_none()); + /// println!("Nothing in the buffer..."); + /// + /// thread::spawn(move || { + /// sender.send(1).unwrap(); + /// sender.send(2).unwrap(); + /// sender.send(3).unwrap(); + /// }); + /// + /// println!("Going to sleep..."); + /// thread::sleep(Duration::from_secs(2)); // block for two seconds + /// + /// for x in receiver.try_iter() { + /// println!("Got: {}", x); + /// } + /// ``` #[stable(feature = "receiver_try_iter", since = "1.15.0")] pub fn try_iter(&self) -> TryIter<T> { TryIter { rx: self } @@ -1132,7 +1517,7 @@ impl<T> Drop for Receiver<T> { } } -#[stable(feature = "mpsc_debug", since = "1.7.0")] +#[stable(feature = "mpsc_debug", since = "1.8.0")] impl<T> fmt::Debug for Receiver<T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Receiver {{ .. }}") @@ -1259,7 +1644,7 @@ impl error::Error for TryRecvError { } } -#[stable(feature = "mpsc_recv_timeout_error", since = "1.14.0")] +#[stable(feature = "mpsc_recv_timeout_error", since = "1.15.0")] impl fmt::Display for RecvTimeoutError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -1273,7 +1658,7 @@ impl fmt::Display for RecvTimeoutError { } } -#[stable(feature = "mpsc_recv_timeout_error", since = "1.14.0")] +#[stable(feature = "mpsc_recv_timeout_error", since = "1.15.0")] impl error::Error for RecvTimeoutError { fn description(&self) -> &str { match *self { diff --git a/src/libstd/sync/mpsc/mpsc_queue.rs b/src/libstd/sync/mpsc/mpsc_queue.rs index 8d80f942ff7..296773d20f6 100644 --- a/src/libstd/sync/mpsc/mpsc_queue.rs +++ b/src/libstd/sync/mpsc/mpsc_queue.rs @@ -1,29 +1,12 @@ -/* Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are - * those of the authors and should not be interpreted as representing official - * policies, either expressed or implied, of Dmitry Vyukov. - */ +// Copyright 2017 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. //! A mostly lock-free multi-producer, single consumer queue. //! diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs index 5858e4b6ddb..1148bc66fba 100644 --- a/src/libstd/sync/mpsc/spsc_queue.rs +++ b/src/libstd/sync/mpsc/spsc_queue.rs @@ -1,31 +1,12 @@ -/* Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are - * those of the authors and should not be interpreted as representing official - * policies, either expressed or implied, of Dmitry Vyukov. - */ - -// http://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue +// Copyright 2017 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. //! A single-producer single-consumer concurrent queue //! @@ -33,6 +14,8 @@ //! concurrently between two threads. This data structure is safe to use and //! enforces the semantics that there is one pusher and one popper. +// http://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue + use alloc::boxed::Box; use core::ptr; use core::cell::UnsafeCell; diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 97b84d59218..9a242a96d46 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -10,7 +10,6 @@ use cell::UnsafeCell; use fmt; -use marker; use mem; use ops::{Deref, DerefMut}; use ptr; @@ -30,7 +29,7 @@ use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; /// /// The mutexes in this module implement a strategy called "poisoning" where a /// mutex is considered poisoned whenever a thread panics while holding the -/// lock. Once a mutex is poisoned, all other threads are unable to access the +/// mutex. Once a mutex is poisoned, all other threads are unable to access the /// data by default as it is likely tainted (some invariant is not being /// upheld). /// @@ -61,7 +60,7 @@ use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; /// let data = Arc::new(Mutex::new(0)); /// /// let (tx, rx) = channel(); -/// for _ in 0..10 { +/// for _ in 0..N { /// let (data, tx) = (data.clone(), tx.clone()); /// thread::spawn(move || { /// // The shared state can only be accessed once the lock is held. @@ -115,7 +114,7 @@ pub struct Mutex<T: ?Sized> { // Note that this mutex is in a *box*, not inlined into the struct itself. // Once a native mutex has been used once, its address can never change (it // can't be moved). This mutex type can be safely moved at any time, so to - // ensure that the native mutex is used correctly we box the inner lock to + // ensure that the native mutex is used correctly we box the inner mutex to // give it a constant address. inner: Box<sys::Mutex>, poison: poison::Flag, @@ -132,16 +131,16 @@ unsafe impl<T: ?Sized + Send> Sync for Mutex<T> { } /// An RAII implementation of a "scoped lock" of a mutex. When this structure is /// dropped (falls out of scope), the lock will be unlocked. /// -/// The data protected by the mutex can be access through this guard via its +/// The data protected by the mutex can be accessed through this guard via its /// [`Deref`] and [`DerefMut`] implementations. /// -/// This structure is created by the [`lock()`] and [`try_lock()`] methods on +/// This structure is created by the [`lock`] and [`try_lock`] methods on /// [`Mutex`]. /// /// [`Deref`]: ../../std/ops/trait.Deref.html /// [`DerefMut`]: ../../std/ops/trait.DerefMut.html -/// [`lock()`]: struct.Mutex.html#method.lock -/// [`try_lock()`]: struct.Mutex.html#method.try_lock +/// [`lock`]: struct.Mutex.html#method.lock +/// [`try_lock`]: struct.Mutex.html#method.try_lock /// [`Mutex`]: struct.Mutex.html #[must_use] #[stable(feature = "rust1", since = "1.0.0")] @@ -153,7 +152,9 @@ pub struct MutexGuard<'a, T: ?Sized + 'a> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized> !marker::Send for MutexGuard<'a, T> {} +impl<'a, T: ?Sized> !Send for MutexGuard<'a, T> { } +#[stable(feature = "mutexguard", since = "1.19.0")] +unsafe impl<'a, T: ?Sized + Sync> Sync for MutexGuard<'a, T> { } impl<T> Mutex<T> { /// Creates a new mutex in an unlocked state ready for use. @@ -183,7 +184,7 @@ impl<T: ?Sized> Mutex<T> { /// Acquires a mutex, blocking the current thread until it is able to do so. /// /// This function will block the local thread until it is available to acquire - /// the mutex. Upon returning, the thread is the only thread with the mutex + /// the mutex. Upon returning, the thread is the only thread with the lock /// held. An RAII guard is returned to allow scoped unlock of the lock. When /// the guard goes out of scope, the mutex will be unlocked. /// @@ -267,9 +268,9 @@ impl<T: ?Sized> Mutex<T> { } } - /// Determines whether the lock is poisoned. + /// Determines whether the mutex is poisoned. /// - /// If another thread is active, the lock can still become poisoned at any + /// If another thread is active, the mutex can still become poisoned at any /// time. You should not trust a `false` value for program correctness /// without additional synchronization. /// @@ -312,7 +313,7 @@ impl<T: ?Sized> Mutex<T> { #[stable(feature = "mutex_into_inner", since = "1.6.0")] pub fn into_inner(self) -> LockResult<T> where T: Sized { // We know statically that there are no outstanding references to - // `self` so there's no need to lock the inner lock. + // `self` so there's no need to lock the inner mutex. // // To get the inner value, we'd like to call `data.into_inner()`, // but because `Mutex` impl-s `Drop`, we can't move out of it, so @@ -353,7 +354,7 @@ impl<T: ?Sized> Mutex<T> { #[stable(feature = "mutex_get_mut", since = "1.6.0")] pub fn get_mut(&mut self) -> LockResult<&mut T> { // We know statically that there are no other references to `self`, so - // there's no need to lock the inner lock. + // there's no need to lock the inner mutex. let data = unsafe { &mut *self.data.get() }; poison::map_result(self.poison.borrow(), |_| data ) } @@ -371,7 +372,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Mutex<T> { } } -#[stable(feature = "mutex_default", since = "1.9.0")] +#[stable(feature = "mutex_default", since = "1.10.0")] impl<T: ?Sized + Default> Default for Mutex<T> { /// Creates a `Mutex<T>`, with the `Default` value for T. fn default() -> Mutex<T> { @@ -459,9 +460,6 @@ mod tests { #[derive(Eq, PartialEq, Debug)] struct NonCopy(i32); - unsafe impl<T: Send> Send for Packet<T> {} - unsafe impl<T> Sync for Packet<T> {} - #[test] fn smoke() { let m = Mutex::new(()); diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 1e7394c0b09..d9edf5d1254 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -72,9 +72,11 @@ use thread::{self, Thread}; /// A synchronization primitive which can be used to run a one-time global /// initialization. Useful for one-time initialization for FFI or related -/// functionality. This type can only be constructed with the `ONCE_INIT` +/// functionality. This type can only be constructed with the [`ONCE_INIT`] /// value. /// +/// [`ONCE_INIT`]: constant.ONCE_INIT.html +/// /// # Examples /// /// ``` @@ -101,15 +103,28 @@ unsafe impl Sync for Once {} #[stable(feature = "rust1", since = "1.0.0")] unsafe impl Send for Once {} -/// State yielded to the `call_once_force` method which can be used to query -/// whether the `Once` was previously poisoned or not. +/// State yielded to the [`call_once_force`] method which can be used to query +/// whether the [`Once`] was previously poisoned or not. +/// +/// [`call_once_force`]: struct.Once.html#method.call_once_force +/// [`Once`]: struct.Once.html #[unstable(feature = "once_poison", issue = "33577")] #[derive(Debug)] pub struct OnceState { poisoned: bool, } -/// Initialization value for static `Once` values. +/// Initialization value for static [`Once`] values. +/// +/// [`Once`]: struct.Once.html +/// +/// # Examples +/// +/// ``` +/// use std::sync::{Once, ONCE_INIT}; +/// +/// static START: Once = ONCE_INIT; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const ONCE_INIT: Once = Once::new(); @@ -212,15 +227,19 @@ impl Once { self.call_inner(false, &mut |_| f.take().unwrap()()); } - /// Performs the same function as `call_once` except ignores poisoning. + /// Performs the same function as [`call_once`] except ignores poisoning. + /// + /// [`call_once`]: struct.Once.html#method.call_once /// /// If this `Once` has been poisoned (some initialization panicked) then /// this function will continue to attempt to call initialization functions /// until one of them doesn't panic. /// - /// The closure `f` is yielded a structure which can be used to query the + /// The closure `f` is yielded a [`OnceState`] structure which can be used to query the /// state of this `Once` (whether initialization has previously panicked or /// not). + /// + /// [`OnceState`]: struct.OnceState.html #[unstable(feature = "once_poison", issue = "33577")] pub fn call_once_force<F>(&'static self, f: F) where F: FnOnce(&OnceState) { // same as above, just with a different parameter to `call_inner`. @@ -366,10 +385,12 @@ impl Drop for Finish { } impl OnceState { - /// Returns whether the associated `Once` has been poisoned. + /// Returns whether the associated [`Once`] has been poisoned. /// - /// Once an initalization routine for a `Once` has panicked it will forever + /// Once an initalization routine for a [`Once`] has panicked it will forever /// indicate to future forced initialization routines that it is poisoned. + /// + /// [`Once`]: struct.Once.html #[unstable(feature = "once_poison", issue = "33577")] pub fn poisoned(&self) -> bool { self.poisoned diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index a3db0adeda0..95bc8d30932 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -78,11 +78,11 @@ unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {} /// RAII structure used to release the shared read access of a lock when /// dropped. /// -/// This structure is created by the [`read()`] and [`try_read()`] methods on +/// This structure is created by the [`read`] and [`try_read`] methods on /// [`RwLock`]. /// -/// [`read()`]: struct.RwLock.html#method.read -/// [`try_read()`]: struct.RwLock.html#method.try_read +/// [`read`]: struct.RwLock.html#method.read +/// [`try_read`]: struct.RwLock.html#method.try_read /// [`RwLock`]: struct.RwLock.html #[must_use] #[stable(feature = "rust1", since = "1.0.0")] @@ -96,11 +96,11 @@ impl<'a, T: ?Sized> !marker::Send for RwLockReadGuard<'a, T> {} /// RAII structure used to release the exclusive write access of a lock when /// dropped. /// -/// This structure is created by the [`write()`] and [`try_write()`] methods +/// This structure is created by the [`write`] and [`try_write`] methods /// on [`RwLock`]. /// -/// [`write()`]: struct.RwLock.html#method.write -/// [`try_write()`]: struct.RwLock.html#method.try_write +/// [`write`]: struct.RwLock.html#method.write +/// [`try_write`]: struct.RwLock.html#method.try_write /// [`RwLock`]: struct.RwLock.html #[must_use] #[stable(feature = "rust1", since = "1.0.0")] @@ -330,7 +330,7 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> { } } -#[stable(feature = "rw_lock_default", since = "1.9.0")] +#[stable(feature = "rw_lock_default", since = "1.10.0")] impl<T: Default> Default for RwLock<T> { /// Creates a new `RwLock<T>`, with the `Default` value for T. fn default() -> RwLock<T> { diff --git a/src/libstd/sys/redox/fast_thread_local.rs b/src/libstd/sys/redox/fast_thread_local.rs index 6eeae2d90ea..7dc61ce6654 100644 --- a/src/libstd/sys/redox/fast_thread_local.rs +++ b/src/libstd/sys/redox/fast_thread_local.rs @@ -12,9 +12,10 @@ #![unstable(feature = "thread_local_internals", issue = "0")] use cell::{Cell, UnsafeCell}; -use intrinsics; +use mem; use ptr; + pub struct Key<T> { inner: UnsafeCell<Option<T>>, @@ -37,7 +38,7 @@ impl<T> Key<T> { pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> { unsafe { - if intrinsics::needs_drop::<T>() && self.dtor_running.get() { + if mem::needs_drop::<T>() && self.dtor_running.get() { return None } self.register_dtor(); @@ -46,7 +47,7 @@ impl<T> Key<T> { } unsafe fn register_dtor(&self) { - if !intrinsics::needs_drop::<T>() || self.dtor_registered.get() { + if !mem::needs_drop::<T>() || self.dtor_registered.get() { return } @@ -96,17 +97,17 @@ pub unsafe extern fn destroy_value<T>(ptr: *mut u8) { // `None`. (*ptr).dtor_running.set(true); - // The OSX implementation of TLS apparently had an odd aspect to it + // The macOS implementation of TLS apparently had an odd aspect to it // where the pointer we have may be overwritten while this destructor // is running. Specifically if a TLS destructor re-accesses TLS it may // trigger a re-initialization of all TLS variables, paving over at // least some destroyed ones with initial values. // - // This means that if we drop a TLS value in place on OSX that we could + // This means that if we drop a TLS value in place on macOS that we could // revert the value to its original state halfway through the // destructor, which would be bad! // - // Hence, we use `ptr::read` on OSX (to move to a "safe" location) + // Hence, we use `ptr::read` on macOS (to move to a "safe" location) // instead of drop_in_place. if cfg!(target_os = "macos") { ptr::read((*ptr).inner.get()); diff --git a/src/libstd/sys/redox/os_str.rs b/src/libstd/sys/redox/os_str.rs index 474d59eed83..c2bba07f68c 100644 --- a/src/libstd/sys/redox/os_str.rs +++ b/src/libstd/sys/redox/os_str.rs @@ -104,6 +104,12 @@ impl Buf { pub fn into_box(self) -> Box<Slice> { unsafe { mem::transmute(self.inner.into_boxed_slice()) } } + + #[inline] + pub fn from_box(boxed: Box<Slice>) -> Buf { + let inner: Box<[u8]> = unsafe { mem::transmute(boxed) }; + Buf { inner: inner.into_vec() } + } } impl Slice { diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index 60dc03fcf47..95e9438cd71 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -249,7 +249,7 @@ impl Command { // mutex, and then after the fork they unlock it. // // Despite this information, libnative's spawn has been witnessed to - // deadlock on both OSX and FreeBSD. I'm not entirely sure why, but + // deadlock on both macOS and FreeBSD. I'm not entirely sure why, but // all collected backtraces point at malloc/free traffic in the // child spawned process. // @@ -270,19 +270,22 @@ impl Command { } if let Some(fd) = stdio.stderr.fd() { - let _ = syscall::close(2); - t!(cvt(syscall::dup(fd, &[]))); - let _ = syscall::close(fd); + t!(cvt(syscall::dup2(fd, 2, &[]))); + let mut flags = t!(cvt(syscall::fcntl(2, syscall::F_GETFL, 0))); + flags &= ! syscall::O_CLOEXEC; + t!(cvt(syscall::fcntl(2, syscall::F_SETFL, flags))); } if let Some(fd) = stdio.stdout.fd() { - let _ = syscall::close(1); - t!(cvt(syscall::dup(fd, &[]))); - let _ = syscall::close(fd); + t!(cvt(syscall::dup2(fd, 1, &[]))); + let mut flags = t!(cvt(syscall::fcntl(1, syscall::F_GETFL, 0))); + flags &= ! syscall::O_CLOEXEC; + t!(cvt(syscall::fcntl(1, syscall::F_SETFL, flags))); } if let Some(fd) = stdio.stdin.fd() { - let _ = syscall::close(0); - t!(cvt(syscall::dup(fd, &[]))); - let _ = syscall::close(fd); + t!(cvt(syscall::dup2(fd, 0, &[]))); + let mut flags = t!(cvt(syscall::fcntl(0, syscall::F_GETFL, 0))); + flags &= ! syscall::O_CLOEXEC; + t!(cvt(syscall::fcntl(0, syscall::F_SETFL, flags))); } if let Some(g) = self.gid { diff --git a/src/libstd/sys/redox/syscall/call.rs b/src/libstd/sys/redox/syscall/call.rs index f58c240f31e..fadf7325d75 100644 --- a/src/libstd/sys/redox/syscall/call.rs +++ b/src/libstd/sys/redox/syscall/call.rs @@ -71,6 +71,11 @@ pub fn dup(fd: usize, buf: &[u8]) -> Result<usize> { unsafe { syscall3(SYS_DUP, fd, buf.as_ptr() as usize, buf.len()) } } +/// Copy and transform a file descriptor +pub fn dup2(fd: usize, newfd: usize, buf: &[u8]) -> Result<usize> { + unsafe { syscall4(SYS_DUP2, fd, newfd, buf.as_ptr() as usize, buf.len()) } +} + /// Replace the current process with a new executable pub fn execve(path: &str, args: &[[usize; 2]]) -> Result<usize> { unsafe { syscall4(SYS_EXECVE, path.as_ptr() as usize, path.len(), diff --git a/src/libstd/sys/redox/syscall/number.rs b/src/libstd/sys/redox/syscall/number.rs index 358746cd20a..98f8b73e4e1 100644 --- a/src/libstd/sys/redox/syscall/number.rs +++ b/src/libstd/sys/redox/syscall/number.rs @@ -28,6 +28,7 @@ pub const SYS_UNLINK: usize = SYS_CLASS_PATH | 10; pub const SYS_CLOSE: usize = SYS_CLASS_FILE | 6; pub const SYS_DUP: usize = SYS_CLASS_FILE | SYS_RET_FILE | 41; +pub const SYS_DUP2: usize = SYS_CLASS_FILE | SYS_RET_FILE | 63; pub const SYS_READ: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 3; pub const SYS_WRITE: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 4; pub const SYS_LSEEK: usize = SYS_CLASS_FILE | 19; diff --git a/src/libstd/sys/redox/thread_local.rs b/src/libstd/sys/redox/thread_local.rs index abdd9ace795..cacd84e2102 100644 --- a/src/libstd/sys/redox/thread_local.rs +++ b/src/libstd/sys/redox/thread_local.rs @@ -64,3 +64,8 @@ pub unsafe fn set(key: Key, value: *mut u8) { pub unsafe fn destroy(key: Key) { keys().remove(&key); } + +#[inline] +pub fn requires_synchronized_create() -> bool { + false +} diff --git a/src/libstd/sys/unix/backtrace/mod.rs b/src/libstd/sys/unix/backtrace/mod.rs index 29d4012dcdf..bf52da2ed4a 100644 --- a/src/libstd/sys/unix/backtrace/mod.rs +++ b/src/libstd/sys/unix/backtrace/mod.rs @@ -13,7 +13,7 @@ /// Some methods of getting a backtrace: /// /// * The backtrace() functions on unix. It turns out this doesn't work very -/// well for green threads on OSX, and the address to symbol portion of it +/// well for green threads on macOS, and the address to symbol portion of it /// suffers problems that are described below. /// /// * Using libunwind. This is more difficult than it sounds because libunwind @@ -51,9 +51,9 @@ /// /// * Use dladdr(). The original backtrace()-based idea actually uses dladdr() /// behind the scenes to translate, and this is why backtrace() was not used. -/// Conveniently, this method works fantastically on OSX. It appears dladdr() +/// Conveniently, this method works fantastically on macOS. It appears dladdr() /// uses magic to consult the local symbol table, or we're putting everything -/// in the dynamic symbol table anyway. Regardless, for OSX, this is the +/// in the dynamic symbol table anyway. Regardless, for macOS, this is the /// method used for translation. It's provided by the system and easy to do.o /// /// Sadly, all other systems have a dladdr() implementation that does not @@ -75,7 +75,7 @@ /// * Use `libbacktrace`. It turns out that this is a small library bundled in /// the gcc repository which provides backtrace and symbol translation /// functionality. All we really need from it is the backtrace functionality, -/// and we only really need this on everything that's not OSX, so this is the +/// and we only really need this on everything that's not macOS, so this is the /// chosen route for now. /// /// In summary, the current situation uses libgcc_s to get a trace of stack diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 1ba4a104e51..d688f2fa504 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -204,7 +204,7 @@ impl SocketAddr { let len = self.len as usize - sun_path_offset(); let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; - // OSX seems to return a len of 16 and a zeroed sun_path for unnamed addresses + // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses if len == 0 || (cfg!(not(target_os = "linux")) && self.addr.sun_path[0] == 0) { AddressKind::Unnamed } else if self.addr.sun_path[0] == 0 { @@ -375,12 +375,12 @@ impl UnixStream { /// Sets the read timeout for the socket. /// - /// If the provided value is [`None`], then [`read()`] calls will block + /// If the provided value is [`None`], then [`read`] calls will block /// indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`read()`]: ../../../../std/io/trait.Read.html#tymethod.read + /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read /// [`Duration`]: ../../../../std/time/struct.Duration.html /// /// # Examples @@ -399,12 +399,12 @@ impl UnixStream { /// Sets the write timeout for the socket. /// - /// If the provided value is [`None`], then [`write()`] calls will block + /// If the provided value is [`None`], then [`write`] calls will block /// indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`read()`]: ../../../../std/io/trait.Write.html#tymethod.write + /// [`read`]: ../../../../std/io/trait.Write.html#tymethod.write /// [`Duration`]: ../../../../std/time/struct.Duration.html /// /// # Examples @@ -641,7 +641,7 @@ impl UnixListener { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path)?; - cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len))?; + cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; cvt(libc::listen(*inner.as_inner(), 128))?; Ok(UnixListener(inner)) @@ -920,7 +920,7 @@ impl UnixDatagram { let socket = UnixDatagram::unbound()?; let (addr, len) = sockaddr_un(path)?; - cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len))?; + cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; Ok(socket) } @@ -974,12 +974,12 @@ impl UnixDatagram { /// Connects the socket to the specified address. /// - /// The [`send()`] method may be used to send data to the specified address. - /// [`recv()`] and [`recv_from()`] will only receive data from that address. + /// The [`send`] method may be used to send data to the specified address. + /// [`recv`] and [`recv_from`] will only receive data from that address. /// - /// [`send()`]: #method.send - /// [`recv()`]: #method.recv - /// [`recv_from()`]: #method.recv_from + /// [`send`]: #method.send + /// [`recv`]: #method.recv + /// [`recv_from`]: #method.recv_from /// /// # Examples /// @@ -1047,9 +1047,9 @@ impl UnixDatagram { /// Returns the address of this socket's peer. /// - /// The [`connect()`] method will connect the socket to a peer. + /// The [`connect`] method will connect the socket to a peer. /// - /// [`connect()`]: #method.connect + /// [`connect`]: #method.connect /// /// # Examples /// @@ -1178,13 +1178,13 @@ impl UnixDatagram { /// Sets the read timeout for the socket. /// - /// If the provided value is [`None`], then [`recv()`] and [`recv_from()`] calls will + /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will /// block indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`recv()`]: #method.recv - /// [`recv_from()`]: #method.recv_from + /// [`recv`]: #method.recv + /// [`recv_from`]: #method.recv_from /// [`Duration`]: ../../../../std/time/struct.Duration.html /// /// # Examples @@ -1203,13 +1203,13 @@ impl UnixDatagram { /// Sets the write timeout for the socket. /// - /// If the provided value is [`None`], then [`send()`] and [`send_to()`] calls will + /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will /// block indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`send()`]: #method.send - /// [`send_to()`]: #method.send_to + /// [`send`]: #method.send + /// [`send_to`]: #method.send_to /// [`Duration`]: ../../../../std/time/struct.Duration.html /// /// # Examples diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs index f4f73646e1b..6b3973de84c 100644 --- a/src/libstd/sys/unix/fast_thread_local.rs +++ b/src/libstd/sys/unix/fast_thread_local.rs @@ -13,7 +13,7 @@ use cell::{Cell, UnsafeCell}; use fmt; -use intrinsics; +use mem; use ptr; pub struct Key<T> { @@ -44,7 +44,7 @@ impl<T> Key<T> { pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> { unsafe { - if intrinsics::needs_drop::<T>() && self.dtor_running.get() { + if mem::needs_drop::<T>() && self.dtor_running.get() { return None } self.register_dtor(); @@ -53,7 +53,7 @@ impl<T> Key<T> { } unsafe fn register_dtor(&self) { - if !intrinsics::needs_drop::<T>() || self.dtor_registered.get() { + if !mem::needs_drop::<T>() || self.dtor_registered.get() { return } @@ -128,7 +128,7 @@ unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { register_dtor_fallback(t, dtor); } -// OSX's analog of the above linux function is this _tlv_atexit function. +// macOS's analog of the above linux function is this _tlv_atexit function. // The disassembly of thread_local globals in C++ (at least produced by // clang) will have this show up in the output. #[cfg(target_os = "macos")] @@ -154,17 +154,17 @@ pub unsafe extern fn destroy_value<T>(ptr: *mut u8) { // `None`. (*ptr).dtor_running.set(true); - // The OSX implementation of TLS apparently had an odd aspect to it + // The macOS implementation of TLS apparently had an odd aspect to it // where the pointer we have may be overwritten while this destructor // is running. Specifically if a TLS destructor re-accesses TLS it may // trigger a re-initialization of all TLS variables, paving over at // least some destroyed ones with initial values. // - // This means that if we drop a TLS value in place on OSX that we could + // This means that if we drop a TLS value in place on macOS that we could // revert the value to its original state halfway through the // destructor, which would be bad! // - // Hence, we use `ptr::read` on OSX (to move to a "safe" location) + // Hence, we use `ptr::read` on macOS (to move to a "safe" location) // instead of drop_in_place. if cfg!(target_os = "macos") { ptr::read((*ptr).inner.get()); diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index c690fd467ee..405fac2b9d7 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -29,7 +29,7 @@ fn max_len() -> usize { // with the man page quoting that if the count of bytes to read is // greater than `SSIZE_MAX` the result is "unspecified". // - // On OSX, however, apparently the 64-bit libc is either buggy or + // On macOS, however, apparently the 64-bit libc is either buggy or // intentionally showing odd behavior by rejecting any read with a size // larger than or equal to INT_MAX. To handle both of these the read // size is capped on both platforms. diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index d0fb96b1ff1..e893a139094 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -439,7 +439,7 @@ impl File { // Linux kernel then the flag is just ignored by the OS, so we continue // to explicitly ask for a CLOEXEC fd here. // - // The CLOEXEC flag, however, is supported on versions of OSX/BSD/etc + // The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc // that we support, so we only do this on Linux currently. if cfg!(target_os = "linux") { fd.set_cloexec()?; @@ -573,7 +573,7 @@ impl fmt::Debug for File { #[cfg(target_os = "macos")] fn get_path(fd: c_int) -> Option<PathBuf> { // FIXME: The use of PATH_MAX is generally not encouraged, but it - // is inevitable in this case because OS X defines `fcntl` with + // is inevitable in this case because macOS defines `fcntl` with // `F_GETPATH` in terms of `MAXPATHLEN`, and there are no // alternatives. If a better method is invented, it should be used // instead. diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index c57751a01d7..854d380d128 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -92,7 +92,7 @@ pub fn init() { #[cfg(not(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia")))] unsafe fn reset_sigpipe() { - assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0); + assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); } #[cfg(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia"))] unsafe fn reset_sigpipe() {} diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 36928696c40..8e41fd009be 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -253,7 +253,12 @@ pub fn current_exe() -> io::Result<PathBuf> { #[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))] pub fn current_exe() -> io::Result<PathBuf> { - ::fs::read_link("/proc/self/exe") + let selfexe = PathBuf::from("/proc/self/exe"); + if selfexe.exists() { + ::fs::read_link(selfexe) + } else { + Err(io::Error::new(io::ErrorKind::Other, "no /proc/self/exe available. Is /proc mounted?")) + } } #[cfg(any(target_os = "macos", target_os = "ios"))] diff --git a/src/libstd/sys/unix/os_str.rs b/src/libstd/sys/unix/os_str.rs index c27599ec020..f5b942d3343 100644 --- a/src/libstd/sys/unix/os_str.rs +++ b/src/libstd/sys/unix/os_str.rs @@ -104,6 +104,12 @@ impl Buf { pub fn into_box(self) -> Box<Slice> { unsafe { mem::transmute(self.inner.into_boxed_slice()) } } + + #[inline] + pub fn from_box(boxed: Box<Slice>) -> Buf { + let inner: Box<[u8]> = unsafe { mem::transmute(boxed) }; + Buf { inner: inner.into_vec() } + } } impl Slice { diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 51e00fc1ab9..706256ff10e 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -8,11 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use cmp; use io; use libc::{self, c_int}; use mem; -use ptr; use sys::{cvt, cvt_r}; use sys::fd::FileDesc; @@ -80,16 +78,14 @@ pub fn read2(p1: AnonPipe, p1.set_nonblocking(true)?; p2.set_nonblocking(true)?; - let max = cmp::max(p1.raw(), p2.raw()); + let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() }; + fds[0].fd = p1.raw(); + fds[0].events = libc::POLLIN; + fds[1].fd = p2.raw(); + fds[1].events = libc::POLLIN; loop { - // wait for either pipe to become readable using `select` - cvt_r(|| unsafe { - let mut read: libc::fd_set = mem::zeroed(); - libc::FD_SET(p1.raw(), &mut read); - libc::FD_SET(p2.raw(), &mut read); - libc::select(max + 1, &mut read, ptr::null_mut(), ptr::null_mut(), - ptr::null_mut()) - })?; + // wait for either pipe to become readable using `poll` + cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?; // Read as much as we can from each pipe, ignoring EWOULDBLOCK or // EAGAIN. If we hit EOF, then this will happen because the underlying @@ -109,11 +105,11 @@ pub fn read2(p1: AnonPipe, } } }; - if read(&p1, v1)? { + if fds[0].revents != 0 && read(&p1, v1)? { p2.set_nonblocking(false)?; return p2.read_to_end(v2).map(|_| ()); } - if read(&p2, v2)? { + if fds[1].revents != 0 && read(&p2, v2)? { p1.set_nonblocking(false)?; return p1.read_to_end(v1).map(|_| ()); } diff --git a/src/libstd/sys/unix/process/magenta.rs b/src/libstd/sys/unix/process/magenta.rs index 07f29784df6..5b5e29c0374 100644 --- a/src/libstd/sys/unix/process/magenta.rs +++ b/src/libstd/sys/unix/process/magenta.rs @@ -202,7 +202,7 @@ pub const LP_CLONE_MXIO_CWD: u32 = 0x0002; // ERR_NO_RESOURCES: The system was not able to allocate some resource // needed for the operation. -#[allow(unused)] pub const ERR_NO_RESOURCES: mx_status_t = -5; +#[allow(unused)] pub const ERR_NO_RESOURCES: mx_status_t = -3; // ERR_NO_MEMORY: The system was not able to allocate memory needed // for the operation. @@ -210,30 +210,34 @@ pub const LP_CLONE_MXIO_CWD: u32 = 0x0002; // ERR_CALL_FAILED: The second phase of mx_channel_call(; did not complete // successfully. -#[allow(unused)] pub const ERR_CALL_FAILED: mx_status_t = -53; +#[allow(unused)] pub const ERR_CALL_FAILED: mx_status_t = -5; + +// ERR_INTERRUPTED_RETRY: The system call was interrupted, but should be +// retried. This should not be seen outside of the VDSO. +#[allow(unused)] pub const ERR_INTERRUPTED_RETRY: mx_status_t = -6; // ======= Parameter errors ======= // ERR_INVALID_ARGS: an argument is invalid, ex. null pointer #[allow(unused)] pub const ERR_INVALID_ARGS: mx_status_t = -10; +// ERR_BAD_HANDLE: A specified handle value does not refer to a handle. +#[allow(unused)] pub const ERR_BAD_HANDLE: mx_status_t = -11; + // ERR_WRONG_TYPE: The subject of the operation is the wrong type to // perform the operation. // Example: Attempting a message_read on a thread handle. -#[allow(unused)] pub const ERR_WRONG_TYPE: mx_status_t = -54; +#[allow(unused)] pub const ERR_WRONG_TYPE: mx_status_t = -12; // ERR_BAD_SYSCALL: The specified syscall number is invalid. -#[allow(unused)] pub const ERR_BAD_SYSCALL: mx_status_t = -11; - -// ERR_BAD_HANDLE: A specified handle value does not refer to a handle. -#[allow(unused)] pub const ERR_BAD_HANDLE: mx_status_t = -12; +#[allow(unused)] pub const ERR_BAD_SYSCALL: mx_status_t = -13; // ERR_OUT_OF_RANGE: An argument is outside the valid range for this // operation. -#[allow(unused)] pub const ERR_OUT_OF_RANGE: mx_status_t = -13; +#[allow(unused)] pub const ERR_OUT_OF_RANGE: mx_status_t = -14; // ERR_BUFFER_TOO_SMALL: A caller provided buffer is too small for // this operation. -#[allow(unused)] pub const ERR_BUFFER_TOO_SMALL: mx_status_t = -14; +#[allow(unused)] pub const ERR_BUFFER_TOO_SMALL: mx_status_t = -15; // ======= Precondition or state errors ======= // ERR_BAD_STATE: operation failed because the current state of the @@ -241,47 +245,48 @@ pub const LP_CLONE_MXIO_CWD: u32 = 0x0002; // not satisfied #[allow(unused)] pub const ERR_BAD_STATE: mx_status_t = -20; +// ERR_TIMED_OUT: The time limit for the operation elapsed before +// the operation completed. +#[allow(unused)] pub const ERR_TIMED_OUT: mx_status_t = -21; + +// ERR_SHOULD_WAIT: The operation cannot be performed currently but +// potentially could succeed if the caller waits for a prerequisite +// to be satisfied, for example waiting for a handle to be readable +// or writable. +// Example: Attempting to read from a message pipe that has no +// messages waiting but has an open remote will return ERR_SHOULD_WAIT. +// Attempting to read from a message pipe that has no messages waiting +// and has a closed remote end will return ERR_REMOTE_CLOSED. +#[allow(unused)] pub const ERR_SHOULD_WAIT: mx_status_t = -22; + +// ERR_CANCELED: The in-progress operation (e.g. a wait) has been +// // canceled. +#[allow(unused)] pub const ERR_CANCELED: mx_status_t = -23; + +// ERR_PEER_CLOSED: The operation failed because the remote end +// of the subject of the operation was closed. +#[allow(unused)] pub const ERR_PEER_CLOSED: mx_status_t = -24; + // ERR_NOT_FOUND: The requested entity is not found. -#[allow(unused)] pub const ERR_NOT_FOUND: mx_status_t = -3; +#[allow(unused)] pub const ERR_NOT_FOUND: mx_status_t = -25; // ERR_ALREADY_EXISTS: An object with the specified identifier // already exists. // Example: Attempting to create a file when a file already exists // with that name. -#[allow(unused)] pub const ERR_ALREADY_EXISTS: mx_status_t = -15; +#[allow(unused)] pub const ERR_ALREADY_EXISTS: mx_status_t = -26; // ERR_ALREADY_BOUND: The operation failed because the named entity // is already owned or controlled by another entity. The operation // could succeed later if the current owner releases the entity. -#[allow(unused)] pub const ERR_ALREADY_BOUND: mx_status_t = -16; - -// ERR_TIMED_OUT: The time limit for the operation elapsed before -// the operation completed. -#[allow(unused)] pub const ERR_TIMED_OUT: mx_status_t = -23; - -// ERR_HANDLE_CLOSED: a handle being waited on was closed -#[allow(unused)] pub const ERR_HANDLE_CLOSED: mx_status_t = -24; - -// ERR_REMOTE_CLOSED: The operation failed because the remote end -// of the subject of the operation was closed. -#[allow(unused)] pub const ERR_REMOTE_CLOSED: mx_status_t = -25; +#[allow(unused)] pub const ERR_ALREADY_BOUND: mx_status_t = -27; // ERR_UNAVAILABLE: The subject of the operation is currently unable // to perform the operation. // Note: This is used when there's no direct way for the caller to // observe when the subject will be able to perform the operation // and should thus retry. -#[allow(unused)] pub const ERR_UNAVAILABLE: mx_status_t = -26; - -// ERR_SHOULD_WAIT: The operation cannot be performed currently but -// potentially could succeed if the caller waits for a prerequisite -// to be satisfied, for example waiting for a handle to be readable -// or writable. -// Example: Attempting to read from a message pipe that has no -// messages waiting but has an open remote will return ERR_SHOULD_WAIT. -// Attempting to read from a message pipe that has no messages waiting -// and has a closed remote end will return ERR_REMOTE_CLOSED. -#[allow(unused)] pub const ERR_SHOULD_WAIT: mx_status_t = -27; +#[allow(unused)] pub const ERR_UNAVAILABLE: mx_status_t = -28; // ======= Permission check errors ======= // ERR_ACCESS_DENIED: The caller did not have permission to perform @@ -312,3 +317,7 @@ pub const LP_CLONE_MXIO_CWD: u32 = 0x0002; #[allow(unused)] pub const ERR_BAD_PATH: mx_status_t = -50; #[allow(unused)] pub const ERR_NOT_DIR: mx_status_t = -51; #[allow(unused)] pub const ERR_NOT_FILE: mx_status_t = -52; +// ERR_FILE_BIG: A file exceeds a filesystem-specific size limit. +#[allow(unused)] pub const ERR_FILE_BIG: mx_status_t = -53; +// ERR_NO_SPACE: Filesystem or device space is exhausted. +#[allow(unused)] pub const ERR_NO_SPACE: mx_status_t = -54; diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index a4536520376..e9f41009064 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -417,13 +417,27 @@ mod tests { } } + // Android with api less than 21 define sig* functions inline, so it is not + // available for dynamic link. Implementing sigemptyset and sigaddset allow us + // to support older Android version (independent of libc version). + // The following implementations are based on https://git.io/vSkNf + #[cfg(not(target_os = "android"))] extern { + #[cfg_attr(target_os = "netbsd", link_name = "__sigemptyset14")] + fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")] fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int; } #[cfg(target_os = "android")] + unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int { + libc::memset(set as *mut _, 0, mem::size_of::<libc::sigset_t>()); + return 0; + } + + #[cfg(target_os = "android")] unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int { use slice; @@ -434,8 +448,8 @@ mod tests { } // See #14232 for more information, but it appears that signal delivery to a - // newly spawned process may just be raced in the OSX, so to prevent this - // test from being flaky we ignore it on OSX. + // newly spawned process may just be raced in the macOS, so to prevent this + // test from being flaky we ignore it on macOS. #[test] #[cfg_attr(target_os = "macos", ignore)] #[cfg_attr(target_os = "nacl", ignore)] // no signals on NaCl. @@ -450,7 +464,7 @@ mod tests { let mut set: libc::sigset_t = mem::uninitialized(); let mut old_set: libc::sigset_t = mem::uninitialized(); - t!(cvt(libc::sigemptyset(&mut set))); + t!(cvt(sigemptyset(&mut set))); t!(cvt(sigaddset(&mut set, libc::SIGINT))); t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut old_set))); diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index bbc987209e3..edd322ca6fa 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -129,7 +129,7 @@ impl Command { // mutex, and then after the fork they unlock it. // // Despite this information, libnative's spawn has been witnessed to - // deadlock on both OSX and FreeBSD. I'm not entirely sure why, but + // deadlock on both macOS and FreeBSD. I'm not entirely sure why, but // all collected backtraces point at malloc/free traffic in the // child spawned process. // @@ -193,7 +193,16 @@ impl Command { // need to clean things up now to avoid confusing the program // we're about to run. let mut set: libc::sigset_t = mem::uninitialized(); - t!(cvt(libc::sigemptyset(&mut set))); + if cfg!(target_os = "android") { + // Implementing sigemptyset allow us to support older Android + // versions. See the comment about Android and sig* functions in + // process_common.rs + libc::memset(&mut set as *mut _ as *mut _, + 0, + mem::size_of::<libc::sigset_t>()); + } else { + t!(cvt(libc::sigemptyset(&mut set))); + } t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, ptr::null_mut()))); let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL); diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 22d47ba0f62..51adbc24ae0 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -187,7 +187,7 @@ mod imp { let stack = libc::stack_t { ss_sp: ptr::null_mut(), ss_flags: SS_DISABLE, - // Workaround for bug in MacOS implementation of sigaltstack + // Workaround for bug in macOS implementation of sigaltstack // UNIX2003 which returns ENOMEM when disabling a stack while // passing ss_size smaller than MINSIGSTKSZ. According to POSIX // both ss_sp and ss_size should be ignored in this case. diff --git a/src/libstd/sys/unix/thread_local.rs b/src/libstd/sys/unix/thread_local.rs index d22118d4d79..2487f6bcaf7 100644 --- a/src/libstd/sys/unix/thread_local.rs +++ b/src/libstd/sys/unix/thread_local.rs @@ -38,3 +38,8 @@ pub unsafe fn destroy(key: Key) { let r = libc::pthread_key_delete(key); debug_assert_eq!(r, 0); } + +#[inline] +pub fn requires_synchronized_create() -> bool { + false +} diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index a08cec38f73..a1ad94872de 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -157,7 +157,7 @@ mod inner { pub fn sub_duration(&self, other: &Duration) -> Instant { Instant { t: self.t.checked_sub(dur2intervals(other)) - .expect("overflow when adding duration to instant"), + .expect("overflow when subtracting duration from instant"), } } } diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 4daab31c28f..1646f8cce72 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -14,8 +14,9 @@ #![cfg_attr(test, allow(dead_code))] #![unstable(issue = "0", feature = "windows_c")] -use os::raw::{c_int, c_uint, c_ulong, c_long, c_longlong, c_ushort,}; -use os::raw::{c_char, c_ulonglong}; +use os::raw::{c_int, c_uint, c_ulong, c_long, c_longlong, c_ushort, c_char}; +#[cfg(target_arch = "x86_64")] +use os::raw::c_ulonglong; use libc::{wchar_t, size_t, c_void}; use ptr; @@ -45,7 +46,7 @@ pub type SIZE_T = usize; pub type WORD = u16; pub type CHAR = c_char; pub type HCRYPTPROV = LONG_PTR; -pub type ULONG_PTR = c_ulonglong; +pub type ULONG_PTR = usize; pub type ULONG = c_ulong; #[cfg(target_arch = "x86_64")] pub type ULONGLONG = u64; @@ -198,7 +199,10 @@ pub const ERROR_TIMEOUT: DWORD = 0x5B4; pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE; +pub const FACILITY_NT_BIT: DWORD = 0x1000_0000; + pub const FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000; +pub const FORMAT_MESSAGE_FROM_HMODULE: DWORD = 0x00000800; pub const FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200; pub const TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF; @@ -935,7 +939,6 @@ extern "system" { args: *const c_void) -> DWORD; pub fn TlsAlloc() -> DWORD; - pub fn TlsFree(dwTlsIndex: DWORD) -> BOOL; pub fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID; pub fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL; pub fn GetLastError() -> DWORD; diff --git a/src/libstd/sys/windows/ext/ffi.rs b/src/libstd/sys/windows/ext/ffi.rs index 253787546c1..3f6c2827a3f 100644 --- a/src/libstd/sys/windows/ext/ffi.rs +++ b/src/libstd/sys/windows/ext/ffi.rs @@ -26,8 +26,22 @@ pub trait OsStringExt { /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of /// 16-bit code units. /// - /// This is lossless: calling `.encode_wide()` on the resulting string + /// This is lossless: calling [`encode_wide`] on the resulting string /// will always return the original code units. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// use std::os::windows::prelude::*; + /// + /// // UTF-16 encoding for "Unicode". + /// let source = [0x0055, 0x006E, 0x0069, 0x0063, 0x006F, 0x0064, 0x0065]; + /// + /// let string = OsString::from_wide(&source[..]); + /// ``` + /// + /// [`encode_wide`]: ./trait.OsStrExt.html#tymethod.encode_wide #[stable(feature = "rust1", since = "1.0.0")] fn from_wide(wide: &[u16]) -> Self; } @@ -42,11 +56,29 @@ impl OsStringExt for OsString { /// Windows-specific extensions to `OsStr`. #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStrExt { - /// Re-encodes an `OsStr` as a wide character sequence, - /// i.e. potentially ill-formed UTF-16. + /// Re-encodes an `OsStr` as a wide character sequence, i.e. potentially + /// ill-formed UTF-16. + /// + /// This is lossless: calling [`OsString::from_wide`] and then + /// `encode_wide` on the result will yield the original code units. + /// Note that the encoding does not add a final null terminator. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// use std::os::windows::prelude::*; + /// + /// // UTF-16 encoding for "Unicode". + /// let source = [0x0055, 0x006E, 0x0069, 0x0063, 0x006F, 0x0064, 0x0065]; + /// + /// let string = OsString::from_wide(&source[..]); + /// + /// let result: Vec<u16> = string.encode_wide().collect(); + /// assert_eq!(&source[..], &result[..]); + /// ``` /// - /// This is lossless. Note that the encoding does not include a final - /// null. + /// [`OsString::from_wide`]: ./trait.OsStringExt.html#tymethod.from_wide #[stable(feature = "rust1", since = "1.0.0")] fn encode_wide(&self) -> EncodeWide; } diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs index c63dd8a47ca..2d00cb38ec4 100644 --- a/src/libstd/sys/windows/ext/fs.rs +++ b/src/libstd/sys/windows/ext/fs.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Windows-specific extensions for the primitives in `std::fs` +//! Windows-specific extensions for the primitives in the `std::fs` module. #![stable(feature = "rust1", since = "1.0.0")] @@ -18,7 +18,9 @@ use path::Path; use sys; use sys_common::{AsInnerMut, AsInner}; -/// Windows-specific extensions to `File` +/// Windows-specific extensions to [`File`]. +/// +/// [`File`]: ../../../fs/struct.File.html #[stable(feature = "file_offset", since = "1.15.0")] pub trait FileExt { /// Seeks to a given position and reads a number of bytes. @@ -35,6 +37,24 @@ pub trait FileExt { /// Note that similar to `File::read`, it is not an error to return with a /// short read. When returning from such a short read, the file pointer is /// still updated. + /// + /// # Examples + /// + /// ```no_run + /// use std::io; + /// use std::fs::File; + /// use std::os::windows::prelude::*; + /// + /// # fn foo() -> io::Result<()> { + /// let mut file = File::open("foo.txt")?; + /// let mut buffer = [0; 10]; + /// + /// // Read 10 bytes, starting 72 bytes from the + /// // start of the file. + /// file.seek_read(&mut buffer[..], 72)?; + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "file_offset", since = "1.15.0")] fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>; @@ -52,6 +72,22 @@ pub trait FileExt { /// Note that similar to `File::write`, it is not an error to return a /// short write. When returning from such a short write, the file pointer /// is still updated. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use std::os::windows::prelude::*; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut buffer = File::create("foo.txt")?; + /// + /// // Write a byte string starting 72 bytes from + /// // the start of the file. + /// buffer.seek_write(b"some bytes", 72)?; + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "file_offset", since = "1.15.0")] fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize>; } @@ -67,84 +103,97 @@ impl FileExt for fs::File { } } -/// Windows-specific extensions to `OpenOptions` +/// Windows-specific extensions to [`OpenOptions`]. +/// +/// [`OpenOptions`]: ../../../fs/struct.OpenOptions.html #[stable(feature = "open_options_ext", since = "1.10.0")] pub trait OpenOptionsExt { - /// Overrides the `dwDesiredAccess` argument to the call to `CreateFile` + /// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`] /// with the specified value. /// /// This will override the `read`, `write`, and `append` flags on the /// `OpenOptions` structure. This method provides fine-grained control over /// the permissions to read, write and append data, attributes (like hidden - /// and system) and extended attributes. + /// and system), and extended attributes. /// /// # Examples /// /// ```no_run /// use std::fs::OpenOptions; - /// use std::os::windows::fs::OpenOptionsExt; + /// use std::os::windows::prelude::*; /// /// // Open without read and write permission, for example if you only need - /// // to call `stat()` on the file + /// // to call `stat` on the file /// let file = OpenOptions::new().access_mode(0).open("foo.txt"); /// ``` + /// + /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx #[stable(feature = "open_options_ext", since = "1.10.0")] fn access_mode(&mut self, access: u32) -> &mut Self; - /// Overrides the `dwShareMode` argument to the call to `CreateFile` with + /// Overrides the `dwShareMode` argument to the call to [`CreateFile`] with /// the specified value. /// /// By default `share_mode` is set to - /// `FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE`. Specifying - /// less permissions denies others to read from, write to and/or delete the - /// file while it is open. + /// `FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE`. This allows + /// other processes to to read, write, and delete/rename the same file + /// while it is open. Removing any of the flags will prevent other + /// processes from performing the corresponding operation until the file + /// handle is closed. /// /// # Examples /// /// ```no_run /// use std::fs::OpenOptions; - /// use std::os::windows::fs::OpenOptionsExt; + /// use std::os::windows::prelude::*; /// /// // Do not allow others to read or modify this file while we have it open - /// // for writing - /// let file = OpenOptions::new().write(true) - /// .share_mode(0) - /// .open("foo.txt"); + /// // for writing. + /// let file = OpenOptions::new() + /// .write(true) + /// .share_mode(0) + /// .open("foo.txt"); /// ``` + /// + /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx #[stable(feature = "open_options_ext", since = "1.10.0")] fn share_mode(&mut self, val: u32) -> &mut Self; /// Sets extra flags for the `dwFileFlags` argument to the call to - /// `CreateFile2` (or combines it with `attributes` and `security_qos_flags` - /// to set the `dwFlagsAndAttributes` for `CreateFile`). + /// [`CreateFile2`] to the specified value (or combines it with + /// `attributes` and `security_qos_flags` to set the `dwFlagsAndAttributes` + /// for [`CreateFile`]). /// - /// Custom flags can only set flags, not remove flags set by Rusts options. - /// This options overwrites any previously set custom flags. + /// Custom flags can only set flags, not remove flags set by Rust's options. + /// This option overwrites any previously set custom flags. /// /// # Examples /// - /// ```rust,ignore + /// ```ignore /// extern crate winapi; + /// /// use std::fs::OpenOptions; - /// use std::os::windows::fs::OpenOptionsExt; - /// - /// let mut options = OpenOptions::new(); - /// options.create(true).write(true); - /// if cfg!(windows) { - /// options.custom_flags(winapi::FILE_FLAG_DELETE_ON_CLOSE); - /// } - /// let file = options.open("foo.txt"); + /// use std::os::windows::prelude::*; + /// + /// let file = OpenOptions::new() + /// .create(true) + /// .write(true) + /// .custom_flags(winapi::FILE_FLAG_DELETE_ON_CLOSE) + /// .open("foo.txt"); /// ``` + /// + /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx + /// [`CreateFile2`]: https://msdn.microsoft.com/en-us/library/windows/desktop/hh449422.aspx #[stable(feature = "open_options_ext", since = "1.10.0")] fn custom_flags(&mut self, flags: u32) -> &mut Self; - /// Sets the `dwFileAttributes` argument to the call to `CreateFile2` to + /// Sets the `dwFileAttributes` argument to the call to [`CreateFile2`] to /// the specified value (or combines it with `custom_flags` and /// `security_qos_flags` to set the `dwFlagsAndAttributes` for - /// `CreateFile`). + /// [`CreateFile`]). /// /// If a _new_ file is created because it does not yet exist and - ///`.create(true)` or `.create_new(true)` are specified, the new file is + /// `.create(true)` or `.create_new(true)` are specified, the new file is /// given the attributes declared with `.attributes()`. /// /// If an _existing_ file is opened with `.create(true).truncate(true)`, its @@ -155,21 +204,52 @@ pub trait OpenOptionsExt { /// /// # Examples /// - /// ```rust,ignore + /// ```ignore /// extern crate winapi; + /// /// use std::fs::OpenOptions; - /// use std::os::windows::fs::OpenOptionsExt; + /// use std::os::windows::prelude::*; /// - /// let file = OpenOptions::new().write(true).create(true) - /// .attributes(winapi::FILE_ATTRIBUTE_HIDDEN) - /// .open("foo.txt"); + /// let file = OpenOptions::new() + /// .write(true) + /// .create(true) + /// .attributes(winapi::FILE_ATTRIBUTE_HIDDEN) + /// .open("foo.txt"); /// ``` + /// + /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx + /// [`CreateFile2`]: https://msdn.microsoft.com/en-us/library/windows/desktop/hh449422.aspx #[stable(feature = "open_options_ext", since = "1.10.0")] fn attributes(&mut self, val: u32) -> &mut Self; - /// Sets the `dwSecurityQosFlags` argument to the call to `CreateFile2` to + /// Sets the `dwSecurityQosFlags` argument to the call to [`CreateFile2`] to /// the specified value (or combines it with `custom_flags` and `attributes` - /// to set the `dwFlagsAndAttributes` for `CreateFile`). + /// to set the `dwFlagsAndAttributes` for [`CreateFile`]). + /// + /// By default, `security_qos_flags` is set to `SECURITY_ANONYMOUS`. For + /// information about possible values, see [Impersonation Levels] on the + /// Windows Dev Center site. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::OpenOptions; + /// use std::os::windows::prelude::*; + /// + /// let file = OpenOptions::new() + /// .write(true) + /// .create(true) + /// + /// // Sets the flag value to `SecurityIdentification`. + /// .security_qos_flags(1) + /// + /// .open("foo.txt"); + /// ``` + /// + /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx + /// [`CreateFile2`]: https://msdn.microsoft.com/en-us/library/windows/desktop/hh449422.aspx + /// [Impersonation Levels]: + /// https://msdn.microsoft.com/en-us/library/windows/desktop/aa379572.aspx #[stable(feature = "open_options_ext", since = "1.10.0")] fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions; } @@ -197,35 +277,136 @@ impl OpenOptionsExt for OpenOptions { } } -/// Extension methods for `fs::Metadata` to access the raw fields contained +/// Extension methods for [`fs::Metadata`] to access the raw fields contained /// within. +/// +/// The data members that this trait exposes correspond to the members +/// of the [`BY_HANDLE_FILE_INFORMATION`] structure. +/// +/// [`fs::Metadata`]: ../../../fs/struct.Metadata.html +/// [`BY_HANDLE_FILE_INFORMATION`]: +/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363788.aspx #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Returns the value of the `dwFileAttributes` field of this metadata. /// /// This field contains the file system attribute information for a file - /// or directory. + /// or directory. For possible values and their descriptions, see + /// [File Attribute Constants] in the Windows Dev Center. + /// + /// # Examples + /// + /// ```no_run + /// use std::io; + /// use std::fs; + /// use std::os::windows::prelude::*; + /// + /// # fn foo() -> io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; + /// let attributes = metadata.file_attributes(); + /// # Ok(()) + /// # } + /// ``` + /// + /// [File Attribute Constants]: + /// https://msdn.microsoft.com/en-us/library/windows/desktop/gg258117.aspx #[stable(feature = "metadata_ext", since = "1.1.0")] fn file_attributes(&self) -> u32; /// Returns the value of the `ftCreationTime` field of this metadata. /// - /// The returned 64-bit value represents the number of 100-nanosecond - /// intervals since January 1, 1601 (UTC). + /// The returned 64-bit value is equivalent to a [`FILETIME`] struct, + /// which represents the number of 100-nanosecond intervals since + /// January 1, 1601 (UTC). The struct is automatically + /// converted to a `u64` value, as that is the recommended way + /// to use it. + /// + /// If the underlying filesystem does not support creation time, the + /// returned value is 0. + /// + /// # Examples + /// + /// ```no_run + /// use std::io; + /// use std::fs; + /// use std::os::windows::prelude::*; + /// + /// # fn foo() -> io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; + /// let creation_time = metadata.creation_time(); + /// # Ok(()) + /// # } + /// ``` + /// + /// [`FILETIME`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx #[stable(feature = "metadata_ext", since = "1.1.0")] fn creation_time(&self) -> u64; /// Returns the value of the `ftLastAccessTime` field of this metadata. /// - /// The returned 64-bit value represents the number of 100-nanosecond - /// intervals since January 1, 1601 (UTC). + /// The returned 64-bit value is equivalent to a [`FILETIME`] struct, + /// which represents the number of 100-nanosecond intervals since + /// January 1, 1601 (UTC). The struct is automatically + /// converted to a `u64` value, as that is the recommended way + /// to use it. + /// + /// For a file, the value specifies the last time that a file was read + /// from or written to. For a directory, the value specifies when + /// the directory was created. For both files and directories, the + /// specified date is correct, but the time of day is always set to + /// midnight. + /// + /// If the underlying filesystem does not support last access time, the + /// returned value is 0. + /// + /// # Examples + /// + /// ```no_run + /// use std::io; + /// use std::fs; + /// use std::os::windows::prelude::*; + /// + /// # fn foo() -> io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; + /// let last_access_time = metadata.last_access_time(); + /// # Ok(()) + /// # } + /// ``` + /// + /// [`FILETIME`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx #[stable(feature = "metadata_ext", since = "1.1.0")] fn last_access_time(&self) -> u64; /// Returns the value of the `ftLastWriteTime` field of this metadata. /// - /// The returned 64-bit value represents the number of 100-nanosecond - /// intervals since January 1, 1601 (UTC). + /// The returned 64-bit value is equivalent to a [`FILETIME`] struct, + /// which represents the number of 100-nanosecond intervals since + /// January 1, 1601 (UTC). The struct is automatically + /// converted to a `u64` value, as that is the recommended way + /// to use it. + /// + /// For a file, the value specifies the last time that a file was written + /// to. For a directory, the structure specifies when the directory was + /// created. + /// + /// If the underlying filesystem does not support the last write time + /// time, the returned value is 0. + /// + /// # Examples + /// + /// ```no_run + /// use std::io; + /// use std::fs; + /// use std::os::windows::prelude::*; + /// + /// # fn foo() -> io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; + /// let last_write_time = metadata.last_write_time(); + /// # Ok(()) + /// # } + /// ``` + /// + /// [`FILETIME`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx #[stable(feature = "metadata_ext", since = "1.1.0")] fn last_write_time(&self) -> u64; @@ -233,6 +414,20 @@ pub trait MetadataExt { /// metadata. /// /// The returned value does not have meaning for directories. + /// + /// # Examples + /// + /// ```no_run + /// use std::io; + /// use std::fs; + /// use std::os::windows::prelude::*; + /// + /// # fn foo() -> io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; + /// let file_size = metadata.file_size(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn file_size(&self) -> u64; } @@ -253,7 +448,7 @@ impl MetadataExt for Metadata { /// /// # Examples /// -/// ```ignore +/// ```no_run /// use std::os::windows::fs; /// /// # fn foo() -> std::io::Result<()> { @@ -274,7 +469,7 @@ pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) /// /// # Examples /// -/// ```ignore +/// ```no_run /// use std::os::windows::fs; /// /// # fn foo() -> std::io::Result<()> { diff --git a/src/libstd/sys/windows/ext/mod.rs b/src/libstd/sys/windows/ext/mod.rs index f12e50cc923..11b1337a8ae 100644 --- a/src/libstd/sys/windows/ext/mod.rs +++ b/src/libstd/sys/windows/ext/mod.rs @@ -8,11 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Experimental extensions to `std` for Windows. +//! Platform-specific extensions to `std` for Windows. //! -//! For now, this module is limited to extracting handles, file -//! descriptors, and sockets, but its functionality will grow over -//! time. +//! Provides access to platform-level information for Windows, and exposes +//! Windows-specific idioms that would otherwise be inappropriate as part +//! the core `std` library. These extensions allow developers to use +//! `std` types and idioms with Windows in a way that the normal +//! platform-agnostic idioms would not normally support. #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index 1419a4af427..759f055c4b1 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -104,6 +104,7 @@ pub trait CommandExt { /// Sets the [process creation flags][1] to be passed to `CreateProcess`. /// /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`. + /// /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx #[stable(feature = "windows_process_extensions", since = "1.16.0")] fn creation_flags(&mut self, flags: u32) -> &mut process::Command; diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index 7e28dd1e259..a51b458451e 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -32,7 +32,7 @@ pub fn errno() -> i32 { } /// Gets a detailed string description for the given error number. -pub fn error_string(errnum: i32) -> String { +pub fn error_string(mut errnum: i32) -> String { // This value is calculated from the macro // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) let langId = 0x0800 as c::DWORD; @@ -40,9 +40,27 @@ pub fn error_string(errnum: i32) -> String { let mut buf = [0 as c::WCHAR; 2048]; unsafe { - let res = c::FormatMessageW(c::FORMAT_MESSAGE_FROM_SYSTEM | + let mut module = ptr::null_mut(); + let mut flags = 0; + + // NTSTATUS errors may be encoded as HRESULT, which may returned from + // GetLastError. For more information about Windows error codes, see + // `[MS-ERREF]`: https://msdn.microsoft.com/en-us/library/cc231198.aspx + if (errnum & c::FACILITY_NT_BIT as i32) != 0 { + // format according to https://support.microsoft.com/en-us/help/259693 + const NTDLL_DLL: &'static [u16] = &['N' as _, 'T' as _, 'D' as _, 'L' as _, 'L' as _, + '.' as _, 'D' as _, 'L' as _, 'L' as _, 0]; + module = c::GetModuleHandleW(NTDLL_DLL.as_ptr()); + + if module != ptr::null_mut() { + errnum ^= c::FACILITY_NT_BIT as i32; + flags = c::FORMAT_MESSAGE_FROM_HMODULE; + } + } + + let res = c::FormatMessageW(flags | c::FORMAT_MESSAGE_FROM_SYSTEM | c::FORMAT_MESSAGE_IGNORE_INSERTS, - ptr::null_mut(), + module, errnum as c::DWORD, langId, buf.as_mut_ptr(), @@ -299,3 +317,17 @@ pub fn home_dir() -> Option<PathBuf> { pub fn exit(code: i32) -> ! { unsafe { c::ExitProcess(code as c::UINT) } } + +#[cfg(test)] +mod tests { + use io::Error; + use sys::c; + + // tests `error_string` above + #[test] + fn ntstatus_error() { + const STATUS_UNSUCCESSFUL: u32 = 0xc000_0001; + assert!(!Error::from_raw_os_error((STATUS_UNSUCCESSFUL | c::FACILITY_NT_BIT) as _) + .to_string().contains("FormatMessageW() returned error")); + } +} diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index b02b06e1ef2..f401e7b35c8 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -97,6 +97,12 @@ impl Buf { pub fn into_box(self) -> Box<Slice> { unsafe { mem::transmute(self.inner.into_box()) } } + + #[inline] + pub fn from_box(boxed: Box<Slice>) -> Buf { + let inner: Box<Wtf8> = unsafe { mem::transmute(boxed) }; + Buf { inner: Wtf8Buf::from_box(inner) } + } } impl Slice { diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 1afb3728c9d..dfbc1b581ee 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -257,8 +257,13 @@ impl Stdio { // INVALID_HANDLE_VALUE. Stdio::Inherit => { match stdio::get(stdio_id) { - Ok(io) => io.handle().duplicate(0, true, - c::DUPLICATE_SAME_ACCESS), + Ok(io) => { + let io = Handle::new(io.handle()); + let ret = io.duplicate(0, true, + c::DUPLICATE_SAME_ACCESS); + io.into_raw(); + return ret + } Err(..) => Ok(Handle::new(c::INVALID_HANDLE_VALUE)), } } diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index b1a57c349fb..d72e4b4438b 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -22,42 +22,43 @@ use sys::cvt; use sys::handle::Handle; use sys_common::io::read_to_end_uninitialized; -pub struct NoClose(Option<Handle>); - pub enum Output { - Console(NoClose), - Pipe(NoClose), + Console(c::HANDLE), + Pipe(c::HANDLE), } pub struct Stdin { - handle: Output, utf8: Mutex<io::Cursor<Vec<u8>>>, } -pub struct Stdout(Output); -pub struct Stderr(Output); +pub struct Stdout; +pub struct Stderr; pub fn get(handle: c::DWORD) -> io::Result<Output> { let handle = unsafe { c::GetStdHandle(handle) }; if handle == c::INVALID_HANDLE_VALUE { Err(io::Error::last_os_error()) } else if handle.is_null() { - Err(io::Error::new(io::ErrorKind::Other, - "no stdio handle available for this process")) + Err(io::Error::from_raw_os_error(c::ERROR_INVALID_HANDLE as i32)) } else { - let ret = NoClose::new(handle); let mut out = 0; match unsafe { c::GetConsoleMode(handle, &mut out) } { - 0 => Ok(Output::Pipe(ret)), - _ => Ok(Output::Console(ret)), + 0 => Ok(Output::Pipe(handle)), + _ => Ok(Output::Console(handle)), } } } -fn write(out: &Output, data: &[u8]) -> io::Result<usize> { - let handle = match *out { - Output::Console(ref c) => c.get().raw(), - Output::Pipe(ref p) => return p.get().write(data), +fn write(handle: c::DWORD, data: &[u8]) -> io::Result<usize> { + let handle = match try!(get(handle)) { + Output::Console(c) => c, + Output::Pipe(p) => { + let handle = Handle::new(p); + let ret = handle.write(data); + handle.into_raw(); + return ret + } }; + // As with stdin on windows, stdout often can't handle writes of large // sizes. For an example, see #14940. For this reason, don't try to // write the entire output buffer on windows. @@ -93,18 +94,20 @@ fn write(out: &Output, data: &[u8]) -> io::Result<usize> { impl Stdin { pub fn new() -> io::Result<Stdin> { - get(c::STD_INPUT_HANDLE).map(|handle| { - Stdin { - handle: handle, - utf8: Mutex::new(Cursor::new(Vec::new())), - } + Ok(Stdin { + utf8: Mutex::new(Cursor::new(Vec::new())), }) } pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { - let handle = match self.handle { - Output::Console(ref c) => c.get().raw(), - Output::Pipe(ref p) => return p.get().read(buf), + let handle = match try!(get(c::STD_INPUT_HANDLE)) { + Output::Console(c) => c, + Output::Pipe(p) => { + let handle = Handle::new(p); + let ret = handle.read(buf); + handle.into_raw(); + return ret + } }; let mut utf8 = self.utf8.lock().unwrap(); // Read more if the buffer is empty @@ -125,11 +128,9 @@ impl Stdin { Ok(utf8) => utf8.into_bytes(), Err(..) => return Err(invalid_encoding()), }; - if let Output::Console(_) = self.handle { - if let Some(&last_byte) = data.last() { - if last_byte == CTRL_Z { - data.pop(); - } + if let Some(&last_byte) = data.last() { + if last_byte == CTRL_Z { + data.pop(); } } *utf8 = Cursor::new(data); @@ -158,11 +159,11 @@ impl<'a> Read for &'a Stdin { impl Stdout { pub fn new() -> io::Result<Stdout> { - get(c::STD_OUTPUT_HANDLE).map(Stdout) + Ok(Stdout) } pub fn write(&self, data: &[u8]) -> io::Result<usize> { - write(&self.0, data) + write(c::STD_OUTPUT_HANDLE, data) } pub fn flush(&self) -> io::Result<()> { @@ -172,11 +173,11 @@ impl Stdout { impl Stderr { pub fn new() -> io::Result<Stderr> { - get(c::STD_ERROR_HANDLE).map(Stderr) + Ok(Stderr) } pub fn write(&self, data: &[u8]) -> io::Result<usize> { - write(&self.0, data) + write(c::STD_ERROR_HANDLE, data) } pub fn flush(&self) -> io::Result<()> { @@ -197,27 +198,12 @@ impl io::Write for Stderr { } } -impl NoClose { - fn new(handle: c::HANDLE) -> NoClose { - NoClose(Some(Handle::new(handle))) - } - - fn get(&self) -> &Handle { self.0.as_ref().unwrap() } -} - -impl Drop for NoClose { - fn drop(&mut self) { - self.0.take().unwrap().into_raw(); - } -} - impl Output { - pub fn handle(&self) -> &Handle { - let nc = match *self { - Output::Console(ref c) => c, - Output::Pipe(ref c) => c, - }; - nc.0.as_ref().unwrap() + pub fn handle(&self) -> c::HANDLE { + match *self { + Output::Console(c) => c, + Output::Pipe(c) => c, + } } } diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs index 597f05622a5..ad57f87dc1f 100644 --- a/src/libstd/sys/windows/thread_local.rs +++ b/src/libstd/sys/windows/thread_local.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use mem; use ptr; +use sync::atomic::AtomicPtr; +use sync::atomic::Ordering::SeqCst; use sys::c; -use sys_common::mutex::Mutex; -use sys_common; pub type Key = c::DWORD; pub type Dtor = unsafe extern fn(*mut u8); @@ -34,8 +35,6 @@ pub type Dtor = unsafe extern fn(*mut u8); // * All TLS destructors are tracked by *us*, not the windows runtime. This // means that we have a global list of destructors for each TLS key that // we know about. -// * When a TLS key is destroyed, we're sure to remove it from the dtor list -// if it's in there. // * When a thread exits, we run over the entire list and run dtors for all // non-null keys. This attempts to match Unix semantics in this regard. // @@ -50,13 +49,6 @@ pub type Dtor = unsafe extern fn(*mut u8); // [2]: https://github.com/ChromiumWebApps/chromium/blob/master/base // /threading/thread_local_storage_win.cc#L42 -// NB these are specifically not types from `std::sync` as they currently rely -// on poisoning and this module needs to operate at a lower level than requiring -// the thread infrastructure to be in place (useful on the borders of -// initialization/destruction). -static DTOR_LOCK: Mutex = Mutex::new(); -static mut DTORS: *mut Vec<(Key, Dtor)> = ptr::null_mut(); - // ------------------------------------------------------------------------- // Native bindings // @@ -85,81 +77,64 @@ pub unsafe fn get(key: Key) -> *mut u8 { } #[inline] -pub unsafe fn destroy(key: Key) { - if unregister_dtor(key) { - // FIXME: Currently if a key has a destructor associated with it we - // can't actually ever unregister it. If we were to - // unregister it, then any key destruction would have to be - // serialized with respect to actually running destructors. - // - // We want to avoid a race where right before run_dtors runs - // some destructors TlsFree is called. Allowing the call to - // TlsFree would imply that the caller understands that *all - // known threads* are not exiting, which is quite a difficult - // thing to know! - // - // For now we just leak all keys with dtors to "fix" this. - // Note that source [2] above shows precedent for this sort - // of strategy. - } else { - let r = c::TlsFree(key); - debug_assert!(r != 0); - } +pub unsafe fn destroy(_key: Key) { + rtabort!("can't destroy tls keys on windows") +} + +#[inline] +pub fn requires_synchronized_create() -> bool { + true } // ------------------------------------------------------------------------- // Dtor registration // -// These functions are associated with registering and unregistering -// destructors. They're pretty simple, they just push onto a vector and scan -// a vector currently. +// Windows has no native support for running destructors so we manage our own +// list of destructors to keep track of how to destroy keys. We then install a +// callback later to get invoked whenever a thread exits, running all +// appropriate destructors. // -// FIXME: This could probably be at least a little faster with a BTree. - -unsafe fn init_dtors() { - if !DTORS.is_null() { return } +// Currently unregistration from this list is not supported. A destructor can be +// registered but cannot be unregistered. There's various simplifying reasons +// for doing this, the big ones being: +// +// 1. Currently we don't even support deallocating TLS keys, so normal operation +// doesn't need to deallocate a destructor. +// 2. There is no point in time where we know we can unregister a destructor +// because it could always be getting run by some remote thread. +// +// Typically processes have a statically known set of TLS keys which is pretty +// small, and we'd want to keep this memory alive for the whole process anyway +// really. +// +// Perhaps one day we can fold the `Box` here into a static allocation, +// expanding the `StaticKey` structure to contain not only a slot for the TLS +// key but also a slot for the destructor queue on windows. An optimization for +// another day! - let dtors = box Vec::<(Key, Dtor)>::new(); +static DTORS: AtomicPtr<Node> = AtomicPtr::new(ptr::null_mut()); - let res = sys_common::at_exit(move|| { - DTOR_LOCK.lock(); - let dtors = DTORS; - DTORS = 1 as *mut _; - Box::from_raw(dtors); - assert!(DTORS as usize == 1); // can't re-init after destructing - DTOR_LOCK.unlock(); - }); - if res.is_ok() { - DTORS = Box::into_raw(dtors); - } else { - DTORS = 1 as *mut _; - } +struct Node { + dtor: Dtor, + key: Key, + next: *mut Node, } unsafe fn register_dtor(key: Key, dtor: Dtor) { - DTOR_LOCK.lock(); - init_dtors(); - assert!(DTORS as usize != 0); - assert!(DTORS as usize != 1, - "cannot create new TLS keys after the main thread has exited"); - (*DTORS).push((key, dtor)); - DTOR_LOCK.unlock(); -} + let mut node = Box::new(Node { + key: key, + dtor: dtor, + next: ptr::null_mut(), + }); -unsafe fn unregister_dtor(key: Key) -> bool { - DTOR_LOCK.lock(); - init_dtors(); - assert!(DTORS as usize != 0); - assert!(DTORS as usize != 1, - "cannot unregister destructors after the main thread has exited"); - let ret = { - let dtors = &mut *DTORS; - let before = dtors.len(); - dtors.retain(|&(k, _)| k != key); - dtors.len() != before - }; - DTOR_LOCK.unlock(); - ret + let mut head = DTORS.load(SeqCst); + loop { + node.next = head; + match DTORS.compare_exchange(head, &mut *node, SeqCst, SeqCst) { + Ok(_) => return mem::forget(node), + Err(cur) => head = cur, + } + } } // ------------------------------------------------------------------------- @@ -196,16 +171,12 @@ unsafe fn unregister_dtor(key: Key) -> bool { // # Ok, what's up with running all these destructors? // // This will likely need to be improved over time, but this function -// attempts a "poor man's" destructor callback system. To do this we clone a -// local copy of the dtor list to start out with. This is our fudgy attempt -// to not hold the lock while destructors run and not worry about the list -// changing while we're looking at it. -// -// Once we've got a list of what to run, we iterate over all keys, check -// their values, and then run destructors if the values turn out to be non -// null (setting them to null just beforehand). We do this a few times in a -// loop to basically match Unix semantics. If we don't reach a fixed point -// after a short while then we just inevitably leak something most likely. +// attempts a "poor man's" destructor callback system. Once we've got a list +// of what to run, we iterate over all keys, check their values, and then run +// destructors if the values turn out to be non null (setting them to null just +// beforehand). We do this a few times in a loop to basically match Unix +// semantics. If we don't reach a fixed point after a short while then we just +// inevitably leak something most likely. // // # The article mentions weird stuff about "/INCLUDE"? // @@ -259,25 +230,21 @@ unsafe extern "system" fn on_tls_callback(h: c::LPVOID, unsafe fn run_dtors() { let mut any_run = true; for _ in 0..5 { - if !any_run { break } + if !any_run { + break + } any_run = false; - let dtors = { - DTOR_LOCK.lock(); - let ret = if DTORS as usize <= 1 { - Vec::new() - } else { - (*DTORS).iter().map(|s| *s).collect() - }; - DTOR_LOCK.unlock(); - ret - }; - for &(key, dtor) in &dtors { - let ptr = c::TlsGetValue(key); + let mut cur = DTORS.load(SeqCst); + while !cur.is_null() { + let ptr = c::TlsGetValue((*cur).key); + if !ptr.is_null() { - c::TlsSetValue(key, ptr::null_mut()); - dtor(ptr as *mut _); + c::TlsSetValue((*cur).key, ptr::null_mut()); + ((*cur).dtor)(ptr as *mut _); any_run = true; } + + cur = (*cur).next; } } } diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 99297b781e4..617218fe7a5 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -19,7 +19,7 @@ use io; use libc; use str; use sync::atomic::{self, Ordering}; -use path::Path; +use path::{self, Path}; use sys::mutex::Mutex; use ptr; @@ -93,6 +93,8 @@ fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> { Ok(()) } +/// Returns a number of frames to remove at the beginning and at the end of the +/// backtrace, according to the backtrace format. fn filter_frames(frames: &[Frame], format: PrintFormat, context: &BacktraceContext) -> (usize, usize) @@ -101,74 +103,23 @@ fn filter_frames(frames: &[Frame], return (0, 0); } - // We want to filter out frames with some prefixes - // from both top and bottom of the call stack. - static BAD_PREFIXES_TOP: &'static [&'static str] = &[ - "_ZN3std3sys3imp9backtrace", - "ZN3std3sys3imp9backtrace", - "std::sys::imp::backtrace", - "_ZN3std10sys_common9backtrace", - "ZN3std10sys_common9backtrace", - "std::sys_common::backtrace", - "_ZN3std9panicking", - "ZN3std9panicking", - "std::panicking", - "_ZN4core9panicking", - "ZN4core9panicking", - "core::panicking", - "_ZN4core6result13unwrap_failed", - "ZN4core6result13unwrap_failed", - "core::result::unwrap_failed", - "rust_begin_unwind", - "_ZN4drop", - "mingw_set_invalid_parameter_handler", - ]; - static BAD_PREFIXES_BOTTOM: &'static [&'static str] = &[ - "_ZN3std9panicking", - "ZN3std9panicking", - "std::panicking", - "_ZN3std5panic", - "ZN3std5panic", - "std::panic", - "_ZN4core9panicking", - "ZN4core9panicking", - "core::panicking", - "_ZN3std2rt10lang_start", - "ZN3std2rt10lang_start", - "std::rt::lang_start", - "panic_unwind::__rust_maybe_catch_panic", - "__rust_maybe_catch_panic", - "_rust_maybe_catch_panic", - "__libc_start_main", - "__rust_try", - "_start", - "main", - "BaseThreadInitThunk", - "RtlInitializeExceptionChain", - "__scrt_common_main_seh", - "_ZN4drop", - "mingw_set_invalid_parameter_handler", - ]; - - let is_good_frame = |frame: Frame, bad_prefixes: &[&str]| { - resolve_symname(frame, |symname| { + let skipped_before = 0; + + let skipped_after = frames.len() - frames.iter().position(|frame| { + let mut is_marker = false; + let _ = resolve_symname(*frame, |symname| { if let Some(mangled_symbol_name) = symname { - if !bad_prefixes.iter().any(|s| mangled_symbol_name.starts_with(s)) { - return Ok(()) + // Use grep to find the concerned functions + if mangled_symbol_name.contains("__rust_begin_short_backtrace") { + is_marker = true; } } - Err(io::Error::from(io::ErrorKind::Other)) - }, context).is_ok() - }; - - let skipped_before = frames.iter().position(|frame| { - is_good_frame(*frame, BAD_PREFIXES_TOP) + Ok(()) + }, context); + is_marker }).unwrap_or(frames.len()); - let skipped_after = frames[skipped_before..].iter().rev().position(|frame| { - is_good_frame(*frame, BAD_PREFIXES_BOTTOM) - }).unwrap_or(frames.len() - skipped_before); - if skipped_before + skipped_after == frames.len() { + if skipped_before + skipped_after >= frames.len() { // Avoid showing completely empty backtraces return (0, 0); } @@ -176,6 +127,15 @@ fn filter_frames(frames: &[Frame], (skipped_before, skipped_after) } + +/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. +#[inline(never)] +pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T + where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static +{ + f() +} + /// Controls how the backtrace should be formated. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum PrintFormat { @@ -262,7 +222,7 @@ fn output_fileline(w: &mut Write, file: &[u8], line: libc::c_int, if let Ok(cwd) = env::current_dir() { if let Ok(stripped) = file_path.strip_prefix(&cwd) { if let Some(s) = stripped.to_str() { - write!(w, " at ./{}:{}", s, line)?; + write!(w, " at .{}{}:{}", path::MAIN_SEPARATOR, s, line)?; already_printed = true; } } diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs index 3cdeb511945..a1897c8bd67 100644 --- a/src/libstd/sys_common/net.rs +++ b/src/libstd/sys_common/net.rs @@ -177,9 +177,22 @@ pub fn lookup_host(host: &str) -> io::Result<LookupHost> { }; let mut res = ptr::null_mut(); unsafe { - cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, - &mut res))?; - Ok(LookupHost { original: res, cur: res }) + match cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)) { + Ok(_) => { + Ok(LookupHost { original: res, cur: res }) + }, + #[cfg(unix)] + Err(e) => { + // The lookup failure could be caused by using a stale /etc/resolv.conf. + // See https://github.com/rust-lang/rust/issues/41570. + // We therefore force a reload of the nameserver information. + c::res_init(); + Err(e) + }, + // the cfg is needed here to avoid an "unreachable pattern" warning + #[cfg(not(unix))] + Err(e) => Err(e), + } } } @@ -339,7 +352,7 @@ impl TcpListener { // Bind our new socket let (addrp, len) = addr.into_inner(); - cvt(unsafe { c::bind(*sock.as_inner(), addrp, len) })?; + cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?; // Start listening cvt(unsafe { c::listen(*sock.as_inner(), 128) })?; @@ -430,7 +443,7 @@ impl UdpSocket { let sock = Socket::new(addr, c::SOCK_DGRAM)?; let (addrp, len) = addr.into_inner(); - cvt(unsafe { c::bind(*sock.as_inner(), addrp, len) })?; + cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?; Ok(UdpSocket { inner: sock }) } diff --git a/src/libstd/sys_common/poison.rs b/src/libstd/sys_common/poison.rs index d9d13240fcc..0127a9eb759 100644 --- a/src/libstd/sys_common/poison.rs +++ b/src/libstd/sys_common/poison.rs @@ -73,7 +73,9 @@ pub struct PoisonError<T> { } /// An enumeration of possible errors which can occur while calling the -/// `try_lock` method. +/// [`try_lock`] method. +/// +/// [`try_lock`]: struct.Mutex.html#method.try_lock #[stable(feature = "rust1", since = "1.0.0")] pub enum TryLockError<T> { /// The lock could not be acquired because another thread failed while holding diff --git a/src/libstd/sys_common/thread_info.rs b/src/libstd/sys_common/thread_info.rs index 95d8b6cc951..5ed48ee4558 100644 --- a/src/libstd/sys_common/thread_info.rs +++ b/src/libstd/sys_common/thread_info.rs @@ -31,7 +31,7 @@ impl ThreadInfo { if c.borrow().is_none() { *c.borrow_mut() = Some(ThreadInfo { stack_guard: None, - thread: NewThread::new(None), + thread: Thread::new(None), }) } Some(f(c.borrow_mut().as_mut().unwrap())) @@ -54,8 +54,3 @@ pub fn set(stack_guard: Option<usize>, thread: Thread) { thread: thread, })); } - -// a hack to get around privacy restrictions; implemented by `std::thread` -pub trait NewThread { - fn new(name: Option<String>) -> Self; -} diff --git a/src/libstd/sys_common/thread_local.rs b/src/libstd/sys_common/thread_local.rs index 25a9d5720d9..0ade90e64c3 100644 --- a/src/libstd/sys_common/thread_local.rs +++ b/src/libstd/sys_common/thread_local.rs @@ -61,6 +61,7 @@ use sync::atomic::{self, AtomicUsize, Ordering}; use sys::thread_local as imp; +use sys_common::mutex::Mutex; /// A type for TLS keys that are statically allocated. /// @@ -145,20 +146,6 @@ impl StaticKey { #[inline] pub unsafe fn set(&self, val: *mut u8) { imp::set(self.key(), val) } - /// Deallocates this OS TLS key. - /// - /// This function is unsafe as there is no guarantee that the key is not - /// currently in use by other threads or will not ever be used again. - /// - /// Note that this does *not* run the user-provided destructor if one was - /// specified at definition time. Doing so must be done manually. - pub unsafe fn destroy(&self) { - match self.key.swap(0, Ordering::SeqCst) { - 0 => {} - n => { imp::destroy(n as imp::Key) } - } - } - #[inline] unsafe fn key(&self) -> imp::Key { match self.key.load(Ordering::Relaxed) { @@ -168,6 +155,24 @@ impl StaticKey { } unsafe fn lazy_init(&self) -> usize { + // Currently the Windows implementation of TLS is pretty hairy, and + // it greatly simplifies creation if we just synchronize everything. + // + // Additionally a 0-index of a tls key hasn't been seen on windows, so + // we just simplify the whole branch. + if imp::requires_synchronized_create() { + static INIT_LOCK: Mutex = Mutex::new(); + INIT_LOCK.lock(); + let mut key = self.key.load(Ordering::SeqCst); + if key == 0 { + key = imp::create(self.dtor) as usize; + self.key.store(key, Ordering::SeqCst); + } + INIT_LOCK.unlock(); + assert!(key != 0); + return key + } + // POSIX allows the key created here to be 0, but the compare_and_swap // below relies on using 0 as a sentinel value to check who won the // race to set the shared TLS key. As far as I know, there is no @@ -227,7 +232,9 @@ impl Key { impl Drop for Key { fn drop(&mut self) { - unsafe { imp::destroy(self.key) } + // Right now Windows doesn't support TLS key destruction, but this also + // isn't used anywhere other than tests, so just leak the TLS key. + // unsafe { imp::destroy(self.key) } } } diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index b486d4ffda3..df5e4ef1d88 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -351,6 +351,12 @@ impl Wtf8Buf { pub fn into_box(self) -> Box<Wtf8> { unsafe { mem::transmute(self.bytes.into_boxed_slice()) } } + + /// Converts a `Box<Wtf8>` into a `Wtf8Buf`. + pub fn from_box(boxed: Box<Wtf8>) -> Wtf8Buf { + let bytes: Box<[u8]> = unsafe { mem::transmute(boxed) }; + Wtf8Buf { bytes: bytes.into_vec() } + } } /// Create a new WTF-8 string from an iterator of code points. @@ -744,6 +750,7 @@ impl<'a> Iterator for Wtf8CodePoints<'a> { } } +/// Generates a wide character sequence for potentially ill-formed UTF-16. #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct EncodeWide<'a> { diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 66f09a7069c..c2c6e6cf87d 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -19,16 +19,16 @@ use mem; /// A thread local storage key which owns its contents. /// /// This key uses the fastest possible implementation available to it for the -/// target platform. It is instantiated with the `thread_local!` macro and the -/// primary method is the `with` method. +/// target platform. It is instantiated with the [`thread_local!`] macro and the +/// primary method is the [`with`] method. /// -/// The `with` method yields a reference to the contained value which cannot be +/// The [`with`] method yields a reference to the contained value which cannot be /// sent across threads or escape the given closure. /// /// # Initialization and Destruction /// -/// Initialization is dynamically performed on the first call to `with()` -/// within a thread, and values that implement `Drop` get destructed when a +/// Initialization is dynamically performed on the first call to [`with`] +/// within a thread, and values that implement [`Drop`] get destructed when a /// thread exits. Some caveats apply, which are explained below. /// /// # Examples @@ -74,9 +74,13 @@ use mem; /// destroyed, but not all platforms have this guard. Those platforms that do /// not guard typically have a synthetic limit after which point no more /// destructors are run. -/// 3. On OSX, initializing TLS during destruction of other TLS slots can +/// 3. On macOS, initializing TLS during destruction of other TLS slots can /// sometimes cancel *all* destructors for the current thread, whether or not /// the slots have already had their destructors run or not. +/// +/// [`with`]: ../../std/thread/struct.LocalKey.html#method.with +/// [`thread_local!`]: ../../std/macro.thread_local.html +/// [`Drop`]: ../../std/ops/trait.Drop.html #[stable(feature = "rust1", since = "1.0.0")] pub struct LocalKey<T: 'static> { // This outer `LocalKey<T>` type is what's going to be stored in statics, @@ -106,7 +110,7 @@ impl<T: 'static> fmt::Debug for LocalKey<T> { } } -/// Declare a new thread local storage key of type `std::thread::LocalKey`. +/// Declare a new thread local storage key of type [`std::thread::LocalKey`]. /// /// # Syntax /// @@ -124,8 +128,10 @@ impl<T: 'static> fmt::Debug for LocalKey<T> { /// # fn main() {} /// ``` /// -/// See [LocalKey documentation](thread/struct.LocalKey.html) for more +/// See [LocalKey documentation][`std::thread::LocalKey`] for more /// information. +/// +/// [`std::thread::LocalKey`]: ../std/thread/struct.LocalKey.html #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable] @@ -195,11 +201,13 @@ macro_rules! __thread_local_inner { #[derive(Debug, Eq, PartialEq, Copy, Clone)] pub enum LocalKeyState { /// All keys are in this state whenever a thread starts. Keys will - /// transition to the `Valid` state once the first call to `with` happens + /// transition to the `Valid` state once the first call to [`with`] happens /// and the initialization expression succeeds. /// /// Keys in the `Uninitialized` state will yield a reference to the closure - /// passed to `with` so long as the initialization routine does not panic. + /// passed to [`with`] so long as the initialization routine does not panic. + /// + /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with Uninitialized, /// Once a key has been accessed successfully, it will enter the `Valid` @@ -208,7 +216,9 @@ pub enum LocalKeyState { /// `Destroyed` state. /// /// Keys in the `Valid` state will be guaranteed to yield a reference to the - /// closure passed to `with`. + /// closure passed to [`with`]. + /// + /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with Valid, /// When a thread exits, the destructors for keys will be run (if @@ -216,7 +226,9 @@ pub enum LocalKeyState { /// destructor has run, a key is in the `Destroyed` state. /// /// Keys in the `Destroyed` states will trigger a panic when accessed via - /// `with`. + /// [`with`]. + /// + /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with Destroyed, } @@ -283,23 +295,26 @@ impl<T: 'static> LocalKey<T> { /// Query the current state of this key. /// /// A key is initially in the `Uninitialized` state whenever a thread - /// starts. It will remain in this state up until the first call to `with` + /// starts. It will remain in this state up until the first call to [`with`] /// within a thread has run the initialization expression successfully. /// /// Once the initialization expression succeeds, the key transitions to the - /// `Valid` state which will guarantee that future calls to `with` will + /// `Valid` state which will guarantee that future calls to [`with`] will /// succeed within the thread. /// /// When a thread exits, each key will be destroyed in turn, and as keys are /// destroyed they will enter the `Destroyed` state just before the /// destructor starts to run. Keys may remain in the `Destroyed` state after /// destruction has completed. Keys without destructors (e.g. with types - /// that are `Copy`), may never enter the `Destroyed` state. + /// that are [`Copy`]), may never enter the `Destroyed` state. /// /// Keys in the `Uninitialized` state can be accessed so long as the /// initialization does not panic. Keys in the `Valid` state are guaranteed /// to be able to be accessed. Keys in the `Destroyed` state will panic on - /// any call to `with`. + /// any call to [`with`]. + /// + /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with + /// [`Copy`]: ../../std/marker/trait.Copy.html #[unstable(feature = "thread_local_state", reason = "state querying was recently added", issue = "27716")] @@ -524,9 +539,9 @@ mod tests { } // Note that this test will deadlock if TLS destructors aren't run (this - // requires the destructor to be run to pass the test). OSX has a known bug + // requires the destructor to be run to pass the test). macOS has a known bug // where dtors-in-dtors may cancel other destructors, so we just ignore this - // test on OSX. + // test on macOS. #[test] #[cfg_attr(target_os = "macos", ignore)] fn dtors_in_dtors_in_dtors() { diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 2bc066d3fea..d0e3b00d75f 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -66,7 +66,7 @@ //! let res = child.join(); //! ``` //! -//! The [`join`] method returns a [`Result`] containing [`Ok`] of the final +//! The [`join`] method returns a [`thread::Result`] containing [`Ok`] of the final //! value produced by the child thread, or [`Err`] of the value given to //! a call to [`panic!`] if the child panicked. //! @@ -90,47 +90,12 @@ //! two ways: //! //! * By spawning a new thread, e.g. using the [`thread::spawn`][`spawn`] -//! function, and calling [`thread()`] on the [`JoinHandle`]. -//! * By requesting the current thread, using the [`thread::current()`] function. +//! function, and calling [`thread`][`JoinHandle::thread`] on the [`JoinHandle`]. +//! * By requesting the current thread, using the [`thread::current`] function. //! -//! The [`thread::current()`] function is available even for threads not spawned +//! The [`thread::current`] function is available even for threads not spawned //! by the APIs of this module. //! -//! ## Blocking support: park and unpark -//! -//! Every thread is equipped with some basic low-level blocking support, via the -//! [`thread::park()`][`park()`] function and [`thread::Thread::unpark()`][`unpark()`] -//! method. [`park()`] blocks the current thread, which can then be resumed from -//! another thread by calling the [`unpark()`] method on the blocked thread's handle. -//! -//! Conceptually, each [`Thread`] handle has an associated token, which is -//! initially not present: -//! -//! * The [`thread::park()`][`park()`] function blocks the current thread unless or until -//! the token is available for its thread handle, at which point it atomically -//! consumes the token. It may also return *spuriously*, without consuming the -//! token. [`thread::park_timeout()`] does the same, but allows specifying a -//! maximum time to block the thread for. -//! -//! * The [`unpark()`] method on a [`Thread`] atomically makes the token available -//! if it wasn't already. -//! -//! In other words, each [`Thread`] acts a bit like a semaphore with initial count -//! 0, except that the semaphore is *saturating* (the count cannot go above 1), -//! and can return spuriously. -//! -//! The API is typically used by acquiring a handle to the current thread, -//! placing that handle in a shared data structure so that other threads can -//! find it, and then `park`ing. When some desired condition is met, another -//! thread calls [`unpark()`] on the handle. -//! -//! The motivation for this design is twofold: -//! -//! * It avoids the need to allocate mutexes and condvars when building new -//! synchronization primitives; the threads already provide basic blocking/signaling. -//! -//! * It can be implemented very efficiently on many platforms. -//! //! ## Thread-local storage //! //! This module also provides an implementation of thread-local storage for Rust @@ -151,18 +116,19 @@ //! [`Arc`]: ../../std/sync/struct.Arc.html //! [`spawn`]: ../../std/thread/fn.spawn.html //! [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html -//! [`thread()`]: ../../std/thread/struct.JoinHandle.html#method.thread +//! [`JoinHandle::thread`]: ../../std/thread/struct.JoinHandle.html#method.thread //! [`join`]: ../../std/thread/struct.JoinHandle.html#method.join //! [`Result`]: ../../std/result/enum.Result.html //! [`Ok`]: ../../std/result/enum.Result.html#variant.Ok //! [`Err`]: ../../std/result/enum.Result.html#variant.Err //! [`panic!`]: ../../std/macro.panic.html //! [`Builder`]: ../../std/thread/struct.Builder.html -//! [`thread::current()`]: ../../std/thread/fn.spawn.html +//! [`thread::current`]: ../../std/thread/fn.current.html +//! [`thread::Result`]: ../../std/thread/type.Result.html //! [`Thread`]: ../../std/thread/struct.Thread.html -//! [`park()`]: ../../std/thread/fn.park.html -//! [`unpark()`]: ../../std/thread/struct.Thread.html#method.unpark -//! [`thread::park_timeout()`]: ../../std/thread/fn.park_timeout.html +//! [`park`]: ../../std/thread/fn.park.html +//! [`unpark`]: ../../std/thread/struct.Thread.html#method.unpark +//! [`thread::park_timeout`]: ../../std/thread/fn.park_timeout.html //! [`Cell`]: ../cell/struct.Cell.html //! [`RefCell`]: ../cell/struct.RefCell.html //! [`thread_local!`]: ../macro.thread_local.html @@ -214,8 +180,33 @@ pub use self::local::{LocalKey, LocalKeyState}; // Builder //////////////////////////////////////////////////////////////////////////////// -/// Thread configuration. Provides detailed control over the properties -/// and behavior of new threads. +/// Thread factory, which can be used in order to configure the properties of +/// a new thread. +/// +/// Methods can be chained on it in order to configure it. +/// +/// The two configurations available are: +/// +/// - [`name`]: allows to give a name to the thread which is currently +/// only used in `panic` messages. +/// - [`stack_size`]: specifies the desired stack size. Note that this can +/// be overriden by the OS. +/// +/// If the [`stack_size`] field is not specified, the stack size +/// will be the `RUST_MIN_STACK` environment variable. If it is +/// not specified either, a sensible default will be set. +/// +/// If the [`name`] field is not specified, the thread will not be named. +/// +/// The [`spawn`] method will take ownership of the builder and create an +/// [`io::Result`] to the thread handle with the given configuration. +/// +/// The [`thread::spawn`] free function uses a `Builder` with default +/// configuration and [`unwrap`]s its return value. +/// +/// You may want to use [`spawn`] instead of [`thread::spawn`], when you want +/// to recover from a failure to launch a thread, indeed the free function will +/// panick where the `Builder` method will return a [`io::Result`]. /// /// # Examples /// @@ -230,6 +221,13 @@ pub use self::local::{LocalKey, LocalKeyState}; /// /// handler.join().unwrap(); /// ``` +/// +/// [`thread::spawn`]: ../../std/thread/fn.spawn.html +/// [`stack_size`]: ../../std/thread/struct.Builder.html#method.stack_size +/// [`name`]: ../../std/thread/struct.Builder.html#method.name +/// [`spawn`]: ../../std/thread/struct.Builder.html#method.spawn +/// [`io::Result`]: ../../std/io/type.Result.html +/// [`unwrap`]: ../../std/result/enum.Result.html#method.unwrap #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Builder { @@ -307,13 +305,16 @@ impl Builder { self } - /// Spawns a new thread, and returns a join handle for it. + /// Spawns a new thread by taking ownership of the `Builder`, and returns an + /// [`io::Result`] to its [`JoinHandle`]. /// - /// The child thread may outlive the parent (unless the parent thread + /// The spawned thread may outlive the caller (unless the caller thread /// is the main thread; the whole process is terminated when the main /// thread finishes). The join handle can be used to block on /// termination of the child thread, including recovering its panics. /// + /// For a more complete documentation see [`thread::spawn`][`spawn`]. + /// /// # Errors /// /// Unlike the [`spawn`] free function, this method yields an @@ -322,6 +323,7 @@ impl Builder { /// /// [`spawn`]: ../../std/thread/fn.spawn.html /// [`io::Result`]: ../../std/io/type.Result.html + /// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html /// /// # Examples /// @@ -357,6 +359,11 @@ impl Builder { } unsafe { thread_info::set(imp::guard::current(), their_thread); + #[cfg(feature = "backtrace")] + let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { + ::sys_common::backtrace::__rust_begin_short_backtrace(f) + })); + #[cfg(not(feature = "backtrace"))] let try_result = panic::catch_unwind(panic::AssertUnwindSafe(f)); *their_packet.get() = Some(try_result); } @@ -386,19 +393,39 @@ impl Builder { /// panics, [`join`] will return an [`Err`] containing the argument given to /// [`panic`]. /// +/// This will create a thread using default parameters of [`Builder`], if you +/// want to specify the stack size or the name of the thread, use this API +/// instead. +/// +/// As you can see in the signature of `spawn` there are two constraints on +/// both the closure given to `spawn` and its return value, let's explain them: +/// +/// - The `'static` constraint means that the closure and its return value +/// must have a lifetime of the whole program execution. The reason for this +/// is that threads can `detach` and outlive the lifetime they have been +/// created in. +/// Indeed if the thread, and by extension its return value, can outlive their +/// caller, we need to make sure that they will be valid afterwards, and since +/// we *can't* know when it will return we need to have them valid as long as +/// possible, that is until the end of the program, hence the `'static` +/// lifetime. +/// - The [`Send`] constraint is because the closure will need to be passed +/// *by value* from the thread where it is spawned to the new thread. Its +/// return value will need to be passed from the new thread to the thread +/// where it is `join`ed. +/// As a reminder, the [`Send`] marker trait, expresses that it is safe to be +/// passed from thread to thread. [`Sync`] expresses that it is safe to have a +/// reference be passed from thread to thread. +/// /// # Panics /// /// Panics if the OS fails to create a thread; use [`Builder::spawn`] /// to recover from such errors. /// -/// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html -/// [`join`]: ../../std/thread/struct.JoinHandle.html#method.join -/// [`Err`]: ../../std/result/enum.Result.html#variant.Err -/// [`panic`]: ../../std/macro.panic.html -/// [`Builder::spawn`]: ../../std/thread/struct.Builder.html#method.spawn -/// /// # Examples /// +/// Creating a thread. +/// /// ``` /// use std::thread; /// @@ -408,6 +435,56 @@ impl Builder { /// /// handler.join().unwrap(); /// ``` +/// +/// As mentioned in the module documentation, threads are usually made to +/// communicate using [`channels`], here is how it usually looks. +/// +/// This example also shows how to use `move`, in order to give ownership +/// of values to a thread. +/// +/// ``` +/// use std::thread; +/// use std::sync::mpsc::channel; +/// +/// let (tx, rx) = channel(); +/// +/// let sender = thread::spawn(move || { +/// let _ = tx.send("Hello, thread".to_owned()); +/// }); +/// +/// let receiver = thread::spawn(move || { +/// println!("{}", rx.recv().unwrap()); +/// }); +/// +/// let _ = sender.join(); +/// let _ = receiver.join(); +/// ``` +/// +/// A thread can also return a value through its [`JoinHandle`], you can use +/// this to make asynchronous computations (futures might be more appropriate +/// though). +/// +/// ``` +/// use std::thread; +/// +/// let computation = thread::spawn(|| { +/// // Some expensive computation. +/// 42 +/// }); +/// +/// let result = computation.join().unwrap(); +/// println!("{}", result); +/// ``` +/// +/// [`channels`]: ../../std/sync/mpsc/index.html +/// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html +/// [`join`]: ../../std/thread/struct.JoinHandle.html#method.join +/// [`Err`]: ../../std/result/enum.Result.html#variant.Err +/// [`panic`]: ../../std/macro.panic.html +/// [`Builder::spawn`]: ../../std/thread/struct.Builder.html#method.spawn +/// [`Builder`]: ../../std/thread/struct.Builder.html +/// [`Send`]: ../../std/marker/trait.Send.html +/// [`Sync`]: ../../std/marker/trait.Sync.html #[stable(feature = "rust1", since = "1.0.0")] pub fn spawn<F, T>(f: F) -> JoinHandle<T> where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static @@ -443,6 +520,23 @@ pub fn current() -> Thread { /// Cooperatively gives up a timeslice to the OS scheduler. /// +/// This is used when the programmer knows that the thread will have nothing +/// to do for some time, and thus avoid wasting computing time. +/// +/// For example when polling on a resource, it is common to check that it is +/// available, and if not to yield in order to avoid busy waiting. +/// +/// Thus the pattern of `yield`ing after a failed poll is rather common when +/// implementing low-level shared resources or synchronization primitives. +/// +/// However programmers will usualy prefer to use, [`channel`]s, [`Condvar`]s, +/// [`Mutex`]es or [`join`] for their synchronisation routines, as they avoid +/// thinking about thread schedulling. +/// +/// Note that [`channel`]s for example are implemented using this primitive. +/// Indeed when you call `send` or `recv`, which are blocking, they will yield +/// if the channel is not available. +/// /// # Examples /// /// ``` @@ -450,6 +544,12 @@ pub fn current() -> Thread { /// /// thread::yield_now(); /// ``` +/// +/// [`channel`]: ../../std/sync/mpsc/index.html +/// [`spawn`]: ../../std/thread/fn.spawn.html +/// [`join`]: ../../std/thread/struct.JoinHandle.html#method.join +/// [`Mutex`]: ../../std/sync/struct.Mutex.html +/// [`Condvar`]: ../../std/sync/struct.Condvar.html #[stable(feature = "rust1", since = "1.0.0")] pub fn yield_now() { imp::Thread::yield_now() @@ -457,6 +557,16 @@ pub fn yield_now() { /// Determines whether the current thread is unwinding because of panic. /// +/// A common use of this feature is to poison shared resources when writing +/// unsafe code, by checking `panicking` when the `drop` is called. +/// +/// This is usually not needed when writing safe code, as [`Mutex`es][Mutex] +/// already poison themselves when a thread panics while holding the lock. +/// +/// This can also be used in multithreaded applications, in order to send a +/// message to other threads warning that a thread has panicked (e.g. for +/// monitoring purposes). +/// /// # Examples /// /// ```should_panic @@ -485,6 +595,8 @@ pub fn yield_now() { /// panic!() /// } /// ``` +/// +/// [Mutex]: ../../std/sync/struct.Mutex.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn panicking() -> bool { @@ -546,23 +658,72 @@ pub fn sleep(dur: Duration) { /// Blocks unless or until the current thread's token is made available. /// -/// Every thread is equipped with some basic low-level blocking support, via -/// the `park()` function and the [`unpark()`][unpark] method. These can be -/// used as a more CPU-efficient implementation of a spinlock. +/// A call to `park` does not guarantee that the thread will remain parked +/// forever, and callers should be prepared for this possibility. +/// +/// # park and unpark /// -/// [unpark]: struct.Thread.html#method.unpark +/// Every thread is equipped with some basic low-level blocking support, via the +/// [`thread::park`][`park`] function and [`thread::Thread::unpark`][`unpark`] +/// method. [`park`] blocks the current thread, which can then be resumed from +/// another thread by calling the [`unpark`] method on the blocked thread's +/// handle. +/// +/// Conceptually, each [`Thread`] handle has an associated token, which is +/// initially not present: +/// +/// * The [`thread::park`][`park`] function blocks the current thread unless or +/// until the token is available for its thread handle, at which point it +/// atomically consumes the token. It may also return *spuriously*, without +/// consuming the token. [`thread::park_timeout`] does the same, but allows +/// specifying a maximum time to block the thread for. +/// +/// * The [`unpark`] method on a [`Thread`] atomically makes the token available +/// if it wasn't already. +/// +/// In other words, each [`Thread`] acts a bit like a spinlock that can be +/// locked and unlocked using `park` and `unpark`. /// /// The API is typically used by acquiring a handle to the current thread, /// placing that handle in a shared data structure so that other threads can -/// find it, and then parking (in a loop with a check for the token actually -/// being acquired). +/// find it, and then `park`ing. When some desired condition is met, another +/// thread calls [`unpark`] on the handle. /// -/// A call to `park` does not guarantee that the thread will remain parked -/// forever, and callers should be prepared for this possibility. +/// The motivation for this design is twofold: +/// +/// * It avoids the need to allocate mutexes and condvars when building new +/// synchronization primitives; the threads already provide basic +/// blocking/signaling. +/// +/// * It can be implemented very efficiently on many platforms. +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use std::time::Duration; +/// +/// let parked_thread = thread::Builder::new() +/// .spawn(|| { +/// println!("Parking thread"); +/// thread::park(); +/// println!("Thread unparked"); +/// }) +/// .unwrap(); /// -/// See the [module documentation][thread] for more detail. +/// // Let some time pass for the thread to be spawned. +/// thread::sleep(Duration::from_millis(10)); /// -/// [thread]: index.html +/// println!("Unpark the thread"); +/// parked_thread.thread().unpark(); +/// +/// parked_thread.join().unwrap(); +/// ``` +/// +/// [`Thread`]: ../../std/thread/struct.Thread.html +/// [`park`]: ../../std/thread/fn.park.html +/// [`unpark`]: ../../std/thread/struct.Thread.html#method.unpark +/// [`thread::park_timeout`]: ../../std/thread/fn.park_timeout.html // // The implementation currently uses the trivial strategy of a Mutex+Condvar // with wakeup flag, which does not actually allow spurious wakeups. In the @@ -579,21 +740,21 @@ pub fn park() { *guard = false; } -/// Use [park_timeout]. +/// Use [`park_timeout`]. /// /// Blocks unless or until the current thread's token is made available or /// the specified duration has been reached (may wake spuriously). /// -/// The semantics of this function are equivalent to `park()` except that the -/// thread will be blocked for roughly no longer than `ms`. This method -/// should not be used for precise timing due to anomalies such as +/// The semantics of this function are equivalent to [`park`] except +/// that the thread will be blocked for roughly no longer than `dur`. This +/// method should not be used for precise timing due to anomalies such as /// preemption or platform differences that may not cause the maximum /// amount of time waited to be precisely `ms` long. /// -/// See the [module documentation][thread] for more detail. +/// See the [park documentation][`park`] for more detail. /// -/// [thread]: index.html -/// [park_timeout]: fn.park_timeout.html +/// [`park_timeout`]: fn.park_timeout.html +/// [`park`]: ../../std/thread/fn.park.html #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::thread::park_timeout`")] pub fn park_timeout_ms(ms: u32) { @@ -603,13 +764,13 @@ pub fn park_timeout_ms(ms: u32) { /// Blocks unless or until the current thread's token is made available or /// the specified duration has been reached (may wake spuriously). /// -/// The semantics of this function are equivalent to `park()` except that the -/// thread will be blocked for roughly no longer than `dur`. This method -/// should not be used for precise timing due to anomalies such as +/// The semantics of this function are equivalent to [`park`][park] except +/// that the thread will be blocked for roughly no longer than `dur`. This +/// method should not be used for precise timing due to anomalies such as /// preemption or platform differences that may not cause the maximum /// amount of time waited to be precisely `dur` long. /// -/// See the module doc for more detail. +/// See the [park dococumentation][park] for more details. /// /// # Platform behavior /// @@ -634,6 +795,8 @@ pub fn park_timeout_ms(ms: u32) { /// park_timeout(timeout); /// } /// ``` +/// +/// [park]: fn.park.html #[stable(feature = "park_timeout", since = "1.4.0")] pub fn park_timeout(dur: Duration) { let thread = current(); @@ -652,8 +815,8 @@ pub fn park_timeout(dur: Duration) { /// A unique identifier for a running thread. /// /// A `ThreadId` is an opaque object that has a unique value for each thread -/// that creates one. `ThreadId`s do not correspond to a thread's system- -/// designated identifier. +/// that creates one. `ThreadId`s are not guaranteed to correspond to a thread's +/// system-designated identifier. /// /// # Examples /// @@ -662,17 +825,15 @@ pub fn park_timeout(dur: Duration) { /// /// use std::thread; /// -/// let handler = thread::Builder::new() -/// .spawn(|| { -/// let thread = thread::current(); -/// let thread_id = thread.id(); -/// }) -/// .unwrap(); +/// let other_thread = thread::spawn(|| { +/// thread::current().id() +/// }); /// -/// handler.join().unwrap(); +/// let other_thread_id = other_thread.join().unwrap(); +/// assert!(thread::current().id() != other_thread_id); /// ``` #[unstable(feature = "thread_id", issue = "21507")] -#[derive(Eq, PartialEq, Copy, Clone)] +#[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)] pub struct ThreadId(u64); impl ThreadId { @@ -701,13 +862,6 @@ impl ThreadId { } } -#[unstable(feature = "thread_id", issue = "21507")] -impl fmt::Debug for ThreadId { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("ThreadId { .. }") - } -} - //////////////////////////////////////////////////////////////////////////////// // Thread //////////////////////////////////////////////////////////////////////////////// @@ -724,28 +878,31 @@ struct Inner { #[stable(feature = "rust1", since = "1.0.0")] /// A handle to a thread. /// -/// # Examples +/// Threads are represented via the `Thread` type, which you can get in one of +/// two ways: /// -/// ``` -/// use std::thread; +/// * By spawning a new thread, e.g. using the [`thread::spawn`][`spawn`] +/// function, and calling [`thread`][`JoinHandle::thread`] on the +/// [`JoinHandle`]. +/// * By requesting the current thread, using the [`thread::current`] function. /// -/// let handler = thread::Builder::new() -/// .name("foo".into()) -/// .spawn(|| { -/// let thread = thread::current(); -/// println!("thread name: {}", thread.name().unwrap()); -/// }) -/// .unwrap(); +/// The [`thread::current`] function is available even for threads not spawned +/// by the APIs of this module. /// -/// handler.join().unwrap(); -/// ``` +/// There is usualy no need to create a `Thread` struct yourself, one +/// should instead use a function like `spawn` to create new threads, see the +/// docs of [`Builder`] and [`spawn`] for more details. +/// +/// [`Builder`]: ../../std/thread/struct.Builder.html +/// [`spawn`]: ../../std/thread/fn.spawn.html + pub struct Thread { inner: Arc<Inner>, } impl Thread { // Used only internally to construct a thread object without spawning - fn new(name: Option<String>) -> Thread { + pub(crate) fn new(name: Option<String>) -> Thread { let cname = name.map(|n| { CString::new(n).expect("thread name may not contain interior null bytes") }); @@ -761,22 +918,36 @@ impl Thread { /// Atomically makes the handle's token available if it is not already. /// - /// See the module doc for more detail. + /// Every thread is equipped with some basic low-level blocking support, via + /// the [`park`][park] function and the `unpark()` method. These can be + /// used as a more CPU-efficient implementation of a spinlock. + /// + /// See the [park documentation][park] for more details. /// /// # Examples /// /// ``` /// use std::thread; + /// use std::time::Duration; /// - /// let handler = thread::Builder::new() + /// let parked_thread = thread::Builder::new() /// .spawn(|| { - /// let thread = thread::current(); - /// thread.unpark(); + /// println!("Parking thread"); + /// thread::park(); + /// println!("Thread unparked"); /// }) /// .unwrap(); /// - /// handler.join().unwrap(); + /// // Let some time pass for the thread to be spawned. + /// thread::sleep(Duration::from_millis(10)); + /// + /// println!("Unpark the thread"); + /// parked_thread.thread().unpark(); + /// + /// parked_thread.join().unwrap(); /// ``` + /// + /// [park]: fn.park.html #[stable(feature = "rust1", since = "1.0.0")] pub fn unpark(&self) { let mut guard = self.inner.lock.lock().unwrap(); @@ -795,14 +966,12 @@ impl Thread { /// /// use std::thread; /// - /// let handler = thread::Builder::new() - /// .spawn(|| { - /// let thread = thread::current(); - /// println!("thread id: {:?}", thread.id()); - /// }) - /// .unwrap(); + /// let other_thread = thread::spawn(|| { + /// thread::current().id() + /// }); /// - /// handler.join().unwrap(); + /// let other_thread_id = other_thread.join().unwrap(); + /// assert!(thread::current().id() != other_thread_id); /// ``` #[unstable(feature = "thread_id", issue = "21507")] pub fn id(&self) -> ThreadId { @@ -858,18 +1027,35 @@ impl fmt::Debug for Thread { } } -// a hack to get around privacy restrictions -impl thread_info::NewThread for Thread { - fn new(name: Option<String>) -> Thread { Thread::new(name) } -} - //////////////////////////////////////////////////////////////////////////////// // JoinHandle //////////////////////////////////////////////////////////////////////////////// +/// A specialized [`Result`] type for threads. +/// /// Indicates the manner in which a thread exited. /// /// A thread that completes without panicking is considered to exit successfully. +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::fs; +/// +/// fn copy_in_thread() -> thread::Result<()> { +/// thread::spawn(move || { fs::copy("foo.txt", "bar.txt").unwrap(); }).join() +/// } +/// +/// fn main() { +/// match copy_in_thread() { +/// Ok(_) => println!("this is fine"), +/// Err(_) => println!("thread panicked"), +/// } +/// } +/// ``` +/// +/// [`Result`]: ../../std/result/enum.Result.html #[stable(feature = "rust1", since = "1.0.0")] pub type Result<T> = ::result::Result<T, Box<Any + Send + 'static>>; diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index af7eaeb3106..55766ba3fed 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -84,7 +84,10 @@ impl Duration { /// ``` /// use std::time::Duration; /// - /// let five_seconds = Duration::from_secs(5); + /// let duration = Duration::from_secs(5); + /// + /// assert_eq!(5, duration.as_secs()); + /// assert_eq!(0, duration.subsec_nanos()); /// ``` #[stable(feature = "duration", since = "1.3.0")] #[inline] @@ -99,7 +102,10 @@ impl Duration { /// ``` /// use std::time::Duration; /// - /// let five_seconds = Duration::from_millis(5000); + /// let duration = Duration::from_millis(2569); + /// + /// assert_eq!(2, duration.as_secs()); + /// assert_eq!(569000000, duration.subsec_nanos()); /// ``` #[stable(feature = "duration", since = "1.3.0")] #[inline] @@ -119,9 +125,24 @@ impl Duration { /// ``` /// use std::time::Duration; /// - /// let five_seconds = Duration::new(5, 0); - /// assert_eq!(five_seconds.as_secs(), 5); + /// let duration = Duration::new(5, 730023852); + /// assert_eq!(duration.as_secs(), 5); + /// ``` + /// + /// To determine the total number of seconds represented by the `Duration`, + /// use `as_secs` in combination with [`subsec_nanos`]: + /// /// ``` + /// use std::time::Duration; + /// + /// let duration = Duration::new(5, 730023852); + /// + /// assert_eq!(5.730023852, + /// duration.as_secs() as f64 + /// + duration.subsec_nanos() as f64 * 1e-9); + /// ``` + /// + /// [`subsec_nanos`]: #method.subsec_nanos #[stable(feature = "duration", since = "1.3.0")] #[inline] pub fn as_secs(&self) -> u64 { self.secs } |
