diff options
| author | Matthew <mjjasper1@gmail.com> | 2017-05-23 14:00:20 +0100 |
|---|---|---|
| committer | Matthew <mjjasper1@gmail.com> | 2017-05-23 14:00:20 +0100 |
| commit | 6627ef228c1396c045b3e9f24edaf66b76516cbd (patch) | |
| tree | fbead309f0165e668a895b2b33ce607aa0f4d2cb /src/libstd | |
| parent | 158b085f06a41004ebf36d87afa3548f8b60861a (diff) | |
| parent | 852b7cb91ed44f6cc77f855bd8281da4accbd2fb (diff) | |
| download | rust-6627ef228c1396c045b3e9f24edaf66b76516cbd.tar.gz rust-6627ef228c1396c045b3e9f24edaf66b76516cbd.zip | |
Stabilize in 1.19
Diffstat (limited to 'src/libstd')
42 files changed, 1594 insertions, 525 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/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 51d127f8ba7..8c4cbb66b45 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1231,14 +1231,13 @@ 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 { diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 7215e1bde85..d80df5f18b6 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -116,8 +116,6 @@ use super::map::{self, HashMap, Keys, RandomState}; /// [`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> { @@ -658,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]; @@ -666,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 { @@ -1041,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() } } @@ -1070,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() } } @@ -1100,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() } } @@ -1143,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() } } @@ -1202,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() } } @@ -1243,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() } } @@ -1269,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() } } @@ -1698,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 9623706548b..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 } } @@ -1112,10 +1113,12 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> { #[inline] fn next(&mut self) -> Option<(SafeHash, K, V)> { - self.iter.next().map(|raw| unsafe { - (*self.table.as_mut_ptr()).size -= 1; - let (k, v) = ptr::read(raw.pair()); - (SafeHash { hash: ptr::replace(&mut *raw.hash(), EMPTY_BUCKET) }, k, v) + self.iter.next().map(|raw| { + unsafe { + self.table.as_mut().size -= 1; + let (k, v) = ptr::read(raw.pair()); + (SafeHash { hash: ptr::replace(&mut *raw.hash(), EMPTY_BUCKET) }, k, v) + } }) } 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 9ff7d746733..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,7 +209,7 @@ 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)) @@ -282,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/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 29f977ecd8c..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,26 +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 } - /// Extracts a `CStr` slice containing the entire string. + /// 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`. + /// 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); @@ -421,14 +449,14 @@ impl<'a> From<&'a CStr> for Box<CStr> { } } -#[stable(feature = "c_string_from_box", since = "1.17.0")] +#[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.17.0")] +#[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() @@ -445,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 /// @@ -520,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 @@ -559,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. /// @@ -705,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() @@ -734,23 +770,29 @@ 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. + /// 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) } diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index b90192dd8af..f497734e249 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -529,14 +529,14 @@ impl<'a> From<&'a OsStr> for Box<OsStr> { } } -#[stable(feature = "os_string_from_box", since = "1.17.0")] -impl<'a> From<Box<OsStr>> for OsString { +#[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_c_string", since = "1.17.0")] +#[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() diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 6b1267d89b6..528d903b8b0 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -2412,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/mod.rs b/src/libstd/io/mod.rs index cd096c115ba..c872a8e5261 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -287,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}; @@ -466,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`: @@ -481,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(()) /// # } @@ -885,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 /// /// ``` @@ -894,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(()) /// # } @@ -929,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 /// @@ -1494,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 { @@ -1606,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")] diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 38ad23e14b3..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! { @@ -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/lib.rs b/src/libstd/lib.rs index 70225da5f33..b0820d6f05a 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -281,6 +281,7 @@ #![feature(linkage)] #![feature(macro_reexport)] #![feature(needs_panic_runtime)] +#![feature(needs_drop)] #![feature(never_type)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] @@ -318,7 +319,6 @@ #![feature(unwind_attributes)] #![feature(vec_push_all)] #![cfg_attr(test, feature(update_panic_count))] -#![cfg_attr(stage0, feature(pub_restricted))] #![cfg_attr(test, feature(float_bits_conv))] // Explicitly import the prelude. The compiler uses this same unstable attribute 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/ip.rs b/src/libstd/net/ip.rs index c46fe4a58c7..1e5368896af 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -657,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 { @@ -667,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 { @@ -694,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 { @@ -704,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 { @@ -1200,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 { @@ -1210,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 { @@ -1237,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 { @@ -1247,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 { @@ -1302,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/tcp.rs b/src/libstd/net/tcp.rs index bc315d54100..c1493c9c6f4 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -72,24 +72,23 @@ pub struct TcpStream(net_imp::TcpStream); /// /// # 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); @@ -177,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 @@ -337,7 +343,6 @@ impl TcpStream { /// # Examples /// /// ```no_run - /// #![feature(peek)] /// use std::net::TcpStream; /// /// let stream = TcpStream::connect("127.0.0.1:8000") @@ -345,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) } diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index cdf04f7f1a4..80151dc2b44 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -112,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"); @@ -120,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) } @@ -638,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"); @@ -649,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/path.rs b/src/libstd/path.rs index 9d66430bc93..e128a4164d7 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -51,10 +51,17 @@ //! ``` //! use std::path::PathBuf; //! +//! // This way works... //! let mut path = PathBuf::from("c:\\"); +//! //! path.push("windows"); //! path.push("system32"); +//! //! path.set_extension("dll"); +//! +//! // ... 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 @@ -63,6 +70,7 @@ //! [`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 @@ -1036,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 { @@ -1307,14 +1341,14 @@ impl<'a> From<&'a Path> for Box<Path> { } } -#[stable(feature = "path_buf_from_box", since = "1.17.0")] -impl<'a> From<Box<Path>> for PathBuf { +#[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.17.0")] +#[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() @@ -1390,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() diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 4ec9076de61..da64704efba 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -148,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 @@ -190,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 @@ -752,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); @@ -786,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() @@ -903,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(); @@ -919,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)) } @@ -1035,7 +1058,7 @@ impl Child { /// ```no_run /// use std::process; /// -/// process::exit(0x0f00); +/// process::exit(0x0100); /// ``` /// /// [platform-specific behavior]: #platform-specific-behavior diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index 6c791cd336d..acff7faf8a7 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -29,8 +29,7 @@ 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; @@ -54,7 +53,9 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { sys::args::init(argc, argv); // Let's run some code! - let res = panic::catch_unwind(mem::transmute::<_, fn()>(main)); + let res = panic::catch_unwind(|| { + ::sys_common::backtrace::__rust_begin_short_backtrace(main) + }); sys_common::cleanup(); res.is_err() }; diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 7ad9d9ee37c..c120a3045e4 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -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 6c8839224f7..69507cada2b 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -297,12 +297,14 @@ 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`]. /// -/// [`recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv +/// [`channel`]: fn.channel.html +/// [`sync_channel`]: fn.sync_channel.html +/// [`recv`]: struct.Receiver.html#method.recv /// /// # Examples /// @@ -336,51 +338,128 @@ 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 +/// 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 if -/// the corresponding channel has hung up. +/// 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 +/// 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`]. /// -/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send +/// [`channel`]: fn.channel.html +/// [`send`]: struct.Sender.html#method.send /// /// # Examples /// @@ -419,12 +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; /// -/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send -/// [`SyncSender::send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send +/// // 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>>, @@ -799,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 {{ .. }}") @@ -823,8 +945,9 @@ 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 @@ -832,6 +955,27 @@ impl<T> SyncSender<T> { /// /// [`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) @@ -844,11 +988,48 @@ impl<T> SyncSender<T> { /// 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.Sender.html#method.send - /// [`SyncSender::send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send + /// [`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) @@ -870,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 {{ .. }}") @@ -886,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 @@ -894,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 { @@ -949,8 +1145,8 @@ 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 @@ -958,7 +1154,8 @@ impl<T> Receiver<T> { /// However, since channels are buffered, messages sent before the disconnect /// will still be properly received. /// - /// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html + /// [`Sender`]: struct.Sender.html + /// [`SyncSender`]: struct.SyncSender.html /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err /// /// # Examples @@ -1040,8 +1237,8 @@ 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 @@ -1049,7 +1246,8 @@ impl<T> Receiver<T> { /// However, since channels are buffered, messages sent before the disconnect /// will still be properly received. /// - /// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html + /// [`Sender`]: struct.Sender.html + /// [`SyncSender`]: struct.SyncSender.html /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err /// /// # Examples @@ -1163,6 +1361,33 @@ impl<T> Receiver<T> { /// 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 } @@ -1292,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 {{ .. }}") @@ -1419,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 { @@ -1433,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/mutex.rs b/src/libstd/sync/mutex.rs index a27f621e6b2..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; @@ -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. @@ -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/rwlock.rs b/src/libstd/sync/rwlock.rs index d26f2f7bb7e..95bc8d30932 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -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 f6414673dac..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 } diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs index 07d76a93dd1..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 } 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/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 d6e2fed56be..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,81 +103,94 @@ 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 @@ -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/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/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 04fe5f78b03..617218fe7a5 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -93,11 +93,47 @@ fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> { Ok(()) } -fn filter_frames(_frames: &[Frame], - _format: PrintFormat, - _context: &BacktraceContext) -> (usize, usize) +/// 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) { - (0, 0) + if format == PrintFormat::Full { + return (0, 0); + } + + 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 { + // Use grep to find the concerned functions + if mangled_symbol_name.contains("__rust_begin_short_backtrace") { + is_marker = true; + } + } + Ok(()) + }, context); + is_marker + }).unwrap_or(frames.len()); + + if skipped_before + skipped_after >= frames.len() { + // Avoid showing completely empty backtraces + return (0, 0); + } + + (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. diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs index 9239c18e597..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), + } } } 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 79aaf34ce2e..df5e4ef1d88 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -750,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 e2b22b1d89f..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 @@ -77,6 +77,10 @@ use mem; /// 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")] diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index e37cc7e963e..154406a1d8b 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. //! @@ -96,41 +96,6 @@ //! 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 @@ -159,6 +124,7 @@ //! [`panic!`]: ../../std/macro.panic.html //! [`Builder`]: ../../std/thread/struct.Builder.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 @@ -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,7 +359,9 @@ impl Builder { } unsafe { thread_info::set(imp::guard::current(), their_thread); - let try_result = panic::catch_unwind(panic::AssertUnwindSafe(f)); + let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { + ::sys_common::backtrace::__rust_begin_short_backtrace(f) + })); *their_packet.get() = Some(try_result); } }; @@ -386,19 +390,19 @@ 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. +/// /// # 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 +412,54 @@ 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 #[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 +495,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 +519,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 +532,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 +570,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 +633,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. /// -/// [unpark]: struct.Thread.html#method.unpark +/// # 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 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: /// -/// See the [module documentation][thread] for more detail. +/// * It avoids the need to allocate mutexes and condvars when building new +/// synchronization primitives; the threads already provide basic +/// blocking/signaling. /// -/// [thread]: index.html +/// * 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(); +/// +/// // 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(); +/// ``` +/// +/// [`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 +715,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 +739,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 +770,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(); @@ -715,21 +853,24 @@ 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>, } @@ -752,22 +893,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(); @@ -851,9 +1006,31 @@ impl fmt::Debug for Thread { // 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 } |
