diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2018-08-19 18:34:46 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-08-19 18:34:46 +0200 |
| commit | 08b1d83a46848dd7bd778aeae67a1e529e95d8cd (patch) | |
| tree | 9153a34f91860b175afb24f904fd50ac09e77c4e /src/libstd | |
| parent | ac64ef33756d05557153e00211cdf8fcf65d4be3 (diff) | |
| parent | b355906919927ab3c879becd14392f023af883a1 (diff) | |
| download | rust-08b1d83a46848dd7bd778aeae67a1e529e95d8cd.tar.gz rust-08b1d83a46848dd7bd778aeae67a1e529e95d8cd.zip | |
Merge branch 'master' into feature/core_convert_id
Diffstat (limited to 'src/libstd')
183 files changed, 8190 insertions, 5892 deletions
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 3430ecabcbe..5348c9a0f34 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -22,11 +22,10 @@ core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } compiler_builtins = { path = "../rustc/compiler_builtins_shim" } profiler_builtins = { path = "../libprofiler_builtins", optional = true } -std_unicode = { path = "../libstd_unicode" } unwind = { path = "../libunwind" } [dev-dependencies] -rand = "0.3" +rand = "0.4" [target.x86_64-apple-darwin.dependencies] rustc_asan = { path = "../librustc_asan" } @@ -39,6 +38,7 @@ rustc_msan = { path = "../librustc_msan" } rustc_tsan = { path = "../librustc_tsan" } [build-dependencies] +cc = "1.0" build_helper = { path = "../build_helper" } [features] @@ -48,3 +48,4 @@ jemalloc = ["alloc_jemalloc"] force_alloc_system = [] panic-unwind = ["panic_unwind"] profiler = ["profiler_builtins"] +wasm_syscall = [] diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs new file mode 100644 index 00000000000..b9aba1e9cab --- /dev/null +++ b/src/libstd/alloc.rs @@ -0,0 +1,184 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Memory allocation APIs +//! +//! In a given program, the standard library has one “global” memory allocator +//! that is used for example by `Box<T>` and `Vec<T>`. +//! +//! Currently the default global allocator is unspecified. +//! The compiler may link to a version of [jemalloc] on some platforms, +//! but this is not guaranteed. +//! Libraries, however, like `cdylib`s and `staticlib`s are guaranteed +//! to use the [`System`] by default. +//! +//! [jemalloc]: https://github.com/jemalloc/jemalloc +//! [`System`]: struct.System.html +//! +//! # The `#[global_allocator]` attribute +//! +//! This attribute allows configuring the choice of global allocator. +//! You can use this to implement a completely custom global allocator +//! to route all default allocation requests to a custom object. +//! +//! ```rust +//! use std::alloc::{GlobalAlloc, System, Layout}; +//! +//! struct MyAllocator; +//! +//! unsafe impl GlobalAlloc for MyAllocator { +//! unsafe fn alloc(&self, layout: Layout) -> *mut u8 { +//! System.alloc(layout) +//! } +//! +//! unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { +//! System.dealloc(ptr, layout) +//! } +//! } +//! +//! #[global_allocator] +//! static GLOBAL: MyAllocator = MyAllocator; +//! +//! fn main() { +//! // This `Vec` will allocate memory through `GLOBAL` above +//! let mut v = Vec::new(); +//! v.push(1); +//! } +//! ``` +//! +//! The attribute is used on a `static` item whose type implements the +//! [`GlobalAlloc`] trait. This type can be provided by an external library: +//! +//! [`GlobalAlloc`]: ../../core/alloc/trait.GlobalAlloc.html +//! +//! ```rust,ignore (demonstrates crates.io usage) +//! extern crate jemallocator; +//! +//! use jemallocator::Jemalloc; +//! +//! #[global_allocator] +//! static GLOBAL: Jemalloc = Jemalloc; +//! +//! fn main() {} +//! ``` +//! +//! The `#[global_allocator]` can only be used once in a crate +//! or its recursive dependencies. + +#![stable(feature = "alloc_module", since = "1.28.0")] + +use core::sync::atomic::{AtomicPtr, Ordering}; +use core::{mem, ptr}; +use sys_common::util::dumb_print; + +#[stable(feature = "alloc_module", since = "1.28.0")] +#[doc(inline)] +pub use alloc_crate::alloc::*; + +#[stable(feature = "alloc_system_type", since = "1.28.0")] +#[doc(inline)] +pub use alloc_system::System; + +static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); + +/// Registers a custom allocation error hook, replacing any that was previously registered. +/// +/// The allocation error hook is invoked when an infallible memory allocation fails, before +/// the runtime aborts. The default hook prints a message to standard error, +/// but this behavior can be customized with the [`set_alloc_error_hook`] and +/// [`take_alloc_error_hook`] functions. +/// +/// The hook is provided with a `Layout` struct which contains information +/// about the allocation that failed. +/// +/// The allocation error hook is a global resource. +#[unstable(feature = "alloc_error_hook", issue = "51245")] +pub fn set_alloc_error_hook(hook: fn(Layout)) { + HOOK.store(hook as *mut (), Ordering::SeqCst); +} + +/// Unregisters the current allocation error hook, returning it. +/// +/// *See also the function [`set_alloc_error_hook`].* +/// +/// If no custom hook is registered, the default hook will be returned. +#[unstable(feature = "alloc_error_hook", issue = "51245")] +pub fn take_alloc_error_hook() -> fn(Layout) { + let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst); + if hook.is_null() { + default_alloc_error_hook + } else { + unsafe { mem::transmute(hook) } + } +} + +fn default_alloc_error_hook(layout: Layout) { + dumb_print(format_args!("memory allocation of {} bytes failed", layout.size())); +} + +#[cfg(not(test))] +#[doc(hidden)] +#[alloc_error_handler] +#[unstable(feature = "alloc_internals", issue = "0")] +pub fn rust_oom(layout: Layout) -> ! { + let hook = HOOK.load(Ordering::SeqCst); + let hook: fn(Layout) = if hook.is_null() { + default_alloc_error_hook + } else { + unsafe { mem::transmute(hook) } + }; + hook(layout); + unsafe { ::sys::abort_internal(); } +} + +#[cfg(not(test))] +#[doc(hidden)] +#[allow(unused_attributes)] +#[unstable(feature = "alloc_internals", issue = "0")] +pub mod __default_lib_allocator { + use super::{System, Layout, GlobalAlloc}; + // for symbol names src/librustc/middle/allocator.rs + // for signatures src/librustc_allocator/lib.rs + + // linkage directives are provided as part of the current compiler allocator + // ABI + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 { + let layout = Layout::from_size_align_unchecked(size, align); + System.alloc(layout) + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, + size: usize, + align: usize) { + System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_realloc(ptr: *mut u8, + old_size: usize, + align: usize, + new_size: usize) -> *mut u8 { + let old_layout = Layout::from_size_align_unchecked(old_size, align); + System.realloc(ptr, old_layout, new_size) + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 { + let layout = Layout::from_size_align_unchecked(size, align); + System.alloc_zeroed(layout) + } +} diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 82e1a3447dc..0c8e95aa426 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -26,9 +26,8 @@ #![stable(feature = "rust1", since = "1.0.0")] -use fmt; -use ops::Range; -use iter::FusedIterator; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::ascii::{EscapeDefault, escape_default}; /// Extension methods for ASCII-subset only operations. /// @@ -53,6 +52,7 @@ use iter::FusedIterator; /// /// [combining character]: https://en.wikipedia.org/wiki/Combining_character #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] pub trait AsciiExt { /// Container type for copied ASCII characters. #[stable(feature = "rust1", since = "1.0.0")] @@ -85,6 +85,7 @@ pub trait AsciiExt { /// [`make_ascii_uppercase`]: #tymethod.make_ascii_uppercase /// [`str::to_uppercase`]: ../primitive.str.html#method.to_uppercase #[stable(feature = "rust1", since = "1.0.0")] + #[allow(deprecated)] fn to_ascii_uppercase(&self) -> Self::Owned; /// Makes a copy of the value in its ASCII lower case equivalent. @@ -105,6 +106,7 @@ pub trait AsciiExt { /// [`make_ascii_lowercase`]: #tymethod.make_ascii_lowercase /// [`str::to_lowercase`]: ../primitive.str.html#method.to_lowercase #[stable(feature = "rust1", since = "1.0.0")] + #[allow(deprecated)] fn to_ascii_lowercase(&self) -> Self::Owned; /// Checks that two values are an ASCII case-insensitive match. @@ -152,150 +154,6 @@ pub trait AsciiExt { /// [`to_ascii_lowercase`]: #tymethod.to_ascii_lowercase #[stable(feature = "ascii", since = "1.9.0")] fn make_ascii_lowercase(&mut self); - - /// Checks if the value is an ASCII alphabetic character: - /// U+0041 'A' ... U+005A 'Z' or U+0061 'a' ... U+007A 'z'. - /// For strings, true if all characters in the string are - /// ASCII alphabetic. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[unstable(feature = "ascii_ctype", issue = "39658")] - fn is_ascii_alphabetic(&self) -> bool { unimplemented!(); } - - /// Checks if the value is an ASCII uppercase character: - /// U+0041 'A' ... U+005A 'Z'. - /// For strings, true if all characters in the string are - /// ASCII uppercase. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[unstable(feature = "ascii_ctype", issue = "39658")] - fn is_ascii_uppercase(&self) -> bool { unimplemented!(); } - - /// Checks if the value is an ASCII lowercase character: - /// U+0061 'a' ... U+007A 'z'. - /// For strings, true if all characters in the string are - /// ASCII lowercase. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[unstable(feature = "ascii_ctype", issue = "39658")] - fn is_ascii_lowercase(&self) -> bool { unimplemented!(); } - - /// Checks if the value is an ASCII alphanumeric character: - /// U+0041 'A' ... U+005A 'Z', U+0061 'a' ... U+007A 'z', or - /// U+0030 '0' ... U+0039 '9'. - /// For strings, true if all characters in the string are - /// ASCII alphanumeric. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[unstable(feature = "ascii_ctype", issue = "39658")] - fn is_ascii_alphanumeric(&self) -> bool { unimplemented!(); } - - /// Checks if the value is an ASCII decimal digit: - /// U+0030 '0' ... U+0039 '9'. - /// For strings, true if all characters in the string are - /// ASCII digits. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[unstable(feature = "ascii_ctype", issue = "39658")] - fn is_ascii_digit(&self) -> bool { unimplemented!(); } - - /// Checks if the value is an ASCII hexadecimal digit: - /// U+0030 '0' ... U+0039 '9', U+0041 'A' ... U+0046 'F', or - /// U+0061 'a' ... U+0066 'f'. - /// For strings, true if all characters in the string are - /// ASCII hex digits. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[unstable(feature = "ascii_ctype", issue = "39658")] - fn is_ascii_hexdigit(&self) -> bool { unimplemented!(); } - - /// Checks if the value is an ASCII punctuation character: - /// - /// U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /` - /// U+003A ... U+0040 `: ; < = > ? @` - /// U+005B ... U+0060 ``[ \\ ] ^ _ ` `` - /// U+007B ... U+007E `{ | } ~` - /// - /// For strings, true if all characters in the string are - /// ASCII punctuation. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[unstable(feature = "ascii_ctype", issue = "39658")] - fn is_ascii_punctuation(&self) -> bool { unimplemented!(); } - - /// Checks if the value is an ASCII graphic character: - /// U+0021 '@' ... U+007E '~'. - /// For strings, true if all characters in the string are - /// ASCII graphic characters. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[unstable(feature = "ascii_ctype", issue = "39658")] - fn is_ascii_graphic(&self) -> bool { unimplemented!(); } - - /// Checks if the value is an ASCII whitespace character: - /// U+0020 SPACE, U+0009 HORIZONTAL TAB, U+000A LINE FEED, - /// U+000C FORM FEED, or U+000D CARRIAGE RETURN. - /// For strings, true if all characters in the string are - /// ASCII whitespace. - /// - /// Rust uses the WhatWG Infra Standard's [definition of ASCII - /// whitespace][infra-aw]. There are several other definitions in - /// wide use. For instance, [the POSIX locale][pct] includes - /// U+000B VERTICAL TAB as well as all the above characters, - /// but—from the very same specification—[the default rule for - /// "field splitting" in the Bourne shell][bfs] considers *only* - /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace. - /// - /// If you are writing a program that will process an existing - /// file format, check what that format's definition of whitespace is - /// before using this function. - /// - /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace - /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01 - /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[unstable(feature = "ascii_ctype", issue = "39658")] - fn is_ascii_whitespace(&self) -> bool { unimplemented!(); } - - /// Checks if the value is an ASCII control character: - /// U+0000 NUL ... U+001F UNIT SEPARATOR, or U+007F DELETE. - /// Note that most ASCII whitespace characters are control - /// characters, but SPACE is not. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[unstable(feature = "ascii_ctype", issue = "39658")] - fn is_ascii_control(&self) -> bool { unimplemented!(); } } macro_rules! delegating_ascii_methods { @@ -320,640 +178,34 @@ macro_rules! delegating_ascii_methods { } } -macro_rules! delegating_ascii_ctype_methods { - () => { - #[inline] - fn is_ascii_alphabetic(&self) -> bool { self.is_ascii_alphabetic() } - - #[inline] - fn is_ascii_uppercase(&self) -> bool { self.is_ascii_uppercase() } - - #[inline] - fn is_ascii_lowercase(&self) -> bool { self.is_ascii_lowercase() } - - #[inline] - fn is_ascii_alphanumeric(&self) -> bool { self.is_ascii_alphanumeric() } - - #[inline] - fn is_ascii_digit(&self) -> bool { self.is_ascii_digit() } - - #[inline] - fn is_ascii_hexdigit(&self) -> bool { self.is_ascii_hexdigit() } - - #[inline] - fn is_ascii_punctuation(&self) -> bool { self.is_ascii_punctuation() } - - #[inline] - fn is_ascii_graphic(&self) -> bool { self.is_ascii_graphic() } - - #[inline] - fn is_ascii_whitespace(&self) -> bool { self.is_ascii_whitespace() } - - #[inline] - fn is_ascii_control(&self) -> bool { self.is_ascii_control() } - } -} - #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] impl AsciiExt for u8 { type Owned = u8; delegating_ascii_methods!(); - delegating_ascii_ctype_methods!(); } #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] impl AsciiExt for char { type Owned = char; delegating_ascii_methods!(); - delegating_ascii_ctype_methods!(); } #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] impl AsciiExt for [u8] { type Owned = Vec<u8>; delegating_ascii_methods!(); - - #[inline] - fn is_ascii_alphabetic(&self) -> bool { - self.iter().all(|b| b.is_ascii_alphabetic()) - } - - #[inline] - fn is_ascii_uppercase(&self) -> bool { - self.iter().all(|b| b.is_ascii_uppercase()) - } - - #[inline] - fn is_ascii_lowercase(&self) -> bool { - self.iter().all(|b| b.is_ascii_lowercase()) - } - - #[inline] - fn is_ascii_alphanumeric(&self) -> bool { - self.iter().all(|b| b.is_ascii_alphanumeric()) - } - - #[inline] - fn is_ascii_digit(&self) -> bool { - self.iter().all(|b| b.is_ascii_digit()) - } - - #[inline] - fn is_ascii_hexdigit(&self) -> bool { - self.iter().all(|b| b.is_ascii_hexdigit()) - } - - #[inline] - fn is_ascii_punctuation(&self) -> bool { - self.iter().all(|b| b.is_ascii_punctuation()) - } - - #[inline] - fn is_ascii_graphic(&self) -> bool { - self.iter().all(|b| b.is_ascii_graphic()) - } - - #[inline] - fn is_ascii_whitespace(&self) -> bool { - self.iter().all(|b| b.is_ascii_whitespace()) - } - - #[inline] - fn is_ascii_control(&self) -> bool { - self.iter().all(|b| b.is_ascii_control()) - } } #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] impl AsciiExt for str { type Owned = String; delegating_ascii_methods!(); - - #[inline] - fn is_ascii_alphabetic(&self) -> bool { - self.bytes().all(|b| b.is_ascii_alphabetic()) - } - - #[inline] - fn is_ascii_uppercase(&self) -> bool { - self.bytes().all(|b| b.is_ascii_uppercase()) - } - - #[inline] - fn is_ascii_lowercase(&self) -> bool { - self.bytes().all(|b| b.is_ascii_lowercase()) - } - - #[inline] - fn is_ascii_alphanumeric(&self) -> bool { - self.bytes().all(|b| b.is_ascii_alphanumeric()) - } - - #[inline] - fn is_ascii_digit(&self) -> bool { - self.bytes().all(|b| b.is_ascii_digit()) - } - - #[inline] - fn is_ascii_hexdigit(&self) -> bool { - self.bytes().all(|b| b.is_ascii_hexdigit()) - } - - #[inline] - fn is_ascii_punctuation(&self) -> bool { - self.bytes().all(|b| b.is_ascii_punctuation()) - } - - #[inline] - fn is_ascii_graphic(&self) -> bool { - self.bytes().all(|b| b.is_ascii_graphic()) - } - - #[inline] - fn is_ascii_whitespace(&self) -> bool { - self.bytes().all(|b| b.is_ascii_whitespace()) - } - - #[inline] - fn is_ascii_control(&self) -> bool { - self.bytes().all(|b| b.is_ascii_control()) - } -} - -/// An iterator over the escaped version of a byte. -/// -/// This `struct` is created by the [`escape_default`] function. See its -/// documentation for more. -/// -/// [`escape_default`]: fn.escape_default.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct EscapeDefault { - range: Range<usize>, - data: [u8; 4], -} - -/// Returns an iterator that produces an escaped version of a `u8`. -/// -/// The default is chosen with a bias toward producing literals that are -/// legal in a variety of languages, including C++11 and similar C-family -/// languages. The exact rules are: -/// -/// - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively. -/// - Single-quote, double-quote and backslash chars are backslash-escaped. -/// - Any other chars in the range [0x20,0x7e] are not escaped. -/// - Any other chars are given hex escapes of the form '\xNN'. -/// - Unicode escapes are never generated by this function. -/// -/// # Examples -/// -/// ``` -/// use std::ascii; -/// -/// let escaped = ascii::escape_default(b'0').next().unwrap(); -/// assert_eq!(b'0', escaped); -/// -/// let mut escaped = ascii::escape_default(b'\t'); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b't', escaped.next().unwrap()); -/// -/// let mut escaped = ascii::escape_default(b'\r'); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b'r', escaped.next().unwrap()); -/// -/// let mut escaped = ascii::escape_default(b'\n'); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b'n', escaped.next().unwrap()); -/// -/// let mut escaped = ascii::escape_default(b'\''); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b'\'', escaped.next().unwrap()); -/// -/// let mut escaped = ascii::escape_default(b'"'); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b'"', escaped.next().unwrap()); -/// -/// let mut escaped = ascii::escape_default(b'\\'); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// -/// let mut escaped = ascii::escape_default(b'\x9d'); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b'x', escaped.next().unwrap()); -/// assert_eq!(b'9', escaped.next().unwrap()); -/// assert_eq!(b'd', escaped.next().unwrap()); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn escape_default(c: u8) -> EscapeDefault { - let (data, len) = match c { - b'\t' => ([b'\\', b't', 0, 0], 2), - b'\r' => ([b'\\', b'r', 0, 0], 2), - b'\n' => ([b'\\', b'n', 0, 0], 2), - b'\\' => ([b'\\', b'\\', 0, 0], 2), - b'\'' => ([b'\\', b'\'', 0, 0], 2), - b'"' => ([b'\\', b'"', 0, 0], 2), - b'\x20' ... b'\x7e' => ([c, 0, 0, 0], 1), - _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4), - }; - - return EscapeDefault { range: (0.. len), data: data }; - - fn hexify(b: u8) -> u8 { - match b { - 0 ... 9 => b'0' + b, - _ => b'a' + b - 10, - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for EscapeDefault { - type Item = u8; - fn next(&mut self) -> Option<u8> { self.range.next().map(|i| self.data[i]) } - fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for EscapeDefault { - fn next_back(&mut self) -> Option<u8> { - self.range.next_back().map(|i| self.data[i]) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for EscapeDefault {} -#[unstable(feature = "fused", issue = "35602")] -impl FusedIterator for EscapeDefault {} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for EscapeDefault { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("EscapeDefault { .. }") - } -} - - -#[cfg(test)] -mod tests { - //! Note that most of these tests are not testing `AsciiExt` methods, but - //! test inherent ascii methods of char, u8, str and [u8]. `AsciiExt` is - //! just using those methods, though. - use super::AsciiExt; - use char::from_u32; - - #[test] - fn test_is_ascii() { - assert!(b"".is_ascii()); - assert!(b"banana\0\x7F".is_ascii()); - assert!(b"banana\0\x7F".iter().all(|b| b.is_ascii())); - assert!(!b"Vi\xe1\xbb\x87t Nam".is_ascii()); - assert!(!b"Vi\xe1\xbb\x87t Nam".iter().all(|b| b.is_ascii())); - assert!(!b"\xe1\xbb\x87".iter().any(|b| b.is_ascii())); - - assert!("".is_ascii()); - assert!("banana\0\u{7F}".is_ascii()); - assert!("banana\0\u{7F}".chars().all(|c| c.is_ascii())); - assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii())); - assert!(!"ประเทศไทย中华ệ ".chars().any(|c| c.is_ascii())); - } - - #[test] - fn test_to_ascii_uppercase() { - assert_eq!("url()URL()uRl()ürl".to_ascii_uppercase(), "URL()URL()URL()üRL"); - assert_eq!("hıKß".to_ascii_uppercase(), "HıKß"); - - for i in 0..501 { - let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 } - else { i }; - assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_uppercase(), - (from_u32(upper).unwrap()).to_string()); - } - } - - #[test] - fn test_to_ascii_lowercase() { - assert_eq!("url()URL()uRl()Ürl".to_ascii_lowercase(), "url()url()url()Ürl"); - // Dotted capital I, Kelvin sign, Sharp S. - assert_eq!("HİKß".to_ascii_lowercase(), "hİKß"); - - for i in 0..501 { - let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } - else { i }; - assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_lowercase(), - (from_u32(lower).unwrap()).to_string()); - } - } - - #[test] - fn test_make_ascii_lower_case() { - macro_rules! test { - ($from: expr, $to: expr) => { - { - let mut x = $from; - x.make_ascii_lowercase(); - assert_eq!(x, $to); - } - } - } - test!(b'A', b'a'); - test!(b'a', b'a'); - test!(b'!', b'!'); - test!('A', 'a'); - test!('À', 'À'); - test!('a', 'a'); - test!('!', '!'); - test!(b"H\xc3\x89".to_vec(), b"h\xc3\x89"); - test!("HİKß".to_string(), "hİKß"); - } - - - #[test] - fn test_make_ascii_upper_case() { - macro_rules! test { - ($from: expr, $to: expr) => { - { - let mut x = $from; - x.make_ascii_uppercase(); - assert_eq!(x, $to); - } - } - } - test!(b'a', b'A'); - test!(b'A', b'A'); - test!(b'!', b'!'); - test!('a', 'A'); - test!('à', 'à'); - test!('A', 'A'); - test!('!', '!'); - test!(b"h\xc3\xa9".to_vec(), b"H\xc3\xa9"); - test!("hıKß".to_string(), "HıKß"); - - let mut x = "Hello".to_string(); - x[..3].make_ascii_uppercase(); // Test IndexMut on String. - assert_eq!(x, "HELlo") - } - - #[test] - fn test_eq_ignore_ascii_case() { - assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl")); - assert!(!"Ürl".eq_ignore_ascii_case("ürl")); - // Dotted capital I, Kelvin sign, Sharp S. - assert!("HİKß".eq_ignore_ascii_case("hİKß")); - assert!(!"İ".eq_ignore_ascii_case("i")); - assert!(!"K".eq_ignore_ascii_case("k")); - assert!(!"ß".eq_ignore_ascii_case("s")); - - for i in 0..501 { - let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } - else { i }; - assert!((from_u32(i).unwrap()).to_string().eq_ignore_ascii_case( - &from_u32(lower).unwrap().to_string())); - } - } - - #[test] - fn inference_works() { - let x = "a".to_string(); - x.eq_ignore_ascii_case("A"); - } - - // Shorthands used by the is_ascii_* tests. - macro_rules! assert_all { - ($what:ident, $($str:tt),+) => {{ - $( - for b in $str.chars() { - if !b.$what() { - panic!("expected {}({}) but it isn't", - stringify!($what), b); - } - } - for b in $str.as_bytes().iter() { - if !b.$what() { - panic!("expected {}(0x{:02x})) but it isn't", - stringify!($what), b); - } - } - assert!($str.$what()); - assert!($str.as_bytes().$what()); - )+ - }}; - ($what:ident, $($str:tt),+,) => (assert_all!($what,$($str),+)) - } - macro_rules! assert_none { - ($what:ident, $($str:tt),+) => {{ - $( - for b in $str.chars() { - if b.$what() { - panic!("expected not-{}({}) but it is", - stringify!($what), b); - } - } - for b in $str.as_bytes().iter() { - if b.$what() { - panic!("expected not-{}(0x{:02x})) but it is", - stringify!($what), b); - } - } - )* - }}; - ($what:ident, $($str:tt),+,) => (assert_none!($what,$($str),+)) - } - - #[test] - fn test_is_ascii_alphabetic() { - assert_all!(is_ascii_alphabetic, - "", - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - ); - assert_none!(is_ascii_alphabetic, - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_uppercase() { - assert_all!(is_ascii_uppercase, - "", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - ); - assert_none!(is_ascii_uppercase, - "abcdefghijklmnopqrstuvwxyz", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_lowercase() { - assert_all!(is_ascii_lowercase, - "abcdefghijklmnopqrstuvwxyz", - ); - assert_none!(is_ascii_lowercase, - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_alphanumeric() { - assert_all!(is_ascii_alphanumeric, - "", - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - ); - assert_none!(is_ascii_alphanumeric, - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_digit() { - assert_all!(is_ascii_digit, - "", - "0123456789", - ); - assert_none!(is_ascii_digit, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_hexdigit() { - assert_all!(is_ascii_hexdigit, - "", - "0123456789", - "abcdefABCDEF", - ); - assert_none!(is_ascii_hexdigit, - "ghijklmnopqrstuvwxyz", - "GHIJKLMNOQPRSTUVWXYZ", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_punctuation() { - assert_all!(is_ascii_punctuation, - "", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - ); - assert_none!(is_ascii_punctuation, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_graphic() { - assert_all!(is_ascii_graphic, - "", - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - ); - assert_none!(is_ascii_graphic, - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_whitespace() { - assert_all!(is_ascii_whitespace, - "", - " \t\n\x0c\r", - ); - assert_none!(is_ascii_whitespace, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x0b\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_control() { - assert_all!(is_ascii_control, - "", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - assert_none!(is_ascii_control, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " ", - ); - } } diff --git a/src/libstd/build.rs b/src/libstd/build.rs index a41c155f3fb..016e7adb4c9 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -11,22 +11,21 @@ #![deny(warnings)] extern crate build_helper; +extern crate cc; +use build_helper::native_lib_boilerplate; use std::env; -use std::process::Command; -use build_helper::{run, native_lib_boilerplate}; +use std::fs::File; fn main() { let target = env::var("TARGET").expect("TARGET was not set"); - let host = env::var("HOST").expect("HOST was not set"); if cfg!(feature = "backtrace") && !target.contains("cloudabi") && !target.contains("emscripten") && - !target.contains("fuchsia") && !target.contains("msvc") && !target.contains("wasm32") { - let _ = build_libbacktrace(&host, &target); + let _ = build_libbacktrace(&target); } if target.contains("linux") { @@ -68,13 +67,8 @@ fn main() { println!("cargo:rustc-link-lib=userenv"); println!("cargo:rustc-link-lib=shell32"); } else if target.contains("fuchsia") { - // use system-provided libbacktrace - if cfg!(feature = "backtrace") { - println!("cargo:rustc-link-lib=backtrace"); - } println!("cargo:rustc-link-lib=zircon"); println!("cargo:rustc-link-lib=fdio"); - println!("cargo:rustc-link-lib=launchpad"); // for std::process } else if target.contains("cloudabi") { if cfg!(feature = "backtrace") { println!("cargo:rustc-link-lib=unwind"); @@ -84,25 +78,57 @@ fn main() { } } -fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> { - let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", ".libs")?; +fn build_libbacktrace(target: &str) -> Result<(), ()> { + let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", "")?; + + let mut build = cc::Build::new(); + build + .flag("-fvisibility=hidden") + .include("../libbacktrace") + .include(&native.out_dir) + .out_dir(&native.out_dir) + .warnings(false) + .file("../libbacktrace/alloc.c") + .file("../libbacktrace/backtrace.c") + .file("../libbacktrace/dwarf.c") + .file("../libbacktrace/fileline.c") + .file("../libbacktrace/posix.c") + .file("../libbacktrace/read.c") + .file("../libbacktrace/sort.c") + .file("../libbacktrace/state.c"); + + if target.contains("darwin") { + build.file("../libbacktrace/macho.c"); + } else if target.contains("windows") { + build.file("../libbacktrace/pecoff.c"); + } else { + build.file("../libbacktrace/elf.c"); + + let pointer_width = env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap(); + if pointer_width == "64" { + build.define("BACKTRACE_ELF_SIZE", "64"); + } else { + build.define("BACKTRACE_ELF_SIZE", "32"); + } + } - run(Command::new("sh") - .current_dir(&native.out_dir) - .arg(native.src_dir.join("configure").to_str().unwrap() - .replace("C:\\", "/c/") - .replace("\\", "/")) - .arg("--with-pic") - .arg("--disable-multilib") - .arg("--disable-shared") - .arg("--disable-host-shared") - .arg(format!("--host={}", build_helper::gnu_target(target))) - .arg(format!("--build={}", build_helper::gnu_target(host))) - .env("CFLAGS", env::var("CFLAGS").unwrap_or_default() + " -fvisibility=hidden")); + File::create(native.out_dir.join("backtrace-supported.h")).unwrap(); + build.define("BACKTRACE_SUPPORTED", "1"); + build.define("BACKTRACE_USES_MALLOC", "1"); + build.define("BACKTRACE_SUPPORTS_THREADS", "0"); + build.define("BACKTRACE_SUPPORTS_DATA", "0"); + + File::create(native.out_dir.join("config.h")).unwrap(); + if !target.contains("apple-ios") && + !target.contains("solaris") && + !target.contains("redox") && + !target.contains("android") && + !target.contains("haiku") { + build.define("HAVE_DL_ITERATE_PHDR", "1"); + } + build.define("_GNU_SOURCE", "1"); + build.define("_LARGE_FILES", "1"); - run(Command::new(build_helper::make(host)) - .current_dir(&native.out_dir) - .arg(format!("INCDIR={}", native.src_dir.display())) - .arg("-j").arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set"))); + build.compile("backtrace"); Ok(()) } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 4e5385c17e9..91912e5f241 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -11,6 +11,7 @@ use self::Entry::*; use self::VacantEntryState::*; +use collections::CollectionAllocErr; use cell::Cell; use borrow::Borrow; use cmp::max; @@ -19,12 +20,13 @@ use fmt::{self, Debug}; use hash::{Hash, Hasher, BuildHasher, SipHasher13}; use iter::{FromIterator, FusedIterator}; use mem::{self, replace}; -use ops::{Deref, Index, InPlace, Place, Placer}; -use ptr; +use ops::{Deref, Index}; use sys; -use super::table::{self, Bucket, EmptyBucket, FullBucket, FullBucketMut, RawTable, SafeHash}; +use super::table::{self, Bucket, EmptyBucket, Fallibility, FullBucket, FullBucketMut, RawTable, + SafeHash}; use super::table::BucketState::{Empty, Full}; +use super::table::Fallibility::{Fallible, Infallible}; const MIN_NONZERO_RAW_CAPACITY: usize = 32; // must be a power of two @@ -33,6 +35,7 @@ const MIN_NONZERO_RAW_CAPACITY: usize = 32; // must be a power of two struct DefaultResizePolicy; impl DefaultResizePolicy { + #[inline] fn new() -> DefaultResizePolicy { DefaultResizePolicy } @@ -42,21 +45,28 @@ impl DefaultResizePolicy { /// provide that capacity, accounting for maximum loading. The raw capacity /// is always zero or a power of two. #[inline] - fn raw_capacity(&self, len: usize) -> usize { + fn try_raw_capacity(&self, len: usize) -> Result<usize, CollectionAllocErr> { if len == 0 { - 0 + Ok(0) } else { // 1. Account for loading: `raw_capacity >= len * 1.1`. // 2. Ensure it is a power of two. // 3. Ensure it is at least the minimum size. - let mut raw_cap = len * 11 / 10; - assert!(raw_cap >= len, "raw_cap overflow"); - raw_cap = raw_cap.checked_next_power_of_two().expect("raw_capacity overflow"); + let mut raw_cap = len.checked_mul(11) + .map(|l| l / 10) + .and_then(|l| l.checked_next_power_of_two()) + .ok_or(CollectionAllocErr::CapacityOverflow)?; + raw_cap = max(MIN_NONZERO_RAW_CAPACITY, raw_cap); - raw_cap + Ok(raw_cap) } } + #[inline] + fn raw_capacity(&self, len: usize) -> usize { + self.try_raw_capacity(len).expect("raw_capacity overflow") + } + /// The capacity of the given raw capacity. #[inline] fn capacity(&self, raw_cap: usize) -> usize { @@ -266,17 +276,31 @@ const DISPLACEMENT_THRESHOLD: usize = 128; /// ``` /// use std::collections::HashMap; /// -/// // type inference lets us omit an explicit type signature (which -/// // would be `HashMap<&str, &str>` in this example). +/// // Type inference lets us omit an explicit type signature (which +/// // would be `HashMap<String, String>` in this example). /// let mut book_reviews = HashMap::new(); /// -/// // review some books. -/// book_reviews.insert("Adventures of Huckleberry Finn", "My favorite book."); -/// book_reviews.insert("Grimms' Fairy Tales", "Masterpiece."); -/// book_reviews.insert("Pride and Prejudice", "Very enjoyable."); -/// book_reviews.insert("The Adventures of Sherlock Holmes", "Eye lyked it alot."); +/// // Review some books. +/// book_reviews.insert( +/// "Adventures of Huckleberry Finn".to_string(), +/// "My favorite book.".to_string(), +/// ); +/// book_reviews.insert( +/// "Grimms' Fairy Tales".to_string(), +/// "Masterpiece.".to_string(), +/// ); +/// book_reviews.insert( +/// "Pride and Prejudice".to_string(), +/// "Very enjoyable.".to_string(), +/// ); +/// book_reviews.insert( +/// "The Adventures of Sherlock Holmes".to_string(), +/// "Eye lyked it alot.".to_string(), +/// ); /// -/// // check for a specific one. +/// // Check for a specific one. +/// // When collections store owned values (String), they can still be +/// // queried using references (&str). /// if !book_reviews.contains_key("Les Misérables") { /// println!("We've got {} reviews, but Les Misérables ain't one.", /// book_reviews.len()); @@ -285,16 +309,16 @@ const DISPLACEMENT_THRESHOLD: usize = 128; /// // oops, this review has a lot of spelling mistakes, let's delete it. /// book_reviews.remove("The Adventures of Sherlock Holmes"); /// -/// // look up the values associated with some keys. +/// // Look up the values associated with some keys. /// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"]; -/// for book in &to_find { +/// for &book in &to_find { /// match book_reviews.get(book) { /// Some(review) => println!("{}: {}", book, review), /// None => println!("{} is unreviewed.", book) /// } /// } /// -/// // iterate over everything. +/// // Iterate over everything. /// for (book, review) in &book_reviews { /// println!("{}: \"{}\"", book, review); /// } @@ -398,8 +422,9 @@ pub struct HashMap<K, V, S = RandomState> { } /// Search for a pre-hashed key. +/// If you don't already know the hash, use search or search_mut instead #[inline] -fn search_hashed<K, V, M, F>(table: M, hash: SafeHash, mut is_match: F) -> InternalEntry<K, V, M> +fn search_hashed<K, V, M, F>(table: M, hash: SafeHash, is_match: F) -> InternalEntry<K, V, M> where M: Deref<Target = RawTable<K, V>>, F: FnMut(&K) -> bool { @@ -410,6 +435,18 @@ fn search_hashed<K, V, M, F>(table: M, hash: SafeHash, mut is_match: F) -> Inter return InternalEntry::TableIsEmpty; } + search_hashed_nonempty(table, hash, is_match) +} + +/// Search for a pre-hashed key when the hash map is known to be non-empty. +#[inline] +fn search_hashed_nonempty<K, V, M, F>(table: M, hash: SafeHash, mut is_match: F) + -> InternalEntry<K, V, M> + where M: Deref<Target = RawTable<K, V>>, + F: FnMut(&K) -> bool +{ + // Do not check the capacity as an extra branch could slow the lookup. + let size = table.size(); let mut probe = Bucket::new(table, hash); let mut displacement = 0; @@ -543,24 +580,36 @@ impl<K, V, S> HashMap<K, V, S> } /// Search for a key, yielding the index if it's found in the hashtable. - /// If you already have the hash for the key lying around, use - /// search_hashed. + /// If you already have the hash for the key lying around, or if you need an + /// InternalEntry, use search_hashed or search_hashed_nonempty. #[inline] - fn search<'a, Q: ?Sized>(&'a self, q: &Q) -> InternalEntry<K, V, &'a RawTable<K, V>> + fn search<'a, Q: ?Sized>(&'a self, q: &Q) + -> Option<FullBucket<K, V, &'a RawTable<K, V>>> where K: Borrow<Q>, Q: Eq + Hash { + if self.is_empty() { + return None; + } + let hash = self.make_hash(q); - search_hashed(&self.table, hash, |k| q.eq(k.borrow())) + search_hashed_nonempty(&self.table, hash, |k| q.eq(k.borrow())) + .into_occupied_bucket() } #[inline] - fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) -> InternalEntry<K, V, &'a mut RawTable<K, V>> + fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) + -> Option<FullBucket<K, V, &'a mut RawTable<K, V>>> where K: Borrow<Q>, Q: Eq + Hash { + if self.is_empty() { + return None; + } + let hash = self.make_hash(q); - search_hashed(&mut self.table, hash, |k| q.eq(k.borrow())) + search_hashed_nonempty(&mut self.table, hash, |k| q.eq(k.borrow())) + .into_occupied_bucket() } // The caller should ensure that invariants by Robin Hood Hashing hold @@ -595,7 +644,7 @@ impl<K: Hash + Eq, V> HashMap<K, V, RandomState> { /// /// ``` /// use std::collections::HashMap; - /// let mut map: HashMap<&str, isize> = HashMap::new(); + /// let mut map: HashMap<&str, i32> = HashMap::new(); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -612,7 +661,7 @@ impl<K: Hash + Eq, V> HashMap<K, V, RandomState> { /// /// ``` /// use std::collections::HashMap; - /// let mut map: HashMap<&str, isize> = HashMap::with_capacity(10); + /// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -699,7 +748,7 @@ impl<K, V, S> HashMap<K, V, S> /// use std::collections::hash_map::RandomState; /// /// let hasher = RandomState::new(); - /// let map: HashMap<isize, isize> = HashMap::with_hasher(hasher); + /// let map: HashMap<i32, i32> = HashMap::with_hasher(hasher); /// let hasher: &RandomState = map.hasher(); /// ``` #[stable(feature = "hashmap_public_hasher", since = "1.9.0")] @@ -716,7 +765,7 @@ impl<K, V, S> HashMap<K, V, S> /// /// ``` /// use std::collections::HashMap; - /// let map: HashMap<isize, isize> = HashMap::with_capacity(100); + /// let map: HashMap<i32, i32> = HashMap::with_capacity(100); /// assert!(map.capacity() >= 100); /// ``` #[inline] @@ -745,22 +794,57 @@ impl<K, V, S> HashMap<K, V, S> /// /// ``` /// use std::collections::HashMap; - /// let mut map: HashMap<&str, isize> = HashMap::new(); + /// let mut map: HashMap<&str, i32> = HashMap::new(); /// map.reserve(10); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve(&mut self, additional: usize) { + match self.reserve_internal(additional, Infallible) { + Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), + Err(CollectionAllocErr::AllocErr) => unreachable!(), + Ok(()) => { /* yay */ } + } + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `HashMap<K,V>`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(try_reserve)] + /// use std::collections::HashMap; + /// let mut map: HashMap<&str, isize> = HashMap::new(); + /// map.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); + /// ``` + #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + self.reserve_internal(additional, Fallible) + } + + fn reserve_internal(&mut self, additional: usize, fallibility: Fallibility) + -> Result<(), CollectionAllocErr> { + let remaining = self.capacity() - self.len(); // this can't overflow if remaining < additional { - let min_cap = self.len().checked_add(additional).expect("reserve overflow"); - let raw_cap = self.resize_policy.raw_capacity(min_cap); - self.resize(raw_cap); + let min_cap = self.len() + .checked_add(additional) + .ok_or(CollectionAllocErr::CapacityOverflow)?; + let raw_cap = self.resize_policy.try_raw_capacity(min_cap)?; + self.try_resize(raw_cap, fallibility)?; } else if self.table.tag() && remaining <= self.len() { // Probe sequence is too long and table is half full, // resize early to reduce probing length. let new_capacity = self.table.capacity() * 2; - self.resize(new_capacity); + self.try_resize(new_capacity, fallibility)?; } + Ok(()) } /// Resizes the internal vectors to a new capacity. It's your @@ -770,15 +854,25 @@ impl<K, V, S> HashMap<K, V, S> /// 2) Ensure `new_raw_cap` is a power of two or zero. #[inline(never)] #[cold] - fn resize(&mut self, new_raw_cap: usize) { + fn try_resize( + &mut self, + new_raw_cap: usize, + fallibility: Fallibility, + ) -> Result<(), CollectionAllocErr> { assert!(self.table.size() <= new_raw_cap); assert!(new_raw_cap.is_power_of_two() || new_raw_cap == 0); - let mut old_table = replace(&mut self.table, RawTable::new(new_raw_cap)); + let mut old_table = replace( + &mut self.table, + match fallibility { + Infallible => RawTable::new(new_raw_cap), + Fallible => RawTable::try_new(new_raw_cap)?, + } + ); let old_size = old_table.size(); if old_table.size() == 0 { - return; + return Ok(()); } let mut bucket = Bucket::head_bucket(&mut old_table); @@ -813,6 +907,7 @@ impl<K, V, S> HashMap<K, V, S> } assert_eq!(self.table.size(), old_size); + Ok(()) } /// Shrinks the capacity of the map as much as possible. It will drop @@ -824,7 +919,7 @@ impl<K, V, S> HashMap<K, V, S> /// ``` /// use std::collections::HashMap; /// - /// let mut map: HashMap<isize, isize> = HashMap::with_capacity(100); + /// let mut map: HashMap<i32, i32> = HashMap::with_capacity(100); /// map.insert(1, 2); /// map.insert(3, 4); /// assert!(map.capacity() >= 100); @@ -847,6 +942,46 @@ impl<K, V, S> HashMap<K, V, S> } } + /// Shrinks the capacity of the map with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// #![feature(shrink_to)] + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<i32, i32> = HashMap::with_capacity(100); + /// map.insert(1, 2); + /// map.insert(3, 4); + /// assert!(map.capacity() >= 100); + /// map.shrink_to(10); + /// assert!(map.capacity() >= 10); + /// map.shrink_to(0); + /// assert!(map.capacity() >= 2); + /// ``` + #[unstable(feature = "shrink_to", reason = "new API", issue="0")] + pub fn shrink_to(&mut self, min_capacity: usize) { + assert!(self.capacity() >= min_capacity, "Tried to shrink to a larger capacity"); + + let new_raw_cap = self.resize_policy.raw_capacity(max(self.len(), min_capacity)); + if self.raw_capacity() != new_raw_cap { + let old_table = replace(&mut self.table, RawTable::new(new_raw_cap)); + let old_size = old_table.size(); + + // Shrink the table. Naive algorithm for resizing: + for (h, k, v) in old_table.into_iter() { + self.insert_hashed_nocheck(h, k, v); + } + + debug_assert_eq!(self.table.size(), old_size); + } + } + /// Insert a pre-hashed key-value pair, without first checking /// that there's enough room in the buckets. Returns a reference to the /// newly insert value. @@ -1118,7 +1253,35 @@ impl<K, V, S> HashMap<K, V, S> where K: Borrow<Q>, Q: Hash + Eq { - self.search(k).into_occupied_bucket().map(|bucket| bucket.into_refs().1) + self.search(k).map(|bucket| bucket.into_refs().1) + } + + /// Returns the key-value pair corresponding to the supplied key. + /// + /// The supplied key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: ../../std/cmp/trait.Eq.html + /// [`Hash`]: ../../std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// #![feature(map_get_key_value)] + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); + /// assert_eq!(map.get_key_value(&2), None); + /// ``` + #[unstable(feature = "map_get_key_value", issue = "49347")] + pub fn get_key_value<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)> + where K: Borrow<Q>, + Q: Hash + Eq + { + self.search(k).map(|bucket| bucket.into_refs()) } /// Returns true if the map contains a value for the specified key. @@ -1145,7 +1308,7 @@ impl<K, V, S> HashMap<K, V, S> where K: Borrow<Q>, Q: Hash + Eq { - self.search(k).into_occupied_bucket().is_some() + self.search(k).is_some() } /// Returns a mutable reference to the value corresponding to the key. @@ -1174,7 +1337,7 @@ impl<K, V, S> HashMap<K, V, S> where K: Borrow<Q>, Q: Hash + Eq { - self.search_mut(k).into_occupied_bucket().map(|bucket| bucket.into_mut_refs().1) + self.search_mut(k).map(|bucket| bucket.into_mut_refs().1) } /// Inserts a key-value pair into the map. @@ -1234,11 +1397,7 @@ impl<K, V, S> HashMap<K, V, S> where K: Borrow<Q>, Q: Hash + Eq { - if self.table.size() == 0 { - return None; - } - - self.search_mut(k).into_occupied_bucket().map(|bucket| pop_internal(bucket).1) + self.search_mut(k).map(|bucket| pop_internal(bucket).1) } /// Removes a key from the map, returning the stored key and value if the @@ -1254,7 +1413,6 @@ impl<K, V, S> HashMap<K, V, S> /// # Examples /// /// ``` - /// #![feature(hash_map_remove_entry)] /// use std::collections::HashMap; /// /// # fn main() { @@ -1264,17 +1422,12 @@ impl<K, V, S> HashMap<K, V, S> /// assert_eq!(map.remove(&1), None); /// # } /// ``` - #[unstable(feature = "hash_map_remove_entry", issue = "46344")] + #[stable(feature = "hash_map_remove_entry", since = "1.27.0")] pub fn remove_entry<Q: ?Sized>(&mut self, k: &Q) -> Option<(K, V)> where K: Borrow<Q>, Q: Hash + Eq { - if self.table.size() == 0 { - return None; - } - self.search_mut(k) - .into_occupied_bucket() .map(|bucket| { let (k, v, _) = pop_internal(bucket); (k, v) @@ -1290,7 +1443,7 @@ impl<K, V, S> HashMap<K, V, S> /// ``` /// use std::collections::HashMap; /// - /// let mut map: HashMap<isize, isize> = (0..8).map(|x|(x, x*10)).collect(); + /// let mut map: HashMap<i32, i32> = (0..8).map(|x|(x, x*10)).collect(); /// map.retain(|&k, _| k % 2 == 0); /// assert_eq!(map.len(), 4); /// ``` @@ -1384,9 +1537,14 @@ impl<'a, K, Q: ?Sized, V, S> Index<&'a Q> for HashMap<K, V, S> { type Output = V; + /// Returns a reference to the value corresponding to the supplied key. + /// + /// # Panics + /// + /// Panics if the key is not present in the `HashMap`. #[inline] - fn index(&self, index: &Q) -> &V { - self.get(index).expect("no entry found for key") + fn index(&self, key: &Q) -> &V { + self.get(key).expect("no entry found for key") } } @@ -1701,7 +1859,7 @@ impl<K, V, S> IntoIterator for HashMap<K, V, S> /// map.insert("c", 3); /// /// // Not possible with .iter() - /// let vec: Vec<(&str, isize)> = map.into_iter().collect(); + /// let vec: Vec<(&str, i32)> = map.into_iter().collect(); /// ``` fn into_iter(self) -> IntoIter<K, V> { IntoIter { inner: self.table.into_iter() } @@ -1729,7 +1887,7 @@ impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1752,7 +1910,7 @@ impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1787,7 +1945,7 @@ impl<K, V> ExactSizeIterator for IntoIter<K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<K, V> FusedIterator for IntoIter<K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1819,7 +1977,7 @@ impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1842,7 +2000,7 @@ impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Values<'a, K, V> {} #[stable(feature = "map_values_mut", since = "1.10.0")] @@ -1865,7 +2023,7 @@ impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1900,7 +2058,7 @@ impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Drain<'a, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1915,80 +2073,6 @@ impl<'a, K, V> fmt::Debug for Drain<'a, K, V> } } -/// A place for insertion to a `Entry`. -/// -/// See [`HashMap::entry`](struct.HashMap.html#method.entry) for details. -#[must_use = "places do nothing unless written to with `<-` syntax"] -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol is subject to change", - issue = "30172")] -pub struct EntryPlace<'a, K: 'a, V: 'a> { - bucket: FullBucketMut<'a, K, V>, -} - -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol is subject to change", - issue = "30172")] -impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for EntryPlace<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("EntryPlace") - .field("key", self.bucket.read().0) - .field("value", self.bucket.read().1) - .finish() - } -} - -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol is subject to change", - issue = "30172")] -impl<'a, K, V> Drop for EntryPlace<'a, K, V> { - fn drop(&mut self) { - // Inplacement insertion failed. Only key need to drop. - // The value is failed to insert into map. - unsafe { self.bucket.remove_key() }; - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, K, V> Placer<V> for Entry<'a, K, V> { - type Place = EntryPlace<'a, K, V>; - - fn make_place(self) -> EntryPlace<'a, K, V> { - let b = match self { - Occupied(mut o) => { - unsafe { ptr::drop_in_place(o.elem.read_mut().1); } - o.elem - } - Vacant(v) => { - unsafe { v.insert_key() } - } - }; - EntryPlace { bucket: b } - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, K, V> Place<V> for EntryPlace<'a, K, V> { - fn pointer(&mut self) -> *mut V { - self.bucket.read_mut().1 - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, K, V> InPlace<V> for EntryPlace<'a, K, V> { - type Owner = (); - - unsafe fn finalize(self) { - mem::forget(self); - } -} - impl<'a, K, V> Entry<'a, K, V> { #[stable(feature = "rust1", since = "1.0.0")] /// Ensures a value is in the entry by inserting the default if empty, and returns @@ -2061,7 +2145,6 @@ impl<'a, K, V> Entry<'a, K, V> { /// # Examples /// /// ``` - /// #![feature(entry_and_modify)] /// use std::collections::HashMap; /// /// let mut map: HashMap<&str, u32> = HashMap::new(); @@ -2076,9 +2159,9 @@ impl<'a, K, V> Entry<'a, K, V> { /// .or_insert(42); /// assert_eq!(map["poneyland"], 43); /// ``` - #[unstable(feature = "entry_and_modify", issue = "44733")] - pub fn and_modify<F>(self, mut f: F) -> Self - where F: FnMut(&mut V) + #[stable(feature = "entry_and_modify", since = "1.26.0")] + pub fn and_modify<F>(self, f: F) -> Self + where F: FnOnce(&mut V) { match self { Occupied(mut entry) => { @@ -2092,14 +2175,13 @@ impl<'a, K, V> Entry<'a, K, V> { } impl<'a, K, V: Default> Entry<'a, K, V> { - #[unstable(feature = "entry_or_default", issue = "44324")] + #[stable(feature = "entry_or_default", since = "1.28.0")] /// Ensures a value is in the entry by inserting the default value if empty, /// and returns a mutable reference to the value in the entry. /// /// # Examples /// /// ``` - /// #![feature(entry_or_default)] /// # fn main() { /// use std::collections::HashMap; /// @@ -2115,7 +2197,6 @@ impl<'a, K, V: Default> Entry<'a, K, V> { Vacant(entry) => entry.insert(Default::default()), } } - } impl<'a, K, V> OccupiedEntry<'a, K, V> { @@ -2181,6 +2262,11 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// Gets a mutable reference to the value in the entry. /// + /// If you need a reference to the `OccupiedEntry` which may outlive the + /// destruction of the `Entry` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// /// # Examples /// /// ``` @@ -2192,10 +2278,14 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// /// assert_eq!(map["poneyland"], 12); /// if let Entry::Occupied(mut o) = map.entry("poneyland") { - /// *o.get_mut() += 10; + /// *o.get_mut() += 10; + /// assert_eq!(*o.get(), 22); + /// + /// // We can use the same Entry multiple times. + /// *o.get_mut() += 2; /// } /// - /// assert_eq!(map["poneyland"], 22); + /// assert_eq!(map["poneyland"], 24); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut V { @@ -2205,6 +2295,10 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// Converts the OccupiedEntry into a mutable reference to the value in the entry /// with a lifetime bound to the map itself. /// + /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// /// # Examples /// /// ``` @@ -2412,26 +2506,6 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { }; b.into_mut_refs().1 } - - // Only used for InPlacement insert. Avoid unnecessary value copy. - // The value remains uninitialized. - unsafe fn insert_key(self) -> FullBucketMut<'a, K, V> { - match self.elem { - NeqElem(mut bucket, disp) => { - if disp >= DISPLACEMENT_THRESHOLD { - bucket.table_mut().set_tag(true); - } - let uninit = mem::uninitialized(); - robin_hood(bucket, disp, self.hash, self.key, uninit) - }, - NoElem(mut bucket, disp) => { - if disp >= DISPLACEMENT_THRESHOLD { - bucket.table_mut().set_tag(true); - } - bucket.put_key(self.hash, self.key) - }, - } - } } #[stable(feature = "rust1", since = "1.0.0")] @@ -2627,15 +2701,11 @@ impl<K, S, Q: ?Sized> super::Recover<Q> for HashMap<K, (), S> #[inline] fn get(&self, key: &Q) -> Option<&K> { - self.search(key).into_occupied_bucket().map(|bucket| bucket.into_refs().0) + self.search(key).map(|bucket| bucket.into_refs().0) } fn take(&mut self, key: &Q) -> Option<K> { - if self.table.size() == 0 { - return None; - } - - self.search_mut(key).into_occupied_bucket().map(|bucket| pop_internal(bucket).0) + self.search_mut(key).map(|bucket| pop_internal(bucket).0) } #[inline] @@ -2700,7 +2770,9 @@ mod test_map { use super::RandomState; use cell::RefCell; use rand::{thread_rng, Rng}; - use panic; + use realstd::collections::CollectionAllocErr::*; + use realstd::mem::size_of; + use realstd::usize; #[test] fn test_zero_capacities() { @@ -2770,24 +2842,24 @@ mod test_map { assert_eq!(m2.len(), 2); } - thread_local! { static DROP_VECTOR: RefCell<Vec<isize>> = RefCell::new(Vec::new()) } + thread_local! { static DROP_VECTOR: RefCell<Vec<i32>> = RefCell::new(Vec::new()) } #[derive(Hash, PartialEq, Eq)] - struct Dropable { + struct Droppable { k: usize, } - impl Dropable { - fn new(k: usize) -> Dropable { + impl Droppable { + fn new(k: usize) -> Droppable { DROP_VECTOR.with(|slot| { slot.borrow_mut()[k] += 1; }); - Dropable { k: k } + Droppable { k: k } } } - impl Drop for Dropable { + impl Drop for Droppable { fn drop(&mut self) { DROP_VECTOR.with(|slot| { slot.borrow_mut()[self.k] -= 1; @@ -2795,9 +2867,9 @@ mod test_map { } } - impl Clone for Dropable { - fn clone(&self) -> Dropable { - Dropable::new(self.k) + impl Clone for Droppable { + fn clone(&self) -> Droppable { + Droppable::new(self.k) } } @@ -2817,8 +2889,8 @@ mod test_map { }); for i in 0..100 { - let d1 = Dropable::new(i); - let d2 = Dropable::new(i + 100); + let d1 = Droppable::new(i); + let d2 = Droppable::new(i + 100); m.insert(d1, d2); } @@ -2829,7 +2901,7 @@ mod test_map { }); for i in 0..50 { - let k = Dropable::new(i); + let k = Droppable::new(i); let v = m.remove(&k); assert!(v.is_some()); @@ -2876,8 +2948,8 @@ mod test_map { }); for i in 0..100 { - let d1 = Dropable::new(i); - let d2 = Dropable::new(i + 100); + let d1 = Droppable::new(i); + let d2 = Droppable::new(i + 100); hm.insert(d1, d2); } @@ -2927,13 +2999,13 @@ mod test_map { #[test] fn test_empty_remove() { - let mut m: HashMap<isize, bool> = HashMap::new(); + let mut m: HashMap<i32, bool> = HashMap::new(); assert_eq!(m.remove(&0), None); } #[test] fn test_empty_entry() { - let mut m: HashMap<isize, bool> = HashMap::new(); + let mut m: HashMap<i32, bool> = HashMap::new(); match m.entry(0) { Occupied(_) => panic!(), Vacant(_) => {} @@ -2944,7 +3016,7 @@ mod test_map { #[test] fn test_empty_iter() { - let mut m: HashMap<isize, bool> = HashMap::new(); + let mut m: HashMap<i32, bool> = HashMap::new(); assert_eq!(m.drain().next(), None); assert_eq!(m.keys().next(), None); assert_eq!(m.values().next(), None); @@ -3445,7 +3517,7 @@ mod test_map { fn test_entry_take_doesnt_corrupt() { #![allow(deprecated)] //rand // Test for #19292 - fn check(m: &HashMap<isize, ()>) { + fn check(m: &HashMap<i32, ()>) { for k in m.keys() { assert!(m.contains_key(k), "{} is in keys() but not in the map?", k); @@ -3554,7 +3626,7 @@ mod test_map { #[test] fn test_retain() { - let mut map: HashMap<isize, isize> = (0..100).map(|x|(x, x*10)).collect(); + let mut map: HashMap<i32, i32> = (0..100).map(|x|(x, x*10)).collect(); map.retain(|&k, _| k % 2 == 0); assert_eq!(map.len(), 50); @@ -3584,55 +3656,31 @@ mod test_map { } #[test] - fn test_placement_in() { - let mut map = HashMap::new(); - map.extend((0..10).map(|i| (i, i))); - - map.entry(100) <- 100; - assert_eq!(map[&100], 100); - - map.entry(0) <- 10; - assert_eq!(map[&0], 10); - - assert_eq!(map.len(), 11); - } + fn test_try_reserve() { - #[test] - fn test_placement_panic() { - let mut map = HashMap::new(); - map.extend((0..10).map(|i| (i, i))); + let mut empty_bytes: HashMap<u8,u8> = HashMap::new(); - fn mkpanic() -> usize { panic!() } + const MAX_USIZE: usize = usize::MAX; - // modify existing key - // when panic happens, previous key is removed. - let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { map.entry(0) <- mkpanic(); })); - assert_eq!(map.len(), 9); - assert!(!map.contains_key(&0)); + // HashMap and RawTables use complicated size calculations + // hashes_size is sizeof(HashUint) * capacity; + // pairs_size is sizeof((K. V)) * capacity; + // alignment_hashes_size is 8 + // alignment_pairs size is 4 + let size_of_multiplier = (size_of::<usize>() + size_of::<(u8, u8)>()).next_power_of_two(); + // The following formula is used to calculate the new capacity + let max_no_ovf = ((MAX_USIZE / 11) * 10) / size_of_multiplier - 1; - // add new key - let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { map.entry(100) <- mkpanic(); })); - assert_eq!(map.len(), 9); - assert!(!map.contains_key(&100)); - } + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { + } else { panic!("usize::MAX should trigger an overflow!"); } - #[test] - fn test_placement_drop() { - // correctly drop - struct TestV<'a>(&'a mut bool); - impl<'a> Drop for TestV<'a> { - fn drop(&mut self) { - if !*self.0 { panic!("value double drop!"); } // no double drop - *self.0 = false; - } + if size_of::<usize>() < 8 { + if let Err(CapacityOverflow) = empty_bytes.try_reserve(max_no_ovf) { + } else { panic!("isize::MAX + 1 should trigger a CapacityOverflow!") } + } else { + if let Err(AllocErr) = empty_bytes.try_reserve(max_no_ovf) { + } else { panic!("isize::MAX + 1 should trigger an OOM!") } } - - fn makepanic<'a>() -> TestV<'a> { panic!() } - - let mut can_drop = true; - let mut hm = HashMap::new(); - hm.insert(0, TestV(&mut can_drop)); - let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { hm.entry(0) <- makepanic(); })); - assert_eq!(hm.len(), 0); } + } diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index e9427fb40a0..5ac3e8f9cf7 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -49,14 +49,14 @@ use super::map::{self, HashMap, Keys, RandomState}; /// ``` /// use std::collections::HashSet; /// // Type inference lets us omit an explicit type signature (which -/// // would be `HashSet<&str>` in this example). +/// // would be `HashSet<String>` in this example). /// let mut books = HashSet::new(); /// /// // Add some books. -/// books.insert("A Dance With Dragons"); -/// books.insert("To Kill a Mockingbird"); -/// books.insert("The Odyssey"); -/// books.insert("The Great Gatsby"); +/// books.insert("A Dance With Dragons".to_string()); +/// books.insert("To Kill a Mockingbird".to_string()); +/// books.insert("The Odyssey".to_string()); +/// books.insert("The Great Gatsby".to_string()); /// /// // Check for a specific one. /// if !books.contains("The Winds of Winter") { @@ -80,17 +80,17 @@ use super::map::{self, HashMap, Keys, RandomState}; /// ``` /// use std::collections::HashSet; /// #[derive(Hash, Eq, PartialEq, Debug)] -/// struct Viking<'a> { -/// name: &'a str, +/// struct Viking { +/// name: String, /// power: usize, /// } /// /// let mut vikings = HashSet::new(); /// -/// vikings.insert(Viking { name: "Einar", power: 9 }); -/// vikings.insert(Viking { name: "Einar", power: 9 }); -/// vikings.insert(Viking { name: "Olaf", power: 4 }); -/// vikings.insert(Viking { name: "Harald", power: 8 }); +/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 }); +/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 }); +/// vikings.insert(Viking { name: "Olaf".to_string(), power: 4 }); +/// vikings.insert(Viking { name: "Harald".to_string(), power: 8 }); /// /// // Use derived implementation to print the vikings. /// for x in &vikings { @@ -104,7 +104,7 @@ use super::map::{self, HashMap, Keys, RandomState}; /// use std::collections::HashSet; /// /// fn main() { -/// let viking_names: HashSet<&str> = +/// let viking_names: HashSet<&'static str> = /// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect(); /// // use the values stored in the set /// } @@ -292,6 +292,34 @@ impl<T, S> HashSet<T, S> self.map.shrink_to_fit() } + /// Shrinks the capacity of the set with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// #![feature(shrink_to)] + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::with_capacity(100); + /// set.insert(1); + /// set.insert(2); + /// assert!(set.capacity() >= 100); + /// set.shrink_to(10); + /// assert!(set.capacity() >= 10); + /// set.shrink_to(0); + /// assert!(set.capacity() >= 2); + /// ``` + #[inline] + #[unstable(feature = "shrink_to", reason = "new API", issue="0")] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.map.shrink_to(min_capacity) + } + /// An iterator visiting all elements in arbitrary order. /// The iterator element type is `&'a T`. /// @@ -724,7 +752,7 @@ impl<T, S> HashSet<T, S> /// use std::collections::HashSet; /// /// let xs = [1,2,3,4,5,6]; - /// let mut set: HashSet<isize> = xs.iter().cloned().collect(); + /// let mut set: HashSet<i32> = xs.iter().cloned().collect(); /// set.retain(|&k| k % 2 == 0); /// assert_eq!(set.len(), 3); /// ``` @@ -1097,7 +1125,7 @@ impl<'a, K> ExactSizeIterator for Iter<'a, K> { self.iter.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K> FusedIterator for Iter<'a, K> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1124,7 +1152,7 @@ impl<K> ExactSizeIterator for IntoIter<K> { self.iter.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<K> FusedIterator for IntoIter<K> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1155,7 +1183,7 @@ impl<'a, K> ExactSizeIterator for Drain<'a, K> { self.iter.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K> FusedIterator for Drain<'a, K> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1208,7 +1236,7 @@ impl<'a, T, S> fmt::Debug for Intersection<'a, T, S> } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, S> FusedIterator for Intersection<'a, T, S> where T: Eq + Hash, S: BuildHasher @@ -1244,7 +1272,7 @@ impl<'a, T, S> Iterator for Difference<'a, T, S> } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, S> FusedIterator for Difference<'a, T, S> where T: Eq + Hash, S: BuildHasher @@ -1283,7 +1311,7 @@ impl<'a, T, S> Iterator for SymmetricDifference<'a, T, S> } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, S> FusedIterator for SymmetricDifference<'a, T, S> where T: Eq + Hash, S: BuildHasher @@ -1307,7 +1335,7 @@ impl<'a, T, S> Clone for Union<'a, T, S> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, S> FusedIterator for Union<'a, T, S> where T: Eq + Hash, S: BuildHasher @@ -1745,7 +1773,7 @@ mod test_set { #[test] fn test_retain() { let xs = [1, 2, 3, 4, 5, 6]; - let mut set: HashSet<isize> = xs.iter().cloned().collect(); + let mut set: HashSet<i32> = xs.iter().cloned().collect(); set.retain(|&k| k % 2 == 0); assert_eq!(set.len(), 3); assert!(set.contains(&2)); diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 96f98efe4aa..2b319186a8d 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::heap::{Heap, Alloc, Layout}; - -use cmp; +use alloc::{Global, Alloc, Layout, LayoutErr, handle_alloc_error}; +use collections::CollectionAllocErr; use hash::{BuildHasher, Hash, Hasher}; use marker; -use mem::{align_of, size_of, needs_drop}; +use mem::{size_of, needs_drop}; use mem; use ops::{Deref, DerefMut}; -use ptr::{self, Unique, Shared}; +use ptr::{self, Unique, NonNull}; +use hint; use self::BucketState::*; @@ -80,7 +80,7 @@ impl TaggedHashUintPtr { /// /// Essential invariants of this structure: /// -/// - if t.hashes[i] == EMPTY_BUCKET, then `Bucket::at_index(&t, i).raw` +/// - if `t.hashes[i] == EMPTY_BUCKET`, then `Bucket::at_index(&t, i).raw` /// points to 'undefined' contents. Don't read from it. This invariant is /// enforced outside this module with the `EmptyBucket`, `FullBucket`, /// and `SafeHash` types. @@ -484,21 +484,6 @@ impl<K, V, M> EmptyBucket<K, V, M> table: self.table, } } - - /// Puts given key, remain value uninitialized. - /// It is only used for inplacement insertion. - pub unsafe fn put_key(mut self, hash: SafeHash, key: K) -> FullBucket<K, V, M> { - *self.raw.hash() = hash.inspect(); - let pair_ptr = self.raw.pair(); - ptr::write(&mut (*pair_ptr).0, key); - - self.table.borrow_table_mut().size += 1; - - FullBucket { - raw: self.raw, - table: self.table, - } - } } impl<K, V, M: Deref<Target = RawTable<K, V>>> FullBucket<K, V, M> { @@ -574,17 +559,6 @@ impl<'t, K, V> FullBucket<K, V, &'t mut RawTable<K, V>> { v) } } - - /// Remove this bucket's `key` from the hashtable. - /// Only used for inplacement insertion. - /// NOTE: `Value` is uninitialized when this function is called, don't try to drop the `Value`. - pub unsafe fn remove_key(&mut self) { - self.table.size -= 1; - - *self.raw.hash() = EMPTY_BUCKET; - let pair_ptr = self.raw.pair(); - ptr::drop_in_place(&mut (*pair_ptr).0); // only drop key - } } // This use of `Put` is misleading and restrictive, but safe and sufficient for our use cases @@ -678,144 +652,114 @@ impl<K, V, M> GapThenFull<K, V, M> } } - -/// Rounds up to a multiple of a power of two. Returns the closest multiple -/// of `target_alignment` that is higher or equal to `unrounded`. -/// -/// # Panics -/// -/// Panics if `target_alignment` is not a power of two. -#[inline] -fn round_up_to_next(unrounded: usize, target_alignment: usize) -> usize { - assert!(target_alignment.is_power_of_two()); - (unrounded + target_alignment - 1) & !(target_alignment - 1) -} - -#[test] -fn test_rounding() { - assert_eq!(round_up_to_next(0, 4), 0); - assert_eq!(round_up_to_next(1, 4), 4); - assert_eq!(round_up_to_next(2, 4), 4); - assert_eq!(round_up_to_next(3, 4), 4); - assert_eq!(round_up_to_next(4, 4), 4); - assert_eq!(round_up_to_next(5, 4), 8); -} - -// Returns a tuple of (pairs_offset, end_of_pairs_offset), -// from the start of a mallocated array. -#[inline] -fn calculate_offsets(hashes_size: usize, - pairs_size: usize, - pairs_align: usize) - -> (usize, usize, bool) { - let pairs_offset = round_up_to_next(hashes_size, pairs_align); - let (end_of_pairs, oflo) = pairs_offset.overflowing_add(pairs_size); - - (pairs_offset, end_of_pairs, oflo) +// Returns a Layout which describes the allocation required for a hash table, +// and the offset of the array of (key, value) pairs in the allocation. +fn calculate_layout<K, V>(capacity: usize) -> Result<(Layout, usize), LayoutErr> { + let hashes = Layout::array::<HashUint>(capacity)?; + let pairs = Layout::array::<(K, V)>(capacity)?; + hashes.extend(pairs).map(|(layout, _)| { + // LLVM seems to have trouble properly const-propagating pairs.align(), + // possibly due to the use of NonZeroUsize. This little hack allows it + // to generate optimal code. + // + // See https://github.com/rust-lang/rust/issues/51346 for more details. + ( + layout, + hashes.size() + hashes.padding_needed_for(mem::align_of::<(K, V)>()), + ) + }) } -// Returns a tuple of (minimum required malloc alignment, -// array_size), from the start of a mallocated array. -fn calculate_allocation(hash_size: usize, - hash_align: usize, - pairs_size: usize, - pairs_align: usize) - -> (usize, usize, bool) { - let (_, end_of_pairs, oflo) = calculate_offsets(hash_size, pairs_size, pairs_align); - - let align = cmp::max(hash_align, pairs_align); - - (align, end_of_pairs, oflo) +pub(crate) enum Fallibility { + Fallible, + Infallible, } -#[test] -fn test_offset_calculation() { - assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 144, false)); - assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 5, false)); - assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 20, false)); - assert_eq!(calculate_offsets(128, 15, 4), (128, 143, false)); - assert_eq!(calculate_offsets(3, 2, 4), (4, 6, false)); - assert_eq!(calculate_offsets(6, 12, 4), (8, 20, false)); -} +use self::Fallibility::*; impl<K, V> RawTable<K, V> { /// Does not initialize the buckets. The caller should ensure they, /// at the very least, set every hash to EMPTY_BUCKET. - unsafe fn new_uninitialized(capacity: usize) -> RawTable<K, V> { + /// Returns an error if it cannot allocate or capacity overflows. + unsafe fn new_uninitialized_internal( + capacity: usize, + fallibility: Fallibility, + ) -> Result<RawTable<K, V>, CollectionAllocErr> { if capacity == 0 { - return RawTable { + return Ok(RawTable { size: 0, capacity_mask: capacity.wrapping_sub(1), hashes: TaggedHashUintPtr::new(EMPTY as *mut HashUint), marker: marker::PhantomData, - }; + }); } - // No need for `checked_mul` before a more restrictive check performed - // later in this method. - let hashes_size = capacity.wrapping_mul(size_of::<HashUint>()); - let pairs_size = capacity.wrapping_mul(size_of::<(K, V)>()); - // Allocating hashmaps is a little tricky. We need to allocate two // arrays, but since we know their sizes and alignments up front, // we just allocate a single array, and then have the subarrays // point into it. - // - // This is great in theory, but in practice getting the alignment - // right is a little subtle. Therefore, calculating offsets has been - // factored out into a different function. - let (alignment, size, oflo) = calculate_allocation(hashes_size, - align_of::<HashUint>(), - pairs_size, - align_of::<(K, V)>()); - assert!(!oflo, "capacity overflow"); - - // One check for overflow that covers calculation and rounding of size. - let size_of_bucket = size_of::<HashUint>().checked_add(size_of::<(K, V)>()).unwrap(); - assert!(size >= - capacity.checked_mul(size_of_bucket) - .expect("capacity overflow"), - "capacity overflow"); - - let buffer = Heap.alloc(Layout::from_size_align(size, alignment).unwrap()) - .unwrap_or_else(|e| Heap.oom(e)); - - let hashes = buffer as *mut HashUint; - - RawTable { + let (layout, _) = calculate_layout::<K, V>(capacity)?; + let buffer = Global.alloc(layout).map_err(|e| match fallibility { + Infallible => handle_alloc_error(layout), + Fallible => e, + })?; + + Ok(RawTable { capacity_mask: capacity.wrapping_sub(1), size: 0, - hashes: TaggedHashUintPtr::new(hashes), + hashes: TaggedHashUintPtr::new(buffer.cast().as_ptr()), marker: marker::PhantomData, + }) + } + + /// Does not initialize the buckets. The caller should ensure they, + /// at the very least, set every hash to EMPTY_BUCKET. + unsafe fn new_uninitialized(capacity: usize) -> RawTable<K, V> { + match Self::new_uninitialized_internal(capacity, Infallible) { + Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), + Err(CollectionAllocErr::AllocErr) => unreachable!(), + Ok(table) => { table } } } fn raw_bucket_at(&self, index: usize) -> RawBucket<K, V> { - let hashes_size = self.capacity() * size_of::<HashUint>(); - let pairs_size = self.capacity() * size_of::<(K, V)>(); - - let (pairs_offset, _, oflo) = - calculate_offsets(hashes_size, pairs_size, align_of::<(K, V)>()); - debug_assert!(!oflo, "capacity overflow"); - + let (_, pairs_offset) = calculate_layout::<K, V>(self.capacity()) + .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() }); let buffer = self.hashes.ptr() as *mut u8; unsafe { RawBucket { hash_start: buffer as *mut HashUint, - pair_start: buffer.offset(pairs_offset as isize) as *const (K, V), + pair_start: buffer.add(pairs_offset) as *const (K, V), idx: index, _marker: marker::PhantomData, } } } + fn new_internal( + capacity: usize, + fallibility: Fallibility, + ) -> Result<RawTable<K, V>, CollectionAllocErr> { + unsafe { + let ret = RawTable::new_uninitialized_internal(capacity, fallibility)?; + ptr::write_bytes(ret.hashes.ptr(), 0, capacity); + Ok(ret) + } + } + + /// Tries to create a new raw table from a given capacity. If it cannot allocate, + /// it returns with AllocErr. + pub fn try_new(capacity: usize) -> Result<RawTable<K, V>, CollectionAllocErr> { + Self::new_internal(capacity, Fallible) + } + /// Creates a new raw table from a given capacity. All buckets are /// initially empty. pub fn new(capacity: usize) -> RawTable<K, V> { - unsafe { - let ret = RawTable::new_uninitialized(capacity); - ptr::write_bytes(ret.hashes.ptr(), 0, capacity); - ret + match Self::new_internal(capacity, Infallible) { + Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), + Err(CollectionAllocErr::AllocErr) => unreachable!(), + Ok(table) => { table } } } @@ -873,7 +817,7 @@ impl<K, V> RawTable<K, V> { elems_left, marker: marker::PhantomData, }, - table: Shared::from(self), + table: NonNull::from(self), marker: marker::PhantomData, } } @@ -1020,7 +964,7 @@ impl<K, V> IntoIter<K, V> { /// Iterator over the entries in a table, clearing the table. pub struct Drain<'a, K: 'a, V: 'a> { - table: Shared<RawTable<K, V>>, + table: NonNull<RawTable<K, V>>, iter: RawBuckets<'static, K, V>, marker: marker::PhantomData<&'a RawTable<K, V>>, } @@ -1129,7 +1073,7 @@ impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> { fn drop(&mut self) { - for _ in self {} + self.for_each(drop); } } @@ -1178,18 +1122,10 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> { } } - let hashes_size = self.capacity() * size_of::<HashUint>(); - let pairs_size = self.capacity() * size_of::<(K, V)>(); - let (align, size, oflo) = calculate_allocation(hashes_size, - align_of::<HashUint>(), - pairs_size, - align_of::<(K, V)>()); - - debug_assert!(!oflo, "should be impossible"); - + let (layout, _) = calculate_layout::<K, V>(self.capacity()) + .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() }); unsafe { - Heap.dealloc(self.hashes.ptr() as *mut u8, - Layout::from_size_align(size, align).unwrap()); + Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).cast(), layout); // Remember how everything was allocated out of one buffer // during initialization? We only need one call to free here. } diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index b8a6a66eaa6..8d2c82bc0aa 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -64,11 +64,11 @@ //! * You want a map, with no extra functionality. //! //! ### Use a `BTreeMap` when: +//! * You want a map sorted by its keys. +//! * You want to be able to get a range of entries on-demand. //! * You're interested in what the smallest or largest key-value pair is. //! * You want to find the largest or smallest key that is smaller or larger //! than something. -//! * You want to be able to get all of the entries in order on-demand. -//! * You want a map sorted by its keys. //! //! ### Use the `Set` variant of any of these `Map`s when: //! * You just want to remember which keys you've seen. @@ -420,23 +420,25 @@ #![stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::Bound; +#[rustc_deprecated(reason = "moved to `std::ops::Bound`", since = "1.26.0")] +#[doc(hidden)] +pub use ops::Bound; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::{BinaryHeap, BTreeMap, BTreeSet}; +pub use alloc_crate::collections::{BinaryHeap, BTreeMap, BTreeSet}; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::{LinkedList, VecDeque}; +pub use alloc_crate::collections::{LinkedList, VecDeque}; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::{binary_heap, btree_map, btree_set}; +pub use alloc_crate::collections::{binary_heap, btree_map, btree_set}; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::{linked_list, vec_deque}; +pub use alloc_crate::collections::{linked_list, vec_deque}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::hash_map::HashMap; #[stable(feature = "rust1", since = "1.0.0")] pub use self::hash_set::HashSet; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::range; +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +pub use alloc_crate::collections::CollectionAllocErr; mod hash; diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 27bf326631f..9066c0b7694 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -49,9 +49,11 @@ use sys::os as os_imp; /// ``` /// use std::env; /// -/// // We assume that we are in a valid directory. -/// let path = env::current_dir().unwrap(); -/// println!("The current directory is {}", path.display()); +/// fn main() -> std::io::Result<()> { +/// let path = env::current_dir()?; +/// println!("The current directory is {}", path.display()); +/// Ok(()) +/// } /// ``` #[stable(feature = "env", since = "1.0.0")] pub fn current_dir() -> io::Result<PathBuf> { @@ -441,15 +443,18 @@ pub struct JoinPathsError { /// Joining paths on a Unix-like platform: /// /// ``` -/// # if cfg!(unix) { /// use std::env; /// use std::ffi::OsString; /// use std::path::Path; /// -/// let paths = [Path::new("/bin"), Path::new("/usr/bin")]; -/// let path_os_string = env::join_paths(paths.iter()).unwrap(); -/// assert_eq!(path_os_string, OsString::from("/bin:/usr/bin")); +/// fn main() -> Result<(), env::JoinPathsError> { +/// # if cfg!(unix) { +/// let paths = [Path::new("/bin"), Path::new("/usr/bin")]; +/// let path_os_string = env::join_paths(paths.iter())?; +/// assert_eq!(path_os_string, OsString::from("/bin:/usr/bin")); /// # } +/// Ok(()) +/// } /// ``` /// /// Joining a path containing a colon on a Unix-like platform results in an error: @@ -471,11 +476,15 @@ pub struct JoinPathsError { /// use std::env; /// use std::path::PathBuf; /// -/// if let Some(path) = env::var_os("PATH") { -/// let mut paths = env::split_paths(&path).collect::<Vec<_>>(); -/// paths.push(PathBuf::from("/home/xyz/bin")); -/// let new_path = env::join_paths(paths).unwrap(); -/// env::set_var("PATH", &new_path); +/// fn main() -> Result<(), env::JoinPathsError> { +/// if let Some(path) = env::var_os("PATH") { +/// let mut paths = env::split_paths(&path).collect::<Vec<_>>(); +/// paths.push(PathBuf::from("/home/xyz/bin")); +/// let new_path = env::join_paths(paths)?; +/// env::set_var("PATH", &new_path); +/// } +/// +/// Ok(()) /// } /// ``` #[stable(feature = "env", since = "1.0.0")] @@ -503,18 +512,20 @@ impl Error for JoinPathsError { /// /// # Unix /// -/// Returns the value of the 'HOME' environment variable if it is set -/// and not equal to the empty string. Otherwise, it tries to determine the -/// home directory by invoking the `getpwuid_r` function on the UID of the -/// current user. +/// - Returns the value of the 'HOME' environment variable if it is set +/// (including to an empty string). +/// - Otherwise, it tries to determine the home directory by invoking the `getpwuid_r` function +/// using the UID of the current user. An empty home directory field returned from the +/// `getpwuid_r` function is considered to be a valid value. +/// - Returns `None` if the current user has no entry in the /etc/passwd file. /// /// # Windows /// -/// Returns the value of the 'HOME' environment variable if it is -/// set and not equal to the empty string. Otherwise, returns the value of the -/// 'USERPROFILE' environment variable if it is set and not equal to the empty -/// string. If both do not exist, [`GetUserProfileDirectory`][msdn] is used to -/// return the appropriate path. +/// - Returns the value of the 'HOME' environment variable if it is set +/// (including to an empty string). +/// - Otherwise, returns the value of the 'USERPROFILE' environment variable if it is set +/// (including to an empty string). +/// - If both do not exist, [`GetUserProfileDirectory`][msdn] is used to return the path. /// /// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/bb762280(v=vs.85).aspx /// @@ -524,10 +535,13 @@ impl Error for JoinPathsError { /// use std::env; /// /// match env::home_dir() { -/// Some(path) => println!("{}", path.display()), +/// Some(path) => println!("Your home directory, probably: {}", path.display()), /// None => println!("Impossible to get your home dir!"), /// } /// ``` +#[rustc_deprecated(since = "1.29.0", + reason = "This function's behavior is unexpected and probably not what you want. \ + Consider using the home_dir function from https://crates.io/crates/dirs instead.")] #[stable(feature = "env", since = "1.0.0")] pub fn home_dir() -> Option<PathBuf> { os_imp::home_dir() @@ -552,17 +566,17 @@ pub fn home_dir() -> Option<PathBuf> { /// /// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992(v=vs.85).aspx /// -/// ``` +/// ```no_run /// use std::env; /// use std::fs::File; /// -/// # fn foo() -> std::io::Result<()> { -/// let mut dir = env::temp_dir(); -/// dir.push("foo.txt"); +/// fn main() -> std::io::Result<()> { +/// let mut dir = env::temp_dir(); +/// dir.push("foo.txt"); /// -/// let f = File::create(dir)?; -/// # Ok(()) -/// # } +/// let f = File::create(dir)?; +/// Ok(()) +/// } /// ``` #[stable(feature = "env", since = "1.0.0")] pub fn temp_dir() -> PathBuf { @@ -723,6 +737,12 @@ pub fn args_os() -> ArgsOs { ArgsOs { inner: sys::args::args() } } +#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")] +impl !Send for Args {} + +#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")] +impl !Sync for Args {} + #[stable(feature = "env", since = "1.0.0")] impl Iterator for Args { type Item = String; @@ -754,6 +774,12 @@ impl fmt::Debug for Args { } } +#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")] +impl !Send for ArgsOs {} + +#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")] +impl !Sync for ArgsOs {} + #[stable(feature = "env", since = "1.0.0")] impl Iterator for ArgsOs { type Item = OsString; diff --git a/src/libstd/error.rs b/src/libstd/error.rs index eb5022ad577..29534696abc 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -9,34 +9,6 @@ // except according to those terms. //! Traits for working with Errors. -//! -//! # The `Error` trait -//! -//! `Error` is a trait representing the basic expectations for error values, -//! i.e. values of type `E` in [`Result<T, E>`]. At a minimum, errors must provide -//! a description, but they may optionally provide additional detail (via -//! [`Display`]) and cause chain information: -//! -//! ``` -//! use std::fmt::Display; -//! -//! trait Error: Display { -//! fn description(&self) -> &str; -//! -//! fn cause(&self) -> Option<&Error> { None } -//! } -//! ``` -//! -//! The [`cause`] method is generally used when errors cross "abstraction -//! boundaries", i.e. when a one module must report an error that is "caused" -//! by an error from a lower-level module. This setup makes it possible for the -//! high-level module to provide its own errors that do not commit to any -//! particular implementation, but also reveal some of its implementation for -//! debugging via [`cause`] chains. -//! -//! [`Result<T, E>`]: ../result/enum.Result.html -//! [`Display`]: ../fmt/trait.Display.html -//! [`cause`]: trait.Error.html#method.cause #![stable(feature = "rust1", since = "1.0.0")] @@ -51,12 +23,11 @@ // coherence challenge (e.g., specialization, neg impls, etc) we can // reconsider what crate these items belong in. -use alloc::allocator; +use alloc::{AllocErr, LayoutErr, CannotReallocInPlace}; use any::TypeId; use borrow::Cow; use cell; use char; -use convert; use core::array; use fmt::{self, Debug, Display}; use mem::transmute; @@ -64,33 +35,49 @@ use num; use str; use string; -/// Base functionality for all errors in Rust. +/// `Error` is a trait representing the basic expectations for error values, +/// i.e. values of type `E` in [`Result<T, E>`]. Errors must describe +/// themselves through the [`Display`] and [`Debug`] traits, and may provide +/// cause chain information: +/// +/// The [`cause`] method is generally used when errors cross "abstraction +/// boundaries", i.e. when a one module must report an error that is "caused" +/// by an error from a lower-level module. This setup makes it possible for the +/// high-level module to provide its own errors that do not commit to any +/// particular implementation, but also reveal some of its implementation for +/// debugging via [`cause`] chains. +/// +/// [`Result<T, E>`]: ../result/enum.Result.html +/// [`Display`]: ../fmt/trait.Display.html +/// [`Debug`]: ../fmt/trait.Debug.html +/// [`cause`]: trait.Error.html#method.cause #[stable(feature = "rust1", since = "1.0.0")] pub trait Error: Debug + Display { - /// A short description of the error. + /// **This method is soft-deprecated.** /// - /// The description should only be used for a simple message. - /// It should not contain newlines or sentence-ending punctuation, - /// to facilitate embedding in larger user-facing strings. - /// For showing formatted error messages with more information see - /// [`Display`]. + /// Although using it won’t cause compilation warning, + /// new code should use [`Display`] instead + /// and new `impl`s can omit it. + /// + /// To obtain error description as a string, use `to_string()`. /// /// [`Display`]: ../fmt/trait.Display.html /// /// # Examples /// /// ``` - /// use std::error::Error; - /// /// match "xc".parse::<u32>() { /// Err(e) => { - /// println!("Error: {}", e.description()); + /// // Print `e` itself, not `e.description()`. + /// println!("Error: {}", e); /// } /// _ => println!("No error"), /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - fn description(&self) -> &str; + fn description(&self) -> &str { + "description() is deprecated; use Display" + } /// The lower-level cause of this error, if any. /// @@ -151,7 +138,7 @@ pub trait Error: Debug + Display { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - fn cause(&self) -> Option<&Error> { None } + fn cause(&self) -> Option<&dyn Error> { None } /// Get the `TypeId` of `self` #[doc(hidden)] @@ -164,22 +151,22 @@ pub trait Error: Debug + Display { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, E: Error + 'a> From<E> for Box<Error + 'a> { - fn from(err: E) -> Box<Error + 'a> { +impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> { + fn from(err: E) -> Box<dyn Error + 'a> { Box::new(err) } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<Error + Send + Sync + 'a> { - fn from(err: E) -> Box<Error + Send + Sync + 'a> { +impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync + 'a> { + fn from(err: E) -> Box<dyn Error + Send + Sync + 'a> { Box::new(err) } } #[stable(feature = "rust1", since = "1.0.0")] -impl From<String> for Box<Error + Send + Sync> { - fn from(err: String) -> Box<Error + Send + Sync> { +impl From<String> for Box<dyn Error + Send + Sync> { + fn from(err: String) -> Box<dyn Error + Send + Sync> { #[derive(Debug)] struct StringError(String); @@ -198,38 +185,38 @@ impl From<String> for Box<Error + Send + Sync> { } #[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); - let err2: Box<Error> = err1; +impl From<String> for Box<dyn Error> { + fn from(str_err: String) -> Box<dyn Error> { + let err1: Box<dyn Error + Send + Sync> = From::from(str_err); + let err2: Box<dyn Error> = err1; err2 } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b> From<&'b str> for Box<Error + Send + Sync + 'a> { - fn from(err: &'b str) -> Box<Error + Send + Sync + 'a> { +impl<'a, 'b> From<&'b str> for Box<dyn Error + Send + Sync + 'a> { + fn from(err: &'b str) -> Box<dyn Error + Send + Sync + 'a> { From::from(String::from(err)) } } #[stable(feature = "string_box_error", since = "1.6.0")] -impl<'a> From<&'a str> for Box<Error> { - fn from(err: &'a str) -> Box<Error> { +impl<'a> From<&'a str> for Box<dyn Error> { + fn from(err: &'a str) -> Box<dyn Error> { From::from(String::from(err)) } } #[stable(feature = "cow_box_error", since = "1.22.0")] -impl<'a, 'b> From<Cow<'b, str>> for Box<Error + Send + Sync + 'a> { - fn from(err: Cow<'b, str>) -> Box<Error + Send + Sync + 'a> { +impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> { + fn from(err: Cow<'b, str>) -> Box<dyn Error + Send + Sync + 'a> { From::from(String::from(err)) } } #[stable(feature = "cow_box_error", since = "1.22.0")] -impl<'a> From<Cow<'a, str>> for Box<Error> { - fn from(err: Cow<'a, str>) -> Box<Error> { +impl<'a> From<Cow<'a, str>> for Box<dyn Error> { + fn from(err: Cow<'a, str>) -> Box<dyn Error> { From::from(String::from(err)) } } @@ -242,18 +229,27 @@ impl Error for ! { #[unstable(feature = "allocator_api", reason = "the precise API and guarantees it provides may be tweaked.", issue = "32838")] -impl Error for allocator::AllocErr { +impl Error for AllocErr { + fn description(&self) -> &str { + "memory allocation failed" + } +} + +#[unstable(feature = "allocator_api", + reason = "the precise API and guarantees it provides may be tweaked.", + issue = "32838")] +impl Error for LayoutErr { fn description(&self) -> &str { - allocator::AllocErr::description(self) + "invalid parameters to Layout::from_size_align" } } #[unstable(feature = "allocator_api", reason = "the precise API and guarantees it provides may be tweaked.", issue = "32838")] -impl Error for allocator::CannotReallocInPlace { +impl Error for CannotReallocInPlace { fn description(&self) -> &str { - allocator::CannotReallocInPlace::description(self) + CannotReallocInPlace::description(self) } } @@ -331,7 +327,7 @@ impl<T: Error> Error for Box<T> { Error::description(&**self) } - fn cause(&self) -> Option<&Error> { + fn cause(&self) -> Option<&dyn Error> { Error::cause(&**self) } } @@ -371,16 +367,8 @@ impl Error for char::ParseCharError { } } -#[unstable(feature = "try_from", issue = "33417")] -impl Error for convert::Infallible { - fn description(&self) -> &str { - match *self { - } - } -} - // copied from any.rs -impl Error + 'static { +impl dyn Error + 'static { /// Returns true if the boxed type is the same as `T` #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] @@ -402,7 +390,7 @@ impl Error + 'static { pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> { if self.is::<T>() { unsafe { - Some(&*(self as *const Error as *const T)) + Some(&*(self as *const dyn Error as *const T)) } } else { None @@ -416,7 +404,7 @@ impl Error + 'static { pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> { if self.is::<T>() { unsafe { - Some(&mut *(self as *mut Error as *mut T)) + Some(&mut *(self as *mut dyn Error as *mut T)) } } else { None @@ -424,60 +412,60 @@ impl Error + 'static { } } -impl Error + 'static + Send { +impl dyn Error + 'static + Send { /// Forwards to the method defined on the type `Any`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn is<T: Error + 'static>(&self) -> bool { - <Error + 'static>::is::<T>(self) + <dyn Error + 'static>::is::<T>(self) } /// Forwards to the method defined on the type `Any`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> { - <Error + 'static>::downcast_ref::<T>(self) + <dyn Error + 'static>::downcast_ref::<T>(self) } /// Forwards to the method defined on the type `Any`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> { - <Error + 'static>::downcast_mut::<T>(self) + <dyn Error + 'static>::downcast_mut::<T>(self) } } -impl Error + 'static + Send + Sync { +impl dyn Error + 'static + Send + Sync { /// Forwards to the method defined on the type `Any`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn is<T: Error + 'static>(&self) -> bool { - <Error + 'static>::is::<T>(self) + <dyn Error + 'static>::is::<T>(self) } /// Forwards to the method defined on the type `Any`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> { - <Error + 'static>::downcast_ref::<T>(self) + <dyn Error + 'static>::downcast_ref::<T>(self) } /// Forwards to the method defined on the type `Any`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> { - <Error + 'static>::downcast_mut::<T>(self) + <dyn Error + 'static>::downcast_mut::<T>(self) } } -impl Error { +impl dyn Error { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] /// Attempt to downcast the box to a concrete type. - pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Error>> { + pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>> { if self.is::<T>() { unsafe { - let raw: *mut Error = Box::into_raw(self); + let raw: *mut dyn Error = Box::into_raw(self); Ok(Box::from_raw(raw as *mut T)) } } else { @@ -486,30 +474,30 @@ impl Error { } } -impl Error + Send { +impl dyn Error + Send { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] /// Attempt to downcast the box to a concrete type. pub fn downcast<T: Error + 'static>(self: Box<Self>) - -> Result<Box<T>, Box<Error + Send>> { - let err: Box<Error> = self; - <Error>::downcast(err).map_err(|s| unsafe { + -> Result<Box<T>, Box<dyn Error + Send>> { + let err: Box<dyn Error> = self; + <dyn Error>::downcast(err).map_err(|s| unsafe { // reapply the Send marker - transmute::<Box<Error>, Box<Error + Send>>(s) + transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s) }) } } -impl Error + Send + Sync { +impl dyn Error + Send + Sync { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] /// Attempt to downcast the box to a concrete type. pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>> { - let err: Box<Error> = self; - <Error>::downcast(err).map_err(|s| unsafe { + let err: Box<dyn Error> = self; + <dyn Error>::downcast(err).map_err(|s| unsafe { // reapply the Send+Sync marker - transmute::<Box<Error>, Box<Error + Send + Sync>>(s) + transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s) }) } } @@ -545,13 +533,13 @@ mod tests { #[test] fn downcasting() { let mut a = A; - let a = &mut a as &mut (Error + 'static); + let a = &mut a as &mut (dyn Error + 'static); assert_eq!(a.downcast_ref::<A>(), Some(&A)); assert_eq!(a.downcast_ref::<B>(), None); assert_eq!(a.downcast_mut::<A>(), Some(&mut A)); assert_eq!(a.downcast_mut::<B>(), None); - let a: Box<Error> = Box::new(A); + let a: Box<dyn Error> = Box::new(A); match a.downcast::<B>() { Ok(..) => panic!("expected error"), Err(e) => assert_eq!(*e.downcast::<A>().unwrap(), A), diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 5e5695f15ac..8e8340b3ed9 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -11,20 +11,16 @@ //! This module provides constants which are specific to the implementation //! of the `f32` floating point data type. //! -//! Mathematically significant numbers are provided in the `consts` sub-module. -//! //! *[See also the `f32` primitive type](../../std/primitive.f32.html).* +//! +//! Mathematically significant numbers are provided in the `consts` sub-module. #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] #[cfg(not(test))] -use core::num; -#[cfg(not(test))] use intrinsics; #[cfg(not(test))] -use num::FpCategory; -#[cfg(not(test))] use sys::cmath; #[stable(feature = "rust1", since = "1.0.0")] @@ -39,109 +35,12 @@ pub use core::f32::{MIN, MIN_POSITIVE, MAX}; pub use core::f32::consts; #[cfg(not(test))] -#[lang = "f32"] +#[lang = "f32_runtime"] impl f32 { - /// Returns `true` if this value is `NaN` and false otherwise. - /// - /// ``` - /// use std::f32; - /// - /// let nan = f32::NAN; - /// let f = 7.0_f32; - /// - /// assert!(nan.is_nan()); - /// assert!(!f.is_nan()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_nan(self) -> bool { num::Float::is_nan(self) } - - /// Returns `true` if this value is positive infinity or negative infinity and - /// false otherwise. - /// - /// ``` - /// use std::f32; - /// - /// let f = 7.0f32; - /// let inf = f32::INFINITY; - /// let neg_inf = f32::NEG_INFINITY; - /// let nan = f32::NAN; - /// - /// assert!(!f.is_infinite()); - /// assert!(!nan.is_infinite()); - /// - /// assert!(inf.is_infinite()); - /// assert!(neg_inf.is_infinite()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_infinite(self) -> bool { num::Float::is_infinite(self) } - - /// Returns `true` if this number is neither infinite nor `NaN`. - /// - /// ``` - /// use std::f32; - /// - /// let f = 7.0f32; - /// let inf = f32::INFINITY; - /// let neg_inf = f32::NEG_INFINITY; - /// let nan = f32::NAN; - /// - /// assert!(f.is_finite()); - /// - /// assert!(!nan.is_finite()); - /// assert!(!inf.is_finite()); - /// assert!(!neg_inf.is_finite()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_finite(self) -> bool { num::Float::is_finite(self) } - - /// Returns `true` if the number is neither zero, infinite, - /// [subnormal][subnormal], or `NaN`. - /// - /// ``` - /// use std::f32; - /// - /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32 - /// let max = f32::MAX; - /// let lower_than_min = 1.0e-40_f32; - /// let zero = 0.0_f32; - /// - /// assert!(min.is_normal()); - /// assert!(max.is_normal()); - /// - /// assert!(!zero.is_normal()); - /// assert!(!f32::NAN.is_normal()); - /// assert!(!f32::INFINITY.is_normal()); - /// // Values between `0` and `min` are Subnormal. - /// assert!(!lower_than_min.is_normal()); - /// ``` - /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_normal(self) -> bool { num::Float::is_normal(self) } - - /// Returns the floating point category of the number. If only one property - /// is going to be tested, it is generally faster to use the specific - /// predicate instead. - /// - /// ``` - /// use std::num::FpCategory; - /// use std::f32; - /// - /// let num = 12.4_f32; - /// let inf = f32::INFINITY; - /// - /// assert_eq!(num.classify(), FpCategory::Normal); - /// assert_eq!(inf.classify(), FpCategory::Infinite); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn classify(self) -> FpCategory { num::Float::classify(self) } - /// Returns the largest integer less than or equal to a number. /// + /// # Examples + /// /// ``` /// let f = 3.99_f32; /// let g = 3.0_f32; @@ -173,6 +72,8 @@ impl f32 { /// Returns the smallest integer greater than or equal to a number. /// + /// # Examples + /// /// ``` /// let f = 3.01_f32; /// let g = 4.0_f32; @@ -193,6 +94,8 @@ impl f32 { /// Returns the nearest integer to a number. Round half-way cases away from /// `0.0`. /// + /// # Examples + /// /// ``` /// let f = 3.3_f32; /// let g = -3.3_f32; @@ -208,6 +111,8 @@ impl f32 { /// Returns the integer part of a number. /// + /// # Examples + /// /// ``` /// let f = 3.3_f32; /// let g = -3.7_f32; @@ -223,6 +128,8 @@ impl f32 { /// Returns the fractional part of a number. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -241,6 +148,8 @@ impl f32 { /// Computes the absolute value of `self`. Returns `NAN` if the /// number is `NAN`. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -257,7 +166,9 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn abs(self) -> f32 { num::Float::abs(self) } + pub fn abs(self) -> f32 { + unsafe { intrinsics::fabsf32(self) } + } /// Returns a number that represents the sign of `self`. /// @@ -265,6 +176,8 @@ impl f32 { /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` /// - `NAN` if the number is `NAN` /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -277,39 +190,21 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn signum(self) -> f32 { num::Float::signum(self) } - - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with - /// positive sign bit and positive infinity. - /// - /// ``` - /// let f = 7.0_f32; - /// let g = -7.0_f32; - /// - /// assert!(f.is_sign_positive()); - /// assert!(!g.is_sign_positive()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_sign_positive(self) -> bool { num::Float::is_sign_positive(self) } + pub fn signum(self) -> f32 { + if self.is_nan() { + NAN + } else { + unsafe { intrinsics::copysignf32(1.0, self) } + } + } - /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with - /// negative sign bit and negative infinity. + /// Fused multiply-add. Computes `(self * a) + b` with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. /// - /// ``` - /// let f = 7.0f32; - /// let g = -7.0f32; + /// Using `mul_add` can be more performant than an unfused multiply-add if + /// the target architecture has a dedicated `fma` CPU instruction. /// - /// assert!(!f.is_sign_negative()); - /// assert!(g.is_sign_negative()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_sign_negative(self) -> bool { num::Float::is_sign_negative(self) } - - /// Fused multiply-add. Computes `(self * a) + b` with only one rounding - /// error. This produces a more accurate result with better performance than - /// a separate multiplication operation followed by an add. + /// # Examples /// /// ``` /// use std::f32; @@ -329,24 +224,76 @@ impl f32 { unsafe { intrinsics::fmaf32(self, a, b) } } - /// Takes the reciprocal (inverse) of a number, `1/x`. + /// Calculates Euclidean division, the matching method for `mod_euc`. + /// + /// This computes the integer `n` such that + /// `self = n * rhs + self.mod_euc(rhs)`. + /// In other words, the result is `self / rhs` rounded to the integer `n` + /// such that `self >= n * rhs`. + /// + /// # Examples /// /// ``` - /// use std::f32; + /// #![feature(euclidean_division)] + /// let a: f32 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.div_euc(b), 1.0); // 7.0 > 4.0 * 1.0 + /// assert_eq!((-a).div_euc(b), -2.0); // -7.0 >= 4.0 * -2.0 + /// assert_eq!(a.div_euc(-b), -1.0); // 7.0 >= -4.0 * -1.0 + /// assert_eq!((-a).div_euc(-b), 2.0); // -7.0 >= -4.0 * 2.0 + /// ``` + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn div_euc(self, rhs: f32) -> f32 { + let q = (self / rhs).trunc(); + if self % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 } + } + q + } + + /// Calculates the Euclidean modulo (self mod rhs), which is never negative. /// - /// let x = 2.0_f32; - /// let abs_difference = (x.recip() - (1.0/x)).abs(); + /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in + /// most cases. However, due to a floating point round-off error it can + /// result in `r == rhs.abs()`, violating the mathematical definition, if + /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. + /// This result is not an element of the function's codomain, but it is the + /// closest floating point number in the real numbers and thus fulfills the + /// property `self == self.div_euc(rhs) * rhs + self.mod_euc(rhs)` + /// approximatively. + /// + /// # Examples /// - /// assert!(abs_difference <= f32::EPSILON); /// ``` - #[stable(feature = "rust1", since = "1.0.0")] + /// #![feature(euclidean_division)] + /// let a: f32 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.mod_euc(b), 3.0); + /// assert_eq!((-a).mod_euc(b), 1.0); + /// assert_eq!(a.mod_euc(-b), 3.0); + /// assert_eq!((-a).mod_euc(-b), 1.0); + /// // limitation due to round-off error + /// assert!((-std::f32::EPSILON).mod_euc(3.0) != 0.0); + /// ``` #[inline] - pub fn recip(self) -> f32 { num::Float::recip(self) } + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn mod_euc(self, rhs: f32) -> f32 { + let r = self % rhs; + if r < 0.0 { + r + rhs.abs() + } else { + r + } + } + /// Raises a number to an integer power. /// /// Using this function is generally faster than using `powf` /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -357,10 +304,14 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn powi(self, n: i32) -> f32 { num::Float::powi(self, n) } + pub fn powi(self, n: i32) -> f32 { + unsafe { intrinsics::powif32(self, n) } + } /// Raises a number to a floating point power. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -383,6 +334,8 @@ impl f32 { /// /// Returns NaN if `self` is a negative number. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -406,6 +359,8 @@ impl f32 { /// Returns `e^(self)`, (the exponential function). /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -430,6 +385,8 @@ impl f32 { /// Returns `2^(self)`. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -448,6 +405,8 @@ impl f32 { /// Returns the natural logarithm of the number. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -476,6 +435,8 @@ impl f32 { /// `self.log2()` can produce more accurate results for base 2, and /// `self.log10()` can produce more accurate results for base 10. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -492,6 +453,8 @@ impl f32 { /// Returns the base 2 logarithm of the number. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -513,6 +476,8 @@ impl f32 { /// Returns the base 10 logarithm of the number. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -533,73 +498,13 @@ impl f32 { return unsafe { intrinsics::log10f32(self) }; } - /// Converts radians to degrees. - /// - /// ``` - /// use std::f32::{self, consts}; - /// - /// let angle = consts::PI; - /// - /// let abs_difference = (angle.to_degrees() - 180.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] - #[inline] - pub fn to_degrees(self) -> f32 { num::Float::to_degrees(self) } - - /// Converts degrees to radians. - /// - /// ``` - /// use std::f32::{self, consts}; - /// - /// let angle = 180.0f32; - /// - /// let abs_difference = (angle.to_radians() - consts::PI).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] - #[inline] - pub fn to_radians(self) -> f32 { num::Float::to_radians(self) } - - /// Returns the maximum of the two numbers. - /// - /// ``` - /// let x = 1.0f32; - /// let y = 2.0f32; - /// - /// assert_eq!(x.max(y), y); - /// ``` - /// - /// If one of the arguments is NaN, then the other argument is returned. - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn max(self, other: f32) -> f32 { - num::Float::max(self, other) - } - - /// Returns the minimum of the two numbers. - /// - /// ``` - /// let x = 1.0f32; - /// let y = 2.0f32; - /// - /// assert_eq!(x.min(y), x); - /// ``` - /// - /// If one of the arguments is NaN, then the other argument is returned. - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn min(self, other: f32) -> f32 { - num::Float::min(self, other) - } - /// The positive difference of two numbers. /// /// * If `self <= other`: `0:0` /// * Else: `self - other` /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -627,6 +532,8 @@ impl f32 { /// Takes the cubic root of a number. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -646,6 +553,8 @@ impl f32 { /// Calculates the length of the hypotenuse of a right-angle triangle given /// legs of length `x` and `y`. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -665,6 +574,8 @@ impl f32 { /// Computes the sine of a number (in radians). /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -686,6 +597,8 @@ impl f32 { /// Computes the cosine of a number (in radians). /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -707,6 +620,8 @@ impl f32 { /// Computes the tangent of a number (in radians). /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -725,6 +640,8 @@ impl f32 { /// the range [-pi/2, pi/2] or NaN if the number is outside the range /// [-1, 1]. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -745,6 +662,8 @@ impl f32 { /// the range [0, pi] or NaN if the number is outside the range /// [-1, 1]. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -764,6 +683,8 @@ impl f32 { /// Computes the arctangent of a number. Return value is in radians in the /// range [-pi/2, pi/2]; /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -780,23 +701,26 @@ impl f32 { unsafe { cmath::atanf(self) } } - /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`). + /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. /// /// * `x = 0`, `y = 0`: `0` /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` /// + /// # Examples + /// /// ``` /// use std::f32; /// /// let pi = f32::consts::PI; - /// // All angles from horizontal right (+x) - /// // 45 deg counter-clockwise + /// // Positive angles measured counter-clockwise + /// // from positive x axis + /// // -pi/4 radians (45 deg clockwise) /// let x1 = 3.0f32; /// let y1 = -3.0f32; /// - /// // 135 deg clockwise + /// // 3pi/4 radians (135 deg counter-clockwise) /// let x2 = -3.0f32; /// let y2 = 3.0f32; /// @@ -815,6 +739,8 @@ impl f32 { /// Simultaneously computes the sine and cosine of the number, `x`. Returns /// `(sin(x), cos(x))`. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -836,6 +762,8 @@ impl f32 { /// Returns `e^(self) - 1` in a way that is accurate even if the /// number is close to zero. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -855,6 +783,8 @@ impl f32 { /// Returns `ln(1+n)` (natural logarithm) more accurately than if /// the operations were performed separately. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -873,6 +803,8 @@ impl f32 { /// Hyperbolic sine function. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -894,6 +826,8 @@ impl f32 { /// Hyperbolic cosine function. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -915,6 +849,8 @@ impl f32 { /// Hyperbolic tangent function. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -936,6 +872,8 @@ impl f32 { /// Inverse hyperbolic sine function. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -958,6 +896,8 @@ impl f32 { /// Inverse hyperbolic cosine function. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -979,6 +919,8 @@ impl f32 { /// Inverse hyperbolic tangent function. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -994,74 +936,6 @@ impl f32 { pub fn atanh(self) -> f32 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } - - /// Raw transmutation to `u32`. - /// - /// This is currently identical to `transmute::<f32, u32>(self)` on all platforms. - /// - /// See `from_bits` for some discussion of the portability of this operation - /// (there are almost no issues). - /// - /// Note that this function is distinct from `as` casting, which attempts to - /// preserve the *numeric* value, and not the bitwise value. - /// - /// # Examples - /// - /// ``` - /// assert_ne!((1f32).to_bits(), 1f32 as u32); // to_bits() is not casting! - /// assert_eq!((12.5f32).to_bits(), 0x41480000); - /// - /// ``` - #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[inline] - pub fn to_bits(self) -> u32 { - unsafe { ::mem::transmute(self) } - } - - /// Raw transmutation from `u32`. - /// - /// This is currently identical to `transmute::<u32, f32>(v)` on all platforms. - /// It turns out this is incredibly portable, for two reasons: - /// - /// * Floats and Ints have the same endianess on all supported platforms. - /// * IEEE-754 very precisely specifies the bit layout of floats. - /// - /// However there is one caveat: prior to the 2008 version of IEEE-754, how - /// to interpret the NaN signaling bit wasn't actually specified. Most platforms - /// (notably x86 and ARM) picked the interpretation that was ultimately - /// standardized in 2008, but some didn't (notably MIPS). As a result, all - /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa. - /// - /// Rather than trying to preserve signaling-ness cross-platform, this - /// implementation favours preserving the exact bits. This means that - /// any payloads encoded in NaNs will be preserved even if the result of - /// this method is sent over the network from an x86 machine to a MIPS one. - /// - /// If the results of this method are only manipulated by the same - /// architecture that produced them, then there is no portability concern. - /// - /// If the input isn't NaN, then there is no portability concern. - /// - /// If you don't care about signalingness (very likely), then there is no - /// portability concern. - /// - /// Note that this function is distinct from `as` casting, which attempts to - /// preserve the *numeric* value, and not the bitwise value. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// let v = f32::from_bits(0x41480000); - /// let difference = (v - 12.5).abs(); - /// assert!(difference <= 1e-5); - /// ``` - #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[inline] - pub fn from_bits(v: u32) -> Self { - // It turns out the safety issues with sNaN were overblown! Hooray! - unsafe { ::mem::transmute(v) } - } } #[cfg(test)] @@ -1532,6 +1406,7 @@ mod tests { assert!(nan.to_degrees().is_nan()); assert_eq!(inf.to_degrees(), inf); assert_eq!(neg_inf.to_degrees(), neg_inf); + assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703); } #[test] diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index e4eea745bb7..6880294afca 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -11,20 +11,16 @@ //! This module provides constants which are specific to the implementation //! of the `f64` floating point data type. //! -//! Mathematically significant numbers are provided in the `consts` sub-module. -//! //! *[See also the `f64` primitive type](../../std/primitive.f64.html).* +//! +//! Mathematically significant numbers are provided in the `consts` sub-module. #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] #[cfg(not(test))] -use core::num; -#[cfg(not(test))] use intrinsics; #[cfg(not(test))] -use num::FpCategory; -#[cfg(not(test))] use sys::cmath; #[stable(feature = "rust1", since = "1.0.0")] @@ -39,109 +35,12 @@ pub use core::f64::{MIN, MIN_POSITIVE, MAX}; pub use core::f64::consts; #[cfg(not(test))] -#[lang = "f64"] +#[lang = "f64_runtime"] impl f64 { - /// Returns `true` if this value is `NaN` and false otherwise. - /// - /// ``` - /// use std::f64; - /// - /// let nan = f64::NAN; - /// let f = 7.0_f64; - /// - /// assert!(nan.is_nan()); - /// assert!(!f.is_nan()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_nan(self) -> bool { num::Float::is_nan(self) } - - /// Returns `true` if this value is positive infinity or negative infinity and - /// false otherwise. - /// - /// ``` - /// use std::f64; - /// - /// let f = 7.0f64; - /// let inf = f64::INFINITY; - /// let neg_inf = f64::NEG_INFINITY; - /// let nan = f64::NAN; - /// - /// assert!(!f.is_infinite()); - /// assert!(!nan.is_infinite()); - /// - /// assert!(inf.is_infinite()); - /// assert!(neg_inf.is_infinite()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_infinite(self) -> bool { num::Float::is_infinite(self) } - - /// Returns `true` if this number is neither infinite nor `NaN`. - /// - /// ``` - /// use std::f64; - /// - /// let f = 7.0f64; - /// let inf: f64 = f64::INFINITY; - /// let neg_inf: f64 = f64::NEG_INFINITY; - /// let nan: f64 = f64::NAN; - /// - /// assert!(f.is_finite()); - /// - /// assert!(!nan.is_finite()); - /// assert!(!inf.is_finite()); - /// assert!(!neg_inf.is_finite()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_finite(self) -> bool { num::Float::is_finite(self) } - - /// Returns `true` if the number is neither zero, infinite, - /// [subnormal][subnormal], or `NaN`. - /// - /// ``` - /// use std::f64; - /// - /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308f64 - /// let max = f64::MAX; - /// let lower_than_min = 1.0e-308_f64; - /// let zero = 0.0f64; - /// - /// assert!(min.is_normal()); - /// assert!(max.is_normal()); - /// - /// assert!(!zero.is_normal()); - /// assert!(!f64::NAN.is_normal()); - /// assert!(!f64::INFINITY.is_normal()); - /// // Values between `0` and `min` are Subnormal. - /// assert!(!lower_than_min.is_normal()); - /// ``` - /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_normal(self) -> bool { num::Float::is_normal(self) } - - /// Returns the floating point category of the number. If only one property - /// is going to be tested, it is generally faster to use the specific - /// predicate instead. - /// - /// ``` - /// use std::num::FpCategory; - /// use std::f64; - /// - /// let num = 12.4_f64; - /// let inf = f64::INFINITY; - /// - /// assert_eq!(num.classify(), FpCategory::Normal); - /// assert_eq!(inf.classify(), FpCategory::Infinite); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn classify(self) -> FpCategory { num::Float::classify(self) } - /// Returns the largest integer less than or equal to a number. /// + /// # Examples + /// /// ``` /// let f = 3.99_f64; /// let g = 3.0_f64; @@ -157,6 +56,8 @@ impl f64 { /// Returns the smallest integer greater than or equal to a number. /// + /// # Examples + /// /// ``` /// let f = 3.01_f64; /// let g = 4.0_f64; @@ -173,6 +74,8 @@ impl f64 { /// Returns the nearest integer to a number. Round half-way cases away from /// `0.0`. /// + /// # Examples + /// /// ``` /// let f = 3.3_f64; /// let g = -3.3_f64; @@ -188,6 +91,8 @@ impl f64 { /// Returns the integer part of a number. /// + /// # Examples + /// /// ``` /// let f = 3.3_f64; /// let g = -3.7_f64; @@ -203,6 +108,8 @@ impl f64 { /// Returns the fractional part of a number. /// + /// # Examples + /// /// ``` /// let x = 3.5_f64; /// let y = -3.5_f64; @@ -219,6 +126,8 @@ impl f64 { /// Computes the absolute value of `self`. Returns `NAN` if the /// number is `NAN`. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -235,7 +144,9 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn abs(self) -> f64 { num::Float::abs(self) } + pub fn abs(self) -> f64 { + unsafe { intrinsics::fabsf64(self) } + } /// Returns a number that represents the sign of `self`. /// @@ -243,6 +154,8 @@ impl f64 { /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` /// - `NAN` if the number is `NAN` /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -255,49 +168,21 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn signum(self) -> f64 { num::Float::signum(self) } - - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with - /// positive sign bit and positive infinity. - /// - /// ``` - /// let f = 7.0_f64; - /// let g = -7.0_f64; - /// - /// assert!(f.is_sign_positive()); - /// assert!(!g.is_sign_positive()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_sign_positive(self) -> bool { num::Float::is_sign_positive(self) } - - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_positive")] - #[inline] - pub fn is_positive(self) -> bool { num::Float::is_sign_positive(self) } + pub fn signum(self) -> f64 { + if self.is_nan() { + NAN + } else { + unsafe { intrinsics::copysignf64(1.0, self) } + } + } - /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with - /// negative sign bit and negative infinity. + /// Fused multiply-add. Computes `(self * a) + b` with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. /// - /// ``` - /// let f = 7.0_f64; - /// let g = -7.0_f64; + /// Using `mul_add` can be more performant than an unfused multiply-add if + /// the target architecture has a dedicated `fma` CPU instruction. /// - /// assert!(!f.is_sign_negative()); - /// assert!(g.is_sign_negative()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_sign_negative(self) -> bool { num::Float::is_sign_negative(self) } - - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_negative")] - #[inline] - pub fn is_negative(self) -> bool { num::Float::is_sign_negative(self) } - - /// Fused multiply-add. Computes `(self * a) + b` with only one rounding - /// error. This produces a more accurate result with better performance than - /// a separate multiplication operation followed by an add. + /// # Examples /// /// ``` /// let m = 10.0_f64; @@ -315,22 +200,75 @@ impl f64 { unsafe { intrinsics::fmaf64(self, a, b) } } - /// Takes the reciprocal (inverse) of a number, `1/x`. + /// Calculates Euclidean division, the matching method for `mod_euc`. + /// + /// This computes the integer `n` such that + /// `self = n * rhs + self.mod_euc(rhs)`. + /// In other words, the result is `self / rhs` rounded to the integer `n` + /// such that `self >= n * rhs`. + /// + /// # Examples /// /// ``` - /// let x = 2.0_f64; - /// let abs_difference = (x.recip() - (1.0/x)).abs(); + /// #![feature(euclidean_division)] + /// let a: f64 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.div_euc(b), 1.0); // 7.0 > 4.0 * 1.0 + /// assert_eq!((-a).div_euc(b), -2.0); // -7.0 >= 4.0 * -2.0 + /// assert_eq!(a.div_euc(-b), -1.0); // 7.0 >= -4.0 * -1.0 + /// assert_eq!((-a).div_euc(-b), 2.0); // -7.0 >= -4.0 * 2.0 + /// ``` + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn div_euc(self, rhs: f64) -> f64 { + let q = (self / rhs).trunc(); + if self % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 } + } + q + } + + /// Calculates the Euclidean modulo (self mod rhs), which is never negative. + /// + /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in + /// most cases. However, due to a floating point round-off error it can + /// result in `r == rhs.abs()`, violating the mathematical definition, if + /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. + /// This result is not an element of the function's codomain, but it is the + /// closest floating point number in the real numbers and thus fulfills the + /// property `self == self.div_euc(rhs) * rhs + self.mod_euc(rhs)` + /// approximatively. + /// + /// # Examples /// - /// assert!(abs_difference < 1e-10); /// ``` - #[stable(feature = "rust1", since = "1.0.0")] + /// #![feature(euclidean_division)] + /// let a: f64 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.mod_euc(b), 3.0); + /// assert_eq!((-a).mod_euc(b), 1.0); + /// assert_eq!(a.mod_euc(-b), 3.0); + /// assert_eq!((-a).mod_euc(-b), 1.0); + /// // limitation due to round-off error + /// assert!((-std::f64::EPSILON).mod_euc(3.0) != 0.0); + /// ``` #[inline] - pub fn recip(self) -> f64 { num::Float::recip(self) } + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn mod_euc(self, rhs: f64) -> f64 { + let r = self % rhs; + if r < 0.0 { + r + rhs.abs() + } else { + r + } + } /// Raises a number to an integer power. /// /// Using this function is generally faster than using `powf` /// + /// # Examples + /// /// ``` /// let x = 2.0_f64; /// let abs_difference = (x.powi(2) - x*x).abs(); @@ -339,10 +277,14 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn powi(self, n: i32) -> f64 { num::Float::powi(self, n) } + pub fn powi(self, n: i32) -> f64 { + unsafe { intrinsics::powif64(self, n) } + } /// Raises a number to a floating point power. /// + /// # Examples + /// /// ``` /// let x = 2.0_f64; /// let abs_difference = (x.powf(2.0) - x*x).abs(); @@ -359,6 +301,8 @@ impl f64 { /// /// Returns NaN if `self` is a negative number. /// + /// # Examples + /// /// ``` /// let positive = 4.0_f64; /// let negative = -4.0_f64; @@ -380,6 +324,8 @@ impl f64 { /// Returns `e^(self)`, (the exponential function). /// + /// # Examples + /// /// ``` /// let one = 1.0_f64; /// // e^1 @@ -398,6 +344,8 @@ impl f64 { /// Returns `2^(self)`. /// + /// # Examples + /// /// ``` /// let f = 2.0_f64; /// @@ -414,6 +362,8 @@ impl f64 { /// Returns the natural logarithm of the number. /// + /// # Examples + /// /// ``` /// let one = 1.0_f64; /// // e^1 @@ -436,6 +386,8 @@ impl f64 { /// `self.log2()` can produce more accurate results for base 2, and /// `self.log10()` can produce more accurate results for base 10. /// + /// # Examples + /// /// ``` /// let five = 5.0_f64; /// @@ -450,6 +402,8 @@ impl f64 { /// Returns the base 2 logarithm of the number. /// + /// # Examples + /// /// ``` /// let two = 2.0_f64; /// @@ -471,6 +425,8 @@ impl f64 { /// Returns the base 10 logarithm of the number. /// + /// # Examples + /// /// ``` /// let ten = 10.0_f64; /// @@ -485,73 +441,13 @@ impl f64 { self.log_wrapper(|n| { unsafe { intrinsics::log10f64(n) } }) } - /// Converts radians to degrees. - /// - /// ``` - /// use std::f64::consts; - /// - /// let angle = consts::PI; - /// - /// let abs_difference = (angle.to_degrees() - 180.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn to_degrees(self) -> f64 { num::Float::to_degrees(self) } - - /// Converts degrees to radians. - /// - /// ``` - /// use std::f64::consts; - /// - /// let angle = 180.0_f64; - /// - /// let abs_difference = (angle.to_radians() - consts::PI).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn to_radians(self) -> f64 { num::Float::to_radians(self) } - - /// Returns the maximum of the two numbers. - /// - /// ``` - /// let x = 1.0_f64; - /// let y = 2.0_f64; - /// - /// assert_eq!(x.max(y), y); - /// ``` - /// - /// If one of the arguments is NaN, then the other argument is returned. - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn max(self, other: f64) -> f64 { - num::Float::max(self, other) - } - - /// Returns the minimum of the two numbers. - /// - /// ``` - /// let x = 1.0_f64; - /// let y = 2.0_f64; - /// - /// assert_eq!(x.min(y), x); - /// ``` - /// - /// If one of the arguments is NaN, then the other argument is returned. - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn min(self, other: f64) -> f64 { - num::Float::min(self, other) - } - /// The positive difference of two numbers. /// /// * If `self <= other`: `0:0` /// * Else: `self - other` /// + /// # Examples + /// /// ``` /// let x = 3.0_f64; /// let y = -3.0_f64; @@ -577,6 +473,8 @@ impl f64 { /// Takes the cubic root of a number. /// + /// # Examples + /// /// ``` /// let x = 8.0_f64; /// @@ -594,6 +492,8 @@ impl f64 { /// Calculates the length of the hypotenuse of a right-angle triangle given /// legs of length `x` and `y`. /// + /// # Examples + /// /// ``` /// let x = 2.0_f64; /// let y = 3.0_f64; @@ -611,6 +511,8 @@ impl f64 { /// Computes the sine of a number (in radians). /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -628,6 +530,8 @@ impl f64 { /// Computes the cosine of a number (in radians). /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -645,6 +549,8 @@ impl f64 { /// Computes the tangent of a number (in radians). /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -663,6 +569,8 @@ impl f64 { /// the range [-pi/2, pi/2] or NaN if the number is outside the range /// [-1, 1]. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -683,6 +591,8 @@ impl f64 { /// the range [0, pi] or NaN if the number is outside the range /// [-1, 1]. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -702,6 +612,8 @@ impl f64 { /// Computes the arctangent of a number. Return value is in radians in the /// range [-pi/2, pi/2]; /// + /// # Examples + /// /// ``` /// let f = 1.0_f64; /// @@ -716,23 +628,26 @@ impl f64 { unsafe { cmath::atan(self) } } - /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`). + /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. /// /// * `x = 0`, `y = 0`: `0` /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` /// + /// # Examples + /// /// ``` /// use std::f64; /// /// let pi = f64::consts::PI; - /// // All angles from horizontal right (+x) - /// // 45 deg counter-clockwise + /// // Positive angles measured counter-clockwise + /// // from positive x axis + /// // -pi/4 radians (45 deg clockwise) /// let x1 = 3.0_f64; /// let y1 = -3.0_f64; /// - /// // 135 deg clockwise + /// // 3pi/4 radians (135 deg counter-clockwise) /// let x2 = -3.0_f64; /// let y2 = 3.0_f64; /// @@ -751,6 +666,8 @@ impl f64 { /// Simultaneously computes the sine and cosine of the number, `x`. Returns /// `(sin(x), cos(x))`. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -772,6 +689,8 @@ impl f64 { /// Returns `e^(self) - 1` in a way that is accurate even if the /// number is close to zero. /// + /// # Examples + /// /// ``` /// let x = 7.0_f64; /// @@ -789,6 +708,8 @@ impl f64 { /// Returns `ln(1+n)` (natural logarithm) more accurately than if /// the operations were performed separately. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -807,6 +728,8 @@ impl f64 { /// Hyperbolic sine function. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -828,6 +751,8 @@ impl f64 { /// Hyperbolic cosine function. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -849,6 +774,8 @@ impl f64 { /// Hyperbolic tangent function. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -870,6 +797,8 @@ impl f64 { /// Inverse hyperbolic sine function. /// + /// # Examples + /// /// ``` /// let x = 1.0_f64; /// let f = x.sinh().asinh(); @@ -890,6 +819,8 @@ impl f64 { /// Inverse hyperbolic cosine function. /// + /// # Examples + /// /// ``` /// let x = 1.0_f64; /// let f = x.cosh().acosh(); @@ -909,6 +840,8 @@ impl f64 { /// Inverse hyperbolic tangent function. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -949,74 +882,6 @@ impl f64 { } } } - - /// Raw transmutation to `u64`. - /// - /// This is currently identical to `transmute::<f64, u64>(self)` on all platforms. - /// - /// See `from_bits` for some discussion of the portability of this operation - /// (there are almost no issues). - /// - /// Note that this function is distinct from `as` casting, which attempts to - /// preserve the *numeric* value, and not the bitwise value. - /// - /// # Examples - /// - /// ``` - /// assert!((1f64).to_bits() != 1f64 as u64); // to_bits() is not casting! - /// assert_eq!((12.5f64).to_bits(), 0x4029000000000000); - /// - /// ``` - #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[inline] - pub fn to_bits(self) -> u64 { - unsafe { ::mem::transmute(self) } - } - - /// Raw transmutation from `u64`. - /// - /// This is currently identical to `transmute::<u64, f64>(v)` on all platforms. - /// It turns out this is incredibly portable, for two reasons: - /// - /// * Floats and Ints have the same endianess on all supported platforms. - /// * IEEE-754 very precisely specifies the bit layout of floats. - /// - /// However there is one caveat: prior to the 2008 version of IEEE-754, how - /// to interpret the NaN signaling bit wasn't actually specified. Most platforms - /// (notably x86 and ARM) picked the interpretation that was ultimately - /// standardized in 2008, but some didn't (notably MIPS). As a result, all - /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa. - /// - /// Rather than trying to preserve signaling-ness cross-platform, this - /// implementation favours preserving the exact bits. This means that - /// any payloads encoded in NaNs will be preserved even if the result of - /// this method is sent over the network from an x86 machine to a MIPS one. - /// - /// If the results of this method are only manipulated by the same - /// architecture that produced them, then there is no portability concern. - /// - /// If the input isn't NaN, then there is no portability concern. - /// - /// If you don't care about signalingness (very likely), then there is no - /// portability concern. - /// - /// Note that this function is distinct from `as` casting, which attempts to - /// preserve the *numeric* value, and not the bitwise value. - /// - /// # Examples - /// - /// ``` - /// use std::f64; - /// let v = f64::from_bits(0x4029000000000000); - /// let difference = (v - 12.5).abs(); - /// assert!(difference <= 1e-5); - /// ``` - #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[inline] - pub fn from_bits(v: u64) -> Self { - // It turns out the safety issues with sNaN were overblown! Hooray! - unsafe { ::mem::transmute(v) } - } } #[cfg(test)] diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index a19fe825f21..2b87094926c 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -91,7 +91,7 @@ use sys; /// /// # Examples /// -/// ```no_run +/// ```ignore (extern-declaration) /// # fn main() { /// use std::ffi::CString; /// use std::os::raw::c_char; @@ -150,7 +150,7 @@ pub struct CString { /// /// Inspecting a foreign C string: /// -/// ```no_run +/// ```ignore (extern-declaration) /// use std::ffi::CStr; /// use std::os::raw::c_char; /// @@ -164,7 +164,7 @@ pub struct CString { /// /// Passing a Rust-originating C string: /// -/// ```no_run +/// ```ignore (extern-declaration) /// use std::ffi::{CString, CStr}; /// use std::os::raw::c_char; /// @@ -180,7 +180,7 @@ pub struct CString { /// /// Converting a foreign C string into a Rust [`String`]: /// -/// ```no_run +/// ```ignore (extern-declaration) /// use std::ffi::CStr; /// use std::os::raw::c_char; /// @@ -307,7 +307,7 @@ impl CString { /// /// # Examples /// - /// ```no_run + /// ```ignore (extern-declaration) /// use std::ffi::CString; /// use std::os::raw::c_char; /// @@ -389,7 +389,7 @@ impl CString { /// Create a `CString`, pass ownership to an `extern` function (via raw pointer), then retake /// ownership with `from_raw`: /// - /// ```no_run + /// ```ignore (extern-declaration) /// use std::ffi::CString; /// use std::os::raw::c_char; /// @@ -642,6 +642,12 @@ impl fmt::Debug for CString { #[stable(feature = "cstring_into", since = "1.7.0")] impl From<CString> for Vec<u8> { + /// Converts a [`CString`] into a [`Vec`]`<u8>`. + /// + /// The conversion consumes the [`CString`], and removes the terminating NUL byte. + /// + /// [`Vec`]: ../vec/struct.Vec.html + /// [`CString`]: ../ffi/struct.CString.html #[inline] fn from(s: CString) -> Vec<u8> { s.into_bytes() @@ -682,6 +688,14 @@ impl Borrow<CStr> for CString { fn borrow(&self) -> &CStr { self } } +#[stable(feature = "cstring_from_cow_cstr", since = "1.28.0")] +impl<'a> From<Cow<'a, CStr>> for CString { + #[inline] + fn from(s: Cow<'a, CStr>) -> Self { + s.into_owned() + } +} + #[stable(feature = "box_from_c_str", since = "1.17.0")] impl<'a> From<&'a CStr> for Box<CStr> { fn from(s: &'a CStr) -> Box<CStr> { @@ -692,22 +706,66 @@ impl<'a> From<&'a CStr> for Box<CStr> { #[stable(feature = "c_string_from_box", since = "1.18.0")] impl From<Box<CStr>> for CString { + /// Converts a [`Box`]`<CStr>` into a [`CString`] without copying or allocating. + /// + /// [`Box`]: ../boxed/struct.Box.html + /// [`CString`]: ../ffi/struct.CString.html #[inline] fn from(s: Box<CStr>) -> CString { s.into_c_string() } } +#[stable(feature = "more_box_slice_clone", since = "1.29.0")] +impl Clone for Box<CStr> { + #[inline] + fn clone(&self) -> Self { + (**self).into() + } +} + #[stable(feature = "box_from_c_string", since = "1.20.0")] impl From<CString> for Box<CStr> { + /// Converts a [`CString`] into a [`Box`]`<CStr>` without copying or allocating. + /// + /// [`CString`]: ../ffi/struct.CString.html + /// [`Box`]: ../boxed/struct.Box.html #[inline] fn from(s: CString) -> Box<CStr> { s.into_boxed_c_str() } } +#[stable(feature = "cow_from_cstr", since = "1.28.0")] +impl<'a> From<CString> for Cow<'a, CStr> { + #[inline] + fn from(s: CString) -> Cow<'a, CStr> { + Cow::Owned(s) + } +} + +#[stable(feature = "cow_from_cstr", since = "1.28.0")] +impl<'a> From<&'a CStr> for Cow<'a, CStr> { + #[inline] + fn from(s: &'a CStr) -> Cow<'a, CStr> { + Cow::Borrowed(s) + } +} + +#[stable(feature = "cow_from_cstr", since = "1.28.0")] +impl<'a> From<&'a CString> for Cow<'a, CStr> { + #[inline] + fn from(s: &'a CString) -> Cow<'a, CStr> { + Cow::Borrowed(s.as_c_str()) + } +} + #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<CString> for Arc<CStr> { + /// Converts a [`CString`] into a [`Arc`]`<CStr>` without copying or allocating. + /// + /// [`CString`]: ../ffi/struct.CString.html + /// [`Arc`]: ../sync/struct.Arc.html #[inline] fn from(s: CString) -> Arc<CStr> { let arc: Arc<[u8]> = Arc::from(s.into_inner()); @@ -726,6 +784,10 @@ impl<'a> From<&'a CStr> for Arc<CStr> { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<CString> for Rc<CStr> { + /// Converts a [`CString`] into a [`Rc`]`<CStr>` without copying or allocating. + /// + /// [`CString`]: ../ffi/struct.CString.html + /// [`Rc`]: ../rc/struct.Rc.html #[inline] fn from(s: CString) -> Rc<CStr> { let rc: Rc<[u8]> = Rc::from(s.into_inner()); @@ -799,6 +861,10 @@ impl fmt::Display for NulError { #[stable(feature = "rust1", since = "1.0.0")] impl From<NulError> for io::Error { + /// Converts a [`NulError`] into a [`io::Error`]. + /// + /// [`NulError`]: ../ffi/struct.NulError.html + /// [`io::Error`]: ../io/struct.Error.html fn from(_: NulError) -> io::Error { io::Error::new(io::ErrorKind::InvalidInput, "data provided contains a nul byte") @@ -851,7 +917,7 @@ impl Error for IntoStringError { "C string contained non-utf8 bytes" } - fn cause(&self) -> Option<&Error> { + fn cause(&self) -> Option<&dyn Error> { Some(&self.error) } } @@ -875,6 +941,8 @@ impl CStr { /// `ptr`. /// * There is no guarantee that the memory pointed to by `ptr` contains a /// valid nul terminator byte at the end of the string. + /// * It is not guaranteed that the memory pointed by `ptr` won't change + /// before the `CStr` has been destroyed. /// /// > **Note**: This operation is intended to be a 0-cost cast but it is /// > currently implemented with an up-front calculation of the length of @@ -882,7 +950,7 @@ impl CStr { /// /// # Examples /// - /// ```no_run + /// ```ignore (extern-declaration) /// # fn main() { /// use std::ffi::CStr; /// use std::os::raw::c_char; @@ -986,6 +1054,7 @@ impl CStr { /// behavior when `ptr` is used inside the `unsafe` block: /// /// ```no_run + /// # #![allow(unused_must_use)] /// use std::ffi::{CString}; /// /// let ptr = CString::new("Hello").unwrap().as_ptr(); @@ -1001,6 +1070,7 @@ impl CStr { /// To fix the problem, bind the `CString` to a local variable: /// /// ```no_run + /// # #![allow(unused_must_use)] /// use std::ffi::{CString}; /// /// let hello = CString::new("Hello").unwrap(); @@ -1026,9 +1096,9 @@ impl CStr { /// The returned slice will **not** contain the trailing nul terminator that this C /// string has. /// - /// > **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. + /// > **Note**: This method is currently implemented as a constant-time + /// > cast, but it is planned to alter its definition in the future to + /// > perform the length calculation whenever this method is called. /// /// # Examples /// @@ -1077,9 +1147,9 @@ impl CStr { /// it will return an error with details of where UTF-8 validation failed. /// /// > **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. + /// > after a constant-time 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 /// @@ -1105,19 +1175,21 @@ impl CStr { /// If the contents of the `CStr` are valid UTF-8 data, this /// function will return a [`Cow`]`::`[`Borrowed`]`(`[`&str`]`)` /// with the the corresponding [`&str`] slice. Otherwise, it will - /// replace any invalid UTF-8 sequences with `U+FFFD REPLACEMENT - /// CHARACTER` and return a [`Cow`]`::`[`Owned`]`(`[`String`]`)` - /// with the result. + /// replace any invalid UTF-8 sequences with + /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a + /// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result. /// /// > **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. + /// > after a constant-time 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 /// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed + /// [`Owned`]: ../borrow/enum.Cow.html#variant.Owned /// [`str`]: ../primitive.str.html /// [`String`]: ../string/struct.String.html + /// [U+FFFD]: ../char/constant.REPLACEMENT_CHARACTER.html /// /// # Examples /// diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 3959e8533be..6bcd62dbd59 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -61,7 +61,7 @@ use sys_common::{AsInner, IntoInner, FromInner}; /// # Conversions /// /// See the [module's toplevel documentation about conversions][conversions] for a discussion on -/// the traits which `OsString` implements for conversions from/to native representations. +/// the traits which `OsString` implements for [conversions] from/to native representations. /// /// [`OsStr`]: struct.OsStr.html /// [`&OsStr`]: struct.OsStr.html @@ -74,6 +74,7 @@ use sys_common::{AsInner, IntoInner, FromInner}; /// [`new`]: #method.new /// [`push`]: #method.push /// [`as_os_str`]: #method.as_os_str +/// [conversions]: index.html#conversions #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct OsString { @@ -89,7 +90,7 @@ pub struct OsString { /// references; the latter are owned strings. /// /// See the [module's toplevel documentation about conversions][conversions] for a discussion on -/// the traits which `OsStr` implements for conversions from/to native representations. +/// the traits which `OsStr` implements for [conversions] from/to native representations. /// /// [`OsString`]: struct.OsString.html /// [`&str`]: ../primitive.str.html @@ -295,6 +296,36 @@ impl OsString { self.inner.shrink_to_fit() } + /// Shrinks the capacity of the `OsString` with a lower bound. + /// + /// The capacity will remain at least as large as both the length + /// and the supplied value. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// #![feature(shrink_to)] + /// use std::ffi::OsString; + /// + /// let mut s = OsString::from("foo"); + /// + /// s.reserve(100); + /// assert!(s.capacity() >= 100); + /// + /// s.shrink_to(10); + /// assert!(s.capacity() >= 10); + /// s.shrink_to(0); + /// assert!(s.capacity() >= 3); + /// ``` + #[inline] + #[unstable(feature = "shrink_to", reason = "new API", issue="0")] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.inner.shrink_to(min_capacity) + } + /// Converts this `OsString` into a boxed [`OsStr`]. /// /// [`OsStr`]: struct.OsStr.html @@ -317,6 +348,12 @@ impl OsString { #[stable(feature = "rust1", since = "1.0.0")] impl From<String> for OsString { + /// Converts a [`String`] into a [`OsString`]. + /// + /// The conversion copies the data, and includes an allocation on the heap. + /// + /// [`String`]: ../string/struct.String.html + /// [`OsString`]: struct.OsString.html fn from(s: String) -> OsString { OsString { inner: Buf::from_string(s) } } @@ -386,6 +423,20 @@ impl PartialEq<OsString> for str { } } +#[stable(feature = "os_str_str_ref_eq", since = "1.28.0")] +impl<'a> PartialEq<&'a str> for OsString { + fn eq(&self, other: &&'a str) -> bool { + **self == **other + } +} + +#[stable(feature = "os_str_str_ref_eq", since = "1.28.0")] +impl<'a> PartialEq<OsString> for &'a str { + fn eq(&self, other: &OsString) -> bool { + **other == **self + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Eq for OsString {} @@ -469,10 +520,12 @@ impl OsStr { /// Converts an `OsStr` to a [`Cow`]`<`[`str`]`>`. /// - /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER. + /// Any non-Unicode sequences are replaced with + /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. /// /// [`Cow`]: ../../std/borrow/enum.Cow.html /// [`str`]: ../../std/primitive.str.html + /// [U+FFFD]: ../../std/char/constant.REPLACEMENT_CHARACTER.html /// /// # Examples /// @@ -585,6 +638,10 @@ impl<'a> From<&'a OsStr> for Box<OsStr> { #[stable(feature = "os_string_from_box", since = "1.18.0")] impl From<Box<OsStr>> for OsString { + /// Converts a `Box<OsStr>` into a `OsString` without copying or allocating. + /// + /// [`Box`]: ../boxed/struct.Box.html + /// [`OsString`]: ../ffi/struct.OsString.html fn from(boxed: Box<OsStr>) -> OsString { boxed.into_os_string() } @@ -592,13 +649,29 @@ impl From<Box<OsStr>> for OsString { #[stable(feature = "box_from_os_string", since = "1.20.0")] impl From<OsString> for Box<OsStr> { + /// Converts a [`OsString`] into a [`Box`]`<OsStr>` without copying or allocating. + /// + /// [`Box`]: ../boxed/struct.Box.html + /// [`OsString`]: ../ffi/struct.OsString.html fn from(s: OsString) -> Box<OsStr> { s.into_boxed_os_str() } } +#[stable(feature = "more_box_slice_clone", since = "1.29.0")] +impl Clone for Box<OsStr> { + #[inline] + fn clone(&self) -> Self { + self.to_os_string().into_boxed_os_str() + } +} + #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<OsString> for Arc<OsStr> { + /// Converts a [`OsString`] into a [`Arc`]`<OsStr>` without copying or allocating. + /// + /// [`Arc`]: ../sync/struct.Arc.html + /// [`OsString`]: ../ffi/struct.OsString.html #[inline] fn from(s: OsString) -> Arc<OsStr> { let arc = s.inner.into_arc(); @@ -617,6 +690,10 @@ impl<'a> From<&'a OsStr> for Arc<OsStr> { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<OsString> for Rc<OsStr> { + /// Converts a [`OsString`] into a [`Rc`]`<OsStr>` without copying or allocating. + /// + /// [`Rc`]: ../rc/struct.Rc.html + /// [`OsString`]: ../ffi/struct.OsString.html #[inline] fn from(s: OsString) -> Rc<OsStr> { let rc = s.inner.into_rc(); @@ -633,6 +710,38 @@ impl<'a> From<&'a OsStr> for Rc<OsStr> { } } +#[stable(feature = "cow_from_osstr", since = "1.28.0")] +impl<'a> From<OsString> for Cow<'a, OsStr> { + #[inline] + fn from(s: OsString) -> Cow<'a, OsStr> { + Cow::Owned(s) + } +} + +#[stable(feature = "cow_from_osstr", since = "1.28.0")] +impl<'a> From<&'a OsStr> for Cow<'a, OsStr> { + #[inline] + fn from(s: &'a OsStr) -> Cow<'a, OsStr> { + Cow::Borrowed(s) + } +} + +#[stable(feature = "cow_from_osstr", since = "1.28.0")] +impl<'a> From<&'a OsString> for Cow<'a, OsStr> { + #[inline] + fn from(s: &'a OsString) -> Cow<'a, OsStr> { + Cow::Borrowed(s.as_os_str()) + } +} + +#[stable(feature = "osstring_from_cow_osstr", since = "1.28.0")] +impl<'a> From<Cow<'a, OsStr>> for OsString { + #[inline] + fn from(s: Cow<'a, OsStr>) -> Self { + s.into_owned() + } +} + #[stable(feature = "box_default_extra", since = "1.17.0")] impl Default for Box<OsStr> { fn default() -> Box<OsStr> { diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 4e0ff450cab..7632fbc41f5 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -41,11 +41,11 @@ use time::SystemTime; /// use std::fs::File; /// use std::io::prelude::*; /// -/// # fn foo() -> std::io::Result<()> { -/// let mut file = File::create("foo.txt")?; -/// file.write_all(b"Hello, world!")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// let mut file = File::create("foo.txt")?; +/// file.write_all(b"Hello, world!")?; +/// Ok(()) +/// } /// ``` /// /// Read the contents of a file into a [`String`]: @@ -54,13 +54,13 @@ use time::SystemTime; /// use std::fs::File; /// use std::io::prelude::*; /// -/// # fn foo() -> std::io::Result<()> { -/// let mut file = File::open("foo.txt")?; -/// let mut contents = String::new(); -/// file.read_to_string(&mut contents)?; -/// assert_eq!(contents, "Hello, world!"); -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// let mut file = File::open("foo.txt")?; +/// let mut contents = String::new(); +/// file.read_to_string(&mut contents)?; +/// assert_eq!(contents, "Hello, world!"); +/// Ok(()) +/// } /// ``` /// /// It can be more efficient to read the contents of a file with a buffered @@ -71,19 +71,28 @@ use time::SystemTime; /// use std::io::BufReader; /// use std::io::prelude::*; /// -/// # fn foo() -> std::io::Result<()> { -/// let file = File::open("foo.txt")?; -/// let mut buf_reader = BufReader::new(file); -/// let mut contents = String::new(); -/// buf_reader.read_to_string(&mut contents)?; -/// assert_eq!(contents, "Hello, world!"); -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// let file = File::open("foo.txt")?; +/// let mut buf_reader = BufReader::new(file); +/// let mut contents = String::new(); +/// buf_reader.read_to_string(&mut contents)?; +/// assert_eq!(contents, "Hello, world!"); +/// Ok(()) +/// } /// ``` /// +/// Note that, although read and write methods require a `&mut File`, because +/// of the interfaces for [`Read`] and [`Write`], the holder of a `&File` can +/// still modify the file, either through methods that take `&File` or by +/// retrieving the underlying OS object and modifying the file that way. +/// Additionally, many operating systems allow concurrent modification of files +/// by different processes. Avoid assuming that holding a `&File` means that the +/// file will not change. +/// /// [`Seek`]: ../io/trait.Seek.html /// [`String`]: ../string/struct.String.html /// [`Read`]: ../io/trait.Read.html +/// [`Write`]: ../io/trait.Write.html /// [`BufReader<R>`]: ../io/struct.BufReader.html #[stable(feature = "rust1", since = "1.0.0")] pub struct File { @@ -211,18 +220,20 @@ pub struct DirBuilder { recursive: bool, } -/// How large a buffer to pre-allocate before reading the entire file at `path`. -fn initial_buffer_size<P: AsRef<Path>>(path: P) -> usize { +/// How large a buffer to pre-allocate before reading the entire file. +fn initial_buffer_size(file: &File) -> usize { // Allocate one extra byte so the buffer doesn't need to grow before the // final `read` call at the end of the file. Don't worry about `usize` // overflow because reading will fail regardless in that case. - metadata(path).map(|m| m.len() as usize + 1).unwrap_or(0) + file.metadata().map(|m| m.len() as usize + 1).unwrap_or(0) } /// Read the entire contents of a file into a bytes vector. /// /// This is a convenience function for using [`File::open`] and [`read_to_end`] -/// with fewer imports and without an intermediate variable. +/// with fewer imports and without an intermediate variable. It pre-allocates a +/// buffer based on the file size when available, so it is generally faster than +/// reading into a vector created with `Vec::new()`. /// /// [`File::open`]: struct.File.html#method.open /// [`read_to_end`]: ../io/trait.Read.html#method.read_to_end @@ -242,27 +253,28 @@ fn initial_buffer_size<P: AsRef<Path>>(path: P) -> usize { /// # Examples /// /// ```no_run -/// #![feature(fs_read_write)] -/// /// use std::fs; /// use std::net::SocketAddr; /// -/// # fn foo() -> Result<(), Box<std::error::Error + 'static>> { -/// let foo: SocketAddr = String::from_utf8_lossy(&fs::read("address.txt")?).parse()?; -/// # Ok(()) -/// # } +/// fn main() -> Result<(), Box<std::error::Error + 'static>> { +/// let foo: SocketAddr = String::from_utf8_lossy(&fs::read("address.txt")?).parse()?; +/// Ok(()) +/// } /// ``` -#[unstable(feature = "fs_read_write", issue = "46588")] +#[stable(feature = "fs_read_write_bytes", since = "1.26.0")] pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> { - let mut bytes = Vec::with_capacity(initial_buffer_size(&path)); - File::open(path)?.read_to_end(&mut bytes)?; + let mut file = File::open(path)?; + let mut bytes = Vec::with_capacity(initial_buffer_size(&file)); + file.read_to_end(&mut bytes)?; Ok(bytes) } /// Read the entire contents of a file into a string. /// /// This is a convenience function for using [`File::open`] and [`read_to_string`] -/// with fewer imports and without an intermediate variable. +/// with fewer imports and without an intermediate variable. It pre-allocates a +/// buffer based on the file size when available, so it is generally faster than +/// reading into a string created with `String::new()`. /// /// [`File::open`]: struct.File.html#method.open /// [`read_to_string`]: ../io/trait.Read.html#method.read_to_string @@ -283,20 +295,19 @@ pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> { /// # Examples /// /// ```no_run -/// #![feature(fs_read_write)] -/// /// use std::fs; /// use std::net::SocketAddr; /// -/// # fn foo() -> Result<(), Box<std::error::Error + 'static>> { -/// let foo: SocketAddr = fs::read_string("address.txt")?.parse()?; -/// # Ok(()) -/// # } +/// fn main() -> Result<(), Box<std::error::Error + 'static>> { +/// let foo: SocketAddr = fs::read_to_string("address.txt")?.parse()?; +/// Ok(()) +/// } /// ``` -#[unstable(feature = "fs_read_write", issue = "46588")] -pub fn read_string<P: AsRef<Path>>(path: P) -> io::Result<String> { - let mut string = String::with_capacity(initial_buffer_size(&path)); - File::open(path)?.read_to_string(&mut string)?; +#[stable(feature = "fs_read_write", since = "1.26.0")] +pub fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> { + let mut file = File::open(path)?; + let mut string = String::with_capacity(initial_buffer_size(&file)); + file.read_to_string(&mut string)?; Ok(string) } @@ -314,16 +325,15 @@ pub fn read_string<P: AsRef<Path>>(path: P) -> io::Result<String> { /// # Examples /// /// ```no_run -/// #![feature(fs_read_write)] -/// /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::write("foo.txt", b"Lorem ipsum")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::write("foo.txt", b"Lorem ipsum")?; +/// fs::write("bar.txt", "dolor sit")?; +/// Ok(()) +/// } /// ``` -#[unstable(feature = "fs_read_write", issue = "46588")] +#[stable(feature = "fs_read_write_bytes", since = "1.26.0")] pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> { File::create(path)?.write_all(contents.as_ref()) } @@ -345,10 +355,10 @@ impl File { /// ```no_run /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// # Ok(()) - /// # } + /// fn main() -> std::io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> { @@ -369,10 +379,10 @@ impl File { /// ```no_run /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = File::create("foo.txt")?; - /// # Ok(()) - /// # } + /// fn main() -> std::io::Result<()> { + /// let mut f = File::create("foo.txt")?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> { @@ -390,13 +400,13 @@ impl File { /// use std::fs::File; /// use std::io::prelude::*; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = File::create("foo.txt")?; - /// f.write_all(b"Hello, world!")?; + /// fn main() -> std::io::Result<()> { + /// let mut f = File::create("foo.txt")?; + /// f.write_all(b"Hello, world!")?; /// - /// f.sync_all()?; - /// # Ok(()) - /// # } + /// f.sync_all()?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn sync_all(&self) -> io::Result<()> { @@ -421,13 +431,13 @@ impl File { /// use std::fs::File; /// use std::io::prelude::*; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = File::create("foo.txt")?; - /// f.write_all(b"Hello, world!")?; + /// fn main() -> std::io::Result<()> { + /// let mut f = File::create("foo.txt")?; + /// f.write_all(b"Hello, world!")?; /// - /// f.sync_data()?; - /// # Ok(()) - /// # } + /// f.sync_data()?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn sync_data(&self) -> io::Result<()> { @@ -442,6 +452,10 @@ impl File { /// will be extended to `size` and have all of the intermediate data filled /// in with 0s. /// + /// The file's cursor isn't changed. In particular, if the cursor was at the + /// end and the file is shrunk using this operation, the cursor will now be + /// past the end. + /// /// # Errors /// /// This function will return an error if the file is not opened for writing. @@ -451,12 +465,15 @@ impl File { /// ```no_run /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = File::create("foo.txt")?; - /// f.set_len(10)?; - /// # Ok(()) - /// # } + /// fn main() -> std::io::Result<()> { + /// let mut f = File::create("foo.txt")?; + /// f.set_len(10)?; + /// Ok(()) + /// } /// ``` + /// + /// Note that this method alters the content of the underlying file, even + /// though it takes `&self` rather than `&mut self`. #[stable(feature = "rust1", since = "1.0.0")] pub fn set_len(&self, size: u64) -> io::Result<()> { self.inner.truncate(size) @@ -469,33 +486,55 @@ impl File { /// ```no_run /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let metadata = f.metadata()?; - /// # Ok(()) - /// # } + /// fn main() -> std::io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// let metadata = f.metadata()?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn metadata(&self) -> io::Result<Metadata> { self.inner.file_attr().map(Metadata) } - /// Creates a new independently owned handle to the underlying file. - /// - /// The returned `File` is a reference to the same state that this object - /// references. Both handles will read and write with the same cursor - /// position. + /// Create a new `File` instance that shares the same underlying file handle + /// as the existing `File` instance. Reads, writes, and seeks will affect + /// both `File` instances simultaneously. /// /// # Examples /// + /// Create two handles for a file named `foo.txt`: + /// + /// ```no_run + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let mut file = File::open("foo.txt")?; + /// let file_copy = file.try_clone()?; + /// Ok(()) + /// } + /// ``` + /// + /// Assuming there’s a file named `foo.txt` with contents `abcdef\n`, create + /// two handles, seek one of them, and read the remaining bytes from the + /// other handle: + /// /// ```no_run /// use std::fs::File; + /// use std::io::SeekFrom; + /// use std::io::prelude::*; + /// + /// fn main() -> std::io::Result<()> { + /// let mut file = File::open("foo.txt")?; + /// let mut file_copy = file.try_clone()?; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let file_copy = f.try_clone()?; - /// # Ok(()) - /// # } + /// file.seek(SeekFrom::Start(3))?; + /// + /// let mut contents = vec![]; + /// file_copy.read_to_end(&mut contents)?; + /// assert_eq!(contents, b"def\n"); + /// Ok(()) + /// } /// ``` #[stable(feature = "file_try_clone", since = "1.9.0")] pub fn try_clone(&self) -> io::Result<File> { @@ -522,17 +561,20 @@ impl File { /// /// # Examples /// + /// ```no_run + /// fn main() -> std::io::Result<()> { + /// use std::fs::File; + /// + /// let file = File::open("foo.txt")?; + /// let mut perms = file.metadata()?.permissions(); + /// perms.set_readonly(true); + /// file.set_permissions(perms)?; + /// Ok(()) + /// } /// ``` - /// # fn foo() -> std::io::Result<()> { - /// use std::fs::File; /// - /// let file = File::open("foo.txt")?; - /// let mut perms = file.metadata()?.permissions(); - /// perms.set_readonly(true); - /// file.set_permissions(perms)?; - /// # Ok(()) - /// # } - /// ``` + /// Note that this method alters the permissions of the underlying file, + /// even though it takes `&self` rather than `&mut self`. #[stable(feature = "set_permissions_atomic", since = "1.16.0")] pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> { self.inner.set_permissions(perm.0) @@ -848,51 +890,63 @@ impl Metadata { /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { - /// use std::fs; + /// ```no_run + /// fn main() -> std::io::Result<()> { + /// use std::fs; /// - /// let metadata = fs::metadata("foo.txt")?; + /// let metadata = fs::metadata("foo.txt")?; /// - /// println!("{:?}", metadata.file_type()); - /// # Ok(()) - /// # } + /// println!("{:?}", metadata.file_type()); + /// Ok(()) + /// } /// ``` #[stable(feature = "file_type", since = "1.1.0")] pub fn file_type(&self) -> FileType { FileType(self.0.file_type()) } - /// Returns whether this metadata is for a directory. + /// Returns whether this metadata is for a directory. The + /// result is mutually exclusive to the result of + /// [`is_file`], and will be false for symlink metadata + /// obtained from [`symlink_metadata`]. + /// + /// [`is_file`]: struct.Metadata.html#method.is_file + /// [`symlink_metadata`]: fn.symlink_metadata.html /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { - /// use std::fs; + /// ```no_run + /// fn main() -> std::io::Result<()> { + /// use std::fs; /// - /// let metadata = fs::metadata("foo.txt")?; + /// let metadata = fs::metadata("foo.txt")?; /// - /// assert!(!metadata.is_dir()); - /// # Ok(()) - /// # } + /// assert!(!metadata.is_dir()); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_dir(&self) -> bool { self.file_type().is_dir() } - /// Returns whether this metadata is for a regular file. + /// Returns whether this metadata is for a regular file. The + /// result is mutually exclusive to the result of + /// [`is_dir`], and will be false for symlink metadata + /// obtained from [`symlink_metadata`]. + /// + /// [`is_dir`]: struct.Metadata.html#method.is_dir + /// [`symlink_metadata`]: fn.symlink_metadata.html /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { + /// ```no_run /// use std::fs; /// - /// let metadata = fs::metadata("foo.txt")?; + /// fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; /// - /// assert!(metadata.is_file()); - /// # Ok(()) - /// # } + /// assert!(metadata.is_file()); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_file(&self) -> bool { self.file_type().is_file() } @@ -901,15 +955,15 @@ impl Metadata { /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { + /// ```no_run /// use std::fs; /// - /// let metadata = fs::metadata("foo.txt")?; + /// fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; /// - /// assert_eq!(0, metadata.len()); - /// # Ok(()) - /// # } + /// assert_eq!(0, metadata.len()); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> u64 { self.0.size() } @@ -918,15 +972,15 @@ impl Metadata { /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { + /// ```no_run /// use std::fs; /// - /// let metadata = fs::metadata("foo.txt")?; + /// fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; /// - /// assert!(!metadata.permissions().readonly()); - /// # Ok(()) - /// # } + /// assert!(!metadata.permissions().readonly()); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn permissions(&self) -> Permissions { @@ -945,19 +999,19 @@ impl Metadata { /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { + /// ```no_run /// use std::fs; /// - /// let metadata = fs::metadata("foo.txt")?; + /// fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; /// - /// if let Ok(time) = metadata.modified() { - /// println!("{:?}", time); - /// } else { - /// println!("Not supported on this platform"); + /// if let Ok(time) = metadata.modified() { + /// println!("{:?}", time); + /// } else { + /// println!("Not supported on this platform"); + /// } + /// Ok(()) /// } - /// # Ok(()) - /// # } /// ``` #[stable(feature = "fs_time", since = "1.10.0")] pub fn modified(&self) -> io::Result<SystemTime> { @@ -980,26 +1034,26 @@ impl Metadata { /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { + /// ```no_run /// use std::fs; /// - /// let metadata = fs::metadata("foo.txt")?; + /// fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; /// - /// if let Ok(time) = metadata.accessed() { - /// println!("{:?}", time); - /// } else { - /// println!("Not supported on this platform"); + /// if let Ok(time) = metadata.accessed() { + /// println!("{:?}", time); + /// } else { + /// println!("Not supported on this platform"); + /// } + /// Ok(()) /// } - /// # Ok(()) - /// # } /// ``` #[stable(feature = "fs_time", since = "1.10.0")] pub fn accessed(&self) -> io::Result<SystemTime> { self.0.accessed().map(FromInner::from_inner) } - /// Returns the creation time listed in the this metadata. + /// Returns the creation time listed in this metadata. /// /// The returned value corresponds to the `birthtime` field of `stat` on /// Unix platforms and the `ftCreationTime` field on Windows platforms. @@ -1011,19 +1065,19 @@ impl Metadata { /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { + /// ```no_run /// use std::fs; /// - /// let metadata = fs::metadata("foo.txt")?; + /// fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; /// - /// if let Ok(time) = metadata.created() { - /// println!("{:?}", time); - /// } else { - /// println!("Not supported on this platform"); + /// if let Ok(time) = metadata.created() { + /// println!("{:?}", time); + /// } else { + /// println!("Not supported on this platform"); + /// } + /// Ok(()) /// } - /// # Ok(()) - /// # } /// ``` #[stable(feature = "fs_time", since = "1.10.0")] pub fn created(&self) -> io::Result<SystemTime> { @@ -1055,16 +1109,16 @@ impl Permissions { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; + /// fn main() -> std::io::Result<()> { + /// let mut f = File::create("foo.txt")?; + /// let metadata = f.metadata()?; /// - /// assert_eq!(false, metadata.permissions().readonly()); - /// # Ok(()) - /// # } + /// assert_eq!(false, metadata.permissions().readonly()); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn readonly(&self) -> bool { self.0.readonly() } @@ -1080,23 +1134,23 @@ impl Permissions { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let mut permissions = metadata.permissions(); + /// fn main() -> std::io::Result<()> { + /// let f = File::create("foo.txt")?; + /// let metadata = f.metadata()?; + /// let mut permissions = metadata.permissions(); /// - /// permissions.set_readonly(true); + /// permissions.set_readonly(true); /// - /// // filesystem doesn't change - /// assert_eq!(false, metadata.permissions().readonly()); + /// // filesystem doesn't change + /// assert_eq!(false, metadata.permissions().readonly()); /// - /// // just this particular `permissions`. - /// assert_eq!(true, permissions.readonly()); - /// # Ok(()) - /// # } + /// // just this particular `permissions`. + /// assert_eq!(true, permissions.readonly()); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn set_readonly(&mut self, readonly: bool) { @@ -1105,43 +1159,58 @@ impl Permissions { } impl FileType { - /// Test whether this file type represents a directory. + /// Test whether this file type represents a directory. The + /// result is mutually exclusive to the results of + /// [`is_file`] and [`is_symlink`]; only zero or one of these + /// tests may pass. + /// + /// [`is_file`]: struct.FileType.html#method.is_file + /// [`is_symlink`]: struct.FileType.html#method.is_symlink /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { - /// use std::fs; + /// ```no_run + /// fn main() -> std::io::Result<()> { + /// use std::fs; /// - /// let metadata = fs::metadata("foo.txt")?; - /// let file_type = metadata.file_type(); + /// let metadata = fs::metadata("foo.txt")?; + /// let file_type = metadata.file_type(); /// - /// assert_eq!(file_type.is_dir(), false); - /// # Ok(()) - /// # } + /// assert_eq!(file_type.is_dir(), false); + /// Ok(()) + /// } /// ``` #[stable(feature = "file_type", since = "1.1.0")] pub fn is_dir(&self) -> bool { self.0.is_dir() } /// Test whether this file type represents a regular file. + /// The result is mutually exclusive to the results of + /// [`is_dir`] and [`is_symlink`]; only zero or one of these + /// tests may pass. + /// + /// [`is_dir`]: struct.FileType.html#method.is_dir + /// [`is_symlink`]: struct.FileType.html#method.is_symlink /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { - /// use std::fs; + /// ```no_run + /// fn main() -> std::io::Result<()> { + /// use std::fs; /// - /// let metadata = fs::metadata("foo.txt")?; - /// let file_type = metadata.file_type(); + /// let metadata = fs::metadata("foo.txt")?; + /// let file_type = metadata.file_type(); /// - /// assert_eq!(file_type.is_file(), true); - /// # Ok(()) - /// # } + /// assert_eq!(file_type.is_file(), true); + /// Ok(()) + /// } /// ``` #[stable(feature = "file_type", since = "1.1.0")] pub fn is_file(&self) -> bool { self.0.is_file() } /// Test whether this file type represents a symbolic link. + /// The result is mutually exclusive to the results of + /// [`is_dir`] and [`is_file`]; only zero or one of these + /// tests may pass. /// /// The underlying [`Metadata`] struct needs to be retrieved /// with the [`fs::symlink_metadata`] function and not the @@ -1152,20 +1221,22 @@ impl FileType { /// [`Metadata`]: struct.Metadata.html /// [`fs::metadata`]: fn.metadata.html /// [`fs::symlink_metadata`]: fn.symlink_metadata.html + /// [`is_dir`]: struct.FileType.html#method.is_dir + /// [`is_file`]: struct.FileType.html#method.is_file /// [`is_symlink`]: struct.FileType.html#method.is_symlink /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { + /// ```no_run /// use std::fs; /// - /// let metadata = fs::symlink_metadata("foo.txt")?; - /// let file_type = metadata.file_type(); + /// fn main() -> std::io::Result<()> { + /// let metadata = fs::symlink_metadata("foo.txt")?; + /// let file_type = metadata.file_type(); /// - /// assert_eq!(file_type.is_symlink(), false); - /// # Ok(()) - /// # } + /// assert_eq!(file_type.is_symlink(), false); + /// Ok(()) + /// } /// ``` #[stable(feature = "file_type", since = "1.1.0")] pub fn is_symlink(&self) -> bool { self.0.is_symlink() } @@ -1202,15 +1273,16 @@ impl DirEntry { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; - /// # fn foo() -> std::io::Result<()> { - /// for entry in fs::read_dir(".")? { - /// let dir = entry?; - /// println!("{:?}", dir.path()); + /// + /// fn main() -> std::io::Result<()> { + /// for entry in fs::read_dir(".")? { + /// let dir = entry?; + /// println!("{:?}", dir.path()); + /// } + /// Ok(()) /// } - /// # Ok(()) - /// # } /// ``` /// /// This prints output like: @@ -1355,13 +1427,13 @@ impl AsInner<fs_imp::DirEntry> for DirEntry { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::remove_file("a.txt")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::remove_file("a.txt")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> { @@ -1392,14 +1464,14 @@ pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> { /// /// # Examples /// -/// ```rust -/// # fn foo() -> std::io::Result<()> { +/// ```rust,no_run /// use std::fs; /// -/// let attr = fs::metadata("/some/file/path.txt")?; -/// // inspect attr ... -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// let attr = fs::metadata("/some/file/path.txt")?; +/// // inspect attr ... +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> { @@ -1426,14 +1498,14 @@ pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> { /// /// # Examples /// -/// ```rust -/// # fn foo() -> std::io::Result<()> { +/// ```rust,no_run /// use std::fs; /// -/// let attr = fs::symlink_metadata("/some/file/path.txt")?; -/// // inspect attr ... -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// let attr = fs::symlink_metadata("/some/file/path.txt")?; +/// // inspect attr ... +/// Ok(()) +/// } /// ``` #[stable(feature = "symlink_metadata", since = "1.1.0")] pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> { @@ -1470,13 +1542,13 @@ pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::rename("a.txt", "b.txt")?; // Rename a.txt to b.txt -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::rename("a.txt", "b.txt")?; // Rename a.txt to b.txt +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> { @@ -1521,9 +1593,10 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> /// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::copy("foo.txt", "bar.txt")?; // Copy foo.txt to bar.txt -/// # Ok(()) } +/// fn main() -> std::io::Result<()> { +/// fs::copy("foo.txt", "bar.txt")?; // Copy foo.txt to bar.txt +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> { @@ -1552,13 +1625,13 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::hard_link("a.txt", "b.txt")?; // Hard link a.txt to b.txt -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::hard_link("a.txt", "b.txt")?; // Hard link a.txt to b.txt +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> { @@ -1575,13 +1648,13 @@ pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<( /// /// # Examples /// -/// ``` +/// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::soft_link("a.txt", "b.txt")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::soft_link("a.txt", "b.txt")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(since = "1.1.0", @@ -1612,21 +1685,21 @@ pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<( /// /// # Examples /// -/// ``` +/// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// let path = fs::read_link("a.txt")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// let path = fs::read_link("a.txt")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { fs_imp::readlink(path.as_ref()) } -/// Returns the canonical form of a path with all intermediate components -/// normalized and symbolic links resolved. +/// Returns the canonical, absolute form of a path with all intermediate +/// components normalized and symbolic links resolved. /// /// # Platform-specific behavior /// @@ -1634,7 +1707,14 @@ pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { /// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows. /// Note that, this [may change in the future][changes]. /// +/// On Windows, this converts the path to use [extended length path][path] +/// syntax, which allows your program to use longer path names, but means you +/// can only join backslash-delimited paths to it, and it may be incompatible +/// with other applications (if passed to the application on the command-line, +/// or written to a file another application may read). +/// /// [changes]: ../io/index.html#platform-specific-behavior +/// [path]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath /// /// # Errors /// @@ -1646,13 +1726,13 @@ pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// let path = fs::canonicalize("../a/../foo.txt")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// let path = fs::canonicalize("../a/../foo.txt")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "fs_canonicalize", since = "1.5.0")] pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { @@ -1679,13 +1759,13 @@ pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::create_dir("/some/dir")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::create_dir("/some/dir")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { @@ -1721,13 +1801,13 @@ pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::create_dir_all("/some/dir")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::create_dir_all("/some/dir")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> { @@ -1754,13 +1834,13 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::remove_dir("/some/dir")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::remove_dir("/some/dir")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { @@ -1788,13 +1868,13 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::remove_dir_all("/some/dir")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::remove_dir_all("/some/dir")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> { @@ -1874,15 +1954,15 @@ pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> { /// /// # Examples /// -/// ``` -/// # fn foo() -> std::io::Result<()> { +/// ```no_run /// use std::fs; /// -/// let mut perms = fs::metadata("foo.txt")?.permissions(); -/// perms.set_readonly(true); -/// fs::set_permissions("foo.txt", perms)?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// let mut perms = fs::metadata("foo.txt")?.permissions(); +/// perms.set_readonly(true); +/// fs::set_permissions("foo.txt", perms)?; +/// Ok(()) +/// } /// ``` #[stable(feature = "set_permissions", since = "1.1.0")] pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) @@ -3052,12 +3132,12 @@ mod tests { assert!(v == &bytes[..]); check!(fs::write(&tmpdir.join("not-utf8"), &[0xFF])); - error_contains!(fs::read_string(&tmpdir.join("not-utf8")), + error_contains!(fs::read_to_string(&tmpdir.join("not-utf8")), "stream did not contain valid UTF-8"); let s = "𐁁𐀓𐀠𐀴𐀍"; check!(fs::write(&tmpdir.join("utf8"), s.as_bytes())); - let string = check!(fs::read_string(&tmpdir.join("utf8"))); + let string = check!(fs::read_to_string(&tmpdir.join("utf8"))); assert_eq!(string, s); } diff --git a/src/libstd/future.rs b/src/libstd/future.rs new file mode 100644 index 00000000000..12ea1ea9f9d --- /dev/null +++ b/src/libstd/future.rs @@ -0,0 +1,116 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Asynchronous values. + +use core::cell::Cell; +use core::marker::Unpin; +use core::mem::PinMut; +use core::option::Option; +use core::ptr::NonNull; +use core::task::{self, Poll}; +use core::ops::{Drop, Generator, GeneratorState}; + +#[doc(inline)] +pub use core::future::*; + +/// Wrap a future in a generator. +/// +/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give +/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`). +#[unstable(feature = "gen_future", issue = "50547")] +pub fn from_generator<T: Generator<Yield = ()>>(x: T) -> impl Future<Output = T::Return> { + GenFuture(x) +} + +/// A wrapper around generators used to implement `Future` for `async`/`await` code. +#[unstable(feature = "gen_future", issue = "50547")] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +struct GenFuture<T: Generator<Yield = ()>>(T); + +// We rely on the fact that async/await futures are immovable in order to create +// self-referential borrows in the underlying generator. +impl<T: Generator<Yield = ()>> !Unpin for GenFuture<T> {} + +#[unstable(feature = "gen_future", issue = "50547")] +impl<T: Generator<Yield = ()>> Future for GenFuture<T> { + type Output = T::Return; + fn poll(self: PinMut<Self>, cx: &mut task::Context) -> Poll<Self::Output> { + set_task_cx(cx, || match unsafe { PinMut::get_mut_unchecked(self).0.resume() } { + GeneratorState::Yielded(()) => Poll::Pending, + GeneratorState::Complete(x) => Poll::Ready(x), + }) + } +} + +thread_local! { + static TLS_CX: Cell<Option<NonNull<task::Context<'static>>>> = Cell::new(None); +} + +struct SetOnDrop(Option<NonNull<task::Context<'static>>>); + +impl Drop for SetOnDrop { + fn drop(&mut self) { + TLS_CX.with(|tls_cx| { + tls_cx.set(self.0.take()); + }); + } +} + +#[unstable(feature = "gen_future", issue = "50547")] +/// Sets the thread-local task context used by async/await futures. +pub fn set_task_cx<F, R>(cx: &mut task::Context, f: F) -> R +where + F: FnOnce() -> R +{ + let old_cx = TLS_CX.with(|tls_cx| { + tls_cx.replace(NonNull::new( + cx + as *mut task::Context + as *mut () + as *mut task::Context<'static> + )) + }); + let _reset_cx = SetOnDrop(old_cx); + f() +} + +#[unstable(feature = "gen_future", issue = "50547")] +/// Retrieves the thread-local task context used by async/await futures. +/// +/// This function acquires exclusive access to the task context. +/// +/// Panics if no task has been set or if the task context has already been +/// retrived by a surrounding call to get_task_cx. +pub fn get_task_cx<F, R>(f: F) -> R +where + F: FnOnce(&mut task::Context) -> R +{ + let cx_ptr = TLS_CX.with(|tls_cx| { + // Clear the entry so that nested `with_get_cx` calls + // will fail or set their own value. + tls_cx.replace(None) + }); + let _reset_cx = SetOnDrop(cx_ptr); + + let mut cx_ptr = cx_ptr.expect( + "TLS task::Context not set. This is a rustc bug. \ + Please file an issue on https://github.com/rust-lang/rust."); + unsafe { f(cx_ptr.as_mut()) } +} + +#[unstable(feature = "gen_future", issue = "50547")] +/// Polls a future in the current thread-local task context. +pub fn poll_in_task_cx<F>(f: PinMut<F>) -> Poll<F::Output> +where + F: Future +{ + get_task_cx(|cx| f.poll(cx)) +} diff --git a/src/libstd/heap.rs b/src/libstd/heap.rs deleted file mode 100644 index 4d5e4df6f95..00000000000 --- a/src/libstd/heap.rs +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! dox - -#![unstable(issue = "32838", feature = "allocator_api")] - -pub use alloc::heap::{Heap, Alloc, Layout, Excess, CannotReallocInPlace, AllocErr}; -pub use alloc_system::System; - -#[cfg(not(test))] -#[doc(hidden)] -#[allow(unused_attributes)] -pub mod __default_lib_allocator { - use super::{System, Layout, Alloc, AllocErr}; - use ptr; - - // for symbol names src/librustc/middle/allocator.rs - // for signatures src/librustc_allocator/lib.rs - - // linkage directives are provided as part of the current compiler allocator - // ABI - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_alloc(size: usize, - align: usize, - err: *mut u8) -> *mut u8 { - let layout = Layout::from_size_align_unchecked(size, align); - match System.alloc(layout) { - Ok(p) => p, - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_oom(err: *const u8) -> ! { - System.oom((*(err as *const AllocErr)).clone()) - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, - size: usize, - align: usize) { - System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_usable_size(layout: *const u8, - min: *mut usize, - max: *mut usize) { - let pair = System.usable_size(&*(layout as *const Layout)); - *min = pair.0; - *max = pair.1; - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_realloc(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - err: *mut u8) -> *mut u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, old_align); - let new_layout = Layout::from_size_align_unchecked(new_size, new_align); - match System.realloc(ptr, old_layout, new_layout) { - Ok(p) => p, - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_alloc_zeroed(size: usize, - align: usize, - err: *mut u8) -> *mut u8 { - let layout = Layout::from_size_align_unchecked(size, align); - match System.alloc_zeroed(layout) { - Ok(p) => p, - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_alloc_excess(size: usize, - align: usize, - excess: *mut usize, - err: *mut u8) -> *mut u8 { - let layout = Layout::from_size_align_unchecked(size, align); - match System.alloc_excess(layout) { - Ok(p) => { - *excess = p.1; - p.0 - } - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_realloc_excess(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - excess: *mut usize, - err: *mut u8) -> *mut u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, old_align); - let new_layout = Layout::from_size_align_unchecked(new_size, new_align); - match System.realloc_excess(ptr, old_layout, new_layout) { - Ok(p) => { - *excess = p.1; - p.0 - } - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_grow_in_place(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, old_align); - let new_layout = Layout::from_size_align_unchecked(new_size, new_align); - match System.grow_in_place(ptr, old_layout, new_layout) { - Ok(()) => 1, - Err(_) => 0, - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_shrink_in_place(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, old_align); - let new_layout = Layout::from_size_align_unchecked(new_size, new_align); - match System.shrink_in_place(ptr, old_layout, new_layout) { - Ok(()) => 1, - Err(_) => 0, - } - } -} diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 4e7db5f0826..03c97de6ec1 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -25,26 +25,32 @@ use memchr; /// results in a system call. A `BufReader` performs large, infrequent reads on /// the underlying [`Read`] and maintains an in-memory buffer of the results. /// +/// `BufReader` can improve the speed of programs that make *small* and +/// *repeated* read calls to the same file or network socket. It does not +/// help when reading very large amounts at once, or reading just one or a few +/// times. It also provides no advantage when reading from a source that is +/// already in memory, like a `Vec<u8>`. +/// /// [`Read`]: ../../std/io/trait.Read.html /// [`TcpStream::read`]: ../../std/net/struct.TcpStream.html#method.read /// [`TcpStream`]: ../../std/net/struct.TcpStream.html /// /// # Examples /// -/// ``` +/// ```no_run /// use std::io::prelude::*; /// use std::io::BufReader; /// use std::fs::File; /// -/// # fn foo() -> std::io::Result<()> { -/// let f = File::open("log.txt")?; -/// let mut reader = BufReader::new(f); +/// fn main() -> std::io::Result<()> { +/// let f = File::open("log.txt")?; +/// let mut reader = BufReader::new(f); /// -/// let mut line = String::new(); -/// let len = reader.read_line(&mut line)?; -/// println!("First line is {} bytes long", len); -/// # Ok(()) -/// # } +/// let mut line = String::new(); +/// let len = reader.read_line(&mut line)?; +/// println!("First line is {} bytes long", len); +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct BufReader<R> { @@ -55,19 +61,20 @@ pub struct BufReader<R> { } impl<R: Read> BufReader<R> { - /// Creates a new `BufReader` with a default buffer capacity. + /// Creates a new `BufReader` with a default buffer capacity. The default is currently 8 KB, + /// but may change in the future. /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::BufReader; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let f = File::open("log.txt")?; - /// let reader = BufReader::new(f); - /// # Ok(()) - /// # } + /// fn main() -> std::io::Result<()> { + /// let f = File::open("log.txt")?; + /// let reader = BufReader::new(f); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: R) -> BufReader<R> { @@ -80,15 +87,15 @@ impl<R: Read> BufReader<R> { /// /// Creating a buffer with ten bytes of capacity: /// - /// ``` + /// ```no_run /// use std::io::BufReader; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let f = File::open("log.txt")?; - /// let reader = BufReader::with_capacity(10, f); - /// # Ok(()) - /// # } + /// fn main() -> std::io::Result<()> { + /// let f = File::open("log.txt")?; + /// let reader = BufReader::with_capacity(10, f); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(cap: usize, inner: R) -> BufReader<R> { @@ -111,17 +118,17 @@ impl<R: Read> BufReader<R> { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::BufReader; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let reader = BufReader::new(f1); + /// fn main() -> std::io::Result<()> { + /// let f1 = File::open("log.txt")?; + /// let reader = BufReader::new(f1); /// - /// let f2 = reader.get_ref(); - /// # Ok(()) - /// # } + /// let f2 = reader.get_ref(); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &R { &self.inner } @@ -132,44 +139,46 @@ impl<R: Read> BufReader<R> { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::BufReader; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let mut reader = BufReader::new(f1); + /// fn main() -> std::io::Result<()> { + /// let f1 = File::open("log.txt")?; + /// let mut reader = BufReader::new(f1); /// - /// let f2 = reader.get_mut(); - /// # Ok(()) - /// # } + /// let f2 = reader.get_mut(); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut R { &mut self.inner } - /// Returns `true` if there are no bytes in the internal buffer. + /// Returns a reference to the internally buffered data. + /// + /// Unlike `fill_buf`, this will not attempt to fill the buffer if it is empty. /// /// # Examples - /// ``` - /// # #![feature(bufreader_is_empty)] - /// use std::io::BufReader; - /// use std::io::BufRead; + /// + /// ```no_run + /// # #![feature(bufreader_buffer)] + /// use std::io::{BufReader, BufRead}; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let mut reader = BufReader::new(f1); - /// assert!(reader.is_empty()); + /// fn main() -> std::io::Result<()> { + /// let f = File::open("log.txt")?; + /// let mut reader = BufReader::new(f); + /// assert!(reader.buffer().is_empty()); /// - /// if reader.fill_buf()?.len() > 0 { - /// assert!(!reader.is_empty()); + /// if reader.fill_buf()?.len() > 0 { + /// assert!(!reader.buffer().is_empty()); + /// } + /// Ok(()) /// } - /// # Ok(()) - /// # } /// ``` - #[unstable(feature = "bufreader_is_empty", issue = "45323", reason = "recently added")] - pub fn is_empty(&self) -> bool { - self.pos == self.cap + #[unstable(feature = "bufreader_buffer", issue = "45323")] + pub fn buffer(&self) -> &[u8] { + &self.buf[self.pos..self.cap] } /// Unwraps this `BufReader`, returning the underlying reader. @@ -178,17 +187,17 @@ impl<R: Read> BufReader<R> { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::BufReader; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let reader = BufReader::new(f1); + /// fn main() -> std::io::Result<()> { + /// let f1 = File::open("log.txt")?; + /// let reader = BufReader::new(f1); /// - /// let f2 = reader.into_inner(); - /// # Ok(()) - /// # } + /// let f2 = reader.into_inner(); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> R { self.inner } @@ -293,7 +302,7 @@ impl<R: Seek> Seek for BufReader<R> { /// where `n` minus the internal buffer length overflows an `i64`, two /// seeks will be performed instead of one. If the second seek returns /// `Err`, the underlying reader will be left at the same position it would - /// have if you seeked to `SeekFrom::Current(0)`. + /// have if you called `seek` with `SeekFrom::Current(0)`. /// /// [`seek_relative`]: #method.seek_relative fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { @@ -330,6 +339,12 @@ impl<R: Seek> Seek for BufReader<R> { /// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying /// writer in large, infrequent batches. /// +/// `BufWriter` can improve the speed of programs that make *small* and +/// *repeated* write calls to the same file or network socket. It does not +/// help when writing very large amounts at once, or writing just one or a few +/// times. It also provides no advantage when writing to a destination that is +/// in memory, like a `Vec<u8>`. +/// /// When the `BufWriter` is dropped, the contents of its buffer will be written /// out. However, any errors that happen in the process of flushing the buffer /// when the writer is dropped will be ignored. Code that wishes to handle such @@ -413,7 +428,8 @@ pub struct BufWriter<W: Write> { pub struct IntoInnerError<W>(W, Error); impl<W: Write> BufWriter<W> { - /// Creates a new `BufWriter` with a default buffer capacity. + /// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KB, + /// but may change in the future. /// /// # Examples /// @@ -696,34 +712,47 @@ impl<W> fmt::Display for IntoInnerError<W> { /// We can use `LineWriter` to write one line at a time, significantly /// reducing the number of actual writes to the file. /// -/// ``` -/// use std::fs::File; +/// ```no_run +/// use std::fs::{self, File}; /// use std::io::prelude::*; /// use std::io::LineWriter; /// -/// # fn foo() -> std::io::Result<()> { -/// let road_not_taken = b"I shall be telling this with a sigh +/// fn main() -> std::io::Result<()> { +/// let road_not_taken = b"I shall be telling this with a sigh /// Somewhere ages and ages hence: /// Two roads diverged in a wood, and I - /// I took the one less traveled by, /// And that has made all the difference."; /// -/// let file = File::create("poem.txt")?; -/// let mut file = LineWriter::new(file); +/// let file = File::create("poem.txt")?; +/// let mut file = LineWriter::new(file); /// -/// for &byte in road_not_taken.iter() { -/// file.write(&[byte]).unwrap(); -/// } +/// file.write_all(b"I shall be telling this with a sigh")?; +/// +/// // No bytes are written until a newline is encountered (or +/// // the internal buffer is filled). +/// assert_eq!(fs::read_to_string("poem.txt")?, ""); +/// file.write_all(b"\n")?; +/// assert_eq!( +/// fs::read_to_string("poem.txt")?, +/// "I shall be telling this with a sigh\n", +/// ); /// -/// // let's check we did the right thing. -/// let mut file = File::open("poem.txt")?; -/// let mut contents = String::new(); +/// // Write the rest of the poem. +/// file.write_all(b"Somewhere ages and ages hence: +/// Two roads diverged in a wood, and I - +/// I took the one less traveled by, +/// And that has made all the difference.")?; /// -/// file.read_to_string(&mut contents)?; +/// // The last line of the poem doesn't end in a newline, so +/// // we have to flush or drop the `LineWriter` to finish +/// // writing. +/// file.flush()?; /// -/// assert_eq!(contents.as_bytes(), &road_not_taken[..]); -/// # Ok(()) -/// # } +/// // Confirm the whole poem was written. +/// assert_eq!(fs::read("poem.txt")?, &road_not_taken[..]); +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct LineWriter<W: Write> { @@ -736,15 +765,15 @@ impl<W: Write> LineWriter<W> { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs::File; /// use std::io::LineWriter; /// - /// # fn foo() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let file = LineWriter::new(file); - /// # Ok(()) - /// # } + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let file = LineWriter::new(file); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: W) -> LineWriter<W> { @@ -757,15 +786,15 @@ impl<W: Write> LineWriter<W> { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs::File; /// use std::io::LineWriter; /// - /// # fn foo() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let file = LineWriter::with_capacity(100, file); - /// # Ok(()) - /// # } + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let file = LineWriter::with_capacity(100, file); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(cap: usize, inner: W) -> LineWriter<W> { @@ -779,17 +808,17 @@ impl<W: Write> LineWriter<W> { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs::File; /// use std::io::LineWriter; /// - /// # fn foo() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let file = LineWriter::new(file); + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let file = LineWriter::new(file); /// - /// let reference = file.get_ref(); - /// # Ok(()) - /// # } + /// let reference = file.get_ref(); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &W { self.inner.get_ref() } @@ -801,18 +830,18 @@ impl<W: Write> LineWriter<W> { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs::File; /// use std::io::LineWriter; /// - /// # fn foo() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let mut file = LineWriter::new(file); + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let mut file = LineWriter::new(file); /// - /// // we can use reference just like file - /// let reference = file.get_mut(); - /// # Ok(()) - /// # } + /// // we can use reference just like file + /// let reference = file.get_mut(); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut W { self.inner.get_mut() } @@ -821,24 +850,24 @@ impl<W: Write> LineWriter<W> { /// /// The internal buffer is written out before returning the writer. /// - // # Errors + /// # Errors /// /// An `Err` will be returned if an error occurs while flushing the buffer. /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs::File; /// use std::io::LineWriter; /// - /// # fn foo() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; /// - /// let writer: LineWriter<File> = LineWriter::new(file); + /// let writer: LineWriter<File> = LineWriter::new(file); /// - /// let file: File = writer.into_inner()?; - /// # Ok(()) - /// # } + /// let file: File = writer.into_inner()?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> { @@ -1210,23 +1239,6 @@ mod tests { } #[test] - fn read_char_buffered() { - let buf = [195, 159]; - let reader = BufReader::with_capacity(1, &buf[..]); - assert_eq!(reader.chars().next().unwrap().unwrap(), 'ß'); - } - - #[test] - fn test_chars() { - let buf = [195, 159, b'a']; - let reader = BufReader::with_capacity(1, &buf[..]); - let mut it = reader.chars(); - assert_eq!(it.next().unwrap().unwrap(), 'ß'); - assert_eq!(it.next().unwrap().unwrap(), 'a'); - assert!(it.next().is_none()); - } - - #[test] #[should_panic] fn dont_panic_in_drop_on_panicked_flush() { struct FailFlushWriter; diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index c8447707d5b..14f20151dca 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -14,12 +14,13 @@ use core::convert::TryInto; use cmp; use io::{self, Initializer, SeekFrom, Error, ErrorKind}; -/// A `Cursor` wraps another type and provides it with a +/// A `Cursor` wraps an in-memory buffer and provides it with a /// [`Seek`] implementation. /// -/// `Cursor`s are typically used with in-memory buffers to allow them to -/// implement [`Read`] and/or [`Write`], allowing these buffers to be used -/// anywhere you might use a reader or writer that does actual I/O. +/// `Cursor`s are used with in-memory buffers, anything implementing +/// `AsRef<[u8]>`, to allow them to implement [`Read`] and/or [`Write`], +/// allowing these buffers to be used anywhere you might use a reader or writer +/// that does actual I/O. /// /// The standard library implements some I/O traits on various types which /// are commonly used as a buffer, like `Cursor<`[`Vec`]`<u8>>` and @@ -87,11 +88,11 @@ pub struct Cursor<T> { } impl<T> Cursor<T> { - /// Creates a new cursor wrapping the provided underlying I/O object. + /// Creates a new cursor wrapping the provided underlying in-memory buffer. /// - /// Cursor initial position is `0` even if underlying object (e. - /// g. `Vec`) is not empty. So writing to cursor starts with - /// overwriting `Vec` content, not with appending to it. + /// Cursor initial position is `0` even if underlying buffer (e.g. `Vec`) + /// is not empty. So writing to cursor starts with overwriting `Vec` + /// content, not with appending to it. /// /// # Examples /// @@ -296,7 +297,7 @@ impl<'a> Write for Cursor<&'a mut [u8]> { fn flush(&mut self) -> io::Result<()> { Ok(()) } } -#[unstable(feature = "cursor_mut_vec", issue = "30132")] +#[stable(feature = "cursor_mut_vec", since = "1.25.0")] impl<'a> Write for Cursor<&'a mut Vec<u8>> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { vec_write(&mut self.pos, self.inner, buf) @@ -550,24 +551,6 @@ mod tests { } #[test] - fn test_read_char() { - let b = &b"Vi\xE1\xBB\x87t"[..]; - let mut c = Cursor::new(b).chars(); - assert_eq!(c.next().unwrap().unwrap(), 'V'); - assert_eq!(c.next().unwrap().unwrap(), 'i'); - assert_eq!(c.next().unwrap().unwrap(), 'ệ'); - assert_eq!(c.next().unwrap().unwrap(), 't'); - assert!(c.next().is_none()); - } - - #[test] - fn test_read_bad_char() { - let b = &b"\x80"[..]; - let mut c = Cursor::new(b).chars(); - assert!(c.next().unwrap().is_err()); - } - - #[test] fn seek_past_end() { let buf = [0xff]; let mut r = Cursor::new(&buf[..]); diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index f0b41f30251..3e50988a68b 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -83,7 +83,7 @@ enum Repr { #[derive(Debug)] struct Custom { kind: ErrorKind, - error: Box<error::Error+Send+Sync>, + error: Box<dyn error::Error+Send+Sync>, } /// A list specifying general categories of I/O error. @@ -97,6 +97,7 @@ struct Custom { #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] +#[non_exhaustive] pub enum ErrorKind { /// An entity was not found, often a file. #[stable(feature = "rust1", since = "1.0.0")] @@ -180,15 +181,6 @@ pub enum ErrorKind { /// read. #[stable(feature = "read_exact", since = "1.6.0")] UnexpectedEof, - - /// A marker variant that tells the compiler that users of this enum cannot - /// match it exhaustively. - #[unstable(feature = "io_error_internals", - reason = "better expressed through extensible enums that this \ - enum cannot be exhaustively matched against", - issue = "0")] - #[doc(hidden)] - __Nonexhaustive, } impl ErrorKind { @@ -212,7 +204,6 @@ impl ErrorKind { ErrorKind::Interrupted => "operation interrupted", ErrorKind::Other => "other os error", ErrorKind::UnexpectedEof => "unexpected end of file", - ErrorKind::__Nonexhaustive => unreachable!() } } } @@ -250,12 +241,12 @@ impl Error { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new<E>(kind: ErrorKind, error: E) -> Error - where E: Into<Box<error::Error+Send+Sync>> + where E: Into<Box<dyn error::Error+Send+Sync>> { Self::_new(kind, error.into()) } - fn _new(kind: ErrorKind, error: Box<error::Error+Send+Sync>) -> Error { + fn _new(kind: ErrorKind, error: Box<dyn error::Error+Send+Sync>) -> Error { Error { repr: Repr::Custom(Box::new(Custom { kind, @@ -292,8 +283,8 @@ impl Error { /// # if cfg!(target_os = "linux") { /// use std::io; /// - /// let error = io::Error::from_raw_os_error(98); - /// assert_eq!(error.kind(), io::ErrorKind::AddrInUse); + /// let error = io::Error::from_raw_os_error(22); + /// assert_eq!(error.kind(), io::ErrorKind::InvalidInput); /// # } /// ``` /// @@ -303,8 +294,8 @@ impl Error { /// # if cfg!(windows) { /// use std::io; /// - /// let error = io::Error::from_raw_os_error(10048); - /// assert_eq!(error.kind(), io::ErrorKind::AddrInUse); + /// let error = io::Error::from_raw_os_error(10022); + /// assert_eq!(error.kind(), io::ErrorKind::InvalidInput); /// # } /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -373,7 +364,7 @@ impl Error { /// } /// ``` #[stable(feature = "io_error_inner", since = "1.3.0")] - pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> { + pub fn get_ref(&self) -> Option<&(dyn error::Error+Send+Sync+'static)> { match self.repr { Repr::Os(..) => None, Repr::Simple(..) => None, @@ -444,7 +435,7 @@ impl Error { /// } /// ``` #[stable(feature = "io_error_inner", since = "1.3.0")] - pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> { + pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error+Send+Sync+'static)> { match self.repr { Repr::Os(..) => None, Repr::Simple(..) => None, @@ -478,7 +469,7 @@ impl Error { /// } /// ``` #[stable(feature = "io_error_inner", since = "1.3.0")] - pub fn into_inner(self) -> Option<Box<error::Error+Send+Sync>> { + pub fn into_inner(self) -> Option<Box<dyn error::Error+Send+Sync>> { match self.repr { Repr::Os(..) => None, Repr::Simple(..) => None, @@ -551,7 +542,7 @@ impl error::Error for Error { } } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { match self.repr { Repr::Os(..) => None, Repr::Simple(..) => None, diff --git a/src/libstd/io/lazy.rs b/src/libstd/io/lazy.rs index 9cef4e3cdf1..4fb367fb6ba 100644 --- a/src/libstd/io/lazy.rs +++ b/src/libstd/io/lazy.rs @@ -15,15 +15,21 @@ use sys_common; use sys_common::mutex::Mutex; pub struct Lazy<T> { + // We never call `lock.init()`, so it is UB to attempt to acquire this mutex reentrantly! lock: Mutex, ptr: Cell<*mut Arc<T>>, init: fn() -> Arc<T>, } +#[inline] +const fn done<T>() -> *mut Arc<T> { 1_usize as *mut _ } + unsafe impl<T> Sync for Lazy<T> {} impl<T: Send + Sync + 'static> Lazy<T> { - pub const fn new(init: fn() -> Arc<T>) -> Lazy<T> { + /// Safety: `init` must not call `get` on the variable that is being + /// initialized. + pub const unsafe fn new(init: fn() -> Arc<T>) -> Lazy<T> { Lazy { lock: Mutex::new(), ptr: Cell::new(ptr::null_mut()), @@ -33,32 +39,34 @@ impl<T: Send + Sync + 'static> Lazy<T> { pub fn get(&'static self) -> Option<Arc<T>> { unsafe { - self.lock.lock(); + let _guard = self.lock.lock(); let ptr = self.ptr.get(); - let ret = if ptr.is_null() { + if ptr.is_null() { Some(self.init()) - } else if ptr as usize == 1 { + } else if ptr == done() { None } else { Some((*ptr).clone()) - }; - self.lock.unlock(); - return ret + } } } + // Must only be called with `lock` held unsafe fn init(&'static self) -> Arc<T> { // If we successfully register an at exit handler, then we cache the // `Arc` allocation in our own internal box (it will get deallocated by // the at exit handler). Otherwise we just return the freshly allocated // `Arc`. let registered = sys_common::at_exit(move || { - self.lock.lock(); - let ptr = self.ptr.get(); - self.ptr.set(1 as *mut _); - self.lock.unlock(); + let ptr = { + let _guard = self.lock.lock(); + self.ptr.replace(done()) + }; drop(Box::from_raw(ptr)) }); + // This could reentrantly call `init` again, which is a problem + // because our `lock` allows reentrancy! + // That's why `new` is unsafe and requires the caller to ensure no reentrancy happens. let ret = (self.init)(); if registered.is_ok() { self.ptr.set(Box::into_raw(Box::new(ret.clone()))); diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 33d11ebb350..b83f3fbe7a5 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -24,21 +24,21 @@ //! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on //! [`File`]s: //! -//! ``` +//! ```no_run //! use std::io; //! use std::io::prelude::*; //! use std::fs::File; //! -//! # fn foo() -> io::Result<()> { -//! let mut f = File::open("foo.txt")?; -//! let mut buffer = [0; 10]; +//! fn main() -> io::Result<()> { +//! let mut f = File::open("foo.txt")?; +//! let mut buffer = [0; 10]; //! -//! // read up to 10 bytes -//! f.read(&mut buffer)?; +//! // read up to 10 bytes +//! f.read(&mut buffer)?; //! -//! println!("The bytes: {:?}", buffer); -//! # Ok(()) -//! # } +//! println!("The bytes: {:?}", buffer); +//! Ok(()) +//! } //! ``` //! //! [`Read`] and [`Write`] are so important, implementors of the two traits have a @@ -52,25 +52,25 @@ //! how the reading happens. [`Seek`] lets you control where the next byte is //! coming from: //! -//! ``` +//! ```no_run //! use std::io; //! use std::io::prelude::*; //! use std::io::SeekFrom; //! use std::fs::File; //! -//! # fn foo() -> io::Result<()> { -//! let mut f = File::open("foo.txt")?; -//! let mut buffer = [0; 10]; +//! fn main() -> io::Result<()> { +//! let mut f = File::open("foo.txt")?; +//! let mut buffer = [0; 10]; //! -//! // skip to the last 10 bytes of the file -//! f.seek(SeekFrom::End(-10))?; +//! // skip to the last 10 bytes of the file +//! f.seek(SeekFrom::End(-10))?; //! -//! // read up to 10 bytes -//! f.read(&mut buffer)?; +//! // read up to 10 bytes +//! f.read(&mut buffer)?; //! -//! println!("The bytes: {:?}", buffer); -//! # Ok(()) -//! # } +//! println!("The bytes: {:?}", buffer); +//! Ok(()) +//! } //! ``` //! //! [`BufRead`] uses an internal buffer to provide a number of other ways to read, but @@ -87,70 +87,70 @@ //! For example, [`BufReader`] works with the [`BufRead`] trait to add extra //! methods to any reader: //! -//! ``` +//! ```no_run //! use std::io; //! use std::io::prelude::*; //! use std::io::BufReader; //! use std::fs::File; //! -//! # fn foo() -> io::Result<()> { -//! let f = File::open("foo.txt")?; -//! let mut reader = BufReader::new(f); -//! let mut buffer = String::new(); +//! fn main() -> io::Result<()> { +//! let f = File::open("foo.txt")?; +//! let mut reader = BufReader::new(f); +//! let mut buffer = String::new(); //! -//! // read a line into buffer -//! reader.read_line(&mut buffer)?; +//! // read a line into buffer +//! reader.read_line(&mut buffer)?; //! -//! println!("{}", buffer); -//! # Ok(()) -//! # } +//! println!("{}", buffer); +//! Ok(()) +//! } //! ``` //! //! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call //! to [`write`][`Write::write`]: //! -//! ``` +//! ```no_run //! use std::io; //! use std::io::prelude::*; //! use std::io::BufWriter; //! use std::fs::File; //! -//! # fn foo() -> io::Result<()> { -//! let f = File::create("foo.txt")?; -//! { -//! let mut writer = BufWriter::new(f); +//! fn main() -> io::Result<()> { +//! let f = File::create("foo.txt")?; +//! { +//! let mut writer = BufWriter::new(f); //! -//! // write a byte to the buffer -//! writer.write(&[42])?; +//! // write a byte to the buffer +//! writer.write(&[42])?; //! -//! } // the buffer is flushed once writer goes out of scope +//! } // the buffer is flushed once writer goes out of scope //! -//! # Ok(()) -//! # } +//! Ok(()) +//! } //! ``` //! //! ## Standard input and output //! //! A very common source of input is standard input: //! -//! ``` +//! ```no_run //! use std::io; //! -//! # fn foo() -> io::Result<()> { -//! let mut input = String::new(); +//! fn main() -> io::Result<()> { +//! let mut input = String::new(); //! -//! io::stdin().read_line(&mut input)?; +//! io::stdin().read_line(&mut input)?; //! -//! println!("You typed: {}", input.trim()); -//! # Ok(()) -//! # } +//! println!("You typed: {}", input.trim()); +//! Ok(()) +//! } //! ``` //! //! Note that you cannot use the [`?` operator] in functions that do not return -//! a [`Result<T, E>`][`Result`] (e.g. `main`). Instead, you can call [`.unwrap()`] +//! a [`Result<T, E>`][`Result`]. Instead, you can call [`.unwrap()`] //! or `match` on the return value to catch any possible errors: //! -//! ``` +//! ```no_run //! use std::io; //! //! let mut input = String::new(); @@ -160,14 +160,14 @@ //! //! And a very common source of output is standard output: //! -//! ``` +//! ```no_run //! use std::io; //! use std::io::prelude::*; //! -//! # fn foo() -> io::Result<()> { -//! io::stdout().write(&[42])?; -//! # Ok(()) -//! # } +//! fn main() -> io::Result<()> { +//! io::stdout().write(&[42])?; +//! Ok(()) +//! } //! ``` //! //! Of course, using [`io::stdout`] directly is less common than something like @@ -179,22 +179,21 @@ //! ways of iterating over I/O. For example, [`Lines`] is used to split over //! lines: //! -//! ``` +//! ```no_run //! use std::io; //! use std::io::prelude::*; //! use std::io::BufReader; //! use std::fs::File; //! -//! # fn foo() -> io::Result<()> { -//! let f = File::open("foo.txt")?; -//! let reader = BufReader::new(f); +//! fn main() -> io::Result<()> { +//! let f = File::open("foo.txt")?; +//! let reader = BufReader::new(f); //! -//! for line in reader.lines() { -//! println!("{}", line?); +//! for line in reader.lines() { +//! println!("{}", line?); +//! } +//! Ok(()) //! } -//! -//! # Ok(()) -//! # } //! ``` //! //! ## Functions @@ -203,13 +202,13 @@ //! features. For example, we can use three of these functions to copy everything //! from standard input to standard output: //! -//! ``` +//! ```no_run //! use std::io; //! -//! # fn foo() -> io::Result<()> { -//! io::copy(&mut io::stdin(), &mut io::stdout())?; -//! # Ok(()) -//! # } +//! fn main() -> io::Result<()> { +//! io::copy(&mut io::stdin(), &mut io::stdout())?; +//! Ok(()) +//! } //! ``` //! //! [functions-list]: #functions-1 @@ -271,10 +270,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use cmp; -use core::str as core_str; -use error as std_error; use fmt; -use result; use str; use memchr; use ptr; @@ -358,19 +354,26 @@ fn append_to_string<F>(buf: &mut String, f: F) -> Result<usize> // avoid paying to allocate and zero a huge chunk of memory if the reader only // has 4 bytes while still making large reads if the reader does have a ton // of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every -// time is 4,500 times (!) slower than this if the reader has a very small -// amount of data to return. +// time is 4,500 times (!) slower than a default reservation size of 32 if the +// reader has a very small amount of data to return. // // Because we're extending the buffer with uninitialized data for trusted // readers, we need to make sure to truncate that if any of this panics. fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> { + read_to_end_with_reservation(r, buf, 32) +} + +fn read_to_end_with_reservation<R: Read + ?Sized>(r: &mut R, + buf: &mut Vec<u8>, + reservation_size: usize) -> Result<usize> +{ let start_len = buf.len(); let mut g = Guard { len: buf.len(), buf: buf }; let ret; loop { if g.len == g.buf.len() { unsafe { - g.buf.reserve(32); + g.buf.reserve(reservation_size); let capacity = g.buf.capacity(); g.buf.set_len(capacity); r.initializer().initialize(&mut g.buf[g.len..]); @@ -416,47 +419,47 @@ fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> /// /// [`File`]s implement `Read`: /// -/// ``` -/// # use std::io; +/// ```no_run +/// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// -/// # fn foo() -> io::Result<()> { -/// let mut f = File::open("foo.txt")?; -/// let mut buffer = [0; 10]; +/// fn main() -> io::Result<()> { +/// let mut f = File::open("foo.txt")?; +/// let mut buffer = [0; 10]; /// -/// // read up to 10 bytes -/// f.read(&mut buffer)?; +/// // read up to 10 bytes +/// f.read(&mut buffer)?; /// -/// let mut buffer = vec![0; 10]; -/// // read the whole file -/// f.read_to_end(&mut buffer)?; +/// let mut buffer = vec![0; 10]; +/// // read the whole file +/// f.read_to_end(&mut buffer)?; /// -/// // read into a String, so that you don't need to do the conversion. -/// let mut buffer = String::new(); -/// f.read_to_string(&mut buffer)?; +/// // read into a String, so that you don't need to do the conversion. +/// let mut buffer = String::new(); +/// f.read_to_string(&mut buffer)?; /// -/// // and more! See the other methods for more details. -/// # Ok(()) -/// # } +/// // and more! See the other methods for more details. +/// Ok(()) +/// } /// ``` /// /// Read from [`&str`] because [`&[u8]`][slice] implements `Read`: /// -/// ``` +/// ```no_run /// # use std::io; /// use std::io::prelude::*; /// -/// # fn foo() -> io::Result<()> { -/// let mut b = "This string will be read".as_bytes(); -/// let mut buffer = [0; 10]; +/// fn main() -> io::Result<()> { +/// let mut b = "This string will be read".as_bytes(); +/// let mut buffer = [0; 10]; /// -/// // read up to 10 bytes -/// b.read(&mut buffer)?; +/// // read up to 10 bytes +/// b.read(&mut buffer)?; /// -/// // etc... it works exactly as a File does! -/// # Ok(()) -/// # } +/// // etc... it works exactly as a File does! +/// Ok(()) +/// } /// ``` /// /// [`read()`]: trait.Read.html#tymethod.read @@ -509,19 +512,19 @@ pub trait Read { /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted /// [`File`]: ../fs/struct.File.html /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = [0; 10]; + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// let mut buffer = [0; 10]; /// - /// // read up to 10 bytes - /// f.read(&mut buffer[..])?; - /// # Ok(()) - /// # } + /// // read up to 10 bytes + /// f.read(&mut buffer[..])?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn read(&mut self, buf: &mut [u8]) -> Result<usize>; @@ -582,20 +585,25 @@ pub trait Read { /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted /// [`File`]: ../fs/struct.File.html /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = Vec::new(); + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// let mut buffer = Vec::new(); /// - /// // read the whole file - /// f.read_to_end(&mut buffer)?; - /// # Ok(()) - /// # } + /// // read the whole file + /// f.read_to_end(&mut buffer)?; + /// Ok(()) + /// } /// ``` + /// + /// (See also the [`std::fs::read`] convenience function for reading from a + /// file.) + /// + /// [`std::fs::read`]: ../fs/fn.read.html #[stable(feature = "rust1", since = "1.0.0")] fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> { read_to_end(self, buf) @@ -621,19 +629,24 @@ pub trait Read { /// /// [file]: ../fs/struct.File.html /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = String::new(); + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// let mut buffer = String::new(); /// - /// f.read_to_string(&mut buffer)?; - /// # Ok(()) - /// # } + /// f.read_to_string(&mut buffer)?; + /// Ok(()) + /// } /// ``` + /// + /// (See also the [`std::fs::read_to_string`] convenience function for + /// reading from a file.) + /// + /// [`std::fs::read_to_string`]: ../fs/fn.read_to_string.html #[stable(feature = "rust1", since = "1.0.0")] fn read_to_string(&mut self, buf: &mut String) -> Result<usize> { // Note that we do *not* call `.read_to_end()` here. We are passing @@ -683,19 +696,19 @@ pub trait Read { /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted /// [`ErrorKind::UnexpectedEof`]: ../../std/io/enum.ErrorKind.html#variant.UnexpectedEof /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = [0; 10]; + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// let mut buffer = [0; 10]; /// - /// // read exactly 10 bytes - /// f.read_exact(&mut buffer)?; - /// # Ok(()) - /// # } + /// // read exactly 10 bytes + /// f.read_exact(&mut buffer)?; + /// Ok(()) + /// } /// ``` #[stable(feature = "read_exact", since = "1.6.0")] fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<()> { @@ -726,28 +739,28 @@ pub trait Read { /// /// [file]: ../fs/struct.File.html /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::Read; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = Vec::new(); - /// let mut other_buffer = Vec::new(); + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// let mut buffer = Vec::new(); + /// let mut other_buffer = Vec::new(); /// - /// { - /// let reference = f.by_ref(); + /// { + /// let reference = f.by_ref(); /// - /// // read at most 5 bytes - /// reference.take(5).read_to_end(&mut buffer)?; + /// // read at most 5 bytes + /// reference.take(5).read_to_end(&mut buffer)?; /// - /// } // drop our &mut reference so we can use f again + /// } // drop our &mut reference so we can use f again /// - /// // original file still usable, read the rest - /// f.read_to_end(&mut other_buffer)?; - /// # Ok(()) - /// # } + /// // original file still usable, read the rest + /// f.read_to_end(&mut other_buffer)?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn by_ref(&mut self) -> &mut Self where Self: Sized { self } @@ -772,69 +785,25 @@ pub trait Read { /// [`Err`]: ../../std/result/enum.Result.html#variant.Err /// [`None`]: ../../std/option/enum.Option.html#variant.None /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; /// - /// for byte in f.bytes() { - /// println!("{}", byte.unwrap()); + /// for byte in f.bytes() { + /// println!("{}", byte.unwrap()); + /// } + /// Ok(()) /// } - /// # Ok(()) - /// # } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn bytes(self) -> Bytes<Self> where Self: Sized { Bytes { inner: self } } - /// Transforms this `Read` instance to an [`Iterator`] over [`char`]s. - /// - /// This adaptor will attempt to interpret this reader as a UTF-8 encoded - /// sequence of characters. The returned iterator will return [`None`] once - /// EOF is reached for this reader. Otherwise each element yielded will be a - /// [`Result`]`<`[`char`]`, E>` where `E` may contain information about what I/O error - /// occurred or where decoding failed. - /// - /// Currently this adaptor will discard intermediate data read, and should - /// be avoided if this is not desired. - /// - /// # Examples - /// - /// [`File`]s implement `Read`: - /// - /// [`File`]: ../fs/struct.File.html - /// [`Iterator`]: ../../std/iter/trait.Iterator.html - /// [`Result`]: ../../std/result/enum.Result.html - /// [`char`]: ../../std/primitive.char.html - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// ``` - /// #![feature(io)] - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// # fn foo() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// - /// for c in f.chars() { - /// println!("{}", c.unwrap()); - /// } - /// # Ok(()) - /// # } - /// ``` - #[unstable(feature = "io", reason = "the semantics of a partial read/write \ - of where errors happen is currently \ - unclear and may change", - issue = "27802")] - fn chars(self) -> Chars<Self> where Self: Sized { - Chars { inner: self } - } - /// Creates an adaptor which will chain this stream with another. /// /// The returned `Read` instance will first read all bytes from this object @@ -847,23 +816,23 @@ pub trait Read { /// /// [file]: ../fs/struct.File.html /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut f1 = File::open("foo.txt")?; - /// let mut f2 = File::open("bar.txt")?; + /// fn main() -> io::Result<()> { + /// let mut f1 = File::open("foo.txt")?; + /// let mut f2 = File::open("bar.txt")?; /// - /// let mut handle = f1.chain(f2); - /// let mut buffer = String::new(); + /// let mut handle = f1.chain(f2); + /// let mut buffer = String::new(); /// - /// // read the value into a String. We could use any Read method here, - /// // this is just one example. - /// handle.read_to_string(&mut buffer)?; - /// # Ok(()) - /// # } + /// // read the value into a String. We could use any Read method here, + /// // this is just one example. + /// handle.read_to_string(&mut buffer)?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn chain<R: Read>(self, next: R) -> Chain<Self, R> where Self: Sized { @@ -885,21 +854,21 @@ pub trait Read { /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok /// [`read()`]: trait.Read.html#tymethod.read /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = [0; 5]; + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// let mut buffer = [0; 5]; /// - /// // read at most five bytes - /// let mut handle = f.take(5); + /// // read at most five bytes + /// let mut handle = f.take(5); /// - /// handle.read(&mut buffer)?; - /// # Ok(()) - /// # } + /// handle.read(&mut buffer)?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn take(self, limit: u64) -> Take<Self> where Self: Sized { @@ -974,16 +943,16 @@ impl Initializer { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::io::prelude::*; /// use std::fs::File; /// -/// # fn foo() -> std::io::Result<()> { -/// let mut buffer = File::create("foo.txt")?; +/// fn main() -> std::io::Result<()> { +/// let mut buffer = File::create("foo.txt")?; /// -/// buffer.write(b"some bytes")?; -/// # Ok(()) -/// # } +/// buffer.write(b"some bytes")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[doc(spotlight)] @@ -1022,17 +991,17 @@ pub trait Write { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; + /// fn main() -> 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(()) - /// # } + /// // Writes some prefix of the byte string, not necessarily all of it. + /// buffer.write(b"some bytes")?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn write(&mut self, buf: &[u8]) -> Result<usize>; @@ -1047,18 +1016,18 @@ pub trait Write { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::prelude::*; /// use std::io::BufWriter; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut buffer = BufWriter::new(File::create("foo.txt")?); + /// fn main() -> std::io::Result<()> { + /// let mut buffer = BufWriter::new(File::create("foo.txt")?); /// - /// buffer.write(b"some bytes")?; - /// buffer.flush()?; - /// # Ok(()) - /// # } + /// buffer.write(b"some bytes")?; + /// buffer.flush()?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn flush(&mut self) -> Result<()>; @@ -1082,16 +1051,16 @@ pub trait Write { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; + /// fn main() -> std::io::Result<()> { + /// let mut buffer = File::create("foo.txt")?; /// - /// buffer.write_all(b"some bytes")?; - /// # Ok(()) - /// # } + /// buffer.write_all(b"some bytes")?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn write_all(&mut self, mut buf: &[u8]) -> Result<()> { @@ -1131,19 +1100,19 @@ pub trait Write { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; + /// fn main() -> std::io::Result<()> { + /// let mut buffer = File::create("foo.txt")?; /// - /// // this call - /// write!(buffer, "{:.*}", 2, 1.234567)?; - /// // turns into this: - /// buffer.write_fmt(format_args!("{:.*}", 2, 1.234567))?; - /// # Ok(()) - /// # } + /// // this call + /// write!(buffer, "{:.*}", 2, 1.234567)?; + /// // turns into this: + /// buffer.write_fmt(format_args!("{:.*}", 2, 1.234567))?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<()> { @@ -1187,19 +1156,19 @@ pub trait Write { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::Write; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; + /// fn main() -> std::io::Result<()> { + /// let mut buffer = File::create("foo.txt")?; /// - /// let reference = buffer.by_ref(); + /// let reference = buffer.by_ref(); /// - /// // we can use reference just like our original buffer - /// reference.write_all(b"some bytes")?; - /// # Ok(()) - /// # } + /// // we can use reference just like our original buffer + /// reference.write_all(b"some bytes")?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn by_ref(&mut self) -> &mut Self where Self: Sized { self } @@ -1217,19 +1186,19 @@ pub trait Write { /// /// [file]: ../fs/struct.File.html /// -/// ``` +/// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// use std::io::SeekFrom; /// -/// # fn foo() -> io::Result<()> { -/// let mut f = File::open("foo.txt")?; +/// fn main() -> io::Result<()> { +/// let mut f = File::open("foo.txt")?; /// -/// // move the cursor 42 bytes from the start of the file -/// f.seek(SeekFrom::Start(42))?; -/// # Ok(()) -/// # } +/// // move the cursor 42 bytes from the start of the file +/// f.seek(SeekFrom::Start(42))?; +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait Seek { @@ -1320,7 +1289,7 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>) /// /// A locked standard input implements `BufRead`: /// -/// ``` +/// ```no_run /// use std::io; /// use std::io::prelude::*; /// @@ -1342,21 +1311,21 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>) /// [`lines`]: #method.lines /// [`Read`]: trait.Read.html /// -/// ``` +/// ```no_run /// use std::io::{self, BufReader}; /// use std::io::prelude::*; /// use std::fs::File; /// -/// # fn foo() -> io::Result<()> { -/// let f = File::open("foo.txt")?; -/// let f = BufReader::new(f); +/// fn main() -> io::Result<()> { +/// let f = File::open("foo.txt")?; +/// let f = BufReader::new(f); /// -/// for line in f.lines() { -/// println!("{}", line.unwrap()); -/// } +/// for line in f.lines() { +/// println!("{}", line.unwrap()); +/// } /// -/// # Ok(()) -/// # } +/// Ok(()) +/// } /// ``` /// #[stable(feature = "rust1", since = "1.0.0")] @@ -1383,7 +1352,7 @@ pub trait BufRead: Read { /// /// A locked standard input implements `BufRead`: /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// @@ -1437,8 +1406,6 @@ pub trait BufRead: Read { /// /// If successful, this function will return the total number of bytes read. /// - /// An empty buffer returned indicates that the stream has reached EOF. - /// /// # Errors /// /// This function will ignore all instances of [`ErrorKind::Interrupted`] and @@ -1508,6 +1475,8 @@ pub trait BufRead: Read { /// error is encountered then `buf` may contain some bytes already read in /// the event that all data read so far was valid UTF-8. /// + /// [`read_until`]: #method.read_until + /// /// # Examples /// /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In @@ -1645,19 +1614,19 @@ impl<T, U> Chain<T, U> { /// /// # Examples /// - /// ``` - /// # use std::io; + /// ```no_run + /// 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")?; + /// fn main() -> 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(()) - /// # } + /// let chain = foo_file.chain(bar_file); + /// let (foo_file, bar_file) = chain.into_inner(); + /// Ok(()) + /// } /// ``` #[stable(feature = "more_io_inner_methods", since = "1.20.0")] pub fn into_inner(self) -> (T, U) { @@ -1668,19 +1637,19 @@ impl<T, U> Chain<T, U> { /// /// # Examples /// - /// ``` - /// # use std::io; + /// ```no_run + /// 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")?; + /// fn main() -> 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(()) - /// # } + /// let chain = foo_file.chain(bar_file); + /// let (foo_file, bar_file) = chain.get_ref(); + /// Ok(()) + /// } /// ``` #[stable(feature = "more_io_inner_methods", since = "1.20.0")] pub fn get_ref(&self) -> (&T, &U) { @@ -1695,19 +1664,19 @@ impl<T, U> Chain<T, U> { /// /// # Examples /// - /// ``` - /// # use std::io; + /// ```no_run + /// 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")?; + /// fn main() -> 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(()) - /// # } + /// let mut chain = foo_file.chain(bar_file); + /// let (foo_file, bar_file) = chain.get_mut(); + /// Ok(()) + /// } /// ``` #[stable(feature = "more_io_inner_methods", since = "1.20.0")] pub fn get_mut(&mut self) -> (&mut T, &mut U) { @@ -1794,20 +1763,20 @@ impl<T> Take<T> { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let f = File::open("foo.txt")?; + /// fn main() -> io::Result<()> { + /// let f = File::open("foo.txt")?; /// - /// // read at most five bytes - /// let handle = f.take(5); + /// // read at most five bytes + /// let handle = f.take(5); /// - /// println!("limit: {}", handle.limit()); - /// # Ok(()) - /// # } + /// println!("limit: {}", handle.limit()); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn limit(&self) -> u64 { self.limit } @@ -1819,24 +1788,23 @@ impl<T> Take<T> { /// /// # Examples /// - /// ``` - /// #![feature(take_set_limit)] + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let f = File::open("foo.txt")?; + /// fn main() -> io::Result<()> { + /// let f = File::open("foo.txt")?; /// - /// // read at most five bytes - /// let mut handle = f.take(5); - /// handle.set_limit(10); + /// // read at most five bytes + /// let mut handle = f.take(5); + /// handle.set_limit(10); /// - /// assert_eq!(handle.limit(), 10); - /// # Ok(()) - /// # } + /// assert_eq!(handle.limit(), 10); + /// Ok(()) + /// } /// ``` - #[unstable(feature = "take_set_limit", issue = "42781")] + #[stable(feature = "take_set_limit", since = "1.27.0")] pub fn set_limit(&mut self, limit: u64) { self.limit = limit; } @@ -1845,21 +1813,21 @@ impl<T> Take<T> { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut file = File::open("foo.txt")?; + /// fn main() -> 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 mut buffer = [0; 5]; + /// let mut handle = file.take(5); + /// handle.read(&mut buffer)?; /// - /// let file = handle.into_inner(); - /// # Ok(()) - /// # } + /// let file = handle.into_inner(); + /// Ok(()) + /// } /// ``` #[stable(feature = "io_take_into_inner", since = "1.15.0")] pub fn into_inner(self) -> T { @@ -1870,21 +1838,21 @@ impl<T> Take<T> { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut file = File::open("foo.txt")?; + /// fn main() -> 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 mut buffer = [0; 5]; + /// let mut handle = file.take(5); + /// handle.read(&mut buffer)?; /// - /// let file = handle.get_ref(); - /// # Ok(()) - /// # } + /// let file = handle.get_ref(); + /// Ok(()) + /// } /// ``` #[stable(feature = "more_io_inner_methods", since = "1.20.0")] pub fn get_ref(&self) -> &T { @@ -1899,21 +1867,21 @@ impl<T> Take<T> { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut file = File::open("foo.txt")?; + /// fn main() -> 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 mut buffer = [0; 5]; + /// let mut handle = file.take(5); + /// handle.read(&mut buffer)?; /// - /// let file = handle.get_mut(); - /// # Ok(()) - /// # } + /// let file = handle.get_mut(); + /// Ok(()) + /// } /// ``` #[stable(feature = "more_io_inner_methods", since = "1.20.0")] pub fn get_mut(&mut self) -> &mut T { @@ -1938,6 +1906,12 @@ impl<T: Read> Read for Take<T> { unsafe fn initializer(&self) -> Initializer { self.inner.initializer() } + + fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> { + let reservation_size = cmp::min(self.limit, 32) as usize; + + read_to_end_with_reservation(self, buf, reservation_size) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1961,7 +1935,7 @@ impl<T: BufRead> BufRead for Take<T> { } } -fn read_one_byte(reader: &mut Read) -> Option<Result<u8>> { +fn read_one_byte(reader: &mut dyn Read) -> Option<Result<u8>> { let mut buf = [0]; loop { return match reader.read(&mut buf) { @@ -1994,95 +1968,6 @@ impl<R: Read> Iterator for Bytes<R> { } } -/// An iterator over the `char`s of a reader. -/// -/// This struct is generally created by calling [`chars`][chars] on a reader. -/// Please see the documentation of `chars()` for more details. -/// -/// [chars]: trait.Read.html#method.chars -#[unstable(feature = "io", reason = "awaiting stability of Read::chars", - issue = "27802")] -#[derive(Debug)] -pub struct Chars<R> { - inner: R, -} - -/// An enumeration of possible errors that can be generated from the `Chars` -/// adapter. -#[derive(Debug)] -#[unstable(feature = "io", reason = "awaiting stability of Read::chars", - issue = "27802")] -pub enum CharsError { - /// Variant representing that the underlying stream was read successfully - /// but it did not contain valid utf8 data. - NotUtf8, - - /// Variant representing that an I/O error occurred. - Other(Error), -} - -#[unstable(feature = "io", reason = "awaiting stability of Read::chars", - issue = "27802")] -impl<R: Read> Iterator for Chars<R> { - type Item = result::Result<char, CharsError>; - - fn next(&mut self) -> Option<result::Result<char, CharsError>> { - let first_byte = match read_one_byte(&mut self.inner)? { - Ok(b) => b, - Err(e) => return Some(Err(CharsError::Other(e))), - }; - let width = core_str::utf8_char_width(first_byte); - if width == 1 { return Some(Ok(first_byte as char)) } - if width == 0 { return Some(Err(CharsError::NotUtf8)) } - let mut buf = [first_byte, 0, 0, 0]; - { - let mut start = 1; - while start < width { - match self.inner.read(&mut buf[start..width]) { - Ok(0) => return Some(Err(CharsError::NotUtf8)), - Ok(n) => start += n, - Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, - Err(e) => return Some(Err(CharsError::Other(e))), - } - } - } - Some(match str::from_utf8(&buf[..width]).ok() { - Some(s) => Ok(s.chars().next().unwrap()), - None => Err(CharsError::NotUtf8), - }) - } -} - -#[unstable(feature = "io", reason = "awaiting stability of Read::chars", - issue = "27802")] -impl std_error::Error for CharsError { - fn description(&self) -> &str { - match *self { - CharsError::NotUtf8 => "invalid utf8 encoding", - CharsError::Other(ref e) => std_error::Error::description(e), - } - } - fn cause(&self) -> Option<&std_error::Error> { - match *self { - CharsError::NotUtf8 => None, - CharsError::Other(ref e) => e.cause(), - } - } -} - -#[unstable(feature = "io", reason = "awaiting stability of Read::chars", - issue = "27802")] -impl fmt::Display for CharsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - CharsError::NotUtf8 => { - "byte stream did not contain valid utf8".fmt(f) - } - CharsError::Other(ref e) => e.fmt(f), - } - } -} - /// An iterator over the contents of an instance of `BufRead` split on a /// particular byte. /// diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 831688bb73d..1f256f518c7 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -17,11 +17,11 @@ use io::{self, Initializer, BufReader, LineWriter}; use sync::{Arc, Mutex, MutexGuard}; use sys::stdio; use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; -use thread::{LocalKey, LocalKeyState}; +use thread::LocalKey; /// Stdout used by print! and println! macros thread_local! { - static LOCAL_STDOUT: RefCell<Option<Box<Write + Send>>> = { + static LOCAL_STDOUT: RefCell<Option<Box<dyn Write + Send>>> = { RefCell::new(None) } } @@ -171,38 +171,39 @@ pub struct StdinLock<'a> { /// /// Using implicit synchronization: /// -/// ``` +/// ```no_run /// use std::io::{self, Read}; /// -/// # fn foo() -> io::Result<String> { -/// let mut buffer = String::new(); -/// io::stdin().read_to_string(&mut buffer)?; -/// # Ok(buffer) -/// # } +/// fn main() -> io::Result<()> { +/// let mut buffer = String::new(); +/// io::stdin().read_to_string(&mut buffer)?; +/// Ok(()) +/// } /// ``` /// /// Using explicit synchronization: /// -/// ``` +/// ```no_run /// use std::io::{self, Read}; /// -/// # fn foo() -> io::Result<String> { -/// let mut buffer = String::new(); -/// let stdin = io::stdin(); -/// let mut handle = stdin.lock(); +/// fn main() -> io::Result<()> { +/// let mut buffer = String::new(); +/// let stdin = io::stdin(); +/// let mut handle = stdin.lock(); /// -/// handle.read_to_string(&mut buffer)?; -/// # Ok(buffer) -/// # } +/// handle.read_to_string(&mut buffer)?; +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdin() -> Stdin { - static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = Lazy::new(stdin_init); + static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = unsafe { Lazy::new(stdin_init) }; return Stdin { inner: INSTANCE.get().expect("cannot access stdin during shutdown"), }; fn stdin_init() -> Arc<Mutex<BufReader<Maybe<StdinRaw>>>> { + // This must not reentrantly access `INSTANCE` let stdin = match stdin_raw() { Ok(stdin) => Maybe::Real(stdin), _ => Maybe::Fake @@ -225,17 +226,17 @@ impl Stdin { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::{self, Read}; /// - /// # fn foo() -> io::Result<String> { - /// let mut buffer = String::new(); - /// let stdin = io::stdin(); - /// let mut handle = stdin.lock(); + /// fn main() -> io::Result<()> { + /// let mut buffer = String::new(); + /// let stdin = io::stdin(); + /// let mut handle = stdin.lock(); /// - /// handle.read_to_string(&mut buffer)?; - /// # Ok(buffer) - /// # } + /// handle.read_to_string(&mut buffer)?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> StdinLock { @@ -369,39 +370,40 @@ pub struct StdoutLock<'a> { /// /// Using implicit synchronization: /// -/// ``` +/// ```no_run /// use std::io::{self, Write}; /// -/// # fn foo() -> io::Result<()> { -/// io::stdout().write(b"hello world")?; +/// fn main() -> io::Result<()> { +/// io::stdout().write(b"hello world")?; /// -/// # Ok(()) -/// # } +/// Ok(()) +/// } /// ``` /// /// Using explicit synchronization: /// -/// ``` +/// ```no_run /// use std::io::{self, Write}; /// -/// # fn foo() -> io::Result<()> { -/// let stdout = io::stdout(); -/// let mut handle = stdout.lock(); +/// fn main() -> io::Result<()> { +/// let stdout = io::stdout(); +/// let mut handle = stdout.lock(); /// -/// handle.write(b"hello world")?; +/// handle.write(b"hello world")?; /// -/// # Ok(()) -/// # } +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdout() -> Stdout { static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> - = Lazy::new(stdout_init); + = unsafe { Lazy::new(stdout_init) }; return Stdout { inner: INSTANCE.get().expect("cannot access stdout during shutdown"), }; fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> { + // This must not reentrantly access `INSTANCE` let stdout = match stdout_raw() { Ok(stdout) => Maybe::Real(stdout), _ => Maybe::Fake, @@ -419,17 +421,17 @@ impl Stdout { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::{self, Write}; /// - /// # fn foo() -> io::Result<()> { - /// let stdout = io::stdout(); - /// let mut handle = stdout.lock(); + /// fn main() -> io::Result<()> { + /// let stdout = io::stdout(); + /// let mut handle = stdout.lock(); /// - /// handle.write(b"hello world")?; + /// handle.write(b"hello world")?; /// - /// # Ok(()) - /// # } + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> StdoutLock { @@ -505,38 +507,40 @@ pub struct StderrLock<'a> { /// /// Using implicit synchronization: /// -/// ``` +/// ```no_run /// use std::io::{self, Write}; /// -/// # fn foo() -> io::Result<()> { -/// io::stderr().write(b"hello world")?; +/// fn main() -> io::Result<()> { +/// io::stderr().write(b"hello world")?; /// -/// # Ok(()) -/// # } +/// Ok(()) +/// } /// ``` /// /// Using explicit synchronization: /// -/// ``` +/// ```no_run /// use std::io::{self, Write}; /// -/// # fn foo() -> io::Result<()> { -/// let stderr = io::stderr(); -/// let mut handle = stderr.lock(); +/// fn main() -> io::Result<()> { +/// let stderr = io::stderr(); +/// let mut handle = stderr.lock(); /// -/// handle.write(b"hello world")?; +/// handle.write(b"hello world")?; /// -/// # Ok(()) -/// # } +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stderr() -> Stderr { - static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> = Lazy::new(stderr_init); + static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> = + unsafe { Lazy::new(stderr_init) }; return Stderr { inner: INSTANCE.get().expect("cannot access stderr during shutdown"), }; fn stderr_init() -> Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> { + // This must not reentrantly access `INSTANCE` let stderr = match stderr_raw() { Ok(stderr) => Maybe::Real(stderr), _ => Maybe::Fake, @@ -624,7 +628,7 @@ impl<'a> fmt::Debug for StderrLock<'a> { with a more general mechanism", issue = "0")] #[doc(hidden)] -pub fn set_panic(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> { +pub fn set_panic(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write + Send>> { use panicking::LOCAL_STDERR; use mem; LOCAL_STDERR.with(move |slot| { @@ -648,7 +652,7 @@ pub fn set_panic(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> { with a more general mechanism", issue = "0")] #[doc(hidden)] -pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> { +pub fn set_print(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write + Send>> { use mem; LOCAL_STDOUT.with(move |slot| { mem::replace(&mut *slot.borrow_mut(), sink) @@ -663,29 +667,31 @@ pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> { /// /// 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 +/// For instance, if the TLS key for the local stream is +/// 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 => global_s().write_fmt(args), - LocalKeyState::Valid => { - 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); - } - } - global_s().write_fmt(args) - }) +fn print_to<T>( + args: fmt::Arguments, + local_s: &'static LocalKey<RefCell<Option<Box<dyn Write+Send>>>>, + global_s: fn() -> T, + label: &str, +) +where + T: Write, +{ + let result = local_s.try_with(|s| { + if let Ok(mut borrowed) = s.try_borrow_mut() { + if let Some(w) = borrowed.as_mut() { + return w.write_fmt(args); + } } - }; + global_s().write_fmt(args) + }).unwrap_or_else(|_| { + global_s().write_fmt(args) + }); + if let Err(e) = result { panic!("failed printing to {}: {}", label, e); } @@ -710,10 +716,32 @@ pub fn _eprint(args: fmt::Arguments) { #[cfg(test)] mod tests { + use panic::{UnwindSafe, RefUnwindSafe}; use thread; use super::*; #[test] + fn stdout_unwind_safe() { + assert_unwind_safe::<Stdout>(); + } + #[test] + fn stdoutlock_unwind_safe() { + assert_unwind_safe::<StdoutLock>(); + assert_unwind_safe::<StdoutLock<'static>>(); + } + #[test] + fn stderr_unwind_safe() { + assert_unwind_safe::<Stderr>(); + } + #[test] + fn stderrlock_unwind_safe() { + assert_unwind_safe::<StderrLock>(); + assert_unwind_safe::<StderrLock<'static>>(); + } + + fn assert_unwind_safe<T: UnwindSafe + RefUnwindSafe>() {} + + #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn panic_doesnt_poison() { thread::spawn(|| { diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index 45d281ee34a..33f741dbc38 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -34,16 +34,15 @@ use mem; /// ``` /// use std::io; /// -/// # fn foo() -> io::Result<()> { -/// let mut reader: &[u8] = b"hello"; -/// let mut writer: Vec<u8> = vec![]; +/// fn main() -> io::Result<()> { +/// let mut reader: &[u8] = b"hello"; +/// let mut writer: Vec<u8> = vec![]; /// -/// io::copy(&mut reader, &mut writer)?; +/// io::copy(&mut reader, &mut writer)?; /// -/// assert_eq!(&b"hello"[..], &writer[..]); -/// # Ok(()) -/// # } -/// # foo().unwrap(); +/// assert_eq!(&b"hello"[..], &writer[..]); +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<u64> @@ -224,7 +223,7 @@ mod tests { assert_eq!(copy(&mut r, &mut w).unwrap(), 4); let mut r = repeat(0).take(1 << 17); - assert_eq!(copy(&mut r as &mut Read, &mut w as &mut Write).unwrap(), 1 << 17); + assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17); } #[test] diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs new file mode 100644 index 00000000000..4f6bda6cfe3 --- /dev/null +++ b/src/libstd/keyword_docs.rs @@ -0,0 +1,58 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[doc(keyword = "fn")] +// +/// The `fn` keyword. +/// +/// The `fn` keyword is used to declare a function. +/// +/// Example: +/// +/// ```rust +/// fn some_function() { +/// // code goes in here +/// } +/// ``` +/// +/// For more information about functions, take a look at the [Rust Book][book]. +/// +/// [book]: https://doc.rust-lang.org/book/second-edition/ch03-03-how-functions-work.html +mod fn_keyword { } + +#[doc(keyword = "let")] +// +/// The `let` keyword. +/// +/// The `let` keyword is used to declare a variable. +/// +/// Example: +/// +/// ```rust +/// # #![allow(unused_assignments)] +/// let x = 3; // We create a variable named `x` with the value `3`. +/// ``` +/// +/// By default, all variables are **not** mutable. If you want a mutable variable, +/// you'll have to use the `mut` keyword. +/// +/// Example: +/// +/// ```rust +/// # #![allow(unused_assignments)] +/// let mut x = 3; // We create a mutable variable named `x` with the value `3`. +/// +/// x += 4; // `x` is now equal to `7`. +/// ``` +/// +/// For more information about the `let` keyword, take a look at the [Rust Book][book]. +/// +/// [book]: https://doc.rust-lang.org/book/second-edition/ch03-01-variables-and-mutability.html +mod let_keyword { } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 880b46fa507..b1d45b7f260 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -44,10 +44,10 @@ //! //! Once you are familiar with the contents of the standard library you may //! begin to find the verbosity of the prose distracting. At this stage in your -//! development you may want to press the **[-]** button near the top of the +//! development you may want to press the `[-]` button near the top of the //! page to collapse it into a more skimmable view. //! -//! While you are looking at that **[-]** button also notice the **[src]** +//! While you are looking at that `[-]` button also notice the `[src]` //! button. Rust's API documentation comes with the source code and you are //! encouraged to read it. The standard library source is generally high //! quality and a peek behind the curtains is often enlightening. @@ -227,24 +227,22 @@ // Tell the compiler to link to either panic_abort or panic_unwind #![needs_panic_runtime] -// Turn warnings into errors, but only after stage0, where it can be useful for -// code to emit warnings during language transitions -#![cfg_attr(not(stage0), deny(warnings))] - // std may use features in a platform-specific way #![allow(unused_features)] // std is implemented with unstable features, many of which are internal // compiler details that will never be stable +#![cfg_attr(test, feature(test, update_panic_count))] #![feature(alloc)] -#![feature(allocator_api)] +#![feature(alloc_error_handler)] #![feature(alloc_system)] +#![feature(allocator_api)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] #![feature(align_offset)] +#![feature(arbitrary_self_types)] #![feature(array_error_internals)] -#![feature(ascii_ctype)] #![feature(asm)] #![feature(attr_literals)] #![feature(box_syntax)] @@ -252,79 +250,70 @@ #![feature(cfg_target_thread_local)] #![feature(cfg_target_vendor)] #![feature(char_error_internals)] -#![feature(char_internals)] -#![feature(collections_range)] #![feature(compiler_builtins_lib)] #![feature(const_fn)] -#![feature(convert_id)] #![feature(core_float)] +#![feature(const_int_ops)] +#![feature(const_ip)] +#![feature(convert_id)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] -#![feature(fs_read_write)] +#![feature(external_doc)] #![feature(fixed_size_array)] -#![feature(float_from_str_radix)] #![feature(fn_traits)] #![feature(fnbox)] -#![feature(fused)] -#![feature(generic_param_attrs)] -#![feature(hashmap_hasher)] -#![feature(heap_api)] -#![feature(i128)] -#![feature(i128_type)] -#![feature(inclusive_range)] +#![feature(futures_api)] +#![feature(generator_trait)] +#![feature(hashmap_internals)] #![feature(int_error_internals)] #![feature(integer_atomics)] -#![feature(into_cow)] #![feature(lang_items)] #![feature(libc)] #![feature(link_args)] #![feature(linkage)] -#![feature(macro_reexport)] #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] #![feature(never_type)] -#![feature(num_bits_bytes)] -#![feature(old_wrapping)] +#![cfg_attr(not(stage0), feature(nll))] +#![feature(exhaustive_patterns)] #![feature(on_unimplemented)] -#![feature(oom)] #![feature(optin_builtin_traits)] +#![feature(panic_internals)] #![feature(panic_unwind)] -#![feature(peek)] -#![feature(placement_in_syntax)] -#![feature(placement_new_protocol)] +#![feature(pin)] #![feature(prelude_import)] -#![feature(rand)] +#![feature(ptr_internals)] #![feature(raw)] -#![feature(repr_align)] #![feature(rustc_attrs)] -#![feature(shared)] -#![feature(sip_hash_13)] -#![feature(slice_bytes)] +#![feature(rustc_const_unstable)] +#![feature(std_internals)] +#![feature(stdsimd)] +#![feature(shrink_to)] #![feature(slice_concat_ext)] #![feature(slice_internals)] #![feature(slice_patterns)] #![feature(staged_api)] #![feature(stmt_expr_attributes)] -#![feature(str_char)] #![feature(str_internals)] -#![feature(str_utf16)] -#![feature(termination_trait)] -#![feature(test, rustc_private)] +#![feature(rustc_private)] #![feature(thread_local)] #![feature(toowned_clone_into)] #![feature(try_from)] +#![feature(try_reserve)] #![feature(unboxed_closures)] -#![feature(unicode)] -#![feature(unique)] #![feature(untagged_unions)] #![feature(unwind_attributes)] -#![feature(vec_push_all)] +#![cfg_attr(stage0, feature(use_extern_macros))] #![feature(doc_cfg)] #![feature(doc_masked)] #![feature(doc_spotlight)] -#![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(windows, feature(used))] +#![feature(doc_alias)] +#![feature(doc_keyword)] +#![feature(panic_info_message)] +#![feature(panic_implementation)] +#![feature(non_exhaustive)] #![default_lib_allocator] @@ -334,11 +323,8 @@ // `force_alloc_system` is *only* intended as a workaround for local rebuilds // with a rustc without jemalloc. // FIXME(#44236) shouldn't need MSVC logic -#![cfg_attr(all(not(target_env = "msvc"), - any(stage0, feature = "force_alloc_system")), - feature(global_allocator))] #[cfg(all(not(target_env = "msvc"), - any(stage0, feature = "force_alloc_system")))] + any(all(stage0, not(test)), feature = "force_alloc_system")))] #[global_allocator] static ALLOC: alloc_system::System = alloc_system::System; @@ -352,18 +338,16 @@ use prelude::v1::*; #[cfg(test)] extern crate test; #[cfg(test)] extern crate rand; -// We want to re-export a few macros from core but libcore has already been -// imported by the compiler (via our #[no_std] attribute) In this case we just -// add a new crate name so we can attach the re-exports to it. -#[macro_reexport(assert, assert_eq, assert_ne, debug_assert, debug_assert_eq, - debug_assert_ne, unreachable, unimplemented, write, writeln, try)] -extern crate core as __core; +// Re-export a few macros from core +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::{assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::{unreachable, unimplemented, write, writeln, try}; +#[allow(unused_imports)] // macros from `alloc` are not used on all platforms #[macro_use] -#[macro_reexport(vec, format)] -extern crate alloc; +extern crate alloc as alloc_crate; extern crate alloc_system; -extern crate std_unicode; #[doc(masked)] extern crate libc; @@ -372,14 +356,10 @@ extern crate libc; #[allow(unused_extern_crates)] extern crate unwind; -// compiler-rt intrinsics -#[doc(masked)] -extern crate compiler_builtins; - // During testing, this crate is not actually the "real" std library, but rather // it links to the real std library, which was compiled from this same source // code. So any lang items std defines are conditionally excluded (or else they -// wolud generate duplicate lang item errors), and any globals it defines are +// would generate duplicate lang item errors), and any globals it defines are // _not_ the globals used by "real" std. So this import, defined only during // testing gives test-std access to real-std lang items and globals. See #2912 #[cfg(test)] extern crate std as realstd; @@ -434,7 +414,7 @@ pub use core::i16; pub use core::i32; #[stable(feature = "rust1", since = "1.0.0")] pub use core::i64; -#[unstable(feature = "i128", issue = "35118")] +#[stable(feature = "i128", since = "1.26.0")] pub use core::i128; #[stable(feature = "rust1", since = "1.0.0")] pub use core::usize; @@ -447,25 +427,29 @@ pub use core::u32; #[stable(feature = "rust1", since = "1.0.0")] pub use core::u64; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::boxed; +pub use alloc_crate::boxed; +#[stable(feature = "rust1", since = "1.0.0")] +pub use alloc_crate::rc; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::rc; +pub use alloc_crate::borrow; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::borrow; +pub use alloc_crate::fmt; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::fmt; +pub use alloc_crate::format; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::slice; +pub use alloc_crate::slice; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::str; +pub use alloc_crate::str; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::string; +pub use alloc_crate::string; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::vec; +pub use alloc_crate::vec; #[stable(feature = "rust1", since = "1.0.0")] -pub use std_unicode::char; -#[unstable(feature = "i128", issue = "35118")] +pub use core::char; +#[stable(feature = "i128", since = "1.26.0")] pub use core::u128; +#[stable(feature = "core_hint", since = "1.27.0")] +pub use core::hint; pub mod f32; pub mod f64; @@ -487,13 +471,30 @@ pub mod path; pub mod process; pub mod sync; pub mod time; -pub mod heap; + +#[unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] +pub mod task { + //! Types and Traits for working with asynchronous tasks. + #[doc(inline)] + pub use core::task::*; + #[doc(inline)] + pub use alloc_crate::task::*; +} + +#[unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] +pub mod future; // Platform-abstraction modules #[macro_use] mod sys_common; mod sys; +pub mod alloc; + // Private support modules mod panicking; mod memchr; @@ -501,13 +502,38 @@ mod memchr; // The runtime entry point and a few unstable public functions used by the // compiler pub mod rt; -// The trait to support returning arbitrary types in the main function -mod termination; -#[unstable(feature = "termination_trait", issue = "43301")] -pub use self::termination::Termination; +// Pull in the the `stdsimd` crate directly into libstd. This is the same as +// libcore's arch/simd modules where the source of truth here is in a different +// repository, but we pull things in here manually to get it into libstd. +// +// Note that the #[cfg] here is intended to do two things. First it allows us to +// change the rustc implementation of intrinsics in stage0 by not compiling simd +// intrinsics in stage0. Next it doesn't compile anything in test mode as +// stdsimd has tons of its own tests which we don't want to run. +#[path = "../stdsimd/stdsimd/mod.rs"] +#[allow(missing_debug_implementations, missing_docs, dead_code)] +#[unstable(feature = "stdsimd", issue = "48556")] +#[cfg(all(not(stage0), not(test)))] +mod stdsimd; + +// A "fake" module needed by the `stdsimd` module to compile, not actually +// exported though. +#[cfg(not(stage0))] +mod coresimd { + pub use core::arch; +} + +#[stable(feature = "simd_arch", since = "1.27.0")] +#[cfg(all(not(stage0), not(test)))] +pub use stdsimd::arch; // Include a number of private modules that exist solely to provide // the rustdoc documentation for primitive types. Using `include!` // because rustdoc only looks for these modules at the crate level. include!("primitive_docs.rs"); + +// Include a number of private modules that exist solely to provide +// the rustdoc documentation for the existing keywords. Using `include!` +// because rustdoc only looks for these modules at the crate level. +include!("keyword_docs.rs"); diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index f058b1caef5..f15494c5fd7 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -38,10 +38,13 @@ /// The multi-argument form of this macro panics with a string and has the /// [`format!`] syntax for building a string. /// +/// See also the macro [`compile_error!`], for raising errors during compilation. +/// /// [runwrap]: ../std/result/enum.Result.html#method.unwrap /// [`Option`]: ../std/option/enum.Option.html#method.unwrap /// [`Result`]: ../std/result/enum.Result.html /// [`format!`]: ../std/macro.format.html +/// [`compile_error!`]: ../std/macro.compile_error.html /// [book]: ../book/second-edition/ch09-01-unrecoverable-errors-with-panic.html /// /// # Current implementation @@ -68,6 +71,9 @@ macro_rules! panic { ($msg:expr) => ({ $crate::rt::begin_panic($msg, &(file!(), line!(), __rust_unstable_column!())) }); + ($msg:expr,) => ({ + panic!($msg) + }); ($fmt:expr, $($arg:tt)+) => ({ $crate::rt::begin_panic_fmt(&format_args!($fmt, $($arg)+), &(file!(), line!(), __rust_unstable_column!())) @@ -147,10 +153,12 @@ macro_rules! print { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[allow_internal_unstable] macro_rules! println { () => (print!("\n")); - ($fmt:expr) => (print!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); + ($($arg:tt)*) => ({ + $crate::io::_print(format_args_nl!($($arg)*)); + }) } /// Macro for printing to the standard error. @@ -204,10 +212,34 @@ macro_rules! eprint { /// ``` #[macro_export] #[stable(feature = "eprint", since = "1.19.0")] +#[allow_internal_unstable] macro_rules! eprintln { () => (eprint!("\n")); - ($fmt:expr) => (eprint!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*)); + ($($arg:tt)*) => ({ + $crate::io::_eprint(format_args_nl!($($arg)*)); + }) +} + +#[macro_export] +#[unstable(feature = "await_macro", issue = "50547")] +#[allow_internal_unstable] +#[allow_internal_unsafe] +macro_rules! await { + ($e:expr) => { { + let mut pinned = $e; + loop { + if let $crate::task::Poll::Ready(x) = + $crate::future::poll_in_task_cx(unsafe { + $crate::mem::PinMut::new_unchecked(&mut pinned) + }) + { + break x; + } + // FIXME(cramertj) prior to stabilizing await, we have to ensure that this + // can't be used to create a generator on stable via `|| await!()`. + yield + } + } } } /// A macro to select an event from a number of receivers. @@ -278,18 +310,21 @@ macro_rules! assert_approx_eq { /// macro, but are documented here. Their implementations can be found hardcoded /// into libsyntax itself. #[cfg(dox)] -pub mod builtin { +mod builtin { /// Unconditionally causes compilation to fail with the given error message when encountered. /// /// This macro should be used when a crate uses a conditional compilation strategy to provide - /// better error messages for erroneous conditions. + /// better error messages for erroneous conditions. It's the compiler-level form of [`panic!`], + /// which emits an error at *runtime*, rather than during compilation. /// /// # Examples /// /// Two such examples are macros and `#[cfg]` environments. /// - /// Emit better compiler error if a macro is passed invalid values. + /// Emit better compiler error if a macro is passed invalid values. Without the final branch, + /// the compiler would still emit an error, but the error's message would not mention the two + /// valid values. /// /// ```compile_fail /// macro_rules! give_me_foo_or_bar { @@ -310,9 +345,14 @@ pub mod builtin { /// #[cfg(not(any(feature = "foo", feature = "bar")))] /// compile_error!("Either feature \"foo\" or \"bar\" must be enabled for this crate.") /// ``` + /// + /// [`panic!`]: ../std/macro.panic.html #[stable(feature = "compile_error_macro", since = "1.20.0")] - #[macro_export] - macro_rules! compile_error { ($msg:expr) => ({ /* compiler built-in */ }) } + #[rustc_doc_only_macro] + macro_rules! compile_error { + ($msg:expr) => ({ /* compiler built-in */ }); + ($msg:expr,) => ({ /* compiler built-in */ }); + } /// The core macro for formatted string creation & output. /// @@ -329,6 +369,18 @@ pub mod builtin { /// proxied through this one. `format_args!`, unlike its derived macros, avoids /// heap allocations. /// + /// You can use the [`fmt::Arguments`] value that `format_args!` returns + /// in `Debug` and `Display` contexts as seen below. The example also shows + /// that `Debug` and `Display` format to the same thing: the interpolated + /// format string in `format_args!`. + /// + /// ```rust + /// let debug = format!("{:?}", format_args!("{} foo {:?}", 1, 2)); + /// let display = format!("{}", format_args!("{} foo {:?}", 1, 2)); + /// assert_eq!("1 foo 2", display); + /// assert_eq!(display, debug); + /// ``` + /// /// For more information, see the documentation in [`std::fmt`]. /// /// [`Display`]: ../std/fmt/trait.Display.html @@ -346,10 +398,9 @@ pub mod builtin { /// /// let s = fmt::format(format_args!("hello {}", "world")); /// assert_eq!(s, format!("hello {}", "world")); - /// /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! format_args { ($fmt:expr) => ({ /* compiler built-in */ }); ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }); @@ -361,7 +412,7 @@ pub mod builtin { /// compile time, yielding an expression of type `&'static str`. /// /// If the environment variable is not defined, then a compilation error - /// will be emitted. To not emit a compile error, use the [`option_env!`] + /// will be emitted. To not emit a compile error, use the [`option_env!`] /// macro instead. /// /// [`option_env!`]: ../std/macro.option_env.html @@ -372,8 +423,22 @@ pub mod builtin { /// let path: &'static str = env!("PATH"); /// println!("the $PATH variable at the time of compiling was: {}", path); /// ``` + /// + /// You can customize the error message by passing a string as the second + /// parameter: + /// + /// ```compile_fail + /// let doc: &'static str = env!("documentation", "what's that?!"); + /// ``` + /// + /// If the `documentation` environment variable is not defined, you'll get + /// the following error: + /// + /// ```text + /// error: what's that?! + /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! env { ($name:expr) => ({ /* compiler built-in */ }); ($name:expr,) => ({ /* compiler built-in */ }); @@ -399,8 +464,11 @@ pub mod builtin { /// println!("the secret key might be: {:?}", key); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }) } + #[rustc_doc_only_macro] + macro_rules! option_env { + ($name:expr) => ({ /* compiler built-in */ }); + ($name:expr,) => ({ /* compiler built-in */ }); + } /// Concatenate identifiers into one identifier. /// @@ -427,10 +495,10 @@ pub mod builtin { /// # } /// ``` #[unstable(feature = "concat_idents_macro", issue = "29599")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! concat_idents { - ($($e:ident),*) => ({ /* compiler built-in */ }); - ($($e:ident,)*) => ({ /* compiler built-in */ }); + ($($e:ident),+) => ({ /* compiler built-in */ }); + ($($e:ident,)+) => ({ /* compiler built-in */ }); } /// Concatenates literals into a static string slice. @@ -449,7 +517,7 @@ pub mod builtin { /// assert_eq!(s, "test10btrue"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! concat { ($($e:expr),*) => ({ /* compiler built-in */ }); ($($e:expr,)*) => ({ /* compiler built-in */ }); @@ -463,7 +531,7 @@ pub mod builtin { /// The expanded expression has type `u32` and is 1-based, so the first line /// in each file evaluates to 1, the second to 2, etc. This is consistent /// with error messages by common compilers or popular editors. - /// The returned line is not the invocation of the `line!` macro itself, + /// The returned line is *not necessarily* the line of the `line!` invocation itself, /// but rather the first macro invocation leading up to the invocation /// of the `line!` macro. /// @@ -477,7 +545,7 @@ pub mod builtin { /// println!("defined on line: {}", current_line); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! line { () => ({ /* compiler built-in */ }) } /// A macro which expands to the column number on which it was invoked. @@ -488,7 +556,7 @@ pub mod builtin { /// The expanded expression has type `u32` and is 1-based, so the first column /// in each line evaluates to 1, the second to 2, etc. This is consistent /// with error messages by common compilers or popular editors. - /// The returned column is not the invocation of the `column!` macro itself, + /// The returned column is *not necessarily* the line of the `column!` invocation itself, /// but rather the first macro invocation leading up to the invocation /// of the `column!` macro. /// @@ -502,7 +570,7 @@ pub mod builtin { /// println!("defined on column: {}", current_col); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! column { () => ({ /* compiler built-in */ }) } /// A macro which expands to the file name from which it was invoked. @@ -526,7 +594,7 @@ pub mod builtin { /// println!("defined in file: {}", this_file); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! file { () => ({ /* compiler built-in */ }) } /// A macro which stringifies its arguments. @@ -545,7 +613,7 @@ pub mod builtin { /// assert_eq!(one_plus_one, "1 + 1"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! stringify { ($($t:tt)*) => ({ /* compiler built-in */ }) } /// Includes a utf8-encoded file as a string. @@ -579,8 +647,11 @@ pub mod builtin { /// /// Compiling 'main.rs' and running the resulting binary will print "adiós". #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }) } + #[rustc_doc_only_macro] + macro_rules! include_str { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } /// Includes a file as a reference to a byte array. /// @@ -613,8 +684,11 @@ pub mod builtin { /// /// Compiling 'main.rs' and running the resulting binary will print "adiós". #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }) } + #[rustc_doc_only_macro] + macro_rules! include_bytes { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } /// Expands to a string that represents the current module path. /// @@ -634,7 +708,7 @@ pub mod builtin { /// test::foo(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! module_path { () => ({ /* compiler built-in */ }) } /// Boolean evaluation of configuration flags, at compile-time. @@ -656,7 +730,7 @@ pub mod builtin { /// }; /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) } /// Parse a file as an expression or an item according to the context. @@ -699,17 +773,74 @@ pub mod builtin { /// Compiling 'main.rs' and running the resulting binary will print /// "🙈🙊🙉🙈🙊🙉". #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }) } + #[rustc_doc_only_macro] + macro_rules! include { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } + + /// Ensure that a boolean expression is `true` at runtime. + /// + /// This will invoke the [`panic!`] macro if the provided expression cannot be + /// evaluated to `true` at runtime. + /// + /// # Uses + /// + /// Assertions are always checked in both debug and release builds, and cannot + /// be disabled. See [`debug_assert!`] for assertions that are not enabled in + /// release builds by default. + /// + /// Unsafe code relies on `assert!` to enforce run-time invariants that, if + /// violated could lead to unsafety. + /// + /// Other use-cases of `assert!` include [testing] and enforcing run-time + /// invariants in safe code (whose violation cannot result in unsafety). + /// + /// # Custom Messages + /// + /// This macro has a second form, where a custom panic message can + /// be provided with or without arguments for formatting. See [`std::fmt`] + /// for syntax for this form. + /// + /// [`panic!`]: macro.panic.html + /// [`debug_assert!`]: macro.debug_assert.html + /// [testing]: ../book/second-edition/ch11-01-writing-tests.html#checking-results-with-the-assert-macro + /// [`std::fmt`]: ../std/fmt/index.html + /// + /// # Examples + /// + /// ``` + /// // the panic message for these assertions is the stringified value of the + /// // expression given. + /// assert!(true); + /// + /// fn some_computation() -> bool { true } // a very simple function + /// + /// assert!(some_computation()); + /// + /// // assert with a custom message + /// let x = true; + /// assert!(x, "x wasn't true!"); + /// + /// let a = 3; let b = 27; + /// assert!(a + b == 30, "a = {}, b = {}", a, b); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_doc_only_macro] + macro_rules! assert { + ($cond:expr) => ({ /* compiler built-in */ }); + ($cond:expr,) => ({ /* compiler built-in */ }); + ($cond:expr, $($arg:tt)+) => ({ /* compiler built-in */ }); + } } -/// A macro for defining #[cfg] if-else statements. +/// A macro for defining `#[cfg]` if-else statements. /// /// This is similar to the `if/elif` C preprocessor macro by allowing definition /// of a cascade of `#[cfg]` cases, emitting the implementation which matches /// first. /// -/// This allows you to conveniently provide a long list #[cfg]'d blocks of code +/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code /// without having to rewrite each clause multiple times. macro_rules! cfg_if { ($( diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 1ca7e66ed9c..e80c3eeb876 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -12,10 +12,11 @@ use fmt; use hash; use io; use mem; -use net::{lookup_host, ntoh, hton, IpAddr, Ipv4Addr, Ipv6Addr}; +use net::{ntoh, hton, IpAddr, Ipv4Addr, Ipv6Addr}; use option; use sys::net::netc as c; use sys_common::{FromInner, AsInner, IntoInner}; +use sys_common::net::lookup_host; use vec; use iter; use slice; @@ -26,6 +27,9 @@ use slice; /// as possibly some version-dependent additional information. See [`SocketAddrV4`]'s and /// [`SocketAddrV6`]'s respective documentation for more details. /// +/// The size of a `SocketAddr` instance may vary depending on the target operating +/// system. +/// /// [IP address]: ../../std/net/enum.IpAddr.html /// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html /// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html @@ -59,6 +63,9 @@ pub enum SocketAddr { /// /// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. /// +/// The size of a `SocketAddrV4` struct may vary depending on the target operating +/// system. +/// /// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html @@ -86,6 +93,9 @@ pub struct SocketAddrV4 { inner: c::sockaddr_in } /// /// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. /// +/// The size of a `SocketAddrV6` struct may vary depending on the target operating +/// system. +/// /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 0d73a6f4fd7..9a610cd7d6b 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -16,8 +16,6 @@ use cmp::Ordering; use fmt; use hash; -use mem; -use net::{hton, ntoh}; use sys::net::netc as c; use sys_common::{AsInner, FromInner}; @@ -26,6 +24,9 @@ use sys_common::{AsInner, FromInner}; /// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their /// respective documentation for more details. /// +/// The size of an `IpAddr` instance may vary depending on the target operating +/// system. +/// /// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html /// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html /// @@ -61,6 +62,9 @@ pub enum IpAddr { /// /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. /// +/// The size of an `Ipv4Addr` struct may vary depending on the target operating +/// system. +/// /// [IETF RFC 791]: https://tools.ietf.org/html/rfc791 /// [`IpAddr`]: ../../std/net/enum.IpAddr.html /// @@ -93,6 +97,9 @@ pub struct Ipv4Addr { /// /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. /// +/// The size of an `Ipv6Addr` struct may vary depending on the target operating +/// system. +/// /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// [`IpAddr`]: ../../std/net/enum.IpAddr.html /// @@ -153,9 +160,9 @@ impl IpAddr { /// ``` #[stable(feature = "ip_shared", since = "1.12.0")] pub fn is_unspecified(&self) -> bool { - match *self { - IpAddr::V4(ref a) => a.is_unspecified(), - IpAddr::V6(ref a) => a.is_unspecified(), + match self { + IpAddr::V4(ip) => ip.is_unspecified(), + IpAddr::V6(ip) => ip.is_unspecified(), } } @@ -178,9 +185,9 @@ impl IpAddr { /// ``` #[stable(feature = "ip_shared", since = "1.12.0")] pub fn is_loopback(&self) -> bool { - match *self { - IpAddr::V4(ref a) => a.is_loopback(), - IpAddr::V6(ref a) => a.is_loopback(), + match self { + IpAddr::V4(ip) => ip.is_loopback(), + IpAddr::V6(ip) => ip.is_loopback(), } } @@ -207,9 +214,9 @@ impl IpAddr { /// } /// ``` pub fn is_global(&self) -> bool { - match *self { - IpAddr::V4(ref a) => a.is_global(), - IpAddr::V6(ref a) => a.is_global(), + match self { + IpAddr::V4(ip) => ip.is_global(), + IpAddr::V6(ip) => ip.is_global(), } } @@ -232,9 +239,9 @@ impl IpAddr { /// ``` #[stable(feature = "ip_shared", since = "1.12.0")] pub fn is_multicast(&self) -> bool { - match *self { - IpAddr::V4(ref a) => a.is_multicast(), - IpAddr::V6(ref a) => a.is_multicast(), + match self { + IpAddr::V4(ip) => ip.is_multicast(), + IpAddr::V6(ip) => ip.is_multicast(), } } @@ -261,9 +268,9 @@ impl IpAddr { /// } /// ``` pub fn is_documentation(&self) -> bool { - match *self { - IpAddr::V4(ref a) => a.is_documentation(), - IpAddr::V6(ref a) => a.is_documentation(), + match self { + IpAddr::V4(ip) => ip.is_documentation(), + IpAddr::V6(ip) => ip.is_documentation(), } } @@ -286,7 +293,7 @@ impl IpAddr { /// ``` #[stable(feature = "ipaddr_checker", since = "1.16.0")] pub fn is_ipv4(&self) -> bool { - match *self { + match self { IpAddr::V4(_) => true, IpAddr::V6(_) => false, } @@ -311,7 +318,7 @@ impl IpAddr { /// ``` #[stable(feature = "ipaddr_checker", since = "1.16.0")] pub fn is_ipv6(&self) -> bool { - match *self { + match self { IpAddr::V4(_) => false, IpAddr::V6(_) => true, } @@ -331,18 +338,21 @@ impl Ipv4Addr { /// let addr = Ipv4Addr::new(127, 0, 0, 1); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { + #[rustc_const_unstable(feature = "const_ip")] + pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { Ipv4Addr { inner: c::in_addr { - s_addr: hton(((a as u32) << 24) | - ((b as u32) << 16) | - ((c as u32) << 8) | - (d as u32)), + s_addr: u32::to_be( + ((a as u32) << 24) | + ((b as u32) << 16) | + ((c as u32) << 8) | + (d as u32) + ), } } } - /// Creates a new IPv4 address with the address pointing to localhost: 127.0.0.1. + /// An IPv4 address with the address pointing to localhost: 127.0.0.1. /// /// # Examples /// @@ -350,17 +360,15 @@ impl Ipv4Addr { /// #![feature(ip_constructors)] /// use std::net::Ipv4Addr; /// - /// let addr = Ipv4Addr::localhost(); + /// let addr = Ipv4Addr::LOCALHOST; /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1)); /// ``` #[unstable(feature = "ip_constructors", reason = "requires greater scrutiny before stabilization", issue = "44582")] - pub fn localhost() -> Ipv4Addr { - Ipv4Addr::new(127, 0, 0, 1) - } + pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1); - /// Creates a new IPv4 address representing an unspecified address: 0.0.0.0 + /// An IPv4 address representing an unspecified address: 0.0.0.0 /// /// # Examples /// @@ -368,15 +376,29 @@ impl Ipv4Addr { /// #![feature(ip_constructors)] /// use std::net::Ipv4Addr; /// - /// let addr = Ipv4Addr::unspecified(); + /// let addr = Ipv4Addr::UNSPECIFIED; /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0)); /// ``` #[unstable(feature = "ip_constructors", reason = "requires greater scrutiny before stabilization", issue = "44582")] - pub fn unspecified() -> Ipv4Addr { - Ipv4Addr::new(0, 0, 0, 0) - } + pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0); + + /// An IPv4 address representing the broadcast address: 255.255.255.255 + /// + /// # Examples + /// + /// ``` + /// #![feature(ip_constructors)] + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::BROADCAST; + /// assert_eq!(addr, Ipv4Addr::new(255, 255, 255, 255)); + /// ``` + #[unstable(feature = "ip_constructors", + reason = "requires greater scrutiny before stabilization", + issue = "44582")] + pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255); /// Returns the four eight-bit integers that make up this address. /// @@ -390,7 +412,7 @@ impl Ipv4Addr { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn octets(&self) -> [u8; 4] { - let bits = ntoh(self.inner.s_addr); + let bits = u32::from_be(self.inner.s_addr); [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8] } @@ -461,11 +483,11 @@ impl Ipv4Addr { /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_private(&self) -> bool { - match (self.octets()[0], self.octets()[1]) { - (10, _) => true, - (172, b) if b >= 16 && b <= 31 => true, - (192, 168) => true, - _ => false + match self.octets() { + [10, ..] => true, + [172, b, ..] if b >= 16 && b <= 31 => true, + [192, 168, ..] => true, + _ => false, } } @@ -487,7 +509,10 @@ impl Ipv4Addr { /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_link_local(&self) -> bool { - self.octets()[0] == 169 && self.octets()[1] == 254 + match self.octets() { + [169, 254, ..] => true, + _ => false, + } } /// Returns [`true`] if the address appears to be globally routable. @@ -564,8 +589,7 @@ impl Ipv4Addr { /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_broadcast(&self) -> bool { - self.octets()[0] == 255 && self.octets()[1] == 255 && - self.octets()[2] == 255 && self.octets()[3] == 255 + self == &Self::BROADCAST } /// Returns [`true`] if this address is in a range designated for documentation. @@ -591,11 +615,11 @@ impl Ipv4Addr { /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_documentation(&self) -> bool { - match(self.octets()[0], self.octets()[1], self.octets()[2], self.octets()[3]) { - (192, 0, 2, _) => true, - (198, 51, 100, _) => true, - (203, 0, 113, _) => true, - _ => false + match self.octets() { + [192, 0, 2, _] => true, + [198, 51, 100, _] => true, + [203, 0, 113, _] => true, + _ => false, } } @@ -645,9 +669,9 @@ impl Ipv4Addr { #[stable(feature = "ip_addr", since = "1.7.0")] impl fmt::Display for IpAddr { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match *self { - IpAddr::V4(ref a) => a.fmt(fmt), - IpAddr::V6(ref a) => a.fmt(fmt), + match self { + IpAddr::V4(ip) => ip.fmt(fmt), + IpAddr::V6(ip) => ip.fmt(fmt), } } } @@ -696,8 +720,8 @@ impl PartialEq for Ipv4Addr { #[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialEq<Ipv4Addr> for IpAddr { fn eq(&self, other: &Ipv4Addr) -> bool { - match *self { - IpAddr::V4(ref v4) => v4 == other, + match self { + IpAddr::V4(v4) => v4 == other, IpAddr::V6(_) => false, } } @@ -706,8 +730,8 @@ impl PartialEq<Ipv4Addr> for IpAddr { #[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialEq<IpAddr> for Ipv4Addr { fn eq(&self, other: &IpAddr) -> bool { - match *other { - IpAddr::V4(ref v4) => self == v4, + match other { + IpAddr::V4(v4) => self == v4, IpAddr::V6(_) => false, } } @@ -734,8 +758,8 @@ impl PartialOrd for Ipv4Addr { #[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialOrd<Ipv4Addr> for IpAddr { fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> { - match *self { - IpAddr::V4(ref v4) => v4.partial_cmp(other), + match self { + IpAddr::V4(v4) => v4.partial_cmp(other), IpAddr::V6(_) => Some(Ordering::Greater), } } @@ -744,8 +768,8 @@ impl PartialOrd<Ipv4Addr> for IpAddr { #[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialOrd<IpAddr> for Ipv4Addr { fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> { - match *other { - IpAddr::V4(ref v4) => self.partial_cmp(v4), + match other { + IpAddr::V4(v4) => self.partial_cmp(v4), IpAddr::V6(_) => Some(Ordering::Less), } } @@ -754,7 +778,7 @@ impl PartialOrd<IpAddr> for Ipv4Addr { #[stable(feature = "rust1", since = "1.0.0")] impl Ord for Ipv4Addr { fn cmp(&self, other: &Ipv4Addr) -> Ordering { - ntoh(self.inner.s_addr).cmp(&ntoh(other.inner.s_addr)) + u32::from_be(self.inner.s_addr).cmp(&u32::from_be(other.inner.s_addr)) } } @@ -769,7 +793,16 @@ impl FromInner<c::in_addr> for Ipv4Addr { #[stable(feature = "ip_u32", since = "1.1.0")] impl From<Ipv4Addr> for u32 { - /// It performs the conversion in network order (big-endian). + /// Convert an `Ipv4Addr` into a host byte order `u32`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::new(13, 12, 11, 10); + /// assert_eq!(0x0d0c0b0au32, u32::from(addr)); + /// ``` fn from(ip: Ipv4Addr) -> u32 { let ip = ip.octets(); ((ip[0] as u32) << 24) + ((ip[1] as u32) << 16) + ((ip[2] as u32) << 8) + (ip[3] as u32) @@ -778,7 +811,16 @@ impl From<Ipv4Addr> for u32 { #[stable(feature = "ip_u32", since = "1.1.0")] impl From<u32> for Ipv4Addr { - /// It performs the conversion in network order (big-endian). + /// Convert a host byte order `u32` into an `Ipv4Addr`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::from(0x0d0c0b0au32); + /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); + /// ``` fn from(ip: u32) -> Ipv4Addr { Ipv4Addr::new((ip >> 24) as u8, (ip >> 16) as u8, (ip >> 8) as u8, ip as u8) } @@ -786,6 +828,14 @@ impl From<u32> for Ipv4Addr { #[stable(feature = "from_slice_v4", since = "1.9.0")] impl From<[u8; 4]> for Ipv4Addr { + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::from([13u8, 12u8, 11u8, 10u8]); + /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); + /// ``` fn from(octets: [u8; 4]) -> Ipv4Addr { Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]) } @@ -793,6 +843,16 @@ impl From<[u8; 4]> for Ipv4Addr { #[stable(feature = "ip_from_slice", since = "1.17.0")] impl From<[u8; 4]> for IpAddr { + /// Create an `IpAddr::V4` from a four element byte array. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr}; + /// + /// let addr = IpAddr::from([13u8, 12u8, 11u8, 10u8]); + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(13, 12, 11, 10)), addr); + /// ``` fn from(octets: [u8; 4]) -> IpAddr { IpAddr::V4(Ipv4Addr::from(octets)) } @@ -811,21 +871,27 @@ impl Ipv6Addr { /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, - h: u16) -> Ipv6Addr { - let mut addr: c::in6_addr = unsafe { mem::zeroed() }; - addr.s6_addr = [(a >> 8) as u8, a as u8, - (b >> 8) as u8, b as u8, - (c >> 8) as u8, c as u8, - (d >> 8) as u8, d as u8, - (e >> 8) as u8, e as u8, - (f >> 8) as u8, f as u8, - (g >> 8) as u8, g as u8, - (h >> 8) as u8, h as u8]; - Ipv6Addr { inner: addr } + #[rustc_const_unstable(feature = "const_ip")] + pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, + g: u16, h: u16) -> Ipv6Addr { + Ipv6Addr { + inner: c::in6_addr { + s6_addr: [ + (a >> 8) as u8, a as u8, + (b >> 8) as u8, b as u8, + (c >> 8) as u8, c as u8, + (d >> 8) as u8, d as u8, + (e >> 8) as u8, e as u8, + (f >> 8) as u8, f as u8, + (g >> 8) as u8, g as u8, + (h >> 8) as u8, h as u8 + ], + } + } + } - /// Creates a new IPv6 address representing localhost: `::1`. + /// An IPv6 address representing localhost: `::1`. /// /// # Examples /// @@ -833,17 +899,15 @@ impl Ipv6Addr { /// #![feature(ip_constructors)] /// use std::net::Ipv6Addr; /// - /// let addr = Ipv6Addr::localhost(); + /// let addr = Ipv6Addr::LOCALHOST; /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); /// ``` #[unstable(feature = "ip_constructors", reason = "requires greater scrutiny before stabilization", issue = "44582")] - pub fn localhost() -> Ipv6Addr { - Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1) - } + pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); - /// Creates a new IPv6 address representing the unspecified address: `::` + /// An IPv6 address representing the unspecified address: `::` /// /// # Examples /// @@ -851,15 +915,13 @@ impl Ipv6Addr { /// #![feature(ip_constructors)] /// use std::net::Ipv6Addr; /// - /// let addr = Ipv6Addr::unspecified(); + /// let addr = Ipv6Addr::UNSPECIFIED; /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); /// ``` #[unstable(feature = "ip_constructors", reason = "requires greater scrutiny before stabilization", issue = "44582")] - pub fn unspecified() -> Ipv6Addr { - Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0) - } + pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); /// Returns the eight 16-bit segments that make up this address. /// @@ -1276,9 +1338,9 @@ impl PartialEq for Ipv6Addr { #[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialEq<IpAddr> for Ipv6Addr { fn eq(&self, other: &IpAddr) -> bool { - match *other { + match other { IpAddr::V4(_) => false, - IpAddr::V6(ref v6) => self == v6, + IpAddr::V6(v6) => self == v6, } } } @@ -1286,9 +1348,9 @@ impl PartialEq<IpAddr> for Ipv6Addr { #[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialEq<Ipv6Addr> for IpAddr { fn eq(&self, other: &Ipv6Addr) -> bool { - match *self { + match self { IpAddr::V4(_) => false, - IpAddr::V6(ref v6) => v6 == other, + IpAddr::V6(v6) => v6 == other, } } } @@ -1313,9 +1375,9 @@ impl PartialOrd for Ipv6Addr { #[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialOrd<Ipv6Addr> for IpAddr { fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> { - match *self { + match self { IpAddr::V4(_) => Some(Ordering::Less), - IpAddr::V6(ref v6) => v6.partial_cmp(other), + IpAddr::V6(v6) => v6.partial_cmp(other), } } } @@ -1323,9 +1385,9 @@ impl PartialOrd<Ipv6Addr> for IpAddr { #[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialOrd<IpAddr> for Ipv6Addr { fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> { - match *other { + match other { IpAddr::V4(_) => Some(Ordering::Greater), - IpAddr::V6(ref v6) => self.partial_cmp(v6), + IpAddr::V6(v6) => self.partial_cmp(v6), } } } @@ -1346,7 +1408,7 @@ impl FromInner<c::in6_addr> for Ipv6Addr { } } -#[unstable(feature = "i128", issue = "35118")] +#[stable(feature = "i128", since = "1.26.0")] impl From<Ipv6Addr> for u128 { fn from(ip: Ipv6Addr) -> u128 { let ip = ip.segments(); @@ -1355,7 +1417,7 @@ impl From<Ipv6Addr> for u128 { ((ip[6] as u128) << 16) + (ip[7] as u128) } } -#[unstable(feature = "i128", issue = "35118")] +#[stable(feature = "i128", since = "1.26.0")] impl From<u128> for Ipv6Addr { fn from(ip: u128) -> Ipv6Addr { Ipv6Addr::new( @@ -1369,8 +1431,7 @@ impl From<u128> for Ipv6Addr { #[stable(feature = "ipv6_from_octets", since = "1.9.0")] impl From<[u8; 16]> for Ipv6Addr { fn from(octets: [u8; 16]) -> Ipv6Addr { - let mut inner: c::in6_addr = unsafe { mem::zeroed() }; - inner.s6_addr = octets; + let inner = c::in6_addr { s6_addr: octets }; Ipv6Addr::from_inner(inner) } } @@ -1386,6 +1447,27 @@ impl From<[u16; 8]> for Ipv6Addr { #[stable(feature = "ip_from_slice", since = "1.17.0")] impl From<[u8; 16]> for IpAddr { + /// Create an `IpAddr::V6` from a sixteen element byte array. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv6Addr}; + /// + /// let addr = IpAddr::from([ + /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, + /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, + /// ]); + /// assert_eq!( + /// IpAddr::V6(Ipv6Addr::new( + /// 0x1918, 0x1716, + /// 0x1514, 0x1312, + /// 0x1110, 0x0f0e, + /// 0x0d0c, 0x0b0a + /// )), + /// addr + /// ); + /// ``` fn from(octets: [u8; 16]) -> IpAddr { IpAddr::V6(Ipv6Addr::from(octets)) } @@ -1393,6 +1475,27 @@ impl From<[u8; 16]> for IpAddr { #[stable(feature = "ip_from_slice", since = "1.17.0")] impl From<[u16; 8]> for IpAddr { + /// Create an `IpAddr::V6` from an eight element 16-bit array. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv6Addr}; + /// + /// let addr = IpAddr::from([ + /// 525u16, 524u16, 523u16, 522u16, + /// 521u16, 520u16, 519u16, 518u16, + /// ]); + /// assert_eq!( + /// IpAddr::V6(Ipv6Addr::new( + /// 0x20d, 0x20c, + /// 0x20b, 0x20a, + /// 0x209, 0x208, + /// 0x207, 0x206 + /// )), + /// addr + /// ); + /// ``` fn from(segments: [u16; 8]) -> IpAddr { IpAddr::V6(Ipv6Addr::from(segments)) } @@ -1759,18 +1862,20 @@ mod tests { #[test] fn ipv4_from_constructors() { - assert_eq!(Ipv4Addr::localhost(), Ipv4Addr::new(127, 0, 0, 1)); - assert!(Ipv4Addr::localhost().is_loopback()); - assert_eq!(Ipv4Addr::unspecified(), Ipv4Addr::new(0, 0, 0, 0)); - assert!(Ipv4Addr::unspecified().is_unspecified()); + assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1)); + assert!(Ipv4Addr::LOCALHOST.is_loopback()); + assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0)); + assert!(Ipv4Addr::UNSPECIFIED.is_unspecified()); + assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255)); + assert!(Ipv4Addr::BROADCAST.is_broadcast()); } #[test] fn ipv6_from_contructors() { - assert_eq!(Ipv6Addr::localhost(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); - assert!(Ipv6Addr::localhost().is_loopback()); - assert_eq!(Ipv6Addr::unspecified(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); - assert!(Ipv6Addr::unspecified().is_unspecified()); + assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + assert!(Ipv6Addr::LOCALHOST.is_loopback()); + assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); + assert!(Ipv6Addr::UNSPECIFIED.is_unspecified()); } #[test] diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index 9fcb93e2032..be4bcee8a68 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -38,9 +38,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use fmt; use io::{self, Error, ErrorKind}; -use sys_common::net as net_imp; #[stable(feature = "rust1", since = "1.0.0")] pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; @@ -128,59 +126,3 @@ fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T> "could not resolve to any addresses") })) } - -/// An iterator over `SocketAddr` values returned from a host lookup operation. -#[unstable(feature = "lookup_host", reason = "unsure about the returned \ - iterator and returning socket \ - addresses", - issue = "27705")] -pub struct LookupHost(net_imp::LookupHost); - -#[unstable(feature = "lookup_host", reason = "unsure about the returned \ - iterator and returning socket \ - addresses", - issue = "27705")] -impl Iterator for LookupHost { - type Item = SocketAddr; - fn next(&mut self) -> Option<SocketAddr> { self.0.next() } -} - -#[unstable(feature = "lookup_host", reason = "unsure about the returned \ - iterator and returning socket \ - addresses", - issue = "27705")] -impl fmt::Debug for LookupHost { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("LookupHost { .. }") - } -} - -/// Resolve the host specified by `host` as a number of `SocketAddr` instances. -/// -/// This method may perform a DNS query to resolve `host` and may also inspect -/// system configuration to resolve the specified hostname. -/// -/// The returned iterator will skip over any unknown addresses returned by the -/// operating system. -/// -/// # Examples -/// -/// ```no_run -/// #![feature(lookup_host)] -/// -/// use std::net; -/// -/// # fn foo() -> std::io::Result<()> { -/// for host in net::lookup_host("rust-lang.org")? { -/// println!("found address: {}", host); -/// } -/// # Ok(()) -/// # } -/// ``` -#[unstable(feature = "lookup_host", reason = "unsure about the returned \ - iterator and returning socket \ - addresses", - issue = "27705")] -pub fn lookup_host(host: &str) -> io::Result<LookupHost> { - net_imp::lookup_host(host).map(LookupHost) -} diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs index 261d44eebaa..cf3e5354a31 100644 --- a/src/libstd/net/parser.rs +++ b/src/libstd/net/parser.rs @@ -53,15 +53,12 @@ impl<'a> Parser<'a> { F: FnOnce(&mut Parser) -> Option<T>, { self.read_atomically(move |p| { - match cb(p) { - Some(x) => if p.is_eof() {Some(x)} else {None}, - None => None, - } + cb(p).filter(|_| p.is_eof()) }) } // Return result of first successful parser - fn read_or<T>(&mut self, parsers: &mut [Box<FnMut(&mut Parser) -> Option<T> + 'static>]) + fn read_or<T>(&mut self, parsers: &mut [Box<dyn FnMut(&mut Parser) -> Option<T> + 'static>]) -> Option<T> { for pf in parsers { if let Some(r) = self.read_atomically(|p: &mut Parser| pf(p)) { @@ -372,6 +369,25 @@ impl FromStr for SocketAddr { /// [`IpAddr`], [`Ipv4Addr`], [`Ipv6Addr`], [`SocketAddr`], [`SocketAddrV4`], and /// [`SocketAddrV6`]. /// +/// # Potential causes +/// +/// `AddrParseError` may be thrown because the provided string does not parse as the given type, +/// often because it includes information only handled by a different address type. +/// +/// ```should_panic +/// use std::net::IpAddr; +/// let _foo: IpAddr = "127.0.0.1:8080".parse().expect("Cannot handle the socket port"); +/// ``` +/// +/// [`IpAddr`] doesn't handle the port. Use [`SocketAddr`] instead. +/// +/// ``` +/// use std::net::SocketAddr; +/// +/// // No problem, the `panic!` message has disappeared. +/// let _foo: SocketAddr = "127.0.0.1:8080".parse().expect("unreachable panic"); +/// ``` +/// /// [`FromStr`]: ../../std/str/trait.FromStr.html /// [`IpAddr`]: ../../std/net/enum.IpAddr.html /// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 78235ea1b4b..75c7a3d9280 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -72,7 +72,7 @@ pub struct TcpStream(net_imp::TcpStream); /// /// # Examples /// -/// ``` +/// ```no_run /// # use std::io; /// use std::net::{TcpListener, TcpStream}; /// @@ -80,15 +80,15 @@ pub struct TcpStream(net_imp::TcpStream); /// // ... /// } /// -/// # fn process() -> io::Result<()> { -/// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); +/// fn main() -> io::Result<()> { +/// let listener = TcpListener::bind("127.0.0.1:80")?; /// -/// // accept connections and process them serially -/// for stream in listener.incoming() { -/// handle_client(stream?); +/// // accept connections and process them serially +/// for stream in listener.incoming() { +/// handle_client(stream?); +/// } +/// Ok(()) /// } -/// # Ok(()) -/// # } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct TcpListener(net_imp::TcpListener); @@ -259,19 +259,21 @@ impl TcpStream { /// Sets the read timeout to the timeout specified. /// /// If the value specified is [`None`], then [`read`] calls will block - /// indefinitely. It is an error to pass the zero `Duration` to this - /// method. + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. /// - /// # Note + /// # Platform-specific behavior /// /// Platforms may return a different error code whenever a read times out as /// a result of setting this option. For example Unix typically returns an /// error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err /// [`read`]: ../../std/io/trait.Read.html#tymethod.read /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut + /// [`Duration`]: ../../std/time/struct.Duration.html /// /// # Examples /// @@ -282,6 +284,20 @@ impl TcpStream { /// .expect("Couldn't connect to the server..."); /// stream.set_read_timeout(None).expect("set_read_timeout call failed"); /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::TcpStream; + /// use std::time::Duration; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080").unwrap(); + /// let result = stream.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` #[stable(feature = "socket_timeout", since = "1.4.0")] pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { self.0.set_read_timeout(dur) @@ -290,16 +306,17 @@ impl TcpStream { /// Sets the write timeout to the timeout specified. /// /// If the value specified is [`None`], then [`write`] calls will block - /// indefinitely. It is an error to pass the zero [`Duration`] to this - /// method. + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. /// - /// # Note + /// # Platform-specific behavior /// /// Platforms may return a different error code whenever a write times out /// as a result of setting this option. For example Unix typically returns /// an error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err /// [`write`]: ../../std/io/trait.Write.html#tymethod.write /// [`Duration`]: ../../std/time/struct.Duration.html /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock @@ -314,6 +331,20 @@ impl TcpStream { /// .expect("Couldn't connect to the server..."); /// stream.set_write_timeout(None).expect("set_write_timeout call failed"); /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::TcpStream; + /// use std::time::Duration; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080").unwrap(); + /// let result = stream.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` #[stable(feature = "socket_timeout", since = "1.4.0")] pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { self.0.set_write_timeout(dur) @@ -323,7 +354,7 @@ impl TcpStream { /// /// If the timeout is [`None`], then [`read`] calls will block indefinitely. /// - /// # Note + /// # Platform-specific behavior /// /// Some platforms do not provide access to the current timeout. /// @@ -349,7 +380,7 @@ impl TcpStream { /// /// If the timeout is [`None`], then [`write`] calls will block indefinitely. /// - /// # Note + /// # Platform-specific behavior /// /// Some platforms do not provide access to the current timeout. /// @@ -896,7 +927,7 @@ mod tests { use time::{Instant, Duration}; use thread; - fn each_ip(f: &mut FnMut(SocketAddr)) { + fn each_ip(f: &mut dyn FnMut(SocketAddr)) { f(next_test_ip4()); f(next_test_ip6()); } @@ -1545,6 +1576,26 @@ mod tests { drop(listener); } + // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors + // when passed zero Durations + #[test] + fn test_timeout_zero_duration() { + let addr = next_test_ip4(); + + let listener = t!(TcpListener::bind(&addr)); + let stream = t!(TcpStream::connect(&addr)); + + let result = stream.set_write_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + let result = stream.set_read_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + drop(listener); + } + #[test] fn nodelay() { let addr = next_test_ip4(); diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index fc7f9205d06..0ebe3284b4f 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -44,22 +44,22 @@ use time::Duration; /// ```no_run /// use std::net::UdpSocket; /// -/// # fn foo() -> std::io::Result<()> { -/// { -/// let mut socket = UdpSocket::bind("127.0.0.1:34254")?; +/// fn main() -> std::io::Result<()> { +/// { +/// let mut socket = UdpSocket::bind("127.0.0.1:34254")?; /// -/// // Receives a single datagram message on the socket. If `buf` is too small to hold -/// // the message, it will be cut off. -/// let mut buf = [0; 10]; -/// let (amt, src) = socket.recv_from(&mut buf)?; +/// // Receives a single datagram message on the socket. If `buf` is too small to hold +/// // the message, it will be cut off. +/// let mut buf = [0; 10]; +/// let (amt, src) = socket.recv_from(&mut buf)?; /// -/// // Redeclare `buf` as slice of the received data and send reverse data back to origin. -/// let buf = &mut buf[..amt]; -/// buf.reverse(); -/// socket.send_to(buf, &src)?; -/// # Ok(()) -/// } // the socket is closed here -/// # } +/// // Redeclare `buf` as slice of the received data and send reverse data back to origin. +/// let buf = &mut buf[..amt]; +/// buf.reverse(); +/// socket.send_to(buf, &src)?; +/// } // the socket is closed here +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct UdpSocket(net_imp::UdpSocket); @@ -228,16 +228,17 @@ impl UdpSocket { /// Sets the read timeout to the timeout specified. /// /// If the value specified is [`None`], then [`read`] calls will block - /// indefinitely. It is an error to pass the zero [`Duration`] to this - /// method. + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. /// - /// # Note + /// # Platform-specific behavior /// /// Platforms may return a different error code whenever a read times out as /// a result of setting this option. For example Unix typically returns an /// error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err /// [`read`]: ../../std/io/trait.Read.html#tymethod.read /// [`Duration`]: ../../std/time/struct.Duration.html /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock @@ -251,6 +252,20 @@ impl UdpSocket { /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); /// socket.set_read_timeout(None).expect("set_read_timeout call failed"); /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::UdpSocket; + /// use std::time::Duration; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` #[stable(feature = "socket_timeout", since = "1.4.0")] pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { self.0.set_read_timeout(dur) @@ -259,16 +274,17 @@ impl UdpSocket { /// Sets the write timeout to the timeout specified. /// /// If the value specified is [`None`], then [`write`] calls will block - /// indefinitely. It is an error to pass the zero [`Duration`] to this - /// method. + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. /// - /// # Note + /// # Platform-specific behavior /// /// Platforms may return a different error code whenever a write times out /// as a result of setting this option. For example Unix typically returns /// an error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err /// [`write`]: ../../std/io/trait.Write.html#tymethod.write /// [`Duration`]: ../../std/time/struct.Duration.html /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock @@ -282,6 +298,20 @@ impl UdpSocket { /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); /// socket.set_write_timeout(None).expect("set_write_timeout call failed"); /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::UdpSocket; + /// use std::time::Duration; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` #[stable(feature = "socket_timeout", since = "1.4.0")] pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { self.0.set_write_timeout(dur) @@ -796,7 +826,7 @@ mod tests { use time::{Instant, Duration}; use thread; - fn each_ip(f: &mut FnMut(SocketAddr, SocketAddr)) { + fn each_ip(f: &mut dyn FnMut(SocketAddr, SocketAddr)) { f(next_test_ip4(), next_test_ip4()); f(next_test_ip6(), next_test_ip6()); } @@ -1024,6 +1054,23 @@ mod tests { assert!(start.elapsed() > Duration::from_millis(400)); } + // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors + // when passed zero Durations + #[test] + fn test_timeout_zero_duration() { + let addr = next_test_ip4(); + + let socket = t!(UdpSocket::bind(&addr)); + + let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + } + #[test] fn connect_send_recv() { let addr = next_test_ip4(); diff --git a/src/libstd/num.rs b/src/libstd/num.rs index a2c133954a3..3f90c1fa3b1 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -21,6 +21,9 @@ pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError} #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::Wrapping; +#[stable(feature = "nonzero", since = "1.28.0")] +pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize}; + #[cfg(test)] use fmt; #[cfg(test)] use ops::{Add, Sub, Mul, Div, Rem}; @@ -169,7 +172,6 @@ mod tests { macro_rules! test_checked_next_power_of_two { ($test_name:ident, $T:ident) => ( - #[cfg_attr(target_os = "emscripten", ignore)] // FIXME(#39119) fn $test_name() { #![test] assert_eq!((0 as $T).checked_next_power_of_two(), Some(1)); diff --git a/src/libstd/os/android/fs.rs b/src/libstd/os/android/fs.rs index a51b4655985..5899dc688e2 100644 --- a/src/libstd/os/android/fs.rs +++ b/src/libstd/os/android/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::android::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/bitrig/fs.rs b/src/libstd/os/bitrig/fs.rs index e4f1c9432f3..24caf326ab0 100644 --- a/src/libstd/os/bitrig/fs.rs +++ b/src/libstd/os/bitrig/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::bitrig::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/dragonfly/fs.rs b/src/libstd/os/dragonfly/fs.rs index db672e56435..6aea450774f 100644 --- a/src/libstd/os/dragonfly/fs.rs +++ b/src/libstd/os/dragonfly/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::dragonfly::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/emscripten/fs.rs b/src/libstd/os/emscripten/fs.rs index 8056ce4fdc4..e0e197dc122 100644 --- a/src/libstd/os/emscripten/fs.rs +++ b/src/libstd/os/emscripten/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::emscripten::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/freebsd/fs.rs b/src/libstd/os/freebsd/fs.rs index 2f17d2f7409..5f24cd636d5 100644 --- a/src/libstd/os/freebsd/fs.rs +++ b/src/libstd/os/freebsd/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::freebsd::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/fuchsia/fs.rs b/src/libstd/os/fuchsia/fs.rs index d22f9a628bd..16802576356 100644 --- a/src/libstd/os/fuchsia/fs.rs +++ b/src/libstd/os/fuchsia/fs.rs @@ -13,7 +13,9 @@ use fs::Metadata; use sys_common::AsInner; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { #[stable(feature = "metadata_ext2", since = "1.8.0")] diff --git a/src/libstd/os/haiku/fs.rs b/src/libstd/os/haiku/fs.rs index 54f8ea1b71b..453136e0ac8 100644 --- a/src/libstd/os/haiku/fs.rs +++ b/src/libstd/os/haiku/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::haiku::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/hermit/fs.rs b/src/libstd/os/hermit/fs.rs new file mode 100644 index 00000000000..d2e751668a6 --- /dev/null +++ b/src/libstd/os/hermit/fs.rs @@ -0,0 +1,389 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![stable(feature = "metadata_ext", since = "1.1.0")] + +use libc; + +use fs::Metadata; +use sys_common::AsInner; + +#[allow(deprecated)] +use os::hermit::raw; + +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub trait MetadataExt { + /// Gain a reference to the underlying `stat` structure which contains + /// the raw information returned by the OS. + /// + /// The contents of the returned [`stat`] are **not** consistent across + /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the + /// cross-Unix abstractions contained within the raw stat. + /// + /// [`stat`]: ../../../../std/os/linux/raw/struct.stat.html + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let stat = meta.as_raw_stat(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext", since = "1.1.0")] + #[rustc_deprecated(since = "1.8.0", + reason = "deprecated in favor of the accessor \ + methods of this trait")] + #[allow(deprecated)] + fn as_raw_stat(&self) -> &raw::stat; + + /// Returns the device ID on which this file resides. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_dev()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_dev(&self) -> u64; + /// Returns the inode number. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ino()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ino(&self) -> u64; + /// Returns the file type and mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mode()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mode(&self) -> u32; + /// Returns the number of hard links to file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_nlink()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_nlink(&self) -> u64; + /// Returns the user ID of the file owner. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_uid()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_uid(&self) -> u32; + /// Returns the group ID of the file owner. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_gid()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_gid(&self) -> u32; + /// Returns the device ID that this file represents. Only relevant for special file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_rdev()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_rdev(&self) -> u64; + /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes. + /// + /// The size of a symbolic link is the length of the pathname it contains, + /// without a terminating null byte. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_size()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_size(&self) -> u64; + /// Returns the last access time. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_atime()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime(&self) -> i64; + /// Returns the last access time, nano seconds part. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_atime_nsec()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime_nsec(&self) -> i64; + /// Returns the last modification time. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mtime()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime(&self) -> i64; + /// Returns the last modification time, nano seconds part. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mtime_nsec()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime_nsec(&self) -> i64; + /// Returns the last status change time. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ctime()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime(&self) -> i64; + /// Returns the last status change time, nano seconds part. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ctime_nsec()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime_nsec(&self) -> i64; + /// Returns the "preferred" blocksize for efficient filesystem I/O. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_blksize()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blksize(&self) -> u64; + /// Returns the number of blocks allocated to the file, 512-byte units. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_blocks()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blocks(&self) -> u64; +} + +#[stable(feature = "metadata_ext", since = "1.1.0")] +impl MetadataExt for Metadata { + #[allow(deprecated)] + fn as_raw_stat(&self) -> &raw::stat { + unsafe { + &*(self.as_inner().as_inner() as *const libc::stat64 + as *const raw::stat) + } + } + fn st_dev(&self) -> u64 { + self.as_inner().as_inner().st_dev as u64 + } + fn st_ino(&self) -> u64 { + self.as_inner().as_inner().st_ino as u64 + } + fn st_mode(&self) -> u32 { + self.as_inner().as_inner().st_mode as u32 + } + fn st_nlink(&self) -> u64 { + self.as_inner().as_inner().st_nlink as u64 + } + fn st_uid(&self) -> u32 { + self.as_inner().as_inner().st_uid as u32 + } + fn st_gid(&self) -> u32 { + self.as_inner().as_inner().st_gid as u32 + } + fn st_rdev(&self) -> u64 { + self.as_inner().as_inner().st_rdev as u64 + } + fn st_size(&self) -> u64 { + self.as_inner().as_inner().st_size as u64 + } + fn st_atime(&self) -> i64 { + self.as_inner().as_inner().st_atime as i64 + } + fn st_atime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_atime_nsec as i64 + } + fn st_mtime(&self) -> i64 { + self.as_inner().as_inner().st_mtime as i64 + } + fn st_mtime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_mtime_nsec as i64 + } + fn st_ctime(&self) -> i64 { + self.as_inner().as_inner().st_ctime as i64 + } + fn st_ctime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_ctime_nsec as i64 + } + fn st_blksize(&self) -> u64 { + self.as_inner().as_inner().st_blksize as u64 + } + fn st_blocks(&self) -> u64 { + self.as_inner().as_inner().st_blocks as u64 + } +} diff --git a/src/libstd/os/hermit/mod.rs b/src/libstd/os/hermit/mod.rs new file mode 100644 index 00000000000..fcb22cdad64 --- /dev/null +++ b/src/libstd/os/hermit/mod.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! HermitCore-specific definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] + +pub mod raw; +pub mod fs; diff --git a/src/libstd/os/hermit/raw.rs b/src/libstd/os/hermit/raw.rs new file mode 100644 index 00000000000..282afe0b6e1 --- /dev/null +++ b/src/libstd/os/hermit/raw.rs @@ -0,0 +1,27 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! HermitCore-specific raw type definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] +#![rustc_deprecated(since = "1.8.0", + reason = "these type aliases are no longer supported by \ + the standard library, the `libc` crate on \ + crates.io should be used instead for the correct \ + definitions")] +#![allow(deprecated)] +#![allow(missing_debug_implementations)] + +#[stable(feature = "pthread_t", since = "1.8.0")] +pub use libc::pthread_t; + +#[doc(inline)] +#[stable(feature = "raw_ext", since = "1.1.0")] +pub use libc::{dev_t, mode_t, off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; diff --git a/src/libstd/os/ios/fs.rs b/src/libstd/os/ios/fs.rs index 275daf3d3a0..296ce69ff43 100644 --- a/src/libstd/os/ios/fs.rs +++ b/src/libstd/os/ios/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::ios::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/linux/fs.rs b/src/libstd/os/linux/fs.rs index 5d37d970e89..76fb10da850 100644 --- a/src/libstd/os/linux/fs.rs +++ b/src/libstd/os/linux/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::linux::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains @@ -32,16 +34,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let stat = meta.as_raw_stat(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let stat = meta.as_raw_stat(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] #[rustc_deprecated(since = "1.8.0", @@ -54,16 +56,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_dev()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_dev()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_dev(&self) -> u64; @@ -71,16 +73,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_ino()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ino()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_ino(&self) -> u64; @@ -88,16 +90,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_mode()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mode()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_mode(&self) -> u32; @@ -105,16 +107,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_nlink()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_nlink()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_nlink(&self) -> u64; @@ -122,16 +124,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_uid()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_uid()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_uid(&self) -> u32; @@ -139,16 +141,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_gid()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_gid()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_gid(&self) -> u32; @@ -156,16 +158,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_rdev()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_rdev()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_rdev(&self) -> u64; @@ -176,16 +178,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_size()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_size()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_size(&self) -> u64; @@ -193,16 +195,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_atime()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_atime()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_atime(&self) -> i64; @@ -210,16 +212,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_atime_nsec()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_atime_nsec()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_atime_nsec(&self) -> i64; @@ -227,16 +229,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_mtime()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mtime()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_mtime(&self) -> i64; @@ -244,16 +246,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_mtime_nsec()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mtime_nsec()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_mtime_nsec(&self) -> i64; @@ -261,16 +263,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_ctime()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ctime()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_ctime(&self) -> i64; @@ -278,16 +280,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_ctime_nsec()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ctime_nsec()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_ctime_nsec(&self) -> i64; @@ -295,16 +297,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_blksize()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_blksize()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_blksize(&self) -> u64; @@ -312,16 +314,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_blocks()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_blocks()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_blocks(&self) -> u64; diff --git a/src/libstd/os/macos/fs.rs b/src/libstd/os/macos/fs.rs index 12b44901d03..0b14c05cb55 100644 --- a/src/libstd/os/macos/fs.rs +++ b/src/libstd/os/macos/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::macos::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs index ac7809451d1..c384ec9168a 100644 --- a/src/libstd/os/mod.rs +++ b/src/libstd/os/mod.rs @@ -47,6 +47,7 @@ cfg_if! { #[cfg(target_os = "solaris")] pub mod solaris; #[cfg(target_os = "emscripten")] pub mod emscripten; #[cfg(target_os = "fuchsia")] pub mod fuchsia; + #[cfg(target_os = "hermit")] pub mod hermit; #[cfg(any(target_os = "redox", unix))] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/os/netbsd/fs.rs b/src/libstd/os/netbsd/fs.rs index cd7d5fafd1c..e9cad33fee6 100644 --- a/src/libstd/os/netbsd/fs.rs +++ b/src/libstd/os/netbsd/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::netbsd::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/openbsd/fs.rs b/src/libstd/os/openbsd/fs.rs index cc812fcf12c..0f6b83b6e32 100644 --- a/src/libstd/os/openbsd/fs.rs +++ b/src/libstd/os/openbsd/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::openbsd::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/raw/char.md b/src/libstd/os/raw/char.md new file mode 100644 index 00000000000..9a55767d965 --- /dev/null +++ b/src/libstd/os/raw/char.md @@ -0,0 +1,11 @@ +Equivalent to C's `char` type. + +[C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. This type will always be either [`i8`] or [`u8`], as the type is defined as being one byte long. + +C chars are most commonly used to make C strings. Unlike Rust, where the length of a string is included alongside the string, C strings mark the end of a string with the character `'\0'`. See [`CStr`] for more information. + +[C's `char` type]: https://en.wikipedia.org/wiki/C_data_types#Basic_types +[Rust's `char` type]: ../../primitive.char.html +[`CStr`]: ../../ffi/struct.CStr.html +[`i8`]: ../../primitive.i8.html +[`u8`]: ../../primitive.u8.html diff --git a/src/libstd/os/raw/double.md b/src/libstd/os/raw/double.md new file mode 100644 index 00000000000..6818dada317 --- /dev/null +++ b/src/libstd/os/raw/double.md @@ -0,0 +1,7 @@ +Equivalent to C's `double` type. + +This type will almost always be [`f64`], which is guaranteed to be an [IEEE-754 double-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number with at least the precision of a [`float`], and it may be `f32` or something entirely different from the IEEE-754 standard. + +[IEEE-754 double-precision float]: https://en.wikipedia.org/wiki/IEEE_754 +[`float`]: type.c_float.html +[`f64`]: ../../primitive.f64.html diff --git a/src/libstd/os/raw/float.md b/src/libstd/os/raw/float.md new file mode 100644 index 00000000000..57d1071d0da --- /dev/null +++ b/src/libstd/os/raw/float.md @@ -0,0 +1,6 @@ +Equivalent to C's `float` type. + +This type will almost always be [`f32`], which is guaranteed to be an [IEEE-754 single-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number, and it may have less precision than `f32` or not follow the IEEE-754 standard at all. + +[IEEE-754 single-precision float]: https://en.wikipedia.org/wiki/IEEE_754 +[`f32`]: ../../primitive.f32.html diff --git a/src/libstd/os/raw/int.md b/src/libstd/os/raw/int.md new file mode 100644 index 00000000000..a0d25fd21d8 --- /dev/null +++ b/src/libstd/os/raw/int.md @@ -0,0 +1,7 @@ +Equivalent to C's `signed int` (`int`) type. + +This type will almost always be [`i32`], but may differ on some esoteric systems. The C standard technically only requires that this type be a signed integer that is at least the size of a [`short`]; some systems define it as an [`i16`], for example. + +[`short`]: type.c_short.html +[`i32`]: ../../primitive.i32.html +[`i16`]: ../../primitive.i16.html diff --git a/src/libstd/os/raw/long.md b/src/libstd/os/raw/long.md new file mode 100644 index 00000000000..c620b402819 --- /dev/null +++ b/src/libstd/os/raw/long.md @@ -0,0 +1,7 @@ +Equivalent to C's `signed long` (`long`) type. + +This type will always be [`i32`] or [`i64`]. Most notably, many Linux-based systems assume an `i64`, but Windows assumes `i32`. The C standard technically only requires that this type be a signed integer that is at least 32 bits and at least the size of an [`int`], although in practice, no system would have a `long` that is neither an `i32` nor `i64`. + +[`int`]: type.c_int.html +[`i32`]: ../../primitive.i32.html +[`i64`]: ../../primitive.i64.html diff --git a/src/libstd/os/raw/longlong.md b/src/libstd/os/raw/longlong.md new file mode 100644 index 00000000000..ab3d6436568 --- /dev/null +++ b/src/libstd/os/raw/longlong.md @@ -0,0 +1,7 @@ +Equivalent to C's `signed long long` (`long long`) type. + +This type will almost always be [`i64`], but may differ on some systems. The C standard technically only requires that this type be a signed integer that is at least 64 bits and at least the size of a [`long`], although in practice, no system would have a `long long` that is not an `i64`, as most systems do not have a standardised [`i128`] type. + +[`long`]: type.c_int.html +[`i64`]: ../../primitive.i64.html +[`i128`]: ../../primitive.i128.html diff --git a/src/libstd/os/raw.rs b/src/libstd/os/raw/mod.rs index 279caf8053a..dc33747c05b 100644 --- a/src/libstd/os/raw.rs +++ b/src/libstd/os/raw/mod.rs @@ -8,12 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Raw OS-specific types for the current platform/architecture +//! Platform-specific types, as defined by C. +//! +//! Code that interacts via FFI will almost certainly be using the +//! base types provided by C, which aren't nearly as nicely defined +//! as Rust's primitive types. This module provides types which will +//! match those defined by C, so that code that interacts with C will +//! refer to the correct types. #![stable(feature = "raw_os", since = "1.1.0")] use fmt; +#[doc(include = "os/raw/char.md")] #[cfg(any(all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc", @@ -22,9 +29,13 @@ use fmt; all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), all(target_os = "l4re", target_arch = "x86_64"), + all(target_os = "netbsd", any(target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc")), all(target_os = "openbsd", target_arch = "aarch64"), all(target_os = "fuchsia", target_arch = "aarch64")))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8; +#[doc(include = "os/raw/char.md")] #[cfg(not(any(all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc", @@ -33,33 +44,56 @@ use fmt; all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), all(target_os = "l4re", target_arch = "x86_64"), + all(target_os = "netbsd", any(target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc")), all(target_os = "openbsd", target_arch = "aarch64"), all(target_os = "fuchsia", target_arch = "aarch64"))))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8; +#[doc(include = "os/raw/schar.md")] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8; +#[doc(include = "os/raw/uchar.md")] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8; +#[doc(include = "os/raw/short.md")] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_short = i16; +#[doc(include = "os/raw/ushort.md")] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ushort = u16; +#[doc(include = "os/raw/int.md")] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_int = i32; +#[doc(include = "os/raw/uint.md")] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_uint = u32; +#[doc(include = "os/raw/long.md")] #[cfg(any(target_pointer_width = "32", windows))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i32; +#[doc(include = "os/raw/ulong.md")] #[cfg(any(target_pointer_width = "32", windows))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u32; +#[doc(include = "os/raw/long.md")] #[cfg(all(target_pointer_width = "64", not(windows)))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i64; +#[doc(include = "os/raw/ulong.md")] #[cfg(all(target_pointer_width = "64", not(windows)))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u64; +#[doc(include = "os/raw/longlong.md")] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_longlong = i64; +#[doc(include = "os/raw/ulonglong.md")] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulonglong = u64; +#[doc(include = "os/raw/float.md")] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_float = f32; +#[doc(include = "os/raw/double.md")] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_double = f64; -/// Type used to construct void pointers for use with C. +/// Equivalent to C's `void` type when used as a [pointer]. /// -/// This type is only useful as a pointer target. Do not use it as a -/// return type for FFI functions which have the `void` return type in -/// C. Use the unit type `()` or omit the return type instead. +/// In essence, `*const c_void` is equivalent to C's `const void*` +/// and `*mut c_void` is equivalent to C's `void*`. That said, this is +/// *not* the same as C's `void` return type, which is Rust's `()` type. +/// +/// Ideally, this type would be equivalent to [`!`], but currently it may +/// be more ideal to use `c_void` for FFI purposes. +/// +/// [`!`]: ../../primitive.never.html +/// [pointer]: ../../primitive.pointer.html // NB: For LLVM to recognize the void pointer type and by extension // functions like malloc(), we need to have it represented as i8* in // LLVM bitcode. The enum used here ensures this and prevents misuse diff --git a/src/libstd/os/raw/schar.md b/src/libstd/os/raw/schar.md new file mode 100644 index 00000000000..6aa8b1211d8 --- /dev/null +++ b/src/libstd/os/raw/schar.md @@ -0,0 +1,6 @@ +Equivalent to C's `signed char` type. + +This type will always be [`i8`], but is included for completeness. It is defined as being a signed integer the same size as a C [`char`]. + +[`char`]: type.c_char.html +[`i8`]: ../../primitive.i8.html diff --git a/src/libstd/os/raw/short.md b/src/libstd/os/raw/short.md new file mode 100644 index 00000000000..be92c6c106d --- /dev/null +++ b/src/libstd/os/raw/short.md @@ -0,0 +1,6 @@ +Equivalent to C's `signed short` (`short`) type. + +This type will almost always be [`i16`], but may differ on some esoteric systems. The C standard technically only requires that this type be a signed integer with at least 16 bits; some systems may define it as `i32`, for example. + +[`char`]: type.c_char.html +[`i16`]: ../../primitive.i16.html diff --git a/src/libstd/os/raw/uchar.md b/src/libstd/os/raw/uchar.md new file mode 100644 index 00000000000..b6ca711f869 --- /dev/null +++ b/src/libstd/os/raw/uchar.md @@ -0,0 +1,6 @@ +Equivalent to C's `unsigned char` type. + +This type will always be [`u8`], but is included for completeness. It is defined as being an unsigned integer the same size as a C [`char`]. + +[`char`]: type.c_char.html +[`u8`]: ../../primitive.u8.html diff --git a/src/libstd/os/raw/uint.md b/src/libstd/os/raw/uint.md new file mode 100644 index 00000000000..6f7013a8ac1 --- /dev/null +++ b/src/libstd/os/raw/uint.md @@ -0,0 +1,7 @@ +Equivalent to C's `unsigned int` type. + +This type will almost always be [`u32`], but may differ on some esoteric systems. The C standard technically only requires that this type be an unsigned integer with the same size as an [`int`]; some systems define it as a [`u16`], for example. + +[`int`]: type.c_int.html +[`u32`]: ../../primitive.u32.html +[`u16`]: ../../primitive.u16.html diff --git a/src/libstd/os/raw/ulong.md b/src/libstd/os/raw/ulong.md new file mode 100644 index 00000000000..c350395080e --- /dev/null +++ b/src/libstd/os/raw/ulong.md @@ -0,0 +1,7 @@ +Equivalent to C's `unsigned long` type. + +This type will always be [`u32`] or [`u64`]. Most notably, many Linux-based systems assume an `u64`, but Windows assumes `u32`. The C standard technically only requires that this type be an unsigned integer with the size of a [`long`], although in practice, no system would have a `ulong` that is neither a `u32` nor `u64`. + +[`long`]: type.c_long.html +[`u32`]: ../../primitive.u32.html +[`u64`]: ../../primitive.u64.html diff --git a/src/libstd/os/raw/ulonglong.md b/src/libstd/os/raw/ulonglong.md new file mode 100644 index 00000000000..c41faf74c5c --- /dev/null +++ b/src/libstd/os/raw/ulonglong.md @@ -0,0 +1,7 @@ +Equivalent to C's `unsigned long long` type. + +This type will almost always be [`u64`], but may differ on some systems. The C standard technically only requires that this type be an unsigned integer with the size of a [`long long`], although in practice, no system would have a `long long` that is not a `u64`, as most systems do not have a standardised [`u128`] type. + +[`long long`]: type.c_longlong.html +[`u64`]: ../../primitive.u64.html +[`u128`]: ../../primitive.u128.html diff --git a/src/libstd/os/raw/ushort.md b/src/libstd/os/raw/ushort.md new file mode 100644 index 00000000000..d364abb3c8e --- /dev/null +++ b/src/libstd/os/raw/ushort.md @@ -0,0 +1,6 @@ +Equivalent to C's `unsigned short` type. + +This type will almost always be [`u16`], but may differ on some esoteric systems. The C standard technically only requires that this type be an unsigned integer with the same size as a [`short`]. + +[`short`]: type.c_short.html +[`u16`]: ../../primitive.u16.html diff --git a/src/libstd/os/solaris/fs.rs b/src/libstd/os/solaris/fs.rs index 5dc43d03a86..19dce1ba34c 100644 --- a/src/libstd/os/solaris/fs.rs +++ b/src/libstd/os/solaris/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::solaris::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 53c2211745c..b8c1c4f9e68 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -15,23 +15,33 @@ use any::Any; use cell::UnsafeCell; use fmt; +use future::Future; +use mem::PinMut; use ops::{Deref, DerefMut}; use panicking; -use ptr::{Unique, Shared}; +use ptr::{Unique, NonNull}; use rc::Rc; use sync::{Arc, Mutex, RwLock, atomic}; +use task::{self, Poll}; use thread::Result; #[stable(feature = "panic_hooks", since = "1.10.0")] -pub use panicking::{take_hook, set_hook, PanicInfo, Location}; +pub use panicking::{take_hook, set_hook}; + +#[stable(feature = "panic_hooks", since = "1.10.0")] +pub use core::panic::{PanicInfo, Location}; /// A marker trait which represents "panic safe" types in Rust. /// /// This trait is implemented by default for many types and behaves similarly in -/// terms of inference of implementation to the `Send` and `Sync` traits. The -/// purpose of this trait is to encode what types are safe to cross a `catch_unwind` +/// terms of inference of implementation to the [`Send`] and [`Sync`] traits. The +/// purpose of this trait is to encode what types are safe to cross a [`catch_unwind`] /// boundary with no fear of unwind safety. /// +/// [`Send`]: ../marker/trait.Send.html +/// [`Sync`]: ../marker/trait.Sync.html +/// [`catch_unwind`]: ./fn.catch_unwind.html +/// /// ## What is unwind safety? /// /// In Rust a function can "return" early if it either panics or calls a @@ -92,41 +102,51 @@ pub use panicking::{take_hook, set_hook, PanicInfo, Location}; /// /// ## When should `UnwindSafe` be used? /// -/// Is not intended that most types or functions need to worry about this trait. -/// It is only used as a bound on the `catch_unwind` function and as mentioned above, -/// the lack of `unsafe` means it is mostly an advisory. The `AssertUnwindSafe` -/// wrapper struct in this module can be used to force this trait to be -/// implemented for any closed over variables passed to the `catch_unwind` function -/// (more on this below). +/// It is not intended that most types or functions need to worry about this trait. +/// It is only used as a bound on the `catch_unwind` function and as mentioned +/// above, the lack of `unsafe` means it is mostly an advisory. The +/// [`AssertUnwindSafe`] wrapper struct can be used to force this trait to be +/// implemented for any closed over variables passed to `catch_unwind`. +/// +/// [`AssertUnwindSafe`]: ./struct.AssertUnwindSafe.html #[stable(feature = "catch_unwind", since = "1.9.0")] -#[rustc_on_unimplemented = "the type {Self} may not be safely transferred \ - across an unwind boundary"] +#[rustc_on_unimplemented( + message="the type `{Self}` may not be safely transferred across an unwind boundary", + label="`{Self}` may not be safely transferred across an unwind boundary", +)] pub auto trait UnwindSafe {} /// A marker trait representing types where a shared reference is considered /// unwind safe. /// -/// This trait is namely not implemented by `UnsafeCell`, the root of all +/// This trait is namely not implemented by [`UnsafeCell`], the root of all /// interior mutability. /// /// This is a "helper marker trait" used to provide impl blocks for the -/// `UnwindSafe` trait, for more information see that documentation. +/// [`UnwindSafe`] trait, for more information see that documentation. +/// +/// [`UnsafeCell`]: ../cell/struct.UnsafeCell.html +/// [`UnwindSafe`]: ./trait.UnwindSafe.html #[stable(feature = "catch_unwind", since = "1.9.0")] -#[rustc_on_unimplemented = "the type {Self} may contain interior mutability \ - and a reference may not be safely transferrable \ - across a catch_unwind boundary"] +#[rustc_on_unimplemented( + message="the type `{Self}` may contain interior mutability and a reference may not be safely \ + transferrable across a catch_unwind boundary", + label="`{Self}` may contain interior mutability and a reference may not be safely \ + transferrable across a catch_unwind boundary", +)] pub auto trait RefUnwindSafe {} /// A simple wrapper around a type to assert that it is unwind safe. /// -/// When using `catch_unwind` it may be the case that some of the closed over +/// When using [`catch_unwind`] it may be the case that some of the closed over /// variables are not unwind safe. For example if `&mut T` is captured the /// compiler will generate a warning indicating that it is not unwind safe. It /// may not be the case, however, that this is actually a problem due to the -/// specific usage of `catch_unwind` if unwind safety is specifically taken into +/// specific usage of [`catch_unwind`] if unwind safety is specifically taken into /// account. This wrapper struct is useful for a quick and lightweight /// annotation that a variable is indeed unwind safe. /// +/// [`catch_unwind`]: ./fn.catch_unwind.html /// # Examples /// /// One way to use `AssertUnwindSafe` is to assert that the entire closure @@ -185,7 +205,7 @@ pub struct AssertUnwindSafe<T>( // * By default everything is unwind safe // * pointers T contains mutability of some form are not unwind safe // * Unique, an owning pointer, lifts an implementation -// * Types like Mutex/RwLock which are explicilty poisoned are unwind safe +// * Types like Mutex/RwLock which are explicitly poisoned are unwind safe // * Our custom AssertUnwindSafe wrapper is indeed unwind safe #[stable(feature = "catch_unwind", since = "1.9.0")] @@ -196,10 +216,10 @@ impl<'a, T: RefUnwindSafe + ?Sized> UnwindSafe for &'a T {} impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *const T {} #[stable(feature = "catch_unwind", since = "1.9.0")] impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *mut T {} -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl<T: UnwindSafe + ?Sized> UnwindSafe for Unique<T> {} -#[unstable(feature = "shared", issue = "27730")] -impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Shared<T> {} +#[stable(feature = "nonnull", since = "1.25.0")] +impl<T: RefUnwindSafe + ?Sized> UnwindSafe for NonNull<T> {} #[stable(feature = "catch_unwind", since = "1.9.0")] impl<T: ?Sized> UnwindSafe for Mutex<T> {} #[stable(feature = "catch_unwind", since = "1.9.0")] @@ -303,6 +323,16 @@ impl<T: fmt::Debug> fmt::Debug for AssertUnwindSafe<T> { } } +#[unstable(feature = "futures_api", issue = "50547")] +impl<'a, F: Future> Future for AssertUnwindSafe<F> { + type Output = F::Output; + + fn poll(self: PinMut<Self>, cx: &mut task::Context) -> Poll<Self::Output> { + let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) }; + pinned_field.poll(cx) + } +} + /// Invokes a closure, capturing the cause of an unwinding panic if one occurs. /// /// This function will return `Ok` with the closure's result if the closure @@ -315,18 +345,22 @@ impl<T: fmt::Debug> fmt::Debug for AssertUnwindSafe<T> { /// panic and allowing a graceful handling of the error. /// /// It is **not** recommended to use this function for a general try/catch -/// mechanism. The `Result` type is more appropriate to use for functions that +/// mechanism. The [`Result`] type is more appropriate to use for functions that /// can fail on a regular basis. Additionally, this function is not guaranteed /// to catch all panics, see the "Notes" section below. /// -/// The closure provided is required to adhere to the `UnwindSafe` trait to ensure +/// [`Result`]: ../result/enum.Result.html +/// +/// The closure provided is required to adhere to the [`UnwindSafe`] trait to ensure /// that all captured variables are safe to cross this boundary. The purpose of /// this bound is to encode the concept of [exception safety][rfc] in the type /// system. Most usage of this function should not need to worry about this /// bound as programs are naturally unwind safe without `unsafe` code. If it -/// becomes a problem the associated `AssertUnwindSafe` wrapper type in this -/// module can be used to quickly assert that the usage here is indeed unwind -/// safe. +/// becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to quickly +/// assert that the usage here is indeed unwind safe. +/// +/// [`AssertUnwindSafe`]: ./struct.AssertUnwindSafe.html +/// [`UnwindSafe`]: ./trait.UnwindSafe.html /// /// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md /// @@ -361,9 +395,11 @@ pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> { /// Triggers a panic without invoking the panic hook. /// -/// This is designed to be used in conjunction with `catch_unwind` to, for +/// This is designed to be used in conjunction with [`catch_unwind`] to, for /// example, carry a panic across a layer of C code. /// +/// [`catch_unwind`]: ./fn.catch_unwind.html +/// /// # Notes /// /// Note that panics in Rust are not always implemented via unwinding, but they @@ -385,6 +421,6 @@ pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> { /// } /// ``` #[stable(feature = "resume_unwind", since = "1.9.0")] -pub fn resume_unwind(payload: Box<Any + Send>) -> ! { +pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! { panicking::update_count_then_panic(payload) } diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index f91eaf433d7..283fd36af41 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -17,23 +17,26 @@ //! * Executing a panic up to doing the actual implementation //! * Shims around "try" +use core::panic::BoxMeUp; + use io::prelude::*; use any::Any; use cell::RefCell; +use core::panic::{PanicInfo, Location}; use fmt; use intrinsics; use mem; use ptr; use raw; -use sys::stdio::Stderr; +use sys::stdio::{Stderr, stderr_prints_nothing}; use sys_common::rwlock::RWLock; use sys_common::thread_info; use sys_common::util; use thread; thread_local! { - pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = { + pub static LOCAL_STDERR: RefCell<Option<Box<dyn Write + Send>>> = { RefCell::new(None) } } @@ -54,14 +57,14 @@ extern { data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32; - #[unwind] - fn __rust_start_panic(data: usize, vtable: usize) -> u32; + #[unwind(allowed)] + fn __rust_start_panic(payload: usize) -> u32; } #[derive(Copy, Clone)] enum Hook { Default, - Custom(*mut (Fn(&PanicInfo) + 'static + Sync + Send)), + Custom(*mut (dyn Fn(&PanicInfo) + 'static + Sync + Send)), } static HOOK_LOCK: RWLock = RWLock::new(); @@ -73,7 +76,9 @@ static mut HOOK: Hook = Hook::Default; /// is invoked. As such, the hook will run with both the aborting and unwinding /// runtimes. The default hook prints a message to standard error and generates /// a backtrace if requested, but this behavior can be customized with the -/// `set_hook` and `take_hook` functions. +/// `set_hook` and [`take_hook`] functions. +/// +/// [`take_hook`]: ./fn.take_hook.html /// /// The hook is provided with a `PanicInfo` struct which contains information /// about the origin of the panic, including the payload passed to `panic!` and @@ -99,7 +104,7 @@ static mut HOOK: Hook = Hook::Default; /// panic!("Normal panic"); /// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] -pub fn set_hook(hook: Box<Fn(&PanicInfo) + 'static + Sync + Send>) { +pub fn set_hook(hook: Box<dyn Fn(&PanicInfo) + 'static + Sync + Send>) { if thread::panicking() { panic!("cannot modify the panic hook from a panicking thread"); } @@ -118,6 +123,10 @@ pub fn set_hook(hook: Box<Fn(&PanicInfo) + 'static + Sync + Send>) { /// Unregisters the current panic hook, returning it. /// +/// *See also the function [`set_hook`].* +/// +/// [`set_hook`]: ./fn.set_hook.html +/// /// If no custom hook is registered, the default hook will be returned. /// /// # Panics @@ -140,7 +149,7 @@ pub fn set_hook(hook: Box<Fn(&PanicInfo) + 'static + Sync + Send>) { /// panic!("Normal panic"); /// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] -pub fn take_hook() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> { +pub fn take_hook() -> Box<dyn Fn(&PanicInfo) + 'static + Sync + Send> { if thread::panicking() { panic!("cannot modify the panic hook from a panicking thread"); } @@ -158,182 +167,6 @@ pub fn take_hook() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> { } } -/// A struct providing information about a panic. -/// -/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`] -/// function. -/// -/// [`set_hook`]: ../../std/panic/fn.set_hook.html -/// -/// # Examples -/// -/// ```should_panic -/// use std::panic; -/// -/// panic::set_hook(Box::new(|panic_info| { -/// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap()); -/// })); -/// -/// panic!("Normal panic"); -/// ``` -#[stable(feature = "panic_hooks", since = "1.10.0")] -#[derive(Debug)] -pub struct PanicInfo<'a> { - payload: &'a (Any + Send), - location: Location<'a>, -} - -impl<'a> PanicInfo<'a> { - /// Returns the payload associated with the panic. - /// - /// This will commonly, but not always, be a `&'static str` or [`String`]. - /// - /// [`String`]: ../../std/string/struct.String.html - /// - /// # Examples - /// - /// ```should_panic - /// use std::panic; - /// - /// panic::set_hook(Box::new(|panic_info| { - /// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap()); - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[stable(feature = "panic_hooks", since = "1.10.0")] - pub fn payload(&self) -> &(Any + Send) { - self.payload - } - - /// Returns information about the location from which the panic originated, - /// if available. - /// - /// This method will currently always return [`Some`], but this may change - /// in future versions. - /// - /// [`Some`]: ../../std/option/enum.Option.html#variant.Some - /// - /// # Examples - /// - /// ```should_panic - /// use std::panic; - /// - /// panic::set_hook(Box::new(|panic_info| { - /// if let Some(location) = panic_info.location() { - /// println!("panic occurred in file '{}' at line {}", location.file(), - /// location.line()); - /// } else { - /// println!("panic occurred but can't get location information..."); - /// } - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[stable(feature = "panic_hooks", since = "1.10.0")] - pub fn location(&self) -> Option<&Location> { - Some(&self.location) - } -} - -/// A struct containing information about the location of a panic. -/// -/// This structure is created by the [`location`] method of [`PanicInfo`]. -/// -/// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location -/// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html -/// -/// # Examples -/// -/// ```should_panic -/// use std::panic; -/// -/// panic::set_hook(Box::new(|panic_info| { -/// if let Some(location) = panic_info.location() { -/// println!("panic occurred in file '{}' at line {}", location.file(), location.line()); -/// } else { -/// println!("panic occurred but can't get location information..."); -/// } -/// })); -/// -/// panic!("Normal panic"); -/// ``` -#[derive(Debug)] -#[stable(feature = "panic_hooks", since = "1.10.0")] -pub struct Location<'a> { - file: &'a str, - line: u32, - col: u32, -} - -impl<'a> Location<'a> { - /// Returns the name of the source file from which the panic originated. - /// - /// # Examples - /// - /// ```should_panic - /// use std::panic; - /// - /// panic::set_hook(Box::new(|panic_info| { - /// if let Some(location) = panic_info.location() { - /// println!("panic occurred in file '{}'", location.file()); - /// } else { - /// println!("panic occurred but can't get location information..."); - /// } - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[stable(feature = "panic_hooks", since = "1.10.0")] - pub fn file(&self) -> &str { - self.file - } - - /// Returns the line number from which the panic originated. - /// - /// # Examples - /// - /// ```should_panic - /// use std::panic; - /// - /// panic::set_hook(Box::new(|panic_info| { - /// if let Some(location) = panic_info.location() { - /// println!("panic occurred at line {}", location.line()); - /// } else { - /// println!("panic occurred but can't get location information..."); - /// } - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[stable(feature = "panic_hooks", since = "1.10.0")] - pub fn line(&self) -> u32 { - self.line - } - - /// Returns the column from which the panic originated. - /// - /// # Examples - /// - /// ```should_panic - /// use std::panic; - /// - /// panic::set_hook(Box::new(|panic_info| { - /// if let Some(location) = panic_info.location() { - /// println!("panic occurred at column {}", location.column()); - /// } else { - /// println!("panic occurred but can't get location information..."); - /// } - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[stable(feature = "panic_col", since = "1.25")] - pub fn column(&self) -> u32 { - self.col - } -} - fn default_hook(info: &PanicInfo) { #[cfg(feature = "backtrace")] use sys_common::backtrace; @@ -351,13 +184,11 @@ fn default_hook(info: &PanicInfo) { } }; - let file = info.location.file; - let line = info.location.line; - let col = info.location.col; + let location = info.location().unwrap(); // The current implementation always returns Some - let msg = match info.payload.downcast_ref::<&'static str>() { + let msg = match info.payload().downcast_ref::<&'static str>() { Some(s) => *s, - None => match info.payload.downcast_ref::<String>() { + None => match info.payload().downcast_ref::<String>() { Some(s) => &s[..], None => "Box<Any>", } @@ -366,9 +197,9 @@ fn default_hook(info: &PanicInfo) { let thread = thread_info::current_thread(); let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>"); - let write = |err: &mut ::io::Write| { - let _ = writeln!(err, "thread '{}' panicked at '{}', {}:{}:{}", - name, msg, file, line, col); + let write = |err: &mut dyn (::io::Write)| { + let _ = writeln!(err, "thread '{}' panicked at '{}', {}", + name, msg, location); #[cfg(feature = "backtrace")] { @@ -386,15 +217,15 @@ fn default_hook(info: &PanicInfo) { let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take()); match (prev, err.as_mut()) { - (Some(mut stderr), _) => { - write(&mut *stderr); - let mut s = Some(stderr); - LOCAL_STDERR.with(|slot| { - *slot.borrow_mut() = s.take(); - }); - } - (None, Some(ref mut err)) => { write(err) } - _ => {} + (Some(mut stderr), _) => { + write(&mut *stderr); + let mut s = Some(stderr); + LOCAL_STDERR.with(|slot| { + *slot.borrow_mut() = s.take(); + }); + } + (None, Some(ref mut err)) => { write(err) } + _ => {} } } @@ -417,7 +248,7 @@ pub fn update_panic_count(amt: isize) -> usize { pub use realstd::rt::update_panic_count; /// Invoke a closure, capturing the cause of an unwinding panic if one occurs. -pub unsafe fn try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<Any + Send>> { +pub unsafe fn try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> { #[allow(unions_with_drop_fields)] union Data<F, R> { f: F, @@ -488,13 +319,10 @@ pub fn panicking() -> bool { /// Entry point of panic from the libcore crate. #[cfg(not(test))] -#[lang = "panic_fmt"] -#[unwind] -pub extern fn rust_begin_panic(msg: fmt::Arguments, - file: &'static str, - line: u32, - col: u32) -> ! { - begin_panic_fmt(&msg, &(file, line, col)) +#[panic_implementation] +#[unwind(allowed)] +pub fn rust_begin_panic(info: &PanicInfo) -> ! { + continue_panic_fmt(&info) } /// The entry point for panicking with a formatted message. @@ -509,16 +337,60 @@ pub extern fn rust_begin_panic(msg: fmt::Arguments, #[inline(never)] #[cold] pub fn begin_panic_fmt(msg: &fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { - use fmt::Write; + let (file, line, col) = *file_line_col; + let info = PanicInfo::internal_constructor( + Some(msg), + Location::internal_constructor(file, line, col), + ); + continue_panic_fmt(&info) +} + +fn continue_panic_fmt(info: &PanicInfo) -> ! { + struct PanicPayload<'a> { + inner: &'a fmt::Arguments<'a>, + string: Option<String>, + } + + impl<'a> PanicPayload<'a> { + fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> { + PanicPayload { inner, string: None } + } + + fn fill(&mut self) -> &mut String { + use fmt::Write; + + let inner = self.inner; + self.string.get_or_insert_with(|| { + let mut s = String::new(); + drop(s.write_fmt(*inner)); + s + }) + } + } + + unsafe impl<'a> BoxMeUp for PanicPayload<'a> { + fn box_me_up(&mut self) -> *mut (dyn Any + Send) { + let contents = mem::replace(self.fill(), String::new()); + Box::into_raw(Box::new(contents)) + } + + fn get(&mut self) -> &(dyn Any + Send) { + self.fill() + } + } // We do two allocations here, unfortunately. But (a) they're // required with the current scheme, and (b) we don't handle // panic + OOM properly anyway (see comment in begin_panic // below). - let mut s = String::new(); - let _ = s.write_fmt(*msg); - begin_panic(s, file_line_col) + let loc = info.location().unwrap(); // The current implementation always returns Some + let msg = info.message().unwrap(); // The current implementation always returns Some + let file_line_col = (loc.file(), loc.line(), loc.column()); + rust_panic_with_hook( + &mut PanicPayload::new(msg), + info.message(), + &file_line_col); } /// This is the entry point of panicking for panic!() and assert!(). @@ -534,19 +406,44 @@ pub fn begin_panic<M: Any + Send>(msg: M, file_line_col: &(&'static str, u32, u3 // be performed in the parent of this thread instead of the thread that's // panicking. - rust_panic_with_hook(Box::new(msg), file_line_col) + rust_panic_with_hook(&mut PanicPayload::new(msg), None, file_line_col); + + struct PanicPayload<A> { + inner: Option<A>, + } + + impl<A: Send + 'static> PanicPayload<A> { + fn new(inner: A) -> PanicPayload<A> { + PanicPayload { inner: Some(inner) } + } + } + + unsafe impl<A: Send + 'static> BoxMeUp for PanicPayload<A> { + fn box_me_up(&mut self) -> *mut (dyn Any + Send) { + let data = match self.inner.take() { + Some(a) => Box::new(a) as Box<dyn Any + Send>, + None => Box::new(()), + }; + Box::into_raw(data) + } + + fn get(&mut self) -> &(dyn Any + Send) { + match self.inner { + Some(ref a) => a, + None => &(), + } + } + } } -/// Executes the primary logic for a panic, including checking for recursive -/// panics and panic hooks. +/// Central point for dispatching panics. /// -/// This is the entry point or panics from libcore, formatted panics, and -/// `Box<Any>` panics. Here we'll verify that we're not panicking recursively, -/// run panic hooks, and then delegate to the actual implementation of panics. -#[inline(never)] -#[cold] -fn rust_panic_with_hook(msg: Box<Any + Send>, - file_line_col: &(&'static str, u32, u32)) -> ! { +/// Executes the primary logic for a panic, including checking for recursive +/// panics, panic hooks, and finally dispatching to the panic runtime to either +/// abort or unwind. +fn rust_panic_with_hook(payload: &mut dyn BoxMeUp, + message: Option<&fmt::Arguments>, + file_line_col: &(&str, u32, u32)) -> ! { let (file, line, col) = *file_line_col; let panics = update_panic_count(1); @@ -563,18 +460,24 @@ fn rust_panic_with_hook(msg: Box<Any + Send>, } unsafe { - let info = PanicInfo { - payload: &*msg, - location: Location { - file, - line, - col, - }, - }; + let mut info = PanicInfo::internal_constructor( + message, + Location::internal_constructor(file, line, col), + ); HOOK_LOCK.read(); match HOOK { - Hook::Default => default_hook(&info), - Hook::Custom(ptr) => (*ptr)(&info), + // Some platforms know that printing to stderr won't ever actually + // print anything, and if that's the case we can skip the default + // hook. + Hook::Default if stderr_prints_nothing() => {} + Hook::Default => { + info.set_payload(payload.get()); + default_hook(&info); + } + Hook::Custom(ptr) => { + info.set_payload(payload.get()); + (*ptr)(&info); + } } HOOK_LOCK.read_unlock(); } @@ -589,22 +492,35 @@ fn rust_panic_with_hook(msg: Box<Any + Send>, unsafe { intrinsics::abort() } } - rust_panic(msg) + rust_panic(payload) } /// Shim around rust_panic. Called by resume_unwind. -pub fn update_count_then_panic(msg: Box<Any + Send>) -> ! { +pub fn update_count_then_panic(msg: Box<dyn Any + Send>) -> ! { update_panic_count(1); - rust_panic(msg) + + struct RewrapBox(Box<dyn Any + Send>); + + unsafe impl BoxMeUp for RewrapBox { + fn box_me_up(&mut self) -> *mut (dyn Any + Send) { + Box::into_raw(mem::replace(&mut self.0, Box::new(()))) + } + + fn get(&mut self) -> &(dyn Any + Send) { + &*self.0 + } + } + + rust_panic(&mut RewrapBox(msg)) } /// A private no-mangle function on which to slap yer breakpoints. #[no_mangle] #[allow(private_no_mangle_fns)] // yes we get it, but we like breakpoints -pub fn rust_panic(msg: Box<Any + Send>) -> ! { +pub fn rust_panic(mut msg: &mut dyn BoxMeUp) -> ! { let code = unsafe { - let obj = mem::transmute::<_, raw::TraitObject>(msg); - __rust_start_panic(obj.data as usize, obj.vtable as usize) + let obj = &mut msg as *mut &mut dyn BoxMeUp; + __rust_start_panic(obj as usize) }; rtabort!("failed to initiate panic, error {}", code) } diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 7631a9a44bb..ca8be75fab5 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -297,10 +297,9 @@ pub const MAIN_SEPARATOR: char = ::sys::path::MAIN_SEP; // Iterate through `iter` while it matches `prefix`; return `None` if `prefix` // is not a prefix of `iter`, otherwise return `Some(iter_after_prefix)` giving // `iter` after having exhausted `prefix`. -fn iter_after<A, I, J>(mut iter: I, mut prefix: J) -> Option<I> - where I: Iterator<Item = A> + Clone, - J: Iterator<Item = A>, - A: PartialEq +fn iter_after<'a, 'b, I, J>(mut iter: I, mut prefix: J) -> Option<I> + where I: Iterator<Item = Component<'a>> + Clone, + J: Iterator<Item = Component<'b>>, { loop { let mut iter_next = iter.clone(); @@ -576,7 +575,7 @@ impl<'a> AsRef<OsStr> for Component<'a> { } } -#[stable(feature = "path_component_asref", since = "1.24.0")] +#[stable(feature = "path_component_asref", since = "1.25.0")] impl<'a> AsRef<Path> for Component<'a> { fn as_ref(&self) -> &Path { self.as_os_str().as_ref() @@ -905,7 +904,7 @@ impl<'a> DoubleEndedIterator for Iter<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for Iter<'a> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1008,7 +1007,7 @@ impl<'a> DoubleEndedIterator for Components<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for Components<'a> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1035,6 +1034,45 @@ impl<'a> cmp::Ord for Components<'a> { } } +/// An iterator over [`Path`] and its ancestors. +/// +/// This `struct` is created by the [`ancestors`] method on [`Path`]. +/// See its documentation for more. +/// +/// # Examples +/// +/// ``` +/// use std::path::Path; +/// +/// let path = Path::new("/foo/bar"); +/// +/// for ancestor in path.ancestors() { +/// println!("{}", ancestor.display()); +/// } +/// ``` +/// +/// [`ancestors`]: struct.Path.html#method.ancestors +/// [`Path`]: struct.Path.html +#[derive(Copy, Clone, Debug)] +#[stable(feature = "path_ancestors", since = "1.28.0")] +pub struct Ancestors<'a> { + next: Option<&'a Path>, +} + +#[stable(feature = "path_ancestors", since = "1.28.0")] +impl<'a> Iterator for Ancestors<'a> { + type Item = &'a Path; + + fn next(&mut self) -> Option<Self::Item> { + let next = self.next; + self.next = next.and_then(Path::parent); + next + } +} + +#[stable(feature = "path_ancestors", since = "1.28.0")] +impl<'a> FusedIterator for Ancestors<'a> {} + //////////////////////////////////////////////////////////////////////////////// // Basic types and traits //////////////////////////////////////////////////////////////////////////////// @@ -1369,6 +1407,14 @@ impl From<PathBuf> for Box<Path> { } } +#[stable(feature = "more_box_slice_clone", since = "1.29.0")] +impl Clone for Box<Path> { + #[inline] + fn clone(&self) -> Self { + self.to_path_buf().into_boxed_path() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: ?Sized + AsRef<OsStr>> From<&'a T> for PathBuf { fn from(s: &'a T) -> PathBuf { @@ -1417,7 +1463,7 @@ impl<P: AsRef<Path>> iter::Extend<P> for PathBuf { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for PathBuf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, formatter) } } @@ -1461,6 +1507,22 @@ impl<'a> From<PathBuf> for Cow<'a, Path> { } } +#[stable(feature = "cow_from_pathbuf_ref", since = "1.28.0")] +impl<'a> From<&'a PathBuf> for Cow<'a, Path> { + #[inline] + fn from(p: &'a PathBuf) -> Cow<'a, Path> { + Cow::Borrowed(p.as_path()) + } +} + +#[stable(feature = "pathbuf_from_cow_path", since = "1.28.0")] +impl<'a> From<Cow<'a, Path>> for PathBuf { + #[inline] + fn from(p: Cow<'a, Path>) -> Self { + p.into_owned() + } +} + #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<PathBuf> for Arc<Path> { #[inline] @@ -1675,9 +1737,11 @@ impl Path { /// Converts a `Path` to a [`Cow<str>`]. /// - /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER. + /// Any non-Unicode sequences are replaced with + /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. /// /// [`Cow<str>`]: ../borrow/enum.Cow.html + /// [U+FFFD]: ../char/constant.REPLACEMENT_CHARACTER.html /// /// # Examples /// @@ -1771,7 +1835,7 @@ impl Path { /// * On Unix, a path has a root if it begins with `/`. /// /// * On Windows, a path has a root if it: - /// * has no prefix and begins with a separator, e.g. `\\windows` + /// * has no prefix and begins with a separator, e.g. `\windows` /// * has a prefix followed by a separator, e.g. `c:\windows` but not `c:windows` /// * has any non-disk prefix, e.g. `\\server\share` /// @@ -1820,12 +1884,41 @@ impl Path { }) } + /// Produces an iterator over `Path` and its ancestors. + /// + /// The iterator will yield the `Path` that is returned if the [`parent`] method is used zero + /// or more times. That means, the iterator will yield `&self`, `&self.parent().unwrap()`, + /// `&self.parent().unwrap().parent().unwrap()` and so on. If the [`parent`] method returns + /// [`None`], the iterator will do likewise. The iterator will always yield at least one value, + /// namely `&self`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let mut ancestors = Path::new("/foo/bar").ancestors(); + /// assert_eq!(ancestors.next(), Some(Path::new("/foo/bar"))); + /// assert_eq!(ancestors.next(), Some(Path::new("/foo"))); + /// assert_eq!(ancestors.next(), Some(Path::new("/"))); + /// assert_eq!(ancestors.next(), None); + /// ``` + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`parent`]: struct.Path.html#method.parent + #[stable(feature = "path_ancestors", since = "1.28.0")] + pub fn ancestors(&self) -> Ancestors { + Ancestors { + next: Some(&self), + } + } + /// Returns the final component of the `Path`, if there is one. /// /// If the path is a normal file, this is the file name. If it's the path of a directory, this /// is the directory name. /// - /// Returns [`None`] If the path terminates in `..`. + /// Returns [`None`] if the path terminates in `..`. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None /// @@ -1865,24 +1958,31 @@ impl Path { /// # Examples /// /// ``` - /// use std::path::Path; + /// use std::path::{Path, PathBuf}; /// /// let path = Path::new("/test/haha/foo.txt"); /// + /// assert_eq!(path.strip_prefix("/"), Ok(Path::new("test/haha/foo.txt"))); /// assert_eq!(path.strip_prefix("/test"), Ok(Path::new("haha/foo.txt"))); + /// assert_eq!(path.strip_prefix("/test/"), Ok(Path::new("haha/foo.txt"))); + /// assert_eq!(path.strip_prefix("/test/haha/foo.txt"), Ok(Path::new(""))); + /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new(""))); /// assert_eq!(path.strip_prefix("test").is_ok(), false); /// assert_eq!(path.strip_prefix("/haha").is_ok(), false); + /// + /// let prefix = PathBuf::from("/test/"); + /// assert_eq!(path.strip_prefix(prefix), Ok(Path::new("haha/foo.txt"))); /// ``` #[stable(since = "1.7.0", feature = "path_strip_prefix")] - pub fn strip_prefix<'a, P: ?Sized>(&'a self, base: &'a P) - -> Result<&'a Path, StripPrefixError> + pub fn strip_prefix<P>(&self, base: P) + -> Result<&Path, StripPrefixError> where P: AsRef<Path> { self._strip_prefix(base.as_ref()) } - fn _strip_prefix<'a>(&'a self, base: &'a Path) - -> Result<&'a Path, StripPrefixError> { + fn _strip_prefix(&self, base: &Path) + -> Result<&Path, StripPrefixError> { iter_after(self.components(), base.components()) .map(|c| c.as_path()) .ok_or(StripPrefixError(())) @@ -1900,6 +2000,9 @@ impl Path { /// let path = Path::new("/etc/passwd"); /// /// assert!(path.starts_with("/etc")); + /// assert!(path.starts_with("/etc/")); + /// assert!(path.starts_with("/etc/passwd")); + /// assert!(path.starts_with("/etc/passwd/")); /// /// assert!(!path.starts_with("/e")); /// ``` @@ -2200,8 +2303,8 @@ impl Path { fs::symlink_metadata(self) } - /// Returns the canonical form of the path with all intermediate components - /// normalized and symbolic links resolved. + /// Returns the canonical, absolute form of the path with all intermediate + /// components normalized and symbolic links resolved. /// /// This is an alias to [`fs::canonicalize`]. /// diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs index d256353ab30..53763da5e28 100644 --- a/src/libstd/prelude/v1.rs +++ b/src/libstd/prelude/v1.rs @@ -12,45 +12,68 @@ //! //! See the [module-level documentation](../index.html) for more. + + #![stable(feature = "rust1", since = "1.0.0")] // Re-exported core operators #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use marker::{Copy, Send, Sized, Sync}; +#[doc(no_inline)] +pub use marker::{Copy, Send, Sized, Sync}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use ops::{Drop, Fn, FnMut, FnOnce}; +#[doc(no_inline)] +pub use ops::{Drop, Fn, FnMut, FnOnce}; // Re-exported functions #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use mem::drop; -#[unstable(feature = "convert_id_prelude", issue = "0")] #[doc(no_inline)] -pub use convert::id; +pub use mem::drop; // Re-exported types and traits #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use boxed::Box; +#[doc(no_inline)] +pub use clone::Clone; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use borrow::ToOwned; +#[doc(no_inline)] +pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use clone::Clone; +#[doc(no_inline)] +pub use convert::{AsRef, AsMut, Into, From}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; +#[doc(no_inline)] +pub use default::Default; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use convert::{AsRef, AsMut, Into, From}; +#[doc(no_inline)] +pub use iter::{Iterator, Extend, IntoIterator}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use default::Default; +#[doc(no_inline)] +pub use iter::{DoubleEndedIterator, ExactSizeIterator}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use iter::{Iterator, Extend, IntoIterator}; +#[doc(no_inline)] +pub use option::Option::{self, Some, None}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use iter::{DoubleEndedIterator, ExactSizeIterator}; +#[doc(no_inline)] +pub use result::Result::{self, Ok, Err}; + + +// The file so far is equivalent to src/libcore/prelude/v1.rs, +// and below to src/liballoc/prelude.rs. +// Those files are duplicated rather than using glob imports +// because we want docs to show these re-exports as pointing to within `std`. + + #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use option::Option::{self, Some, None}; +#[doc(no_inline)] +pub use boxed::Box; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use result::Result::{self, Ok, Err}; +#[doc(no_inline)] +pub use borrow::ToOwned; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use slice::SliceConcatExt; +#[doc(no_inline)] +pub use slice::SliceConcatExt; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use string::{String, ToString}; +#[doc(no_inline)] +pub use string::{String, ToString}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use vec::Vec; +#[doc(no_inline)] +pub use vec::Vec; diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index a2caf47e8cc..7074928eaf6 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -9,6 +9,8 @@ // except according to those terms. #[doc(primitive = "bool")] +#[doc(alias = "true")] +#[doc(alias = "false")] // /// The boolean type. /// @@ -68,6 +70,7 @@ mod prim_bool { } #[doc(primitive = "never")] +#[doc(alias = "!")] // /// The `!` type, also called "never". /// @@ -113,6 +116,8 @@ mod prim_bool { } /// /// # `!` and generics /// +/// ## Infallible errors +/// /// The main place you'll see `!` used explicitly is in generic code. Consider the [`FromStr`] /// trait: /// @@ -131,17 +136,70 @@ mod prim_bool { } /// [`Result<String, !>`] which we can unpack like this: /// /// ```ignore (string-from-str-error-type-is-not-never-yet) +/// #[feature(exhaustive_patterns)] /// // NOTE: This does not work today! /// let Ok(s) = String::from_str("hello"); /// ``` /// -/// Since the [`Err`] variant contains a `!`, it can never occur. So we can exhaustively match on -/// [`Result<T, !>`] by just taking the [`Ok`] variant. This illustrates another behaviour of `!` - -/// it can be used to "delete" certain enum variants from generic types like `Result`. +/// Since the [`Err`] variant contains a `!`, it can never occur. If the `exhaustive_patterns` +/// feature is present this means we can exhaustively match on [`Result<T, !>`] by just taking the +/// [`Ok`] variant. This illustrates another behaviour of `!` - it can be used to "delete" certain +/// enum variants from generic types like `Result`. +/// +/// ## Infinite loops +/// +/// While [`Result<T, !>`] is very useful for removing errors, `!` can also be used to remove +/// successes as well. If we think of [`Result<T, !>`] as "if this function returns, it has not +/// errored," we get a very intuitive idea of [`Result<!, E>`] as well: if the function returns, it +/// *has* errored. +/// +/// For example, consider the case of a simple web server, which can be simplified to: +/// +/// ```ignore (hypothetical-example) +/// loop { +/// let (client, request) = get_request().expect("disconnected"); +/// let response = request.process(); +/// response.send(client); +/// } +/// ``` +/// +/// Currently, this isn't ideal, because we simply panic whenever we fail to get a new connection. +/// Instead, we'd like to keep track of this error, like this: +/// +/// ```ignore (hypothetical-example) +/// loop { +/// match get_request() { +/// Err(err) => break err, +/// Ok((client, request)) => { +/// let response = request.process(); +/// response.send(client); +/// }, +/// } +/// } +/// ``` +/// +/// Now, when the server disconnects, we exit the loop with an error instead of panicking. While it +/// might be intuitive to simply return the error, we might want to wrap it in a [`Result<!, E>`] +/// instead: +/// +/// ```ignore (hypothetical-example) +/// fn server_loop() -> Result<!, ConnectionError> { +/// loop { +/// let (client, request) = get_request()?; +/// let response = request.process(); +/// response.send(client); +/// } +/// } +/// ``` +/// +/// Now, we can use `?` instead of `match`, and the return type makes a lot more sense: if the loop +/// ever stops, it means that an error occurred. We don't even have to wrap the loop in an `Ok` +/// because `!` coerces to `Result<!, ConnectionError>` automatically. /// /// [`String::from_str`]: str/trait.FromStr.html#tymethod.from_str /// [`Result<String, !>`]: result/enum.Result.html /// [`Result<T, !>`]: result/enum.Result.html +/// [`Result<!, E>`]: result/enum.Result.html /// [`Ok`]: result/enum.Result.html#variant.Ok /// [`String`]: string/struct.String.html /// [`Err`]: result/enum.Result.html#variant.Err @@ -154,7 +212,7 @@ mod prim_bool { } /// for example: /// /// ``` -/// # #![feature(never_type)] +/// #![feature(never_type)] /// # use std::fmt; /// # trait Debug { /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result; @@ -192,7 +250,6 @@ mod prim_bool { } /// [`Default`]: default/trait.Default.html /// [`default()`]: default/trait.Default.html#tymethod.default /// -#[unstable(feature = "never_type", issue = "35121")] mod prim_never { } #[doc(primitive = "char")] @@ -313,6 +370,8 @@ mod prim_unit { } // /// Raw, unsafe pointers, `*const T`, and `*mut T`. /// +/// *[See also the `std::ptr` module](ptr/index.html).* +/// /// Working with raw pointers in Rust is uncommon, /// typically limited to a few patterns. /// @@ -387,8 +446,6 @@ mod prim_unit { } /// but C APIs hand out a lot of pointers generally, so are a common source /// of raw pointers in Rust. /// -/// *[See also the `std::ptr` module](ptr/index.html).* -/// /// [`null`]: ../std/ptr/fn.null.html /// [`null_mut`]: ../std/ptr/fn.null_mut.html /// [`is_null`]: ../std/primitive.pointer.html#method.is_null @@ -500,9 +557,14 @@ mod prim_pointer { } mod prim_array { } #[doc(primitive = "slice")] +#[doc(alias = "[")] +#[doc(alias = "]")] +#[doc(alias = "[]")] // /// A dynamically-sized view into a contiguous sequence, `[T]`. /// +/// *[See also the `std::slice` module](slice/index.html).* +/// /// Slices are a view into a block of memory represented as a pointer and a /// length. /// @@ -525,8 +587,6 @@ mod prim_array { } /// assert_eq!(x, &[1, 7, 3]); /// ``` /// -/// *[See also the `std::slice` module](slice/index.html).* -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_slice { } @@ -534,15 +594,13 @@ mod prim_slice { } // /// String slices. /// +/// *[See also the `std::str` module](str/index.html).* +/// /// The `str` type, also called a 'string slice', is the most primitive string /// type. It is usually seen in its borrowed form, `&str`. It is also the type /// of string literals, `&'static str`. /// -/// Strings slices are always valid UTF-8. -/// -/// This documentation describes a number of methods and trait implementations -/// on the `str` type. For technical reasons, there is additional, separate -/// documentation in the [`std::str`](str/index.html) module as well. +/// String slices are always valid UTF-8. /// /// # Examples /// @@ -598,6 +656,9 @@ mod prim_slice { } mod prim_str { } #[doc(primitive = "tuple")] +#[doc(alias = "(")] +#[doc(alias = ")")] +#[doc(alias = "()")] // /// A finite heterogeneous sequence, `(T, U, ..)`. /// @@ -720,10 +781,6 @@ mod prim_f64 { } /// The 8-bit signed integer type. /// /// *[See also the `std::i8` module](i8/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `i64` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_i8 { } @@ -732,10 +789,6 @@ mod prim_i8 { } /// The 16-bit signed integer type. /// /// *[See also the `std::i16` module](i16/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `i32` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_i16 { } @@ -744,10 +797,6 @@ mod prim_i16 { } /// The 32-bit signed integer type. /// /// *[See also the `std::i32` module](i32/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `i16` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_i32 { } @@ -756,10 +805,6 @@ mod prim_i32 { } /// The 64-bit signed integer type. /// /// *[See also the `std::i64` module](i64/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `i8` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_i64 { } @@ -768,11 +813,7 @@ mod prim_i64 { } /// The 128-bit signed integer type. /// /// *[See also the `std::i128` module](i128/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `i8` in there. -/// -#[unstable(feature = "i128", issue="35118")] +#[stable(feature = "i128", since="1.26.0")] mod prim_i128 { } #[doc(primitive = "u8")] @@ -780,10 +821,6 @@ mod prim_i128 { } /// The 8-bit unsigned integer type. /// /// *[See also the `std::u8` module](u8/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `u64` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_u8 { } @@ -792,10 +829,6 @@ mod prim_u8 { } /// The 16-bit unsigned integer type. /// /// *[See also the `std::u16` module](u16/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `u32` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_u16 { } @@ -804,10 +837,6 @@ mod prim_u16 { } /// The 32-bit unsigned integer type. /// /// *[See also the `std::u32` module](u32/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `u16` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_u32 { } @@ -816,10 +845,6 @@ mod prim_u32 { } /// The 64-bit unsigned integer type. /// /// *[See also the `std::u64` module](u64/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `u8` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_u64 { } @@ -828,26 +853,18 @@ mod prim_u64 { } /// The 128-bit unsigned integer type. /// /// *[See also the `std::u128` module](u128/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `u8` in there. -/// -#[unstable(feature = "i128", issue="35118")] +#[stable(feature = "i128", since="1.26.0")] mod prim_u128 { } #[doc(primitive = "isize")] // /// The pointer-sized signed integer type. /// +/// *[See also the `std::isize` module](isize/index.html).* +/// /// The size of this primitive is how many bytes it takes to reference any /// location in memory. For example, on a 32 bit target, this is 4 bytes /// and on a 64 bit target, this is 8 bytes. -/// -/// *[See also the `std::isize` module](isize/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `usize` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_isize { } @@ -855,19 +872,16 @@ mod prim_isize { } // /// The pointer-sized unsigned integer type. /// +/// *[See also the `std::usize` module](usize/index.html).* +/// /// The size of this primitive is how many bytes it takes to reference any /// location in memory. For example, on a 32 bit target, this is 4 bytes /// and on a 64 bit target, this is 8 bytes. -/// -/// *[See also the `std::usize` module](usize/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `isize` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_usize { } #[doc(primitive = "reference")] +#[doc(alias = "&")] // /// References, both shared and mutable. /// diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 5c66ac6ddde..53babd449a9 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -381,6 +381,39 @@ impl fmt::Debug for ChildStderr { /// /// let hello = output.stdout; /// ``` +/// +/// `Command` can be reused to spawn multiple processes. The builder methods +/// change the command without needing to immediately spawn the process. +/// +/// ```no_run +/// use std::process::Command; +/// +/// let mut echo_hello = Command::new("sh"); +/// echo_hello.arg("-c") +/// .arg("echo hello"); +/// let hello_1 = echo_hello.output().expect("failed to execute process"); +/// let hello_2 = echo_hello.output().expect("failed to execute process"); +/// ``` +/// +/// Similarly, you can call builder methods after spawning a process and then +/// spawn a new process with the modified settings. +/// +/// ```no_run +/// use std::process::Command; +/// +/// let mut list_dir = Command::new("ls"); +/// +/// // Execute `ls` in the current directory of the program. +/// list_dir.status().expect("process failed to execute"); +/// +/// println!(""); +/// +/// // Change `ls` to execute in the root directory. +/// list_dir.current_dir("/"); +/// +/// // And then execute `ls` again but in the root directory. +/// list_dir.status().expect("process failed to execute"); +/// ``` #[stable(feature = "process", since = "1.0.0")] pub struct Command { inner: imp::Command, @@ -813,13 +846,13 @@ impl fmt::Debug for Output { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let stdout_utf8 = str::from_utf8(&self.stdout); - let stdout_debug: &fmt::Debug = match stdout_utf8 { + let stdout_debug: &dyn fmt::Debug = match stdout_utf8 { Ok(ref str) => str, Err(_) => &self.stdout }; let stderr_utf8 = str::from_utf8(&self.stderr); - let stderr_debug: &fmt::Debug = match stderr_utf8 { + let stderr_debug: &dyn fmt::Debug = match stderr_utf8 { Ok(ref str) => str, Err(_) => &self.stderr }; @@ -1080,9 +1113,54 @@ impl fmt::Display for ExitStatus { } } +/// This type represents the status code a process can return to its +/// parent under normal termination. +/// +/// Numeric values used in this type don't have portable meanings, and +/// different platforms may mask different amounts of them. +/// +/// For the platform's canonical successful and unsuccessful codes, see +/// the [`SUCCESS`] and [`FAILURE`] associated items. +/// +/// [`SUCCESS`]: #associatedconstant.SUCCESS +/// [`FAILURE`]: #associatedconstant.FAILURE +/// +/// **Warning**: While various forms of this were discussed in [RFC #1937], +/// it was ultimately cut from that RFC, and thus this type is more subject +/// to change even than the usual unstable item churn. +/// +/// [RFC #1937]: https://github.com/rust-lang/rfcs/pull/1937 +#[derive(Clone, Copy, Debug)] +#[unstable(feature = "process_exitcode_placeholder", issue = "48711")] +pub struct ExitCode(imp::ExitCode); + +#[unstable(feature = "process_exitcode_placeholder", issue = "48711")] +impl ExitCode { + /// The canonical ExitCode for successful termination on this platform. + /// + /// Note that a `()`-returning `main` implicitly results in a successful + /// termination, so there's no need to return this from `main` unless + /// you're also returning other possible codes. + #[unstable(feature = "process_exitcode_placeholder", issue = "48711")] + pub const SUCCESS: ExitCode = ExitCode(imp::ExitCode::SUCCESS); + + /// The canonical ExitCode for unsuccessful termination on this platform. + /// + /// If you're only returning this and `SUCCESS` from `main`, consider + /// instead returning `Err(_)` and `Ok(())` respectively, which will + /// return the same codes (but will also `eprintln!` the error). + #[unstable(feature = "process_exitcode_placeholder", issue = "48711")] + pub const FAILURE: ExitCode = ExitCode(imp::ExitCode::FAILURE); +} + impl Child { - /// Forces the child to exit. This is equivalent to sending a - /// SIGKILL on unix platforms. + /// Forces the child process to exit. If the child has already exited, an [`InvalidInput`] + /// error is returned. + /// + /// The mapping to [`ErrorKind`]s is not part of the compatibility contract of the function, + /// especially the [`Other`] kind might change to more specific kinds in the future. + /// + /// This is equivalent to sending a SIGKILL on Unix platforms. /// /// # Examples /// @@ -1098,6 +1176,10 @@ impl Child { /// println!("yes command didn't start"); /// } /// ``` + /// + /// [`ErrorKind`]: ../io/enum.ErrorKind.html + /// [`InvalidInput`]: ../io/enum.ErrorKind.html#variant.InvalidInput + /// [`Other`]: ../io/enum.ErrorKind.html#variant.Other #[stable(feature = "process", since = "1.0.0")] pub fn kill(&mut self) -> io::Result<()> { self.handle.kill() @@ -1380,18 +1462,74 @@ pub fn abort() -> ! { /// Basic usage: /// /// ```no_run -/// #![feature(getpid)] /// use std::process; /// /// println!("My pid is {}", process::id()); /// ``` /// /// -#[unstable(feature = "getpid", issue = "44971", reason = "recently added")] +#[stable(feature = "getpid", since = "1.26.0")] pub fn id() -> u32 { ::sys::os::getpid() } +/// A trait for implementing arbitrary return types in the `main` function. +/// +/// The c-main function only supports to return integers as return type. +/// So, every type implementing the `Termination` trait has to be converted +/// to an integer. +/// +/// The default implementations are returning `libc::EXIT_SUCCESS` to indicate +/// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned. +#[cfg_attr(not(test), lang = "termination")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] +#[rustc_on_unimplemented( + message="`main` has invalid return type `{Self}`", + label="`main` can only return types that implement `{Termination}`")] +pub trait Termination { + /// Is called to get the representation of the value as status code. + /// This status code is returned to the operating system. + fn report(self) -> i32; +} + +#[unstable(feature = "termination_trait_lib", issue = "43301")] +impl Termination for () { + #[inline] + fn report(self) -> i32 { ExitCode::SUCCESS.report() } +} + +#[unstable(feature = "termination_trait_lib", issue = "43301")] +impl<E: fmt::Debug> Termination for Result<(), E> { + fn report(self) -> i32 { + match self { + Ok(()) => ().report(), + Err(err) => Err::<!, _>(err).report(), + } + } +} + +#[unstable(feature = "termination_trait_lib", issue = "43301")] +impl Termination for ! { + fn report(self) -> i32 { self } +} + +#[unstable(feature = "termination_trait_lib", issue = "43301")] +impl<E: fmt::Debug> Termination for Result<!, E> { + fn report(self) -> i32 { + let Err(err) = self; + eprintln!("Error: {:?}", err); + ExitCode::FAILURE.report() + } +} + +#[unstable(feature = "termination_trait_lib", issue = "43301")] +impl Termination for ExitCode { + #[inline] + fn report(self) -> i32 { + self.0.as_i32() + } +} + #[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] mod tests { use io::prelude::*; @@ -1843,4 +1981,10 @@ mod tests { } assert!(events > 0); } + + #[test] + fn test_command_implements_send() { + fn take_send_type<T: Send>(_: T) {} + take_send_type(Command::new("")) + } } diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index 9dbaf784f89..9e957bd87d7 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -29,7 +29,7 @@ pub use panicking::{begin_panic, begin_panic_fmt, update_panic_count}; // To reduce the generated code of the new `lang_start`, this function is doing // the real work. #[cfg(not(test))] -fn lang_start_internal(main: &(Fn() -> i32 + Sync + ::panic::RefUnwindSafe), +fn lang_start_internal(main: &(dyn Fn() -> i32 + Sync + ::panic::RefUnwindSafe), argc: isize, argv: *const *const u8) -> isize { use panic; use sys; @@ -68,8 +68,23 @@ fn lang_start_internal(main: &(Fn() -> i32 + Sync + ::panic::RefUnwindSafe), #[cfg(not(test))] #[lang = "start"] -fn lang_start<T: ::termination::Termination + 'static> +fn lang_start<T: ::process::Termination + 'static> (main: fn() -> T, argc: isize, argv: *const *const u8) -> isize { lang_start_internal(&move || main().report(), argc, argv) } + +/// Function used for reverting changes to the main stack before setrlimit(). +/// This is POSIX (non-Linux) specific and unlikely to be directly stabilized. +#[unstable(feature = "rustc_stack_internals", issue = "0")] +pub unsafe fn deinit_stack_guard() { + ::sys::thread::guard::deinit(); +} + +/// Function used for resetting the main stack guard address after setrlimit(). +/// This is POSIX specific and unlikely to be directly stabilized. +#[unstable(feature = "rustc_stack_internals", issue = "0")] +pub unsafe fn update_stack_guard() { + let main_guard = ::sys::thread::guard::init(); + ::sys_common::thread_info::reset_guard(main_guard); +} diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 56402175817..3014283da5b 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -14,7 +14,7 @@ use sync::{mutex, MutexGuard, PoisonError}; use sys_common::condvar as sys; use sys_common::mutex as sys_mutex; use sys_common::poison::{self, LockResult}; -use time::Duration; +use time::{Duration, Instant}; /// A type indicating whether a timed wait on a condition variable returned /// due to a time out or not. @@ -47,11 +47,13 @@ impl WaitTimeoutResult { /// /// thread::spawn(move|| { /// let &(ref lock, ref cvar) = &*pair2; + /// + /// // Let's wait 20 milliseconds before notifying the condvar. + /// thread::sleep(Duration::from_millis(20)); + /// /// let mut started = lock.lock().unwrap(); /// // We update the boolean value. /// *started = true; - /// // Let's wait 20 milliseconds before notifying the condvar. - /// thread::sleep(Duration::from_millis(20)); /// cvar.notify_one(); /// }); /// @@ -219,6 +221,64 @@ impl Condvar { } } + /// Blocks the current thread until this condition variable receives a + /// notification and the required condition is met. Spurious wakeups are + /// ignored and this function will only return once the condition has been + /// met. + /// + /// This function will atomically unlock the mutex specified (represented by + /// `guard`) and block the current thread. This means that any calls + /// to [`notify_one`] or [`notify_all`] which happen logically after the + /// mutex is unlocked are candidates to wake this thread up. When this + /// function call returns, the lock specified will have been re-acquired. + /// + /// # Errors + /// + /// This function will return an error if the mutex being waited on is + /// poisoned when this thread re-acquires the lock. For more information, + /// see information about [poisoning] on the [`Mutex`] type. + /// + /// [`notify_one`]: #method.notify_one + /// [`notify_all`]: #method.notify_all + /// [poisoning]: ../sync/struct.Mutex.html#poisoning + /// [`Mutex`]: ../sync/struct.Mutex.html + /// + /// # Examples + /// + /// ``` + /// #![feature(wait_until)] + /// + /// use std::sync::{Arc, Mutex, Condvar}; + /// use std::thread; + /// + /// let pair = Arc::new((Mutex::new(false), Condvar::new())); + /// let pair2 = pair.clone(); + /// + /// thread::spawn(move|| { + /// let &(ref lock, ref cvar) = &*pair2; + /// let mut started = lock.lock().unwrap(); + /// *started = true; + /// // We notify the condvar that the value has changed. + /// cvar.notify_one(); + /// }); + /// + /// // Wait for the thread to start up. + /// let &(ref lock, ref cvar) = &*pair; + /// // As long as the value inside the `Mutex` is false, we wait. + /// let _guard = cvar.wait_until(lock.lock().unwrap(), |started| { *started }).unwrap(); + /// ``` + #[unstable(feature = "wait_until", issue = "47960")] + pub fn wait_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>, + mut condition: F) + -> LockResult<MutexGuard<'a, T>> + where F: FnMut(&mut T) -> bool { + while !condition(&mut *guard) { + guard = self.wait(guard)?; + } + Ok(guard) + } + + /// Waits on this condition variable for a notification, timing out after a /// specified duration. /// @@ -293,7 +353,15 @@ impl Condvar { /// /// Note that the best effort is made to ensure that the time waited is /// measured with a monotonic clock, and not affected by the changes made to - /// the system time. + /// the system time. This function is susceptible to spurious wakeups. + /// Condition variables normally have a boolean predicate associated with + /// them, and the predicate must always be checked each time this function + /// returns to protect against spurious wakeups. Additionally, it is + /// typically desirable for the time-out to not exceed some duration in + /// spite of spurious wakes, thus the sleep-duration is decremented by the + /// amount slept. Alternatively, use the `wait_timeout_until` method + /// to wait until a condition is met with a total time-out regardless + /// of spurious wakes. /// /// The returned [`WaitTimeoutResult`] value indicates if the timeout is /// known to have elapsed. @@ -302,6 +370,7 @@ impl Condvar { /// returns, regardless of whether the timeout elapsed or not. /// /// [`wait`]: #method.wait + /// [`wait_timeout_until`]: #method.wait_timeout_until /// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html /// /// # Examples @@ -353,6 +422,80 @@ impl Condvar { } } + /// Waits on this condition variable for a notification, timing out after a + /// specified duration. Spurious wakes will not cause this function to + /// return. + /// + /// The semantics of this function are equivalent to [`wait_until`] 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`. + /// + /// Note that the best effort is made to ensure that the time waited is + /// measured with a monotonic clock, and not affected by the changes made to + /// the system time. + /// + /// The returned [`WaitTimeoutResult`] value indicates if the timeout is + /// known to have elapsed without the condition being met. + /// + /// Like [`wait_until`], the lock specified will be re-acquired when this + /// function returns, regardless of whether the timeout elapsed or not. + /// + /// [`wait_until`]: #method.wait_until + /// [`wait_timeout`]: #method.wait_timeout + /// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html + /// + /// # Examples + /// + /// ``` + /// #![feature(wait_timeout_until)] + /// + /// use std::sync::{Arc, Mutex, Condvar}; + /// use std::thread; + /// use std::time::Duration; + /// + /// let pair = Arc::new((Mutex::new(false), Condvar::new())); + /// let pair2 = pair.clone(); + /// + /// thread::spawn(move|| { + /// let &(ref lock, ref cvar) = &*pair2; + /// let mut started = lock.lock().unwrap(); + /// *started = true; + /// // We notify the condvar that the value has changed. + /// cvar.notify_one(); + /// }); + /// + /// // wait for the thread to start up + /// let &(ref lock, ref cvar) = &*pair; + /// let result = cvar.wait_timeout_until( + /// lock.lock().unwrap(), + /// Duration::from_millis(100), + /// |&mut started| started, + /// ).unwrap(); + /// if result.1.timed_out() { + /// // timed-out without the condition ever evaluating to true. + /// } + /// // access the locked mutex via result.0 + /// ``` + #[unstable(feature = "wait_timeout_until", issue = "47960")] + pub fn wait_timeout_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>, + dur: Duration, mut condition: F) + -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> + where F: FnMut(&mut T) -> bool { + let start = Instant::now(); + loop { + if condition(&mut *guard) { + return Ok((guard, WaitTimeoutResult(false))); + } + let timeout = match dur.checked_sub(start.elapsed()) { + Some(timeout) => timeout, + None => return Ok((guard, WaitTimeoutResult(true))), + }; + guard = self.wait_timeout(guard, timeout)?.0; + } + } + /// Wakes up one blocked thread on this condvar. /// /// If there is a blocked thread on this condition variable, then it will @@ -478,6 +621,7 @@ impl Drop for Condvar { #[cfg(test)] mod tests { + /// #![feature(wait_until)] use sync::mpsc::channel; use sync::{Condvar, Mutex, Arc}; use sync::atomic::{AtomicBool, Ordering}; @@ -548,6 +692,29 @@ mod tests { #[test] #[cfg_attr(target_os = "emscripten", ignore)] + fn wait_until() { + let pair = Arc::new((Mutex::new(false), Condvar::new())); + let pair2 = pair.clone(); + + // Inside of our lock, spawn a new thread, and then wait for it to start. + thread::spawn(move|| { + let &(ref lock, ref cvar) = &*pair2; + let mut started = lock.lock().unwrap(); + *started = true; + // We notify the condvar that the value has changed. + cvar.notify_one(); + }); + + // Wait for the thread to start up. + let &(ref lock, ref cvar) = &*pair; + let guard = cvar.wait_until(lock.lock().unwrap(), |started| { + *started + }); + assert!(*guard.unwrap()); + } + + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] fn wait_timeout_wait() { let m = Arc::new(Mutex::new(())); let c = Arc::new(Condvar::new()); @@ -567,6 +734,53 @@ mod tests { #[test] #[cfg_attr(target_os = "emscripten", ignore)] + fn wait_timeout_until_wait() { + let m = Arc::new(Mutex::new(())); + let c = Arc::new(Condvar::new()); + + let g = m.lock().unwrap(); + let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(1), |_| { false }).unwrap(); + // no spurious wakeups. ensure it timed-out + assert!(wait.timed_out()); + } + + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] + fn wait_timeout_until_instant_satisfy() { + let m = Arc::new(Mutex::new(())); + let c = Arc::new(Condvar::new()); + + let g = m.lock().unwrap(); + let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(0), |_| { true }).unwrap(); + // ensure it didn't time-out even if we were not given any time. + assert!(!wait.timed_out()); + } + + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] + fn wait_timeout_until_wake() { + let pair = Arc::new((Mutex::new(false), Condvar::new())); + let pair_copy = pair.clone(); + + let &(ref m, ref c) = &*pair; + let g = m.lock().unwrap(); + let _t = thread::spawn(move || { + let &(ref lock, ref cvar) = &*pair_copy; + let mut started = lock.lock().unwrap(); + thread::sleep(Duration::from_millis(1)); + *started = true; + cvar.notify_one(); + }); + let (g2, wait) = c.wait_timeout_until(g, Duration::from_millis(u64::MAX), |&mut notified| { + notified + }).unwrap(); + // ensure it didn't time-out even if we were not given any time. + assert!(!wait.timed_out()); + assert!(*g2); + } + + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] fn wait_timeout_wake() { let m = Arc::new(Mutex::new(())); let c = Arc::new(Condvar::new()); diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs index 289b47b3484..e12ef8d9eda 100644 --- a/src/libstd/sync/mod.rs +++ b/src/libstd/sync/mod.rs @@ -18,7 +18,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::arc::{Arc, Weak}; +pub use alloc_crate::sync::{Arc, Weak}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::sync::atomic; diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 2dd3aebe610..59cf741487e 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -689,7 +689,7 @@ impl<T> UnsafeFlavor<T> for Receiver<T> { /// only one [`Receiver`] is supported. /// /// If the [`Receiver`] is disconnected while trying to [`send`] with the -/// [`Sender`], the [`send`] method will return a [`SendError`]. Similarly, If the +/// [`Sender`], the [`send`] method will return a [`SendError`]. Similarly, if the /// [`Sender`] is disconnected while trying to [`recv`], the [`recv`] method will /// return a [`RecvError`]. /// @@ -1247,6 +1247,34 @@ impl<T> Receiver<T> { /// [`SyncSender`]: struct.SyncSender.html /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err /// + /// # Known Issues + /// + /// There is currently a known issue (see [`#39364`]) that causes `recv_timeout` + /// to panic unexpectedly with the following example: + /// + /// ```no_run + /// use std::sync::mpsc::channel; + /// use std::thread; + /// use std::time::Duration; + /// + /// let (tx, rx) = channel::<String>(); + /// + /// thread::spawn(move || { + /// let d = Duration::from_millis(10); + /// loop { + /// println!("recv"); + /// let _r = rx.recv_timeout(d); + /// } + /// }); + /// + /// thread::sleep(Duration::from_millis(100)); + /// let _c1 = tx.clone(); + /// + /// thread::sleep(Duration::from_secs(1)); + /// ``` + /// + /// [`#39364`]: https://github.com/rust-lang/rust/issues/39364 + /// /// # Examples /// /// Successfully receiving value before encountering timeout: @@ -1638,7 +1666,7 @@ impl<T: Send> error::Error for SendError<T> { "sending on a closed channel" } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { None } } @@ -1681,7 +1709,7 @@ impl<T: Send> error::Error for TrySendError<T> { } } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { None } } @@ -1709,7 +1737,7 @@ impl error::Error for RecvError { "receiving on a closed channel" } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { None } } @@ -1742,7 +1770,7 @@ impl error::Error for TryRecvError { } } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { None } } @@ -1783,7 +1811,7 @@ impl error::Error for RecvTimeoutError { } } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { None } } diff --git a/src/libstd/sync/mpsc/mpsc_queue.rs b/src/libstd/sync/mpsc/mpsc_queue.rs index 296773d20f6..df945ac3859 100644 --- a/src/libstd/sync/mpsc/mpsc_queue.rs +++ b/src/libstd/sync/mpsc/mpsc_queue.rs @@ -23,10 +23,9 @@ pub use self::PopResult::*; -use alloc::boxed::Box; use core::ptr; use core::cell::UnsafeCell; - +use boxed::Box; use sync::atomic::{AtomicPtr, Ordering}; /// A result of the `pop` function. diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs index a9f3cea243f..a7a284cfb79 100644 --- a/src/libstd/sync/mpsc/select.rs +++ b/src/libstd/sync/mpsc/select.rs @@ -93,7 +93,7 @@ pub struct Handle<'rx, T:Send+'rx> { next: *mut Handle<'static, ()>, prev: *mut Handle<'static, ()>, added: bool, - packet: &'rx (Packet+'rx), + packet: &'rx (dyn Packet+'rx), // due to our fun transmutes, we be sure to place this at the end. (nothing // previous relies on T) @@ -518,6 +518,7 @@ mod tests { } } + #[allow(unused_must_use)] #[test] fn cloning() { let (tx1, rx1) = channel::<i32>(); @@ -540,6 +541,7 @@ mod tests { tx3.send(()).unwrap(); } + #[allow(unused_must_use)] #[test] fn cloning2() { let (tx1, rx1) = channel::<i32>(); diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs index cc4be92276a..9482f6958b3 100644 --- a/src/libstd/sync/mpsc/spsc_queue.rs +++ b/src/libstd/sync/mpsc/spsc_queue.rs @@ -16,7 +16,7 @@ // http://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue -use alloc::boxed::Box; +use boxed::Box; use core::ptr; use core::cell::UnsafeCell; diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 3b4904c98e8..e5a410644b9 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -150,7 +150,7 @@ unsafe impl<T: ?Sized + Send> Sync for Mutex<T> { } /// [`lock`]: struct.Mutex.html#method.lock /// [`try_lock`]: struct.Mutex.html#method.try_lock /// [`Mutex`]: struct.Mutex.html -#[must_use] +#[must_use = "if unused the Mutex will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct MutexGuard<'a, T: ?Sized + 'a> { // funny underscores due to how Deref/DerefMut currently work (they @@ -227,7 +227,7 @@ impl<T: ?Sized> Mutex<T> { #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> LockResult<MutexGuard<T>> { unsafe { - self.inner.lock(); + self.inner.raw_lock(); MutexGuard::new(self) } } @@ -454,7 +454,7 @@ impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { fn drop(&mut self) { unsafe { self.__lock.poison.done(&self.__poison); - self.__lock.inner.unlock(); + self.__lock.inner.raw_unlock(); } } } diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 6fd8b6a5bba..f6cb8beae84 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -31,12 +31,10 @@ // initialization closure panics, the Once enters a "poisoned" state which means // that all future calls will immediately panic as well. // -// So to implement this, one might first reach for a `StaticMutex`, but those -// unfortunately need to be deallocated (e.g. call `destroy()`) to free memory -// on all OSes (some of the BSDs allocate memory for mutexes). It also gets a -// lot harder with poisoning to figure out when the mutex needs to be -// deallocated because it's not after the closure finishes, but after the first -// successful closure finishes. +// So to implement this, one might first reach for a `Mutex`, but those cannot +// be put into a `static`. It also gets a lot harder with poisoning to figure +// out when the mutex needs to be deallocated because it's not after the closure +// finishes, but after the first successful closure finishes. // // All in all, this is instead implemented with atomics and lock-free // operations! Whee! Each `Once` has one word of atomic state, and this state is @@ -73,16 +71,17 @@ use thread::{self, Thread}; /// A synchronization primitive which can be used to run a one-time global /// initialization. Useful for one-time initialization for FFI or related /// functionality. This type can only be constructed with the [`ONCE_INIT`] -/// value. +/// value or the equivalent [`Once::new`] constructor. /// /// [`ONCE_INIT`]: constant.ONCE_INIT.html +/// [`Once::new`]: struct.Once.html#method.new /// /// # Examples /// /// ``` -/// use std::sync::{Once, ONCE_INIT}; +/// use std::sync::Once; /// -/// static START: Once = ONCE_INIT; +/// static START: Once = Once::new(); /// /// START.call_once(|| { /// // run initialization here @@ -148,9 +147,9 @@ struct Waiter { // Helper struct used to clean up after a closure call with a `Drop` // implementation to also run on panic. -struct Finish { +struct Finish<'a> { panicked: bool, - me: &'static Once, + me: &'a Once, } impl Once { @@ -177,13 +176,17 @@ impl Once { /// happens-before relation between the closure and code executing after the /// return). /// + /// If the given closure recusively invokes `call_once` on the same `Once` + /// instance the exact behavior is not specified, allowed outcomes are + /// a panic or a deadlock. + /// /// # Examples /// /// ``` - /// use std::sync::{Once, ONCE_INIT}; + /// use std::sync::Once; /// /// static mut VAL: usize = 0; - /// static INIT: Once = ONCE_INIT; + /// static INIT: Once = Once::new(); /// /// // Accessing a `static mut` is unsafe much of the time, but if we do so /// // in a synchronized fashion (e.g. write once or read all) then we're @@ -217,9 +220,13 @@ impl Once { /// /// [poison]: struct.Mutex.html#poisoning #[stable(feature = "rust1", since = "1.0.0")] - pub fn call_once<F>(&'static self, f: F) where F: FnOnce() { + pub fn call_once<F>(&self, f: F) where F: FnOnce() { // Fast path, just see if we've completed initialization. - if self.state.load(Ordering::SeqCst) == COMPLETE { + // An `Acquire` load is enough because that makes all the initialization + // operations visible to us. The cold path uses SeqCst consistently + // because the performance difference really does not matter there, + // and SeqCst minimizes the chances of something going wrong. + if self.state.load(Ordering::Acquire) == COMPLETE { return } @@ -248,10 +255,10 @@ impl Once { /// ``` /// #![feature(once_poison)] /// - /// use std::sync::{Once, ONCE_INIT}; + /// use std::sync::Once; /// use std::thread; /// - /// static INIT: Once = ONCE_INIT; + /// static INIT: Once = Once::new(); /// /// // poison the once /// let handle = thread::spawn(|| { @@ -274,9 +281,13 @@ impl Once { /// INIT.call_once(|| {}); /// ``` #[unstable(feature = "once_poison", issue = "33577")] - pub fn call_once_force<F>(&'static self, f: F) where F: FnOnce(&OnceState) { + pub fn call_once_force<F>(&self, f: F) where F: FnOnce(&OnceState) { // same as above, just with a different parameter to `call_inner`. - if self.state.load(Ordering::SeqCst) == COMPLETE { + // An `Acquire` load is enough because that makes all the initialization + // operations visible to us. The cold path uses SeqCst consistently + // because the performance difference really does not matter there, + // and SeqCst minimizes the chances of something going wrong. + if self.state.load(Ordering::Acquire) == COMPLETE { return } @@ -298,9 +309,9 @@ impl Once { // currently no way to take an `FnOnce` and call it via virtual dispatch // without some allocation overhead. #[cold] - fn call_inner(&'static self, + fn call_inner(&self, ignore_poisoning: bool, - init: &mut FnMut(bool)) { + init: &mut dyn FnMut(bool)) { let mut state = self.state.load(Ordering::SeqCst); 'outer: loop { @@ -389,7 +400,7 @@ impl fmt::Debug for Once { } } -impl Drop for Finish { +impl<'a> Drop for Finish<'a> { fn drop(&mut self) { // Swap out our state with however we finished. We should only ever see // an old state which was RUNNING. @@ -431,10 +442,10 @@ impl OnceState { /// ``` /// #![feature(once_poison)] /// - /// use std::sync::{Once, ONCE_INIT}; + /// use std::sync::Once; /// use std::thread; /// - /// static INIT: Once = ONCE_INIT; + /// static INIT: Once = Once::new(); /// /// // poison the once /// let handle = thread::spawn(|| { @@ -452,9 +463,9 @@ impl OnceState { /// ``` /// #![feature(once_poison)] /// - /// use std::sync::{Once, ONCE_INIT}; + /// use std::sync::Once; /// - /// static INIT: Once = ONCE_INIT; + /// static INIT: Once = Once::new(); /// /// INIT.call_once_force(|state| { /// assert!(!state.poisoned()); diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 2edf02efc47..e3db60cff84 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -24,8 +24,8 @@ use sys_common::rwlock as sys; /// typically allows for read-only access (shared access). /// /// In comparison, a [`Mutex`] does not distinguish between readers or writers -/// that aquire the lock, therefore blocking any threads waiting for the lock to -/// become available. An `RwLock` will allow any number of readers to aquire the +/// that acquire the lock, therefore blocking any threads waiting for the lock to +/// become available. An `RwLock` will allow any number of readers to acquire the /// lock as long as a writer is not holding the lock. /// /// The priority policy of the lock is dependent on the underlying operating @@ -94,7 +94,7 @@ unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {} /// [`read`]: struct.RwLock.html#method.read /// [`try_read`]: struct.RwLock.html#method.try_read /// [`RwLock`]: struct.RwLock.html -#[must_use] +#[must_use = "if unused the RwLock will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { __lock: &'a RwLock<T>, @@ -115,7 +115,7 @@ unsafe impl<'a, T: ?Sized + Sync> Sync for RwLockReadGuard<'a, T> {} /// [`write`]: struct.RwLock.html#method.write /// [`try_write`]: struct.RwLock.html#method.try_write /// [`RwLock`]: struct.RwLock.html -#[must_use] +#[must_use = "if unused the RwLock will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { __lock: &'a RwLock<T>, diff --git a/src/libstd/sys/cloudabi/abi/cloudabi.rs b/src/libstd/sys/cloudabi/abi/cloudabi.rs index 2909db5098e..cd9a5ad448f 100644 --- a/src/libstd/sys/cloudabi/abi/cloudabi.rs +++ b/src/libstd/sys/cloudabi/abi/cloudabi.rs @@ -121,6 +121,7 @@ include!("bitflags.rs"); /// File or memory access pattern advisory information. #[repr(u8)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[non_exhaustive] pub enum advice { /// The application expects that it will not access the /// specified data in the near future. @@ -140,12 +141,12 @@ pub enum advice { /// The application expects to access the specified data /// in the near future. WILLNEED = 6, - #[doc(hidden)] _NonExhaustive = -1 as isize as u8, } /// Enumeration describing the kind of value stored in [`auxv`](struct.auxv.html). #[repr(u32)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[non_exhaustive] pub enum auxtype { /// Base address of the binary argument data provided to /// [`proc_exec()`](fn.proc_exec.html). @@ -210,12 +211,12 @@ pub enum auxtype { SYSINFO_EHDR = 262, /// Thread ID of the initial thread of the process. TID = 261, - #[doc(hidden)] _NonExhaustive = -1 as isize as u32, } /// Identifiers for clocks. #[repr(u32)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[non_exhaustive] pub enum clockid { /// The system-wide monotonic clock, which is defined as a /// clock measuring real time, whose value cannot be @@ -232,7 +233,6 @@ pub enum clockid { REALTIME = 3, /// The CPU-time clock associated with the current thread. THREAD_CPUTIME_ID = 4, - #[doc(hidden)] _NonExhaustive = -1 as isize as u32, } /// A userspace condition variable. @@ -267,6 +267,7 @@ pub const DIRCOOKIE_START: dircookie = dircookie(0); /// exclusively or merely provided for alignment with POSIX. #[repr(u16)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[non_exhaustive] pub enum errno { /// No error occurred. System call completed successfully. SUCCESS = 0, @@ -422,7 +423,6 @@ pub enum errno { XDEV = 75, /// Extension: Capabilities insufficient. NOTCAPABLE = 76, - #[doc(hidden)] _NonExhaustive = -1 as isize as u16, } bitflags! { @@ -438,6 +438,7 @@ bitflags! { /// Type of a subscription to an event or its occurrence. #[repr(u8)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[non_exhaustive] pub enum eventtype { /// The time value of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id) /// has reached timestamp [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout). @@ -463,7 +464,6 @@ pub enum eventtype { /// The process associated with process descriptor /// [`subscription.union.proc_terminate.fd`](struct.subscription_proc_terminate.html#structfield.fd) has terminated. PROC_TERMINATE = 7, - #[doc(hidden)] _NonExhaustive = -1 as isize as u8, } /// Exit code generated by a process when exiting. @@ -530,6 +530,7 @@ pub type filesize = u64; /// The type of a file descriptor or file. #[repr(u8)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[non_exhaustive] pub enum filetype { /// The type of the file descriptor or file is unknown or /// is different from any of the other types specified. @@ -558,7 +559,6 @@ pub enum filetype { SOCKET_STREAM = 130, /// The file refers to a symbolic link inode. SYMBOLIC_LINK = 144, - #[doc(hidden)] _NonExhaustive = -1 as isize as u8, } bitflags! { @@ -847,12 +847,12 @@ bitflags! { /// memory. #[repr(u8)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[non_exhaustive] pub enum scope { /// The object is stored in private memory. PRIVATE = 4, /// The object is stored in shared memory. SHARED = 8, - #[doc(hidden)] _NonExhaustive = -1 as isize as u8, } bitflags! { @@ -878,6 +878,7 @@ bitflags! { /// Signal condition. #[repr(u8)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[non_exhaustive] pub enum signal { /// Process abort signal. /// @@ -983,7 +984,6 @@ pub enum signal { /// /// Action: Terminates the process. XFSZ = 26, - #[doc(hidden)] _NonExhaustive = -1 as isize as u8, } bitflags! { @@ -1049,6 +1049,7 @@ pub type userdata = u64; /// should be set. #[repr(u8)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[non_exhaustive] pub enum whence { /// Seek relative to current position. CUR = 1, @@ -1056,7 +1057,6 @@ pub enum whence { END = 2, /// Seek relative to start-of-file. SET = 3, - #[doc(hidden)] _NonExhaustive = -1 as isize as u8, } /// Auxiliary vector entry. diff --git a/src/libstd/sys/cloudabi/backtrace.rs b/src/libstd/sys/cloudabi/backtrace.rs index 33d93179237..2c43b5937ce 100644 --- a/src/libstd/sys/cloudabi/backtrace.rs +++ b/src/libstd/sys/cloudabi/backtrace.rs @@ -64,6 +64,10 @@ extern "C" fn trace_fn( arg: *mut libc::c_void, ) -> uw::_Unwind_Reason_Code { let cx = unsafe { &mut *(arg as *mut Context) }; + if cx.idx >= cx.frames.len() { + return uw::_URC_NORMAL_STOP; + } + let mut ip_before_insn = 0; let mut ip = unsafe { uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void }; if !ip.is_null() && ip_before_insn == 0 { @@ -73,13 +77,12 @@ extern "C" fn trace_fn( } let symaddr = unsafe { uw::_Unwind_FindEnclosingFunction(ip) }; - if cx.idx < cx.frames.len() { - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - }; - cx.idx += 1; - } + cx.frames[cx.idx] = Frame { + symbol_addr: symaddr as *mut u8, + exact_position: ip as *mut u8, + inline_context: 0, + }; + cx.idx += 1; uw::_URC_NO_REASON } diff --git a/src/libstd/sys/cloudabi/shims/process.rs b/src/libstd/sys/cloudabi/shims/process.rs index 52e8c82e2b2..fcd40c15c17 100644 --- a/src/libstd/sys/cloudabi/shims/process.rs +++ b/src/libstd/sys/cloudabi/shims/process.rs @@ -126,6 +126,18 @@ impl fmt::Display for ExitStatus { } } +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitCode(bool); + +impl ExitCode { + pub const SUCCESS: ExitCode = ExitCode(false); + pub const FAILURE: ExitCode = ExitCode(true); + + pub fn as_i32(&self) -> i32 { + self.0 as i32 + } +} + pub struct Process(Void); impl Process { diff --git a/src/libstd/sys/cloudabi/stdio.rs b/src/libstd/sys/cloudabi/stdio.rs index 9519a926471..1d7344f921c 100644 --- a/src/libstd/sys/cloudabi/stdio.rs +++ b/src/libstd/sys/cloudabi/stdio.rs @@ -77,3 +77,7 @@ pub fn is_ebadf(err: &io::Error) -> bool { } pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; + +pub fn stderr_prints_nothing() -> bool { + false +} diff --git a/src/libstd/sys/cloudabi/thread.rs b/src/libstd/sys/cloudabi/thread.rs index c980ae75261..8cca47efd22 100644 --- a/src/libstd/sys/cloudabi/thread.rs +++ b/src/libstd/sys/cloudabi/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::boxed::FnBox; +use boxed::FnBox; use cmp; use ffi::CStr; use io; @@ -32,7 +32,7 @@ unsafe impl Send for Thread {} unsafe impl Sync for Thread {} impl Thread { - pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>) -> io::Result<Thread> { + pub unsafe fn new<'a>(stack: usize, p: Box<dyn FnBox() + 'a>) -> io::Result<Thread> { let p = box p; let mut native: libc::pthread_t = mem::zeroed(); let mut attr: libc::pthread_attr_t = mem::zeroed(); @@ -111,12 +111,14 @@ impl Drop for Thread { #[cfg_attr(test, allow(dead_code))] pub mod guard { - pub unsafe fn current() -> Option<usize> { + pub type Guard = !; + pub unsafe fn current() -> Option<Guard> { None } - pub unsafe fn init() -> Option<usize> { + pub unsafe fn init() -> Option<Guard> { None } + pub unsafe fn deinit() {} } fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs index 1231898ed7e..c44db3b1072 100644 --- a/src/libstd/sys/mod.rs +++ b/src/libstd/sys/mod.rs @@ -67,6 +67,7 @@ cfg_if! { // (missing things in `libc` which is empty) so just omit everything // with an empty module #[unstable(issue = "0", feature = "std_internals")] + #[allow(missing_docs)] pub mod unix_ext {} } else { // On other platforms like Windows document the bare bones of unix @@ -80,11 +81,13 @@ cfg_if! { cfg_if! { if #[cfg(windows)] { // On windows we'll just be documenting what's already available + #[allow(missing_docs)] pub use self::ext as windows_ext; } else if #[cfg(any(target_os = "cloudabi", target_arch = "wasm32"))] { // On CloudABI and wasm right now the shim below doesn't compile, so // just omit it #[unstable(issue = "0", feature = "std_internals")] + #[allow(missing_docs)] pub mod windows_ext {} } else { // On all other platforms (aka linux/osx/etc) then pull in a "minimal" diff --git a/src/libstd/sys/redox/args.rs b/src/libstd/sys/redox/args.rs index 59ae2a74a6d..556ed77372e 100644 --- a/src/libstd/sys/redox/args.rs +++ b/src/libstd/sys/redox/args.rs @@ -73,17 +73,15 @@ mod imp { CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec() }).collect(); - LOCK.lock(); + let _guard = LOCK.lock(); let ptr = get_global_ptr(); assert!((*ptr).is_none()); (*ptr) = Some(box args); - LOCK.unlock(); } pub unsafe fn cleanup() { - LOCK.lock(); + let _guard = LOCK.lock(); *get_global_ptr() = None; - LOCK.unlock(); } pub fn args() -> Args { @@ -96,16 +94,14 @@ mod imp { fn clone() -> Option<Vec<Vec<u8>>> { unsafe { - LOCK.lock(); + let _guard = LOCK.lock(); let ptr = get_global_ptr(); - let ret = (*ptr).as_ref().map(|s| (**s).clone()); - LOCK.unlock(); - return ret + (*ptr).as_ref().map(|s| (**s).clone()) } } - fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> { - unsafe { mem::transmute(&GLOBAL_ARGS_PTR) } + unsafe fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> { + mem::transmute(&GLOBAL_ARGS_PTR) } } diff --git a/src/libstd/sys/redox/backtrace/tracing.rs b/src/libstd/sys/redox/backtrace/tracing.rs index 0a174b3c3f5..c0414b78f8d 100644 --- a/src/libstd/sys/redox/backtrace/tracing.rs +++ b/src/libstd/sys/redox/backtrace/tracing.rs @@ -68,6 +68,10 @@ pub fn unwind_backtrace(frames: &mut [Frame]) extern fn trace_fn(ctx: *mut uw::_Unwind_Context, arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { let cx = unsafe { &mut *(arg as *mut Context) }; + if cx.idx >= cx.frames.len() { + return uw::_URC_NORMAL_STOP; + } + let mut ip_before_insn = 0; let mut ip = unsafe { uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void @@ -94,13 +98,12 @@ extern fn trace_fn(ctx: *mut uw::_Unwind_Context, unsafe { uw::_Unwind_FindEnclosingFunction(ip) } }; - if cx.idx < cx.frames.len() { - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - }; - cx.idx += 1; - } + cx.frames[cx.idx] = Frame { + symbol_addr: symaddr as *mut u8, + exact_position: ip as *mut u8, + inline_context: 0, + }; + cx.idx += 1; uw::_URC_NO_REASON } diff --git a/src/libstd/sys/redox/ext/ffi.rs b/src/libstd/sys/redox/ext/ffi.rs index d59b4fc0b70..cd88c8f46b3 100644 --- a/src/libstd/sys/redox/ext/ffi.rs +++ b/src/libstd/sys/redox/ext/ffi.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Unix-specific extension to the primitives in the `std::ffi` module +//! Redox-specific extension to the primitives in the `std::ffi` module. #![stable(feature = "rust1", since = "1.0.0")] @@ -17,7 +17,9 @@ use mem; use sys::os_str::Buf; use sys_common::{FromInner, IntoInner, AsInner}; -/// Unix-specific extensions to `OsString`. +/// Redox-specific extensions to [`OsString`]. +/// +/// [`OsString`]: ../../../../std/ffi/struct.OsString.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStringExt { /// Creates an `OsString` from a byte vector. @@ -39,7 +41,9 @@ impl OsStringExt for OsString { } } -/// Unix-specific extensions to `OsStr`. +/// Redox-specific extensions to [`OsStr`]. +/// +/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStrExt { #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys/redox/ext/fs.rs b/src/libstd/sys/redox/ext/fs.rs index 5d4edc2cf92..c1dba6edda4 100644 --- a/src/libstd/sys/redox/ext/fs.rs +++ b/src/libstd/sys/redox/ext/fs.rs @@ -18,7 +18,9 @@ use path::Path; use sys; use sys_common::{FromInner, AsInner, AsInnerMut}; -/// Redox-specific extensions to `Permissions` +/// Redox-specific extensions to [`fs::Permissions`]. +/// +/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html #[stable(feature = "fs_ext", since = "1.1.0")] pub trait PermissionsExt { /// Returns the underlying raw `mode_t` bits that are the standard Redox @@ -30,13 +32,14 @@ pub trait PermissionsExt { /// use std::fs::File; /// use std::os::redox::fs::PermissionsExt; /// - /// # fn run() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let permissions = metadata.permissions(); + /// fn main() -> std::io::Result<()> { + /// let f = File::create("foo.txt")?; + /// let metadata = f.metadata()?; + /// let permissions = metadata.permissions(); /// - /// println!("permissions: {}", permissions.mode()); - /// # Ok(()) } + /// println!("permissions: {}", permissions.mode()); + /// Ok(()) + /// } /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] fn mode(&self) -> u32; @@ -49,14 +52,15 @@ pub trait PermissionsExt { /// use std::fs::File; /// use std::os::redox::fs::PermissionsExt; /// - /// # fn run() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let mut permissions = metadata.permissions(); + /// fn main() -> std::io::Result<()> { + /// let f = File::create("foo.txt")?; + /// let metadata = f.metadata()?; + /// let mut permissions = metadata.permissions(); /// - /// permissions.set_mode(0o644); // Read/write for owner and read for others. - /// assert_eq!(permissions.mode(), 0o644); - /// # Ok(()) } + /// permissions.set_mode(0o644); // Read/write for owner and read for others. + /// assert_eq!(permissions.mode(), 0o644); + /// Ok(()) + /// } /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] fn set_mode(&mut self, mode: u32); @@ -93,7 +97,9 @@ impl PermissionsExt for Permissions { } } -/// Redox-specific extensions to `OpenOptions` +/// Redox-specific extensions to [`fs::OpenOptions`]. +/// +/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html #[stable(feature = "fs_ext", since = "1.1.0")] pub trait OpenOptionsExt { /// Sets the mode bits that a new file will be created with. @@ -161,13 +167,9 @@ impl OpenOptionsExt for OpenOptions { } } -// Hm, why are there casts here to the returned type, shouldn't the types always -// be the same? Right you are! Turns out, however, on android at least the types -// in the raw `stat` structure are not the same as the types being returned. Who -// knew! -// -// As a result to make sure this compiles for all platforms we do the manual -// casts and rely on manual lowering to `stat` if the raw type is desired. +/// Redox-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { #[stable(feature = "metadata_ext", since = "1.1.0")] @@ -202,6 +204,13 @@ pub trait MetadataExt { fn blocks(&self) -> u64; } +// Hm, why are there casts here to the returned type, shouldn't the types always +// be the same? Right you are! Turns out, however, on android at least the types +// in the raw `stat` structure are not the same as the types being returned. Who +// knew! +// +// As a result to make sure this compiles for all platforms we do the manual +// casts and rely on manual lowering to `stat` if the raw type is desired. #[stable(feature = "metadata_ext", since = "1.1.0")] impl MetadataExt for fs::Metadata { fn dev(&self) -> u64 { @@ -251,7 +260,12 @@ impl MetadataExt for fs::Metadata { } } -/// Add special Redox types (block/char device, fifo and socket) +/// Redox-specific extensions for [`FileType`]. +/// +/// Adds support for special Unix file types such as block/character devices, +/// pipes, and sockets. +/// +/// [`FileType`]: ../../../../std/fs/struct.FileType.html #[stable(feature = "file_type_ext", since = "1.5.0")] pub trait FileTypeExt { /// Returns whether this file type is a block device. @@ -291,13 +305,13 @@ impl FileTypeExt for fs::FileType { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::os::redox::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::symlink("a.txt", "b.txt")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::symlink("a.txt", "b.txt")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "symlink", since = "1.1.0")] pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> @@ -305,8 +319,10 @@ pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> sys::fs::symlink(src.as_ref(), dst.as_ref()) } +/// Redox-specific extensions to [`fs::DirBuilder`]. +/// +/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html #[stable(feature = "dir_builder", since = "1.6.0")] -/// An extension trait for `fs::DirBuilder` for Redox-specific options. pub trait DirBuilderExt { /// Sets the mode to create new directories with. This option defaults to /// 0o777. diff --git a/src/libstd/sys/redox/ext/mod.rs b/src/libstd/sys/redox/ext/mod.rs index 9fd8d6c9186..cb2c75ae0bf 100644 --- a/src/libstd/sys/redox/ext/mod.rs +++ b/src/libstd/sys/redox/ext/mod.rs @@ -33,6 +33,7 @@ pub mod ffi; pub mod fs; pub mod io; +pub mod net; pub mod process; pub mod thread; diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs new file mode 100644 index 00000000000..2ab77703242 --- /dev/null +++ b/src/libstd/sys/redox/ext/net.rs @@ -0,0 +1,769 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![stable(feature = "unix_socket_redox", since = "1.29")] + +//! Unix-specific networking functionality + +use fmt; +use io::{self, Error, ErrorKind, Initializer}; +use net::Shutdown; +use os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; +use path::Path; +use time::Duration; +use sys::{cvt, fd::FileDesc, syscall}; + +/// An address associated with a Unix socket. +/// +/// # Examples +/// +/// ``` +/// use std::os::unix::net::UnixListener; +/// +/// let socket = match UnixListener::bind("/tmp/sock") { +/// Ok(sock) => sock, +/// Err(e) => { +/// println!("Couldn't bind: {:?}", e); +/// return +/// } +/// }; +/// let addr = socket.local_addr().expect("Couldn't get local address"); +/// ``` +#[derive(Clone)] +#[stable(feature = "unix_socket_redox", since = "1.29")] +pub struct SocketAddr(()); + +impl SocketAddr { + /// Returns the contents of this address if it is a `pathname` address. + /// + /// # Examples + /// + /// With a pathname: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// use std::path::Path; + /// + /// let socket = UnixListener::bind("/tmp/sock").unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); + /// ``` + /// + /// Without a pathname: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// let socket = UnixDatagram::unbound().unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), None); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn as_pathname(&self) -> Option<&Path> { + None + } + + /// Returns true if and only if the address is unnamed. + /// + /// # Examples + /// + /// A named address: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let socket = UnixListener::bind("/tmp/sock").unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), false); + /// ``` + /// + /// An unnamed address: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// let socket = UnixDatagram::unbound().unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), true); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn is_unnamed(&self) -> bool { + false + } +} +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl fmt::Debug for SocketAddr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "SocketAddr") + } +} + +/// A Unix stream socket. +/// +/// # Examples +/// +/// ```no_run +/// use std::os::unix::net::UnixStream; +/// use std::io::prelude::*; +/// +/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap(); +/// stream.write_all(b"hello world").unwrap(); +/// let mut response = String::new(); +/// stream.read_to_string(&mut response).unwrap(); +/// println!("{}", response); +/// ``` +#[stable(feature = "unix_socket_redox", since = "1.29")] +pub struct UnixStream(FileDesc); + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl fmt::Debug for UnixStream { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixStream"); + builder.field("fd", &self.0.raw()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + if let Ok(addr) = self.peer_addr() { + builder.field("peer", &addr); + } + builder.finish() + } +} + +impl UnixStream { + /// Connects to the socket named by `path`. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = match UnixStream::connect("/tmp/sock") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> { + if let Some(s) = path.as_ref().to_str() { + cvt(syscall::open(format!("chan:{}", s), syscall::O_CLOEXEC)) + .map(FileDesc::new) + .map(UnixStream) + } else { + Err(Error::new( + ErrorKind::Other, + "UnixStream::connect: non-utf8 paths not supported on redox" + )) + } + } + + /// Creates an unnamed pair of connected sockets. + /// + /// Returns two `UnixStream`s which are connected to each other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let (sock1, sock2) = match UnixStream::pair() { + /// Ok((sock1, sock2)) => (sock1, sock2), + /// Err(e) => { + /// println!("Couldn't create a pair of sockets: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn pair() -> io::Result<(UnixStream, UnixStream)> { + let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC)) + .map(FileDesc::new)?; + let client = server.duplicate_path(b"connect")?; + let stream = server.duplicate_path(b"listen")?; + Ok((UnixStream(client), UnixStream(stream))) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixStream` is a reference to the same stream that this + /// object references. Both handles will read and write the same stream of + /// data, and options set on one stream will be propagated to the other + /// stream. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn try_clone(&self) -> io::Result<UnixStream> { + self.0.duplicate().map(UnixStream) + } + + /// Returns the socket address of the local half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn local_addr(&self) -> io::Result<SocketAddr> { + Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox")) + } + + /// Returns the socket address of the remote half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let addr = socket.peer_addr().expect("Couldn't get peer address"); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn peer_addr(&self) -> io::Result<SocketAddr> { + Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox")) + } + + /// Sets the read timeout for the socket. + /// + /// If the provided value is [`None`], then [`read`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method. + /// + /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err + /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read + /// [`Duration`]: ../../../../std/time/struct.Duration.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn set_read_timeout(&self, _timeout: Option<Duration>) -> io::Result<()> { + Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox")) + } + + /// Sets the write timeout for the socket. + /// + /// If the provided value is [`None`], then [`write`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. + /// + /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err + /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write + /// [`Duration`]: ../../../../std/time/struct.Duration.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::UdpSocket; + /// use std::time::Duration; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn set_write_timeout(&self, _timeout: Option<Duration>) -> io::Result<()> { + Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox")) + } + + /// Returns the read timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0))); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn read_timeout(&self) -> io::Result<Option<Duration>> { + Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox")) + } + + /// Returns the write timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); + /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0))); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn write_timeout(&self) -> io::Result<Option<Duration>> { + Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox")) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// if let Ok(Some(err)) = socket.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// ``` + /// + /// # Platform specific + /// On Redox this always returns None. + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn take_error(&self) -> io::Result<Option<io::Error>> { + Ok(None) + } + + /// Shuts down the read, write, or both halves of this connection. + /// + /// This function will cause all pending and future I/O calls on the + /// specified portions to immediately return with an appropriate value + /// (see the documentation of [`Shutdown`]). + /// + /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::net::Shutdown; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> { + Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox")) + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl io::Read for UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + io::Read::read(&mut &*self, buf) + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl<'a> io::Read for &'a UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + self.0.read(buf) + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl io::Write for UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + io::Write::write(&mut &*self, buf) + } + + fn flush(&mut self) -> io::Result<()> { + io::Write::flush(&mut &*self) + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl<'a> io::Write for &'a UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.0.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl AsRawFd for UnixStream { + fn as_raw_fd(&self) -> RawFd { + self.0.raw() + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl FromRawFd for UnixStream { + unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { + UnixStream(FileDesc::new(fd)) + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl IntoRawFd for UnixStream { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw() + } +} + +/// A structure representing a Unix domain socket server. +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); +/// +/// // accept connections and process them, spawning a new thread for each one +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// /* connection succeeded */ +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// /* connection failed */ +/// break; +/// } +/// } +/// } +/// ``` +#[stable(feature = "unix_socket_redox", since = "1.29")] +pub struct UnixListener(FileDesc); + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl fmt::Debug for UnixListener { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixListener"); + builder.field("fd", &self.0.raw()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + builder.finish() + } +} + +impl UnixListener { + /// Creates a new `UnixListener` bound to the specified socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = match UnixListener::bind("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> { + if let Some(s) = path.as_ref().to_str() { + cvt(syscall::open(format!("chan:{}", s), syscall::O_CREAT | syscall::O_CLOEXEC)) + .map(FileDesc::new) + .map(UnixListener) + } else { + Err(Error::new( + ErrorKind::Other, + "UnixListener::bind: non-utf8 paths not supported on redox" + )) + } + } + + /// Accepts a new incoming connection to this listener. + /// + /// This function will block the calling thread until a new Unix connection + /// is established. When established, the corresponding [`UnixStream`] and + /// the remote peer's address will be returned. + /// + /// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// match listener.accept() { + /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), + /// Err(e) => println!("accept function failed: {:?}", e), + /// } + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { + self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr(()))) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixListener` is a reference to the same socket that this + /// object references. Both handles can be used to accept incoming + /// connections and options set on one listener will affect the other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// let listener_copy = listener.try_clone().expect("try_clone failed"); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn try_clone(&self) -> io::Result<UnixListener> { + self.0.duplicate().map(UnixListener) + } + + /// Returns the local socket address of this listener. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// let addr = listener.local_addr().expect("Couldn't get local address"); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn local_addr(&self) -> io::Result<SocketAddr> { + Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox")) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/tmp/sock").unwrap(); + /// + /// if let Ok(Some(err)) = listener.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// ``` + /// + /// # Platform specific + /// On Redox this always returns None. + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn take_error(&self) -> io::Result<Option<io::Error>> { + Ok(None) + } + + /// Returns an iterator over incoming connections. + /// + /// The iterator will never return [`None`] and will also not yield the + /// peer's [`SocketAddr`] structure. + /// + /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`SocketAddr`]: struct.SocketAddr.html + /// + /// # Examples + /// + /// ```no_run + /// use std::thread; + /// use std::os::unix::net::{UnixStream, UnixListener}; + /// + /// fn handle_client(stream: UnixStream) { + /// // ... + /// } + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// for stream in listener.incoming() { + /// match stream { + /// Ok(stream) => { + /// thread::spawn(|| handle_client(stream)); + /// } + /// Err(err) => { + /// break; + /// } + /// } + /// } + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn incoming<'a>(&'a self) -> Incoming<'a> { + Incoming { listener: self } + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl AsRawFd for UnixListener { + fn as_raw_fd(&self) -> RawFd { + self.0.raw() + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl FromRawFd for UnixListener { + unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { + UnixListener(FileDesc::new(fd)) + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl IntoRawFd for UnixListener { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw() + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl<'a> IntoIterator for &'a UnixListener { + type Item = io::Result<UnixStream>; + type IntoIter = Incoming<'a>; + + fn into_iter(self) -> Incoming<'a> { + self.incoming() + } +} + +/// An iterator over incoming connections to a [`UnixListener`]. +/// +/// It will never return [`None`]. +/// +/// [`None`]: ../../../../std/option/enum.Option.html#variant.None +/// [`UnixListener`]: struct.UnixListener.html +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); +/// +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// break; +/// } +/// } +/// } +/// ``` +#[derive(Debug)] +#[stable(feature = "unix_socket_redox", since = "1.29")] +pub struct Incoming<'a> { + listener: &'a UnixListener, +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl<'a> Iterator for Incoming<'a> { + type Item = io::Result<UnixStream>; + + fn next(&mut self) -> Option<io::Result<UnixStream>> { + Some(self.listener.accept().map(|s| s.0)) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (usize::max_value(), None) + } +} diff --git a/src/libstd/sys/redox/ext/process.rs b/src/libstd/sys/redox/ext/process.rs index e68e180acf1..cfb6d5fc703 100644 --- a/src/libstd/sys/redox/ext/process.rs +++ b/src/libstd/sys/redox/ext/process.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Unix-specific extensions to primitives in the `std::process` module. +//! Redox-specific extensions to primitives in the `std::process` module. #![stable(feature = "rust1", since = "1.0.0")] @@ -18,7 +18,9 @@ use process; use sys; use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner}; -/// Unix-specific extensions to the `std::process::Command` builder +/// Redox-specific extensions to the [`process::Command`] builder, +/// +/// [`process::Command`]: ../../../../std/process/struct.Command.html #[stable(feature = "rust1", since = "1.0.0")] pub trait CommandExt { /// Sets the child process's user id. This translates to a @@ -107,7 +109,9 @@ impl CommandExt for process::Command { } } -/// Unix-specific extensions to `std::process::ExitStatus` +/// Redox-specific extensions to [`process::ExitStatus`]. +/// +/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html #[stable(feature = "rust1", since = "1.0.0")] pub trait ExitStatusExt { /// Creates a new `ExitStatus` from the raw underlying `i32` return value of diff --git a/src/libstd/sys/redox/ext/thread.rs b/src/libstd/sys/redox/ext/thread.rs index 52be2ccd9f9..71ff0d46b91 100644 --- a/src/libstd/sys/redox/ext/thread.rs +++ b/src/libstd/sys/redox/ext/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Unix-specific extensions to primitives in the `std::thread` module. +//! Redox-specific extensions to primitives in the `std::thread` module. #![stable(feature = "thread_extensions", since = "1.9.0")] @@ -19,7 +19,9 @@ use thread::JoinHandle; #[allow(deprecated)] pub type RawPthread = usize; -/// Unix-specific extensions to `std::thread::JoinHandle` +/// Redox-specific extensions to [`thread::JoinHandle`]. +/// +/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html #[stable(feature = "thread_extensions", since = "1.9.0")] pub trait JoinHandleExt { /// Extracts the raw pthread_t without taking ownership diff --git a/src/libstd/sys/redox/fd.rs b/src/libstd/sys/redox/fd.rs index ba7bbdc657f..e04e2791b23 100644 --- a/src/libstd/sys/redox/fd.rs +++ b/src/libstd/sys/redox/fd.rs @@ -47,7 +47,10 @@ impl FileDesc { } pub fn duplicate(&self) -> io::Result<FileDesc> { - let new_fd = cvt(syscall::dup(self.fd, &[]))?; + self.duplicate_path(&[]) + } + pub fn duplicate_path(&self, path: &[u8]) -> io::Result<FileDesc> { + let new_fd = cvt(syscall::dup(self.fd, path))?; Ok(FileDesc::new(new_fd)) } diff --git a/src/libstd/sys/redox/net/mod.rs b/src/libstd/sys/redox/net/mod.rs index 0291d7f0e92..67f22231d5f 100644 --- a/src/libstd/sys/redox/net/mod.rs +++ b/src/libstd/sys/redox/net/mod.rs @@ -41,12 +41,12 @@ impl Iterator for LookupHost { pub fn lookup_host(host: &str) -> Result<LookupHost> { let mut ip_string = String::new(); File::open("/etc/net/ip")?.read_to_string(&mut ip_string)?; - let ip: Vec<u8> = ip_string.trim().split(".").map(|part| part.parse::<u8>() + let ip: Vec<u8> = ip_string.trim().split('.').map(|part| part.parse::<u8>() .unwrap_or(0)).collect(); let mut dns_string = String::new(); File::open("/etc/net/dns")?.read_to_string(&mut dns_string)?; - let dns: Vec<u8> = dns_string.trim().split(".").map(|part| part.parse::<u8>() + let dns: Vec<u8> = dns_string.trim().split('.').map(|part| part.parse::<u8>() .unwrap_or(0)).collect(); if ip.len() == 4 && dns.len() == 4 { diff --git a/src/libstd/sys/redox/net/netc.rs b/src/libstd/sys/redox/net/netc.rs index d443a4d68a1..b6d9f456295 100644 --- a/src/libstd/sys/redox/net/netc.rs +++ b/src/libstd/sys/redox/net/netc.rs @@ -24,10 +24,10 @@ pub struct in_addr { } #[derive(Copy, Clone)] +#[repr(align(4))] #[repr(C)] pub struct in6_addr { pub s6_addr: [u8; 16], - __align: [u32; 0], } #[derive(Copy, Clone)] diff --git a/src/libstd/sys/redox/net/tcp.rs b/src/libstd/sys/redox/net/tcp.rs index 319965ab396..b5664908479 100644 --- a/src/libstd/sys/redox/net/tcp.rs +++ b/src/libstd/sys/redox/net/tcp.rs @@ -9,7 +9,7 @@ // except according to those terms. use cmp; -use io::{Error, ErrorKind, Result}; +use io::{self, Error, ErrorKind, Result}; use mem; use net::{SocketAddr, Shutdown}; use path::Path; @@ -130,6 +130,10 @@ impl TcpStream { pub fn set_read_timeout(&self, duration_option: Option<Duration>) -> Result<()> { let file = self.0.dup(b"read_timeout")?; if let Some(duration) = duration_option { + if duration.as_secs() == 0 && duration.subsec_nanos() == 0 { + return Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot set a 0 duration timeout")); + } file.write(&TimeSpec { tv_sec: duration.as_secs() as i64, tv_nsec: duration.subsec_nanos() as i32 @@ -143,6 +147,10 @@ impl TcpStream { pub fn set_write_timeout(&self, duration_option: Option<Duration>) -> Result<()> { let file = self.0.dup(b"write_timeout")?; if let Some(duration) = duration_option { + if duration.as_secs() == 0 && duration.subsec_nanos() == 0 { + return Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot set a 0 duration timeout")); + } file.write(&TimeSpec { tv_sec: duration.as_secs() as i64, tv_nsec: duration.subsec_nanos() as i32 diff --git a/src/libstd/sys/redox/net/udp.rs b/src/libstd/sys/redox/net/udp.rs index 7e7666e7ef3..22af02079e7 100644 --- a/src/libstd/sys/redox/net/udp.rs +++ b/src/libstd/sys/redox/net/udp.rs @@ -10,7 +10,7 @@ use cell::UnsafeCell; use cmp; -use io::{Error, ErrorKind, Result}; +use io::{self, Error, ErrorKind, Result}; use mem; use net::{SocketAddr, Ipv4Addr, Ipv6Addr}; use path::Path; @@ -58,7 +58,7 @@ impl UdpSocket { pub fn recv(&self, buf: &mut [u8]) -> Result<usize> { if let Some(addr) = *self.get_conn() { - let from = self.0.dup(format!("{}", addr).as_bytes())?; + let from = self.0.dup(addr.to_string().as_bytes())?; from.read(buf) } else { Err(Error::new(ErrorKind::Other, "UdpSocket::recv not connected")) @@ -179,6 +179,10 @@ impl UdpSocket { pub fn set_read_timeout(&self, duration_option: Option<Duration>) -> Result<()> { let file = self.0.dup(b"read_timeout")?; if let Some(duration) = duration_option { + if duration.as_secs() == 0 && duration.subsec_nanos() == 0 { + return Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot set a 0 duration timeout")); + } file.write(&TimeSpec { tv_sec: duration.as_secs() as i64, tv_nsec: duration.subsec_nanos() as i32 @@ -192,6 +196,10 @@ impl UdpSocket { pub fn set_write_timeout(&self, duration_option: Option<Duration>) -> Result<()> { let file = self.0.dup(b"write_timeout")?; if let Some(duration) = duration_option { + if duration.as_secs() == 0 && duration.subsec_nanos() == 0 { + return Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot set a 0 duration timeout")); + } file.write(&TimeSpec { tv_sec: duration.as_secs() as i64, tv_nsec: duration.subsec_nanos() as i32 diff --git a/src/libstd/sys/redox/os.rs b/src/libstd/sys/redox/os.rs index 480765b77a0..5822216779b 100644 --- a/src/libstd/sys/redox/os.rs +++ b/src/libstd/sys/redox/os.rs @@ -30,9 +30,6 @@ use sys_common::mutex::Mutex; use sys::{cvt, fd, syscall}; use vec; -const TMPBUF_SZ: usize = 128; -static ENV_LOCK: Mutex = Mutex::new(); - extern { #[link_name = "__errno_location"] fn errno_location() -> *mut i32; diff --git a/src/libstd/sys/redox/os_str.rs b/src/libstd/sys/redox/os_str.rs index 655bfdb9167..eb3a1ead58c 100644 --- a/src/libstd/sys/redox/os_str.rs +++ b/src/libstd/sys/redox/os_str.rs @@ -19,7 +19,7 @@ use rc::Rc; use sync::Arc; use sys_common::{AsInner, IntoInner}; use sys_common::bytestring::debug_fmt_bytestring; -use std_unicode::lossy::Utf8Lossy; +use core::str::lossy::Utf8Lossy; #[derive(Clone, Hash)] pub struct Buf { @@ -104,6 +104,11 @@ impl Buf { self.inner.shrink_to_fit() } + #[inline] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.inner.shrink_to(min_capacity) + } + pub fn as_slice(&self) -> &Slice { unsafe { mem::transmute(&*self.inner) } } diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index 3fd54973896..2037616e6ac 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -13,6 +13,8 @@ use ffi::OsStr; use os::unix::ffi::OsStrExt; use fmt; use io::{self, Error, ErrorKind}; +use iter; +use libc::{EXIT_SUCCESS, EXIT_FAILURE}; use path::{Path, PathBuf}; use sys::fd::FileDesc; use sys::fs::{File, OpenOptions}; @@ -50,7 +52,7 @@ pub struct Command { uid: Option<u32>, gid: Option<u32>, saw_nul: bool, - closures: Vec<Box<FnMut() -> io::Result<()> + Send + Sync>>, + closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>, stdin: Option<Stdio>, stdout: Option<Stdio>, stderr: Option<Stdio>, @@ -121,7 +123,7 @@ impl Command { } pub fn before_exec(&mut self, - f: Box<FnMut() -> io::Result<()> + Send + Sync>) { + f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>) { self.closures.push(f); } @@ -295,11 +297,11 @@ impl Command { t!(callback()); } - let mut args: Vec<[usize; 2]> = Vec::new(); - args.push([self.program.as_ptr() as usize, self.program.len()]); - for arg in self.args.iter() { - args.push([arg.as_ptr() as usize, arg.len()]); - } + let args: Vec<[usize; 2]> = iter::once( + [self.program.as_ptr() as usize, self.program.len()] + ).chain( + self.args.iter().map(|arg| [arg.as_ptr() as usize, arg.len()]) + ).collect(); self.env.apply(); @@ -480,6 +482,18 @@ impl fmt::Display for ExitStatus { } } +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitCode(u8); + +impl ExitCode { + pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _); + pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _); + + pub fn as_i32(&self) -> i32 { + self.0 as i32 + } +} + /// The unique id of the process (this should never be negative). pub struct Process { pid: usize, diff --git a/src/libstd/sys/redox/stdio.rs b/src/libstd/sys/redox/stdio.rs index 3abb094ac34..7a4d11b0ecb 100644 --- a/src/libstd/sys/redox/stdio.rs +++ b/src/libstd/sys/redox/stdio.rs @@ -75,3 +75,7 @@ pub fn is_ebadf(err: &io::Error) -> bool { } pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; + +pub fn stderr_prints_nothing() -> bool { + false +} diff --git a/src/libstd/sys/redox/syscall/error.rs b/src/libstd/sys/redox/syscall/error.rs index d8d78d55016..1ef79547431 100644 --- a/src/libstd/sys/redox/syscall/error.rs +++ b/src/libstd/sys/redox/syscall/error.rs @@ -48,13 +48,13 @@ impl Error { } impl fmt::Debug for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.text()) } } impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.text()) } } diff --git a/src/libstd/sys/redox/thread.rs b/src/libstd/sys/redox/thread.rs index c4aad8d86f8..f4177087d77 100644 --- a/src/libstd/sys/redox/thread.rs +++ b/src/libstd/sys/redox/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::boxed::FnBox; +use boxed::FnBox; use ffi::CStr; use io; use mem; @@ -28,7 +28,7 @@ unsafe impl Send for Thread {} unsafe impl Sync for Thread {} impl Thread { - pub unsafe fn new<'a>(_stack: usize, p: Box<FnBox() + 'a>) -> io::Result<Thread> { + pub unsafe fn new<'a>(_stack: usize, p: Box<dyn FnBox() + 'a>) -> io::Result<Thread> { let p = box p; let id = cvt(syscall::clone(syscall::CLONE_VM | syscall::CLONE_FS | syscall::CLONE_FILES))?; @@ -88,6 +88,8 @@ impl Thread { } pub mod guard { - pub unsafe fn current() -> Option<usize> { None } - pub unsafe fn init() -> Option<usize> { None } + pub type Guard = !; + pub unsafe fn current() -> Option<Guard> { None } + pub unsafe fn init() -> Option<Guard> { None } + pub unsafe fn deinit() {} } diff --git a/src/libstd/sys/redox/time.rs b/src/libstd/sys/redox/time.rs index cf798500b7f..5c491115c55 100644 --- a/src/libstd/sys/redox/time.rs +++ b/src/libstd/sys/redox/time.rs @@ -144,7 +144,7 @@ impl Instant { pub fn sub_instant(&self, other: &Instant) -> Duration { self.t.sub_timespec(&other.t).unwrap_or_else(|_| { - panic!("other was less than the current instant") + panic!("specified instant was later than self") }) } diff --git a/src/libstd/sys/unix/args.rs b/src/libstd/sys/unix/args.rs index e1c7ffc19e5..c3c033dfbc7 100644 --- a/src/libstd/sys/unix/args.rs +++ b/src/libstd/sys/unix/args.rs @@ -66,7 +66,8 @@ impl DoubleEndedIterator for Args { target_os = "emscripten", target_os = "haiku", target_os = "l4re", - target_os = "fuchsia"))] + target_os = "fuchsia", + target_os = "hermit"))] mod imp { use os::unix::prelude::*; use ptr; @@ -79,20 +80,20 @@ mod imp { static mut ARGC: isize = 0; static mut ARGV: *const *const u8 = ptr::null(); + // We never call `ENV_LOCK.init()`, so it is UB to attempt to + // acquire this mutex reentrantly! static LOCK: Mutex = Mutex::new(); pub unsafe fn init(argc: isize, argv: *const *const u8) { - LOCK.lock(); + let _guard = LOCK.lock(); ARGC = argc; ARGV = argv; - LOCK.unlock(); } pub unsafe fn cleanup() { - LOCK.lock(); + let _guard = LOCK.lock(); ARGC = 0; ARGV = ptr::null(); - LOCK.unlock(); } pub fn args() -> Args { @@ -104,13 +105,11 @@ mod imp { fn clone() -> Vec<OsString> { unsafe { - LOCK.lock(); - let ret = (0..ARGC).map(|i| { + let _guard = LOCK.lock(); + (0..ARGC).map(|i| { let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char); OsStringExt::from_vec(cstr.to_bytes().to_vec()) - }).collect(); - LOCK.unlock(); - return ret + }).collect() } } } diff --git a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs index 400d39cd4bd..6293eeb4ed6 100644 --- a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs +++ b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs @@ -38,6 +38,7 @@ pub fn unwind_backtrace(frames: &mut [Frame]) *to = Frame { exact_position: *from as *mut u8, symbol_addr: *from as *mut u8, + inline_context: 0, }; } Ok((nb_frames as usize, BacktraceContext)) diff --git a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs index 000c08d2e0d..6e841568679 100644 --- a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs +++ b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs @@ -68,6 +68,10 @@ pub fn unwind_backtrace(frames: &mut [Frame]) extern fn trace_fn(ctx: *mut uw::_Unwind_Context, arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { let cx = unsafe { &mut *(arg as *mut Context) }; + if cx.idx >= cx.frames.len() { + return uw::_URC_NORMAL_STOP; + } + let mut ip_before_insn = 0; let mut ip = unsafe { uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void @@ -94,13 +98,12 @@ extern fn trace_fn(ctx: *mut uw::_Unwind_Context, unsafe { uw::_Unwind_FindEnclosingFunction(ip) } }; - if cx.idx < cx.frames.len() { - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - }; - cx.idx += 1; - } + cx.frames[cx.idx] = Frame { + symbol_addr: symaddr as *mut u8, + exact_position: ip as *mut u8, + inline_context: 0, + }; + cx.idx += 1; uw::_URC_NO_REASON } diff --git a/src/libstd/sys/unix/condvar.rs b/src/libstd/sys/unix/condvar.rs index 4f878d8ad1f..2007da7b1f6 100644 --- a/src/libstd/sys/unix/condvar.rs +++ b/src/libstd/sys/unix/condvar.rs @@ -41,13 +41,15 @@ impl Condvar { #[cfg(any(target_os = "macos", target_os = "ios", target_os = "l4re", - target_os = "android"))] + target_os = "android", + target_os = "hermit"))] pub unsafe fn init(&mut self) {} #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "l4re", - target_os = "android")))] + target_os = "android", + target_os = "hermit")))] pub unsafe fn init(&mut self) { use mem; let mut attr: libc::pthread_condattr_t = mem::uninitialized(); @@ -83,7 +85,10 @@ impl Condvar { // where we configure condition variable to use monotonic clock (instead of // default system clock). This approach avoids all problems that result // from changes made to the system time. - #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))] + #[cfg(not(any(target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "hermit")))] pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { use mem; @@ -113,7 +118,7 @@ impl Condvar { // This implementation is modeled after libcxx's condition_variable // https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46 // https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367 - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android", target_os = "hermit"))] pub unsafe fn wait_timeout(&self, mutex: &Mutex, mut dur: Duration) -> bool { use ptr; use time::Instant; diff --git a/src/libstd/sys/unix/env.rs b/src/libstd/sys/unix/env.rs index 00cf7eca75d..ad116c57f55 100644 --- a/src/libstd/sys/unix/env.rs +++ b/src/libstd/sys/unix/env.rs @@ -172,3 +172,14 @@ pub mod os { pub const EXE_SUFFIX: &'static str = ""; pub const EXE_EXTENSION: &'static str = ""; } + +#[cfg(target_os = "hermit")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "hermit"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} diff --git a/src/libstd/sys/unix/ext/ffi.rs b/src/libstd/sys/unix/ext/ffi.rs index fb9984ccbdd..8347145db5a 100644 --- a/src/libstd/sys/unix/ext/ffi.rs +++ b/src/libstd/sys/unix/ext/ffi.rs @@ -17,7 +17,9 @@ use mem; use sys::os_str::Buf; use sys_common::{FromInner, IntoInner, AsInner}; -/// Unix-specific extensions to `OsString`. +/// Unix-specific extensions to [`OsString`]. +/// +/// [`OsString`]: ../../../../std/ffi/struct.OsString.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStringExt { /// Creates an [`OsString`] from a byte vector. @@ -66,7 +68,9 @@ impl OsStringExt for OsString { } } -/// Unix-specific extensions to `OsStr`. +/// Unix-specific extensions to [`OsStr`]. +/// +/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStrExt { #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 2e17fd58e0a..507e9d88171 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -41,24 +41,96 @@ pub trait FileExt { /// /// # Examples /// - /// ``` - /// use std::os::unix::prelude::FileExt; + /// ```no_run + /// use std::io; /// use std::fs::File; + /// use std::os::unix::prelude::FileExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let mut buf = [0u8; 8]; - /// let file = File::open("foo.txt")?; + /// fn main() -> io::Result<()> { + /// let mut buf = [0u8; 8]; + /// let file = File::open("foo.txt")?; /// - /// // We now read 8 bytes from the offset 10. - /// let num_bytes_read = file.read_at(&mut buf, 10)?; - /// println!("read {} bytes: {:?}", num_bytes_read, buf); - /// # Ok(()) - /// # } + /// // We now read 8 bytes from the offset 10. + /// let num_bytes_read = file.read_at(&mut buf, 10)?; + /// println!("read {} bytes: {:?}", num_bytes_read, buf); + /// Ok(()) + /// } /// ``` #[stable(feature = "file_offset", since = "1.15.0")] fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>; + /// Reads the exact number of byte required to fill `buf` from the given offset. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`. + /// + /// [`Read::read_exact`]: ../../../../std/io/trait.Read.html#method.read_exact + /// [`read_at`]: #tymethod.read_at + /// + /// # Errors + /// + /// If this function encounters an error of the kind + /// [`ErrorKind::Interrupted`] then the error is ignored and the operation + /// will continue. + /// + /// If this function encounters an "end of file" before completely filling + /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`]. + /// The contents of `buf` are unspecified in this case. + /// + /// If any other read error is encountered then this function immediately + /// returns. The contents of `buf` are unspecified in this case. + /// + /// If this function returns an error, it is unspecified how many bytes it + /// has read, but it will never read more than would be necessary to + /// completely fill the buffer. + /// + /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted + /// [`ErrorKind::UnexpectedEof`]: ../../../../std/io/enum.ErrorKind.html#variant.UnexpectedEof + /// + /// # Examples + /// + /// ```no_run + /// #![feature(rw_exact_all_at)] + /// use std::io; + /// use std::fs::File; + /// use std::os::unix::prelude::FileExt; + /// + /// fn main() -> io::Result<()> { + /// let mut buf = [0u8; 8]; + /// let file = File::open("foo.txt")?; + /// + /// // We now read exactly 8 bytes from the offset 10. + /// file.read_exact_at(&mut buf, 10)?; + /// println!("read {} bytes: {:?}", buf.len(), buf); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "rw_exact_all_at", issue = "51984")] + fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> { + while !buf.is_empty() { + match self.read_at(buf, offset) { + Ok(0) => break, + Ok(n) => { + let tmp = buf; + buf = &mut tmp[n..]; + offset += n as u64; + } + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + if !buf.is_empty() { + Err(io::Error::new(io::ErrorKind::UnexpectedEof, + "failed to fill whole buffer")) + } else { + Ok(()) + } + } + /// Writes a number of bytes starting from a given offset. /// /// Returns the number of bytes written. @@ -78,21 +150,76 @@ pub trait FileExt { /// /// # Examples /// - /// ``` - /// use std::os::unix::prelude::FileExt; + /// ```no_run /// use std::fs::File; + /// use std::io; + /// use std::os::unix::prelude::FileExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let file = File::open("foo.txt")?; + /// fn main() -> io::Result<()> { + /// let file = File::open("foo.txt")?; /// - /// // We now write at the offset 10. - /// file.write_at(b"sushi", 10)?; - /// # Ok(()) - /// # } + /// // We now write at the offset 10. + /// file.write_at(b"sushi", 10)?; + /// Ok(()) + /// } /// ``` #[stable(feature = "file_offset", since = "1.15.0")] fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>; + + /// Attempts to write an entire buffer starting from a given offset. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// This method will continuously call [`write_at`] 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 of + /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns. + /// + /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted + /// [`write_at`]: #tymethod.write_at + /// + /// # Examples + /// + /// ```no_run + /// #![feature(rw_exact_all_at)] + /// use std::fs::File; + /// use std::io; + /// use std::os::unix::prelude::FileExt; + /// + /// fn main() -> io::Result<()> { + /// let file = File::open("foo.txt")?; + /// + /// // We now write at the offset 10. + /// file.write_all_at(b"sushi", 10)?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "rw_exact_all_at", issue = "51984")] + fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { + while !buf.is_empty() { + match self.write_at(buf, offset) { + Ok(0) => return Err(io::Error::new(io::ErrorKind::WriteZero, + "failed to write whole buffer")), + Ok(n) => { + buf = &buf[n..]; + offset += n as u64 + } + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + Ok(()) + } } #[stable(feature = "file_offset", since = "1.15.0")] @@ -105,7 +232,9 @@ impl FileExt for fs::File { } } -/// Unix-specific extensions to `Permissions` +/// Unix-specific extensions to [`fs::Permissions`]. +/// +/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html #[stable(feature = "fs_ext", since = "1.1.0")] pub trait PermissionsExt { /// Returns the underlying raw `st_mode` bits that contain the standard @@ -117,13 +246,13 @@ pub trait PermissionsExt { /// use std::fs::File; /// use std::os::unix::fs::PermissionsExt; /// - /// # fn run() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let permissions = metadata.permissions(); + /// fn main() -> std::io::Result<()> { + /// let f = File::create("foo.txt")?; + /// let metadata = f.metadata()?; + /// let permissions = metadata.permissions(); /// - /// println!("permissions: {}", permissions.mode()); - /// # Ok(()) } + /// println!("permissions: {}", permissions.mode()); + /// Ok(()) } /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] fn mode(&self) -> u32; @@ -136,14 +265,14 @@ pub trait PermissionsExt { /// use std::fs::File; /// use std::os::unix::fs::PermissionsExt; /// - /// # fn run() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let mut permissions = metadata.permissions(); + /// fn main() -> std::io::Result<()> { + /// let f = File::create("foo.txt")?; + /// let metadata = f.metadata()?; + /// let mut permissions = metadata.permissions(); /// - /// permissions.set_mode(0o644); // Read/write for owner and read for others. - /// assert_eq!(permissions.mode(), 0o644); - /// # Ok(()) } + /// permissions.set_mode(0o644); // Read/write for owner and read for others. + /// assert_eq!(permissions.mode(), 0o644); + /// Ok(()) } /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] fn set_mode(&mut self, mode: u32); @@ -180,7 +309,9 @@ impl PermissionsExt for Permissions { } } -/// Unix-specific extensions to `OpenOptions` +/// Unix-specific extensions to [`fs::OpenOptions`]. +/// +/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html #[stable(feature = "fs_ext", since = "1.1.0")] pub trait OpenOptionsExt { /// Sets the mode bits that a new file will be created with. @@ -246,13 +377,9 @@ impl OpenOptionsExt for OpenOptions { } } -// Hm, why are there casts here to the returned type, shouldn't the types always -// be the same? Right you are! Turns out, however, on android at least the types -// in the raw `stat` structure are not the same as the types being returned. Who -// knew! -// -// As a result to make sure this compiles for all platforms we do the manual -// casts and rely on manual lowering to `stat` if the raw type is desired. +/// Unix-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Returns the ID of the device containing the file. @@ -260,15 +387,15 @@ pub trait MetadataExt { /// # Examples /// /// ```no_run + /// use std::io; /// use std::fs; /// use std::os::unix::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let dev_id = meta.dev(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let dev_id = meta.dev(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn dev(&self) -> u64; @@ -279,13 +406,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let inode = meta.ino(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let inode = meta.ino(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn ino(&self) -> u64; @@ -296,17 +423,17 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; - /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let mode = meta.mode(); - /// let user_has_write_access = mode & 0o200; - /// let user_has_read_write_access = mode & 0o600; - /// let group_has_read_access = mode & 0o040; - /// let others_have_exec_access = mode & 0o001; - /// # Ok(()) - /// # } + /// use std::io; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let mode = meta.mode(); + /// let user_has_write_access = mode & 0o200; + /// let user_has_read_write_access = mode & 0o600; + /// let group_has_read_access = mode & 0o040; + /// let others_have_exec_access = mode & 0o001; + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn mode(&self) -> u32; @@ -317,13 +444,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nb_hard_links = meta.nlink(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let nb_hard_links = meta.nlink(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn nlink(&self) -> u64; @@ -334,13 +461,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let user_id = meta.uid(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let user_id = meta.uid(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn uid(&self) -> u32; @@ -351,13 +478,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let group_id = meta.gid(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let group_id = meta.gid(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn gid(&self) -> u32; @@ -368,13 +495,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let device_id = meta.rdev(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let device_id = meta.rdev(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn rdev(&self) -> u64; @@ -385,13 +512,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let file_size = meta.size(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let file_size = meta.size(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn size(&self) -> u64; @@ -402,13 +529,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let last_access_time = meta.atime(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let last_access_time = meta.atime(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn atime(&self) -> i64; @@ -419,13 +546,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_access_time = meta.atime_nsec(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let nano_last_access_time = meta.atime_nsec(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn atime_nsec(&self) -> i64; @@ -436,13 +563,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let last_modification_time = meta.mtime(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let last_modification_time = meta.mtime(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn mtime(&self) -> i64; @@ -453,13 +580,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_modification_time = meta.mtime_nsec(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let nano_last_modification_time = meta.mtime_nsec(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn mtime_nsec(&self) -> i64; @@ -470,13 +597,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let last_status_change_time = meta.ctime(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let last_status_change_time = meta.ctime(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn ctime(&self) -> i64; @@ -487,13 +614,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_status_change_time = meta.ctime_nsec(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let nano_last_status_change_time = meta.ctime_nsec(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn ctime_nsec(&self) -> i64; @@ -504,13 +631,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let blocksize = meta.blksize(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let blocksize = meta.blksize(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn blksize(&self) -> u64; @@ -523,13 +650,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let blocks = meta.blocks(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let blocks = meta.blocks(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn blocks(&self) -> u64; @@ -555,24 +682,29 @@ impl MetadataExt for fs::Metadata { fn blocks(&self) -> u64 { self.st_blocks() } } -/// Add support for special unix types (block/char device, fifo and socket). +/// Unix-specific extensions for [`FileType`]. +/// +/// Adds support for special Unix file types such as block/character devices, +/// pipes, and sockets. +/// +/// [`FileType`]: ../../../../std/fs/struct.FileType.html #[stable(feature = "file_type_ext", since = "1.5.0")] pub trait FileTypeExt { /// Returns whether this file type is a block device. /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; /// use std::os::unix::fs::FileTypeExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("block_device_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_block_device()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("block_device_file")?; + /// let file_type = meta.file_type(); + /// assert!(file_type.is_block_device()); + /// Ok(()) + /// } /// ``` #[stable(feature = "file_type_ext", since = "1.5.0")] fn is_block_device(&self) -> bool; @@ -580,17 +712,17 @@ pub trait FileTypeExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; /// use std::os::unix::fs::FileTypeExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("char_device_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_char_device()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("char_device_file")?; + /// let file_type = meta.file_type(); + /// assert!(file_type.is_char_device()); + /// Ok(()) + /// } /// ``` #[stable(feature = "file_type_ext", since = "1.5.0")] fn is_char_device(&self) -> bool; @@ -598,17 +730,17 @@ pub trait FileTypeExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; /// use std::os::unix::fs::FileTypeExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("fifo_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_fifo()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("fifo_file")?; + /// let file_type = meta.file_type(); + /// assert!(file_type.is_fifo()); + /// Ok(()) + /// } /// ``` #[stable(feature = "file_type_ext", since = "1.5.0")] fn is_fifo(&self) -> bool; @@ -616,17 +748,17 @@ pub trait FileTypeExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; /// use std::os::unix::fs::FileTypeExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("unix.socket")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_socket()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("unix.socket")?; + /// let file_type = meta.file_type(); + /// assert!(file_type.is_socket()); + /// Ok(()) + /// } /// ``` #[stable(feature = "file_type_ext", since = "1.5.0")] fn is_socket(&self) -> bool; @@ -687,13 +819,13 @@ impl DirEntryExt for fs::DirEntry { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::os::unix::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::symlink("a.txt", "b.txt")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::symlink("a.txt", "b.txt")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "symlink", since = "1.1.0")] pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> @@ -701,10 +833,10 @@ pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> sys::fs::symlink(src.as_ref(), dst.as_ref()) } -#[stable(feature = "dir_builder", since = "1.6.0")] -/// An extension trait for [`fs::DirBuilder`] for unix-specific options. +/// Unix-specific extensions to [`fs::DirBuilder`]. /// /// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html +#[stable(feature = "dir_builder", since = "1.6.0")] pub trait DirBuilderExt { /// Sets the mode to create new directories with. This option defaults to /// 0o777. diff --git a/src/libstd/sys/unix/ext/mod.rs b/src/libstd/sys/unix/ext/mod.rs index c221f7c8cfe..88e4237f8e2 100644 --- a/src/libstd/sys/unix/ext/mod.rs +++ b/src/libstd/sys/unix/ext/mod.rs @@ -35,6 +35,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(cfg(unix))] +#![allow(missing_docs)] pub mod io; pub mod ffi; diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 86b0f35be92..55f43ccd7db 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -51,13 +51,11 @@ use libc::MSG_NOSIGNAL; const MSG_NOSIGNAL: libc::c_int = 0x0; fn sun_path_offset() -> usize { - unsafe { - // Work with an actual instance of the type since using a null pointer is UB - let addr: libc::sockaddr_un = mem::uninitialized(); - let base = &addr as *const _ as usize; - let path = &addr.sun_path as *const _ as usize; - path - base - } + // Work with an actual instance of the type since using a null pointer is UB + let addr: libc::sockaddr_un = unsafe { mem::uninitialized() }; + let base = &addr as *const _ as usize; + let path = &addr.sun_path as *const _ as usize; + path - base } unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { @@ -216,7 +214,10 @@ impl SocketAddr { let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses - if len == 0 || (cfg!(not(target_os = "linux")) && self.addr.sun_path[0] == 0) { + if len == 0 + || (cfg!(not(any(target_os = "linux", target_os = "android"))) + && self.addr.sun_path[0] == 0) + { AddressKind::Unnamed } else if self.addr.sun_path[0] == 0 { AddressKind::Abstract(&path[1..len]) @@ -387,10 +388,11 @@ impl UnixStream { /// Sets the read timeout for the socket. /// /// If the provided value is [`None`], then [`read`] calls will block - /// indefinitely. It is an error to pass the zero [`Duration`] to this + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this /// method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read /// [`Duration`]: ../../../../std/time/struct.Duration.html /// @@ -403,6 +405,20 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> { self.0.set_timeout(timeout, libc::SO_RCVTIMEO) @@ -411,11 +427,12 @@ impl UnixStream { /// Sets the write timeout for the socket. /// /// If the provided value is [`None`], then [`write`] calls will block - /// indefinitely. It is an error to pass the zero [`Duration`] to this - /// method. + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`read`]: ../../../../std/io/trait.Write.html#tymethod.write + /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err + /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write /// [`Duration`]: ../../../../std/time/struct.Duration.html /// /// # Examples @@ -427,6 +444,20 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::UdpSocket; + /// use std::time::Duration; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> { self.0.set_timeout(timeout, libc::SO_SNDTIMEO) @@ -493,6 +524,9 @@ impl UnixStream { /// println!("Got error: {:?}", err); /// } /// ``` + /// + /// # Platform specific + /// On Redox this always returns None. #[stable(feature = "unix_socket", since = "1.10.0")] pub fn take_error(&self) -> io::Result<Option<io::Error>> { self.0.take_error() @@ -815,6 +849,9 @@ impl UnixListener { /// println!("Got error: {:?}", err); /// } /// ``` + /// + /// # Platform specific + /// On Redox this always returns None. #[stable(feature = "unix_socket", since = "1.10.0")] pub fn take_error(&self) -> io::Result<Option<io::Error>> { self.0.take_error() @@ -1250,10 +1287,11 @@ impl UnixDatagram { /// Sets the read timeout for the socket. /// /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will - /// block indefinitely. It is an error to pass the zero [`Duration`] to this - /// method. + /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] + /// is passed to this method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err /// [`recv`]: #method.recv /// [`recv_from`]: #method.recv_from /// [`Duration`]: ../../../../std/time/struct.Duration.html @@ -1267,6 +1305,20 @@ impl UnixDatagram { /// let sock = UnixDatagram::unbound().unwrap(); /// sock.set_read_timeout(Some(Duration::new(1, 0))).expect("set_read_timeout function failed"); /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// let socket = UnixDatagram::unbound().unwrap(); + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> { self.0.set_timeout(timeout, libc::SO_RCVTIMEO) @@ -1275,7 +1327,7 @@ impl UnixDatagram { /// Sets the write timeout for the socket. /// /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will - /// block indefinitely. It is an error to pass the zero [`Duration`] to this + /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this /// method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None @@ -1293,6 +1345,20 @@ impl UnixDatagram { /// sock.set_write_timeout(Some(Duration::new(1, 0))) /// .expect("set_write_timeout function failed"); /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// let socket = UnixDatagram::unbound().unwrap(); + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> { self.0.set_timeout(timeout, libc::SO_SNDTIMEO) @@ -1410,7 +1476,7 @@ impl IntoRawFd for UnixDatagram { #[cfg(all(test, not(target_os = "emscripten")))] mod test { use thread; - use io; + use io::{self, ErrorKind}; use io::prelude::*; use time::Duration; use sys_common::io::test::tmpdir; @@ -1613,6 +1679,27 @@ mod test { assert!(kind == io::ErrorKind::WouldBlock || kind == io::ErrorKind::TimedOut); } + // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors + // when passed zero Durations + #[test] + fn test_unix_stream_timeout_zero_duration() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let listener = or_panic!(UnixListener::bind(&socket_path)); + let stream = or_panic!(UnixStream::connect(&socket_path)); + + let result = stream.set_write_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + let result = stream.set_read_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + drop(listener); + } + #[test] fn test_unix_datagram() { let dir = tmpdir(); @@ -1712,6 +1799,24 @@ mod test { thread.join().unwrap(); } + // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors + // when passed zero Durations + #[test] + fn test_unix_datagram_timeout_zero_duration() { + let dir = tmpdir(); + let path = dir.path().join("sock"); + + let datagram = or_panic!(UnixDatagram::bind(&path)); + + let result = datagram.set_write_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + let result = datagram.set_read_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + } + #[test] fn abstract_namespace_not_allowed() { assert!(UnixStream::connect("\0asdf").is_err()); diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index 60309bec6d4..21630ae9746 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -18,7 +18,9 @@ use process; use sys; use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner}; -/// Unix-specific extensions to the `std::process::Command` builder +/// Unix-specific extensions to the [`process::Command`] builder. +/// +/// [`process::Command`]: ../../../../std/process/struct.Command.html #[stable(feature = "rust1", since = "1.0.0")] pub trait CommandExt { /// Sets the child process's user id. This translates to a @@ -117,7 +119,9 @@ impl CommandExt for process::Command { } } -/// Unix-specific extensions to `std::process::ExitStatus` +/// Unix-specific extensions to [`process::ExitStatus`]. +/// +/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html #[stable(feature = "rust1", since = "1.0.0")] pub trait ExitStatusExt { /// Creates a new `ExitStatus` from the raw underlying `i32` return value of @@ -193,7 +197,7 @@ impl IntoRawFd for process::ChildStderr { } /// Returns the OS-assigned process identifier associated with this process's parent. -#[unstable(feature = "unix_ppid", issue = "46104")] +#[stable(feature = "unix_ppid", since = "1.27.0")] pub fn parent_id() -> u32 { ::sys::os::getppid() } diff --git a/src/libstd/sys/unix/ext/thread.rs b/src/libstd/sys/unix/ext/thread.rs index fe2a48764dc..8dadf29945c 100644 --- a/src/libstd/sys/unix/ext/thread.rs +++ b/src/libstd/sys/unix/ext/thread.rs @@ -21,7 +21,9 @@ use thread::JoinHandle; #[allow(deprecated)] pub type RawPthread = pthread_t; -/// Unix-specific extensions to `std::thread::JoinHandle` +/// Unix-specific extensions to [`thread::JoinHandle`]. +/// +/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html #[stable(feature = "thread_extensions", since = "1.9.0")] pub trait JoinHandleExt { /// Extracts the raw pthread_t without taking ownership diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs index 6cdbe5df75d..c13a0fea1e0 100644 --- a/src/libstd/sys/unix/fast_thread_local.rs +++ b/src/libstd/sys/unix/fast_thread_local.rs @@ -20,7 +20,7 @@ // fallback implementation to use as well. // // Due to rust-lang/rust#18804, make sure this is not generic! -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "hermit"))] pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { use libc; use mem; @@ -55,11 +55,6 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { _tlv_atexit(dtor, t); } -// Just use the thread_local fallback implementation, at least until there's -// a more direct implementation. -#[cfg(target_os = "fuchsia")] -pub use sys_common::thread_local::register_dtor_fallback as register_dtor; - pub fn requires_move_before_drop() -> bool { // The macOS implementation of TLS apparently had an odd aspect to it // where the pointer we have may be overwritten while this destructor diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index 5dafc3251e7..4830e38d6a9 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -75,8 +75,15 @@ impl FileDesc { unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64) -> io::Result<isize> { + use convert::TryInto; use libc::pread64; - cvt(pread64(fd, buf, count, offset as i32)) + // pread64 on emscripten actually takes a 32 bit offset + if let Ok(o) = offset.try_into() { + cvt(pread64(fd, buf, count, o)) + } else { + Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot pread >2GB")) + } } #[cfg(not(any(target_os = "android", target_os = "emscripten")))] @@ -116,8 +123,15 @@ impl FileDesc { unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64) -> io::Result<isize> { + use convert::TryInto; use libc::pwrite64; - cvt(pwrite64(fd, buf, count, offset as i32)) + // pwrite64 on emscripten actually takes a 32 bit offset + if let Ok(o) = offset.try_into() { + cvt(pwrite64(fd, buf, count, o)) + } else { + Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot pwrite >2GB")) + } } #[cfg(not(any(target_os = "android", target_os = "emscripten")))] @@ -140,6 +154,13 @@ impl FileDesc { } } + #[cfg(target_os = "linux")] + pub fn get_cloexec(&self) -> io::Result<bool> { + unsafe { + Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) + } + } + #[cfg(not(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten", diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index a1ca839dc18..7a89d9857bb 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -25,8 +25,12 @@ use sys_common::{AsInner, FromInner}; #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))] use libc::{stat64, fstat64, lstat64, off64_t, ftruncate64, lseek64, dirent64, readdir64_r, open64}; +#[cfg(any(target_os = "linux", target_os = "emscripten"))] +use libc::fstatat64; +#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] +use libc::dirfd; #[cfg(target_os = "android")] -use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, lseek64, +use libc::{stat as stat64, fstat as fstat64, fstatat as fstatat64, lstat as lstat64, lseek64, dirent as dirent64, open as open64}; #[cfg(not(any(target_os = "linux", target_os = "emscripten", @@ -48,9 +52,16 @@ pub struct FileAttr { stat: stat64, } -pub struct ReadDir { +// all DirEntry's will have a reference to this struct +struct InnerReadDir { dirp: Dir, - root: Arc<PathBuf>, + root: PathBuf, +} + +#[derive(Clone)] +pub struct ReadDir { + inner: Arc<InnerReadDir>, + end_of_stream: bool, } struct Dir(*mut libc::DIR); @@ -60,8 +71,8 @@ unsafe impl Sync for Dir {} pub struct DirEntry { entry: dirent64, - root: Arc<PathBuf>, - // We need to store an owned copy of the directory name + dir: ReadDir, + // We need to store an owned copy of the entry name // on Solaris and Fuchsia because a) it uses a zero-length // array to store the name, b) its lifetime between readdir // calls is not guaranteed. @@ -207,7 +218,7 @@ impl fmt::Debug for ReadDir { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. // Thus the result will be e g 'ReadDir("/home")' - fmt::Debug::fmt(&*self.root, f) + fmt::Debug::fmt(&*self.inner.root, f) } } @@ -223,7 +234,7 @@ impl Iterator for ReadDir { // is safe to use in threaded applications and it is generally preferred // over the readdir_r(3C) function. super::os::set_errno(0); - let entry_ptr = libc::readdir(self.dirp.0); + let entry_ptr = libc::readdir(self.inner.dirp.0); if entry_ptr.is_null() { // NULL can mean either the end is reached or an error occurred. // So we had to clear errno beforehand to check for an error now. @@ -240,7 +251,7 @@ impl Iterator for ReadDir { entry: *entry_ptr, name: ::slice::from_raw_parts(name as *const u8, namelen as usize).to_owned().into_boxed_slice(), - root: self.root.clone() + dir: self.clone() }; if ret.name_bytes() != b"." && ret.name_bytes() != b".." { return Some(Ok(ret)) @@ -251,14 +262,25 @@ impl Iterator for ReadDir { #[cfg(not(any(target_os = "solaris", target_os = "fuchsia")))] fn next(&mut self) -> Option<io::Result<DirEntry>> { + if self.end_of_stream { + return None; + } + unsafe { let mut ret = DirEntry { entry: mem::zeroed(), - root: self.root.clone() + dir: self.clone(), }; let mut entry_ptr = ptr::null_mut(); loop { - if readdir64_r(self.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 { + if readdir64_r(self.inner.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 { + if entry_ptr.is_null() { + // We encountered an error (which will be returned in this iteration), but + // we also reached the end of the directory stream. The `end_of_stream` + // flag is enabled to make sure that we return `None` in the next iteration + // (instead of looping forever) + self.end_of_stream = true; + } return Some(Err(Error::last_os_error())) } if entry_ptr.is_null() { @@ -281,23 +303,34 @@ impl Drop for Dir { impl DirEntry { pub fn path(&self) -> PathBuf { - self.root.join(OsStr::from_bytes(self.name_bytes())) + self.dir.inner.root.join(OsStr::from_bytes(self.name_bytes())) } pub fn file_name(&self) -> OsString { OsStr::from_bytes(self.name_bytes()).to_os_string() } + #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] + pub fn metadata(&self) -> io::Result<FileAttr> { + let fd = cvt(unsafe {dirfd(self.dir.inner.dirp.0)})?; + let mut stat: stat64 = unsafe { mem::zeroed() }; + cvt(unsafe { + fstatat64(fd, self.entry.d_name.as_ptr(), &mut stat, libc::AT_SYMLINK_NOFOLLOW) + })?; + Ok(FileAttr { stat: stat }) + } + + #[cfg(not(any(target_os = "linux", target_os = "emscripten", target_os = "android")))] pub fn metadata(&self) -> io::Result<FileAttr> { lstat(&self.path()) } - #[cfg(any(target_os = "solaris", target_os = "haiku"))] + #[cfg(any(target_os = "solaris", target_os = "haiku", target_os = "hermit"))] pub fn file_type(&self) -> io::Result<FileType> { lstat(&self.path()).map(|m| m.file_type()) } - #[cfg(not(any(target_os = "solaris", target_os = "haiku")))] + #[cfg(not(any(target_os = "solaris", target_os = "haiku", target_os = "hermit")))] pub fn file_type(&self) -> io::Result<FileType> { match self.entry.d_type { libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }), @@ -319,7 +352,8 @@ impl DirEntry { target_os = "solaris", target_os = "haiku", target_os = "l4re", - target_os = "fuchsia"))] + target_os = "fuchsia", + target_os = "hermit"))] pub fn ino(&self) -> u64 { self.entry.d_ino as u64 } @@ -350,7 +384,8 @@ impl DirEntry { target_os = "linux", target_os = "emscripten", target_os = "l4re", - target_os = "haiku"))] + target_os = "haiku", + target_os = "hermit"))] fn name_bytes(&self) -> &[u8] { unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() @@ -441,15 +476,48 @@ impl File { // Currently the standard library supports Linux 2.6.18 which did not // have the O_CLOEXEC flag (passed above). If we're running on an older - // Linux kernel then the flag is just ignored by the OS, so we continue - // to explicitly ask for a CLOEXEC fd here. + // Linux kernel then the flag is just ignored by the OS. After we open + // the first file, we check whether it has CLOEXEC set. If it doesn't, + // we will explicitly ask for a CLOEXEC fd for every further file we + // open, if it does, we will skip that step. // // The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc // that we support, so we only do this on Linux currently. - if cfg!(target_os = "linux") { - fd.set_cloexec()?; + #[cfg(target_os = "linux")] + fn ensure_cloexec(fd: &FileDesc) -> io::Result<()> { + use sync::atomic::{AtomicUsize, Ordering}; + + const OPEN_CLOEXEC_UNKNOWN: usize = 0; + const OPEN_CLOEXEC_SUPPORTED: usize = 1; + const OPEN_CLOEXEC_NOTSUPPORTED: usize = 2; + static OPEN_CLOEXEC: AtomicUsize = AtomicUsize::new(OPEN_CLOEXEC_UNKNOWN); + + let need_to_set; + match OPEN_CLOEXEC.load(Ordering::Relaxed) { + OPEN_CLOEXEC_UNKNOWN => { + need_to_set = !fd.get_cloexec()?; + OPEN_CLOEXEC.store(if need_to_set { + OPEN_CLOEXEC_NOTSUPPORTED + } else { + OPEN_CLOEXEC_SUPPORTED + }, Ordering::Relaxed); + }, + OPEN_CLOEXEC_SUPPORTED => need_to_set = false, + OPEN_CLOEXEC_NOTSUPPORTED => need_to_set = true, + _ => unreachable!(), + } + if need_to_set { + fd.set_cloexec()?; + } + Ok(()) + } + + #[cfg(not(target_os = "linux"))] + fn ensure_cloexec(_: &FileDesc) -> io::Result<()> { + Ok(()) } + ensure_cloexec(&fd)?; Ok(File(fd)) } @@ -631,14 +699,18 @@ impl fmt::Debug for File { } pub fn readdir(p: &Path) -> io::Result<ReadDir> { - let root = Arc::new(p.to_path_buf()); + let root = p.to_path_buf(); let p = cstr(p)?; unsafe { let ptr = libc::opendir(p.as_ptr()); if ptr.is_null() { Err(Error::last_os_error()) } else { - Ok(ReadDir { dirp: Dir(ptr), root: root }) + let inner = InnerReadDir { dirp: Dir(ptr), root }; + Ok(ReadDir{ + inner: Arc::new(inner), + end_of_stream: false, + }) } } } @@ -733,7 +805,7 @@ pub fn stat(p: &Path) -> io::Result<FileAttr> { let p = cstr(p)?; let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { - stat64(p.as_ptr(), &mut stat as *mut _ as *mut _) + stat64(p.as_ptr(), &mut stat) })?; Ok(FileAttr { stat: stat }) } @@ -742,7 +814,7 @@ pub fn lstat(p: &Path) -> io::Result<FileAttr> { let p = cstr(p)?; let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { - lstat64(p.as_ptr(), &mut stat as *mut _ as *mut _) + lstat64(p.as_ptr(), &mut stat) })?; Ok(FileAttr { stat: stat }) } @@ -761,8 +833,9 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> { Ok(PathBuf::from(OsString::from_vec(buf))) } +#[cfg(not(any(target_os = "linux", target_os = "android")))] pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { - use fs::{File, set_permissions}; + use fs::File; if !from.is_file() { return Err(Error::new(ErrorKind::InvalidInput, "the source path is not an existing regular file")) @@ -773,6 +846,100 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { let perm = reader.metadata()?.permissions(); let ret = io::copy(&mut reader, &mut writer)?; - set_permissions(to, perm)?; + writer.set_permissions(perm)?; Ok(ret) } + +#[cfg(any(target_os = "linux", target_os = "android"))] +pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { + use cmp; + use fs::File; + use sync::atomic::{AtomicBool, Ordering}; + + // Kernel prior to 4.5 don't have copy_file_range + // We store the availability in a global to avoid unneccessary syscalls + static HAS_COPY_FILE_RANGE: AtomicBool = AtomicBool::new(true); + + unsafe fn copy_file_range( + fd_in: libc::c_int, + off_in: *mut libc::loff_t, + fd_out: libc::c_int, + off_out: *mut libc::loff_t, + len: libc::size_t, + flags: libc::c_uint, + ) -> libc::c_long { + libc::syscall( + libc::SYS_copy_file_range, + fd_in, + off_in, + fd_out, + off_out, + len, + flags, + ) + } + + if !from.is_file() { + return Err(Error::new(ErrorKind::InvalidInput, + "the source path is not an existing regular file")) + } + + let mut reader = File::open(from)?; + let mut writer = File::create(to)?; + let (perm, len) = { + let metadata = reader.metadata()?; + (metadata.permissions(), metadata.size()) + }; + + let has_copy_file_range = HAS_COPY_FILE_RANGE.load(Ordering::Relaxed); + let mut written = 0u64; + while written < len { + let copy_result = if has_copy_file_range { + let bytes_to_copy = cmp::min(len - written, usize::max_value() as u64) as usize; + let copy_result = unsafe { + // We actually don't have to adjust the offsets, + // because copy_file_range adjusts the file offset automatically + cvt(copy_file_range(reader.as_raw_fd(), + ptr::null_mut(), + writer.as_raw_fd(), + ptr::null_mut(), + bytes_to_copy, + 0) + ) + }; + if let Err(ref copy_err) = copy_result { + match copy_err.raw_os_error() { + Some(libc::ENOSYS) | Some(libc::EPERM) => { + HAS_COPY_FILE_RANGE.store(false, Ordering::Relaxed); + } + _ => {} + } + } + copy_result + } else { + Err(io::Error::from_raw_os_error(libc::ENOSYS)) + }; + match copy_result { + Ok(ret) => written += ret as u64, + Err(err) => { + match err.raw_os_error() { + Some(os_err) if os_err == libc::ENOSYS + || os_err == libc::EXDEV + || os_err == libc::EPERM => { + // Try fallback io::copy if either: + // - Kernel version is < 4.5 (ENOSYS) + // - Files are mounted on different fs (EXDEV) + // - copy_file_range is disallowed, for example by seccomp (EPERM) + assert_eq!(written, 0); + let ret = io::copy(&mut reader, &mut writer)?; + writer.set_permissions(perm)?; + return Ok(ret) + }, + _ => return Err(err), + } + } + } + } + writer.set_permissions(perm)?; + Ok(written) +} diff --git a/src/libstd/sys/unix/l4re.rs b/src/libstd/sys/unix/l4re.rs index c3e8d0b7d95..21218489679 100644 --- a/src/libstd/sys/unix/l4re.rs +++ b/src/libstd/sys/unix/l4re.rs @@ -437,9 +437,5 @@ pub mod net { pub fn lookup_host(_: &str) -> io::Result<LookupHost> { unimpl!(); } - - pub fn res_init_if_glibc_before_2_26() -> io::Result<()> { - unimpl!(); - } } diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 9bdea945ea4..c738003caf1 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -28,6 +28,7 @@ use libc; #[cfg(all(not(dox), target_os = "emscripten"))] pub use os::emscripten as platform; #[cfg(all(not(dox), target_os = "fuchsia"))] pub use os::fuchsia as platform; #[cfg(all(not(dox), target_os = "l4re"))] pub use os::linux as platform; +#[cfg(all(not(dox), target_os = "hermit"))] pub use os::hermit as platform; pub use self::rand::hashmap_random_keys; pub use libc::strlen; @@ -80,11 +81,11 @@ pub fn init() { reset_sigpipe(); } - #[cfg(not(any(target_os = "emscripten", target_os="fuchsia")))] + #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))] unsafe fn reset_sigpipe() { assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); } - #[cfg(any(target_os = "emscripten", target_os="fuchsia"))] + #[cfg(any(target_os = "emscripten", target_os = "fuchsia"))] unsafe fn reset_sigpipe() {} } diff --git a/src/libstd/sys/unix/mutex.rs b/src/libstd/sys/unix/mutex.rs index 52cf3f97c5c..1d447de1134 100644 --- a/src/libstd/sys/unix/mutex.rs +++ b/src/libstd/sys/unix/mutex.rs @@ -25,8 +25,10 @@ unsafe impl Sync for Mutex {} #[allow(dead_code)] // sys isn't exported yet impl Mutex { pub const fn new() -> Mutex { - // Might be moved and address is changing it is better to avoid - // initialization of potentially opaque OS data before it landed + // Might be moved to a different address, so it is better to avoid + // initialization of potentially opaque OS data before it landed. + // Be very careful using this newly constructed `Mutex`, reentrant + // locking is undefined behavior until `init` is called! Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) } } #[inline] @@ -49,9 +51,6 @@ impl Mutex { // references, we instead create the mutex with type // PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to // re-lock it from the same thread, thus avoiding undefined behavior. - // - // We can't do anything for StaticMutex, but that type is deprecated - // anyways. let mut attr: libc::pthread_mutexattr_t = mem::uninitialized(); let r = libc::pthread_mutexattr_init(&mut attr); debug_assert_eq!(r, 0); diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index e775f857f2b..04d9f0b06d3 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -51,6 +51,10 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> { if err == 0 { return Ok(()) } + + // We may need to trigger a glibc workaround. See on_resolver_failure() for details. + on_resolver_failure(); + if err == EAI_SYSTEM { return Err(io::Error::last_os_error()) } @@ -377,43 +381,22 @@ impl IntoInner<c_int> for Socket { // res_init unconditionally, we call it only when we detect we're linking // against glibc version < 2.26. (That is, when we both know its needed and // believe it's thread-safe). -pub fn res_init_if_glibc_before_2_26() -> io::Result<()> { +#[cfg(target_env = "gnu")] +fn on_resolver_failure() { + use sys; + // If the version fails to parse, we treat it the same as "not glibc". - if let Some(Ok(version_str)) = glibc_version_cstr().map(CStr::to_str) { - if let Some(version) = parse_glibc_version(version_str) { - if version < (2, 26) { - let ret = unsafe { libc::res_init() }; - if ret != 0 { - return Err(io::Error::last_os_error()); - } - } + if let Some(version) = sys::os::glibc_version() { + if version < (2, 26) { + unsafe { libc::res_init() }; } } - Ok(()) } -fn glibc_version_cstr() -> Option<&'static CStr> { - weak! { - fn gnu_get_libc_version() -> *const libc::c_char - } - if let Some(f) = gnu_get_libc_version.get() { - unsafe { Some(CStr::from_ptr(f())) } - } else { - None - } -} - -// Returns Some((major, minor)) if the string is a valid "x.y" version, -// ignoring any extra dot-separated parts. Otherwise return None. -fn parse_glibc_version(version: &str) -> Option<(usize, usize)> { - let mut parsed_ints = version.split(".").map(str::parse::<usize>).fuse(); - match (parsed_ints.next(), parsed_ints.next()) { - (Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)), - _ => None - } -} +#[cfg(not(target_env = "gnu"))] +fn on_resolver_failure() {} -#[cfg(test)] +#[cfg(all(test, taget_env = "gnu"))] mod test { use super::*; diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index a46e855b4a6..f8f0bbd5bc2 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -33,6 +33,8 @@ use sys::fd; use vec; const TMPBUF_SZ: usize = 128; +// We never call `ENV_LOCK.init()`, so it is UB to attempt to +// acquire this mutex reentrantly! static ENV_LOCK: Mutex = Mutex::new(); @@ -47,6 +49,7 @@ extern { target_os = "netbsd", target_os = "openbsd", target_os = "android", + target_os = "hermit", target_env = "newlib"), link_name = "__errno")] #[cfg_attr(target_os = "solaris", link_name = "___errno")] @@ -376,7 +379,7 @@ pub fn current_exe() -> io::Result<PathBuf> { } } -#[cfg(any(target_os = "fuchsia", target_os = "l4re"))] +#[cfg(any(target_os = "fuchsia", target_os = "l4re", target_os = "hermit"))] pub fn current_exe() -> io::Result<PathBuf> { use io::ErrorKind; Err(io::Error::new(ErrorKind::Other, "Not yet implemented!")) @@ -409,26 +412,19 @@ pub unsafe fn environ() -> *mut *const *const c_char { /// environment variables of the current process. pub fn env() -> Env { unsafe { - ENV_LOCK.lock(); + let _guard = ENV_LOCK.lock(); let mut environ = *environ(); - if environ == ptr::null() { - ENV_LOCK.unlock(); - panic!("os::env() failure getting env string from OS: {}", - io::Error::last_os_error()); - } let mut result = Vec::new(); - while *environ != ptr::null() { + while environ != ptr::null() && *environ != ptr::null() { if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { result.push(key_value); } environ = environ.offset(1); } - let ret = Env { + return Env { iter: result.into_iter(), _dont_send_or_sync_me: PhantomData, - }; - ENV_LOCK.unlock(); - return ret + } } fn parse(input: &[u8]) -> Option<(OsString, OsString)> { @@ -452,15 +448,14 @@ pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> { // always None as well let k = CString::new(k.as_bytes())?; unsafe { - ENV_LOCK.lock(); + let _guard = ENV_LOCK.lock(); let s = libc::getenv(k.as_ptr()) as *const libc::c_char; let ret = if s.is_null() { None } else { Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) }; - ENV_LOCK.unlock(); - return Ok(ret) + Ok(ret) } } @@ -469,10 +464,8 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { let v = CString::new(v.as_bytes())?; unsafe { - ENV_LOCK.lock(); - let ret = cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ()); - ENV_LOCK.unlock(); - return ret + let _guard = ENV_LOCK.lock(); + cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ()) } } @@ -480,10 +473,8 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> { let nbuf = CString::new(n.as_bytes())?; unsafe { - ENV_LOCK.lock(); - let ret = cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ()); - ENV_LOCK.unlock(); - return ret + let _guard = ENV_LOCK.lock(); + cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ()) } } @@ -546,3 +537,35 @@ pub fn getpid() -> u32 { pub fn getppid() -> u32 { unsafe { libc::getppid() as u32 } } + +#[cfg(target_env = "gnu")] +pub fn glibc_version() -> Option<(usize, usize)> { + if let Some(Ok(version_str)) = glibc_version_cstr().map(CStr::to_str) { + parse_glibc_version(version_str) + } else { + None + } +} + +#[cfg(target_env = "gnu")] +fn glibc_version_cstr() -> Option<&'static CStr> { + weak! { + fn gnu_get_libc_version() -> *const libc::c_char + } + if let Some(f) = gnu_get_libc_version.get() { + unsafe { Some(CStr::from_ptr(f())) } + } else { + None + } +} + +// Returns Some((major, minor)) if the string is a valid "x.y" version, +// ignoring any extra dot-separated parts. Otherwise return None. +#[cfg(target_env = "gnu")] +fn parse_glibc_version(version: &str) -> Option<(usize, usize)> { + let mut parsed_ints = version.split('.').map(str::parse::<usize>).fuse(); + match (parsed_ints.next(), parsed_ints.next()) { + (Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)), + _ => None + } +} diff --git a/src/libstd/sys/unix/os_str.rs b/src/libstd/sys/unix/os_str.rs index e0349387998..01c0fb830aa 100644 --- a/src/libstd/sys/unix/os_str.rs +++ b/src/libstd/sys/unix/os_str.rs @@ -19,7 +19,7 @@ use rc::Rc; use sync::Arc; use sys_common::{AsInner, IntoInner}; use sys_common::bytestring::debug_fmt_bytestring; -use std_unicode::lossy::Utf8Lossy; +use core::str::lossy::Utf8Lossy; #[derive(Clone, Hash)] pub struct Buf { @@ -104,6 +104,11 @@ impl Buf { self.inner.shrink_to_fit() } + #[inline] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.inner.shrink_to(min_capacity) + } + pub fn as_slice(&self) -> &Slice { unsafe { mem::transmute(&*self.inner) } } diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index ec9b6f17dca..0a5dccdddda 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -100,24 +100,6 @@ pub fn read2(p1: AnonPipe, // wait for either pipe to become readable using `poll` cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?; - // Read as much as we can from each pipe, ignoring EWOULDBLOCK or - // EAGAIN. If we hit EOF, then this will happen because the underlying - // reader will return Ok(0), in which case we'll see `Ok` ourselves. In - // this case we flip the other fd back into blocking mode and read - // whatever's leftover on that file descriptor. - let read = |fd: &FileDesc, dst: &mut Vec<u8>| { - match fd.read_to_end(dst) { - Ok(_) => Ok(true), - Err(e) => { - if e.raw_os_error() == Some(libc::EWOULDBLOCK) || - e.raw_os_error() == Some(libc::EAGAIN) { - Ok(false) - } else { - Err(e) - } - } - } - }; if fds[0].revents != 0 && read(&p1, v1)? { p2.set_nonblocking(false)?; return p2.read_to_end(v2).map(|_| ()); @@ -127,4 +109,23 @@ pub fn read2(p1: AnonPipe, return p1.read_to_end(v1).map(|_| ()); } } + + // Read as much as we can from each pipe, ignoring EWOULDBLOCK or + // EAGAIN. If we hit EOF, then this will happen because the underlying + // reader will return Ok(0), in which case we'll see `Ok` ourselves. In + // this case we flip the other fd back into blocking mode and read + // whatever's leftover on that file descriptor. + fn read(fd: &FileDesc, dst: &mut Vec<u8>) -> Result<bool, io::Error> { + match fd.read_to_end(dst) { + Ok(_) => Ok(true), + Err(e) => { + if e.raw_os_error() == Some(libc::EWOULDBLOCK) || + e.raw_os_error() == Some(libc::EAGAIN) { + Ok(false) + } else { + Err(e) + } + } + } + } } diff --git a/src/libstd/sys/unix/process/mod.rs b/src/libstd/sys/unix/process/mod.rs index 2a331069bc2..d8ac26c45b1 100644 --- a/src/libstd/sys/unix/process/mod.rs +++ b/src/libstd/sys/unix/process/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::process_common::{Command, ExitStatus, Stdio, StdioPipes}; +pub use self::process_common::{Command, ExitStatus, ExitCode, Stdio, StdioPipes}; pub use self::process_inner::Process; mod process_common; diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index c53bcdbf8e3..77f125f3c5b 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -13,7 +13,7 @@ use os::unix::prelude::*; use ffi::{OsString, OsStr, CString, CStr}; use fmt; use io; -use libc::{self, c_int, gid_t, uid_t, c_char}; +use libc::{self, c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE}; use ptr; use sys::fd::FileDesc; use sys::fs::{File, OpenOptions}; @@ -45,19 +45,25 @@ pub struct Command { // other keys. program: CString, args: Vec<CString>, - argv: Vec<*const c_char>, + argv: Argv, env: CommandEnv<DefaultEnvKey>, cwd: Option<CString>, uid: Option<uid_t>, gid: Option<gid_t>, saw_nul: bool, - closures: Vec<Box<FnMut() -> io::Result<()> + Send + Sync>>, + closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>, stdin: Option<Stdio>, stdout: Option<Stdio>, stderr: Option<Stdio>, } +// Create a new type for argv, so that we can make it `Send` +struct Argv(Vec<*const c_char>); + +// It is safe to make Argv Send, because it contains pointers to memory owned by `Command.args` +unsafe impl Send for Argv {} + // passed back to std::process with the pipes connected to the child, if any // were requested pub struct StdioPipes { @@ -92,7 +98,7 @@ impl Command { let mut saw_nul = false; let program = os2c(program, &mut saw_nul); Command { - argv: vec![program.as_ptr(), ptr::null()], + argv: Argv(vec![program.as_ptr(), ptr::null()]), program, args: Vec::new(), env: Default::default(), @@ -111,8 +117,8 @@ impl Command { // Overwrite the trailing NULL pointer in `argv` and then add a new null // pointer. let arg = os2c(arg, &mut self.saw_nul); - self.argv[self.args.len() + 1] = arg.as_ptr(); - self.argv.push(ptr::null()); + self.argv.0[self.args.len() + 1] = arg.as_ptr(); + self.argv.0.push(ptr::null()); // Also make sure we keep track of the owned value to schedule a // destructor for this memory. @@ -133,7 +139,7 @@ impl Command { self.saw_nul } pub fn get_argv(&self) -> &Vec<*const c_char> { - &self.argv + &self.argv.0 } #[allow(dead_code)] @@ -149,12 +155,12 @@ impl Command { self.gid } - pub fn get_closures(&mut self) -> &mut Vec<Box<FnMut() -> io::Result<()> + Send + Sync>> { + pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> { &mut self.closures } pub fn before_exec(&mut self, - f: Box<FnMut() -> io::Result<()> + Send + Sync>) { + f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>) { self.closures.push(f); } @@ -178,6 +184,10 @@ impl Command { let maybe_env = self.env.capture_if_changed(); maybe_env.map(|env| construct_envp(env, &mut self.saw_nul)) } + #[allow(dead_code)] + pub fn env_saw_path(&self) -> bool { + self.env.have_changed_path() + } pub fn setup_io(&self, default: Stdio, needs_stdin: bool) -> io::Result<(StdioPipes, ChildPipes)> { @@ -387,6 +397,19 @@ impl fmt::Display for ExitStatus { } } +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitCode(u8); + +impl ExitCode { + pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _); + pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _); + + #[inline] + pub fn as_i32(&self) -> i32 { + self.0 as i32 + } +} + #[cfg(all(test, not(target_os = "emscripten")))] mod tests { use super::*; diff --git a/src/libstd/sys/unix/process/process_fuchsia.rs b/src/libstd/sys/unix/process/process_fuchsia.rs index 06c0540fec0..fa48001179e 100644 --- a/src/libstd/sys/unix/process/process_fuchsia.rs +++ b/src/libstd/sys/unix/process/process_fuchsia.rs @@ -56,68 +56,49 @@ impl Command { -> io::Result<zx_handle_t> { use sys::process::zircon::*; - let job_handle = zx_job_default(); let envp = match maybe_envp { Some(envp) => envp.as_ptr(), None => ptr::null(), }; - // To make sure launchpad_destroy gets called on the launchpad if this function fails - struct LaunchpadDestructor(*mut launchpad_t); - impl Drop for LaunchpadDestructor { - fn drop(&mut self) { unsafe { launchpad_destroy(self.0); } } - } - - // Duplicate the job handle - let mut job_copy: zx_handle_t = ZX_HANDLE_INVALID; - zx_cvt(zx_handle_duplicate(job_handle, ZX_RIGHT_SAME_RIGHTS, &mut job_copy))?; - // Create a launchpad - let mut launchpad: *mut launchpad_t = ptr::null_mut(); - zx_cvt(launchpad_create(job_copy, self.get_argv()[0], &mut launchpad))?; - let launchpad_destructor = LaunchpadDestructor(launchpad); - - // Set the process argv - zx_cvt(launchpad_set_args(launchpad, self.get_argv().len() as i32 - 1, - self.get_argv().as_ptr()))?; - // Setup the environment vars - zx_cvt(launchpad_set_environ(launchpad, envp))?; - zx_cvt(launchpad_add_vdso_vmo(launchpad))?; - // Load the executable - zx_cvt(launchpad_elf_load(launchpad, launchpad_vmo_from_file(self.get_argv()[0])))?; - zx_cvt(launchpad_load_vdso(launchpad, ZX_HANDLE_INVALID))?; - zx_cvt(launchpad_clone(launchpad, LP_CLONE_FDIO_NAMESPACE | LP_CLONE_FDIO_CWD))?; + let transfer_or_clone = |opt_fd, target_fd| if let Some(local_fd) = opt_fd { + fdio_spawn_action_t { + action: FDIO_SPAWN_ACTION_TRANSFER_FD, + local_fd, + target_fd, + ..Default::default() + } + } else { + fdio_spawn_action_t { + action: FDIO_SPAWN_ACTION_CLONE_FD, + local_fd: target_fd, + target_fd, + ..Default::default() + } + }; // Clone stdin, stdout, and stderr - if let Some(fd) = stdio.stdin.fd() { - zx_cvt(launchpad_transfer_fd(launchpad, fd, 0))?; - } else { - zx_cvt(launchpad_clone_fd(launchpad, 0, 0))?; - } - if let Some(fd) = stdio.stdout.fd() { - zx_cvt(launchpad_transfer_fd(launchpad, fd, 1))?; - } else { - zx_cvt(launchpad_clone_fd(launchpad, 1, 1))?; - } - if let Some(fd) = stdio.stderr.fd() { - zx_cvt(launchpad_transfer_fd(launchpad, fd, 2))?; - } else { - zx_cvt(launchpad_clone_fd(launchpad, 2, 2))?; - } + let action1 = transfer_or_clone(stdio.stdin.fd(), 0); + let action2 = transfer_or_clone(stdio.stdout.fd(), 1); + let action3 = transfer_or_clone(stdio.stderr.fd(), 2); + let actions = [action1, action2, action3]; - // We don't want FileDesc::drop to be called on any stdio. It would close their fds. The - // fds will be closed once the child process finishes. + // We don't want FileDesc::drop to be called on any stdio. fdio_spawn_etc + // always consumes transferred file descriptors. mem::forget(stdio); for callback in self.get_closures().iter_mut() { callback()?; } - // `launchpad_go` destroys the launchpad, so we must not - mem::forget(launchpad_destructor); - let mut process_handle: zx_handle_t = 0; - let mut err_msg: *const libc::c_char = ptr::null(); - zx_cvt(launchpad_go(launchpad, &mut process_handle, &mut err_msg))?; + zx_cvt(fdio_spawn_etc( + 0, + FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_NAMESPACE, + self.get_argv()[0], self.get_argv().as_ptr(), envp, 3, actions.as_ptr(), + &mut process_handle, + ptr::null_mut(), + ))?; // FIXME: See if we want to do something with that err_msg Ok(process_handle) diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index 189280a4ba9..9d6d607e3f3 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -34,6 +34,11 @@ impl Command { } let (ours, theirs) = self.setup_io(default, needs_stdin)?; + + if let Some(ret) = self.posix_spawn(&theirs, envp.as_ref())? { + return Ok((ret, ours)) + } + let (input, output) = sys::pipe::anon_pipe()?; let pid = unsafe { @@ -229,6 +234,119 @@ impl Command { libc::execvp(self.get_argv()[0], self.get_argv().as_ptr()); io::Error::last_os_error() } + + #[cfg(not(any(target_os = "macos", target_os = "freebsd", + all(target_os = "linux", target_env = "gnu"))))] + fn posix_spawn(&mut self, _: &ChildPipes, _: Option<&CStringArray>) + -> io::Result<Option<Process>> + { + Ok(None) + } + + // Only support platforms for which posix_spawn() can return ENOENT + // directly. + #[cfg(any(target_os = "macos", target_os = "freebsd", + all(target_os = "linux", target_env = "gnu")))] + fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>) + -> io::Result<Option<Process>> + { + use mem; + use sys; + + if self.get_cwd().is_some() || + self.get_gid().is_some() || + self.get_uid().is_some() || + self.env_saw_path() || + self.get_closures().len() != 0 { + return Ok(None) + } + + // Only glibc 2.24+ posix_spawn() supports returning ENOENT directly. + #[cfg(all(target_os = "linux", target_env = "gnu"))] + { + if let Some(version) = sys::os::glibc_version() { + if version < (2, 24) { + return Ok(None) + } + } else { + return Ok(None) + } + } + + let mut p = Process { pid: 0, status: None }; + + struct PosixSpawnFileActions(libc::posix_spawn_file_actions_t); + + impl Drop for PosixSpawnFileActions { + fn drop(&mut self) { + unsafe { + libc::posix_spawn_file_actions_destroy(&mut self.0); + } + } + } + + struct PosixSpawnattr(libc::posix_spawnattr_t); + + impl Drop for PosixSpawnattr { + fn drop(&mut self) { + unsafe { + libc::posix_spawnattr_destroy(&mut self.0); + } + } + } + + unsafe { + let mut file_actions = PosixSpawnFileActions(mem::uninitialized()); + let mut attrs = PosixSpawnattr(mem::uninitialized()); + + libc::posix_spawnattr_init(&mut attrs.0); + libc::posix_spawn_file_actions_init(&mut file_actions.0); + + if let Some(fd) = stdio.stdin.fd() { + cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0, + fd, + libc::STDIN_FILENO))?; + } + if let Some(fd) = stdio.stdout.fd() { + cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0, + fd, + libc::STDOUT_FILENO))?; + } + if let Some(fd) = stdio.stderr.fd() { + cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0, + fd, + libc::STDERR_FILENO))?; + } + + let mut set: libc::sigset_t = mem::uninitialized(); + cvt(libc::sigemptyset(&mut set))?; + cvt(libc::posix_spawnattr_setsigmask(&mut attrs.0, + &set))?; + cvt(libc::sigaddset(&mut set, libc::SIGPIPE))?; + cvt(libc::posix_spawnattr_setsigdefault(&mut attrs.0, + &set))?; + + let flags = libc::POSIX_SPAWN_SETSIGDEF | + libc::POSIX_SPAWN_SETSIGMASK; + cvt(libc::posix_spawnattr_setflags(&mut attrs.0, flags as _))?; + + let envp = envp.map(|c| c.as_ptr()) + .unwrap_or(*sys::os::environ() as *const _); + let ret = libc::posix_spawnp( + &mut p.pid, + self.get_argv()[0], + &file_actions.0, + &attrs.0, + self.get_argv().as_ptr() as *const _, + envp as *const _, + ); + if ret == 0 { + Ok(Some(p)) + } else { + Err(io::Error::from_raw_os_error(ret)) + } + } + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/libstd/sys/unix/process/zircon.rs b/src/libstd/sys/unix/process/zircon.rs index 90864e6ef3f..a06c73ee263 100644 --- a/src/libstd/sys/unix/process/zircon.rs +++ b/src/libstd/sys/unix/process/zircon.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(non_camel_case_types)] +#![allow(non_camel_case_types, unused)] use convert::TryInto; use io; @@ -117,75 +117,36 @@ extern { avail: *mut size_t) -> zx_status_t; } -// From `enum special_handles` in system/ulib/launchpad/launchpad.c -// HND_LOADER_SVC = 0 -// HND_EXEC_VMO = 1 -// HND_SEGMENTS_VMAR = 2 -const HND_SPECIAL_COUNT: c_int = 3; - +#[derive(Default)] #[repr(C)] -pub struct launchpad_t { - argc: u32, - envc: u32, - args: *const c_char, - args_len: size_t, - env: *const c_char, - env_len: size_t, - - handles: *mut zx_handle_t, - handles_info: *mut u32, - handle_count: size_t, - handle_alloc: size_t, - - entry: zx_vaddr_t, - base: zx_vaddr_t, - vdso_base: zx_vaddr_t, - - stack_size: size_t, - - special_handles: [zx_handle_t; HND_SPECIAL_COUNT as usize], - loader_message: bool, +pub struct fdio_spawn_action_t { + pub action: u32, + pub reserved0: u32, + pub local_fd: i32, + pub target_fd: i32, + pub reserved1: u64, } extern { - pub fn launchpad_create(job: zx_handle_t, name: *const c_char, - lp: *mut *mut launchpad_t) -> zx_status_t; - - pub fn launchpad_go(lp: *mut launchpad_t, - proc_handle: *mut zx_handle_t, - err_msg: *mut *const c_char) -> zx_status_t; - - pub fn launchpad_destroy(lp: *mut launchpad_t); - - pub fn launchpad_set_args(lp: *mut launchpad_t, argc: c_int, - argv: *const *const c_char) -> zx_status_t; - - pub fn launchpad_set_environ(lp: *mut launchpad_t, envp: *const *const c_char) -> zx_status_t; - - pub fn launchpad_clone(lp: *mut launchpad_t, what: u32) -> zx_status_t; - - pub fn launchpad_clone_fd(lp: *mut launchpad_t, fd: c_int, target_fd: c_int) -> zx_status_t; - - pub fn launchpad_transfer_fd(lp: *mut launchpad_t, fd: c_int, target_fd: c_int) -> zx_status_t; - - pub fn launchpad_elf_load(lp: *mut launchpad_t, vmo: zx_handle_t) -> zx_status_t; - - pub fn launchpad_add_vdso_vmo(lp: *mut launchpad_t) -> zx_status_t; + pub fn fdio_spawn_etc(job: zx_handle_t, flags: u32, path: *const c_char, + argv: *const *const c_char, envp: *const *const c_char, + action_count: u64, actions: *const fdio_spawn_action_t, + process: *mut zx_handle_t, err_msg: *mut c_char) -> zx_status_t; +} - pub fn launchpad_load_vdso(lp: *mut launchpad_t, vmo: zx_handle_t) -> zx_status_t; +// fdio_spawn_etc flags - pub fn launchpad_vmo_from_file(filename: *const c_char) -> zx_handle_t; -} +pub const FDIO_SPAWN_CLONE_JOB: u32 = 0x0001; +pub const FDIO_SPAWN_CLONE_LDSVC: u32 = 0x0002; +pub const FDIO_SPAWN_CLONE_NAMESPACE: u32 = 0x0004; +pub const FDIO_SPAWN_CLONE_STDIO: u32 = 0x0008; +pub const FDIO_SPAWN_CLONE_ENVIRON: u32 = 0x0010; +pub const FDIO_SPAWN_CLONE_ALL: u32 = 0xFFFF; -// Launchpad clone constants +// fdio_spawn_etc actions -pub const LP_CLONE_FDIO_NAMESPACE: u32 = 0x0001; -pub const LP_CLONE_FDIO_CWD: u32 = 0x0002; -// LP_CLONE_FDIO_STDIO = 0x0004 -// LP_CLONE_FDIO_ALL = 0x00FF -// LP_CLONE_ENVIRON = 0x0100 -// LP_CLONE_DEFAULT_JOB = 0x0200 -// LP_CLONE_ALL = 0xFFFF +pub const FDIO_SPAWN_ACTION_CLONE_FD: u32 = 0x0001; +pub const FDIO_SPAWN_ACTION_TRANSFER_FD: u32 = 0x0002; // Errors diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index caa18945765..01c0ada4ffb 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -183,35 +183,10 @@ mod imp { mod imp { #[link(name = "zircon")] extern { - fn zx_cprng_draw(buffer: *mut u8, len: usize, actual: *mut usize) -> i32; - } - - fn getrandom(buf: &mut [u8]) -> Result<usize, i32> { - unsafe { - let mut actual = 0; - let status = zx_cprng_draw(buf.as_mut_ptr(), buf.len(), &mut actual); - if status == 0 { - Ok(actual) - } else { - Err(status) - } - } + fn zx_cprng_draw(buffer: *mut u8, len: usize); } pub fn fill_bytes(v: &mut [u8]) { - let mut buf = v; - while !buf.is_empty() { - let ret = getrandom(buf); - match ret { - Err(err) => { - panic!("kernel zx_cprng_draw call failed! (returned {}, buf.len() {})", - err, buf.len()) - } - Ok(actual) => { - let move_buf = buf; - buf = &mut move_buf[(actual as usize)..]; - } - } - } + unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) } } } diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 51adbc24ae0..40453f9b8a1 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -57,9 +57,6 @@ mod imp { use sys_common::thread_info; - // This is initialized in init() and only read from after - static mut PAGE_SIZE: usize = 0; - #[cfg(any(target_os = "linux", target_os = "android"))] unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize { #[repr(C)] @@ -102,12 +99,12 @@ mod imp { _data: *mut libc::c_void) { use sys_common::util::report_overflow; - let guard = thread_info::stack_guard().unwrap_or(0); + let guard = thread_info::stack_guard().unwrap_or(0..0); let addr = siginfo_si_addr(info); // If the faulting address is within the guard page, then we print a // message saying so and abort. - if guard != 0 && guard - PAGE_SIZE <= addr && addr < guard { + if guard.start <= addr && addr < guard.end { report_overflow(); rtabort!("stack overflow"); } else { @@ -123,8 +120,6 @@ mod imp { static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut(); pub unsafe fn init() { - PAGE_SIZE = ::sys::os::page_size(); - let mut action: sigaction = mem::zeroed(); action.sa_flags = SA_SIGINFO | SA_ONSTACK; action.sa_sigaction = signal_handler as sighandler_t; diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs index e9b3d4affc7..87ba2aef4f1 100644 --- a/src/libstd/sys/unix/stdio.rs +++ b/src/libstd/sys/unix/stdio.rs @@ -75,3 +75,7 @@ pub fn is_ebadf(err: &io::Error) -> bool { } pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; + +pub fn stderr_prints_nothing() -> bool { + false +} diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index cb249af4254..f3a45d24657 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::boxed::FnBox; +use boxed::FnBox; use cmp; use ffi::CStr; use io; @@ -49,7 +49,7 @@ unsafe fn pthread_attr_setstacksize(_attr: *mut libc::pthread_attr_t, } impl Thread { - pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>) + pub unsafe fn new<'a>(stack: usize, p: Box<dyn FnBox() + 'a>) -> io::Result<Thread> { let p = box p; let mut native: libc::pthread_t = mem::zeroed(); @@ -138,7 +138,8 @@ impl Thread { target_os = "solaris", target_os = "haiku", target_os = "l4re", - target_os = "emscripten"))] + target_os = "emscripten", + target_os = "hermit"))] pub fn set_name(_name: &CStr) { // Newlib, Illumos, Haiku, and Emscripten have no way to set a thread name. } @@ -205,8 +206,11 @@ impl Drop for Thread { not(target_os = "solaris")))] #[cfg_attr(test, allow(dead_code))] pub mod guard { - pub unsafe fn current() -> Option<usize> { None } - pub unsafe fn init() -> Option<usize> { None } + use ops::Range; + pub type Guard = Range<usize>; + pub unsafe fn current() -> Option<Guard> { None } + pub unsafe fn init() -> Option<Guard> { None } + pub unsafe fn deinit() {} } @@ -220,16 +224,45 @@ pub mod guard { #[cfg_attr(test, allow(dead_code))] pub mod guard { use libc; - use libc::mmap; - use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED}; + use libc::{mmap, mprotect}; + use libc::{PROT_NONE, PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED}; + use ops::Range; use sys::os; - #[cfg(any(target_os = "macos", - target_os = "bitrig", - target_os = "openbsd", - target_os = "solaris"))] + // This is initialized in init() and only read from after + static mut PAGE_SIZE: usize = 0; + + pub type Guard = Range<usize>; + + #[cfg(target_os = "solaris")] + unsafe fn get_stack_start() -> Option<*mut libc::c_void> { + let mut current_stack: libc::stack_t = ::mem::zeroed(); + assert_eq!(libc::stack_getbounds(&mut current_stack), 0); + Some(current_stack.ss_sp) + } + + #[cfg(target_os = "macos")] + unsafe fn get_stack_start() -> Option<*mut libc::c_void> { + let stackaddr = libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize - + libc::pthread_get_stacksize_np(libc::pthread_self()); + Some(stackaddr as *mut libc::c_void) + } + + #[cfg(any(target_os = "openbsd", target_os = "bitrig"))] unsafe fn get_stack_start() -> Option<*mut libc::c_void> { - current().map(|s| s as *mut libc::c_void) + let mut current_stack: libc::stack_t = ::mem::zeroed(); + assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(), + &mut current_stack), 0); + + let extra = if cfg!(target_os = "bitrig") {3} else {1} * PAGE_SIZE; + let stackaddr = if libc::pthread_main_np() == 1 { + // main thread + current_stack.ss_sp as usize - current_stack.ss_size + extra + } else { + // new thread + current_stack.ss_sp as usize - current_stack.ss_size + }; + Some(stackaddr as *mut libc::c_void) } #[cfg(any(target_os = "android", target_os = "freebsd", @@ -253,9 +286,10 @@ pub mod guard { ret } - pub unsafe fn init() -> Option<usize> { - let psize = os::page_size(); - let mut stackaddr = get_stack_start()?; + // Precondition: PAGE_SIZE is initialized. + unsafe fn get_stack_start_aligned() -> Option<*mut libc::c_void> { + assert!(PAGE_SIZE != 0); + let stackaddr = get_stack_start()?; // Ensure stackaddr is page aligned! A parent process might // have reset RLIMIT_STACK to be non-page aligned. The @@ -263,11 +297,18 @@ pub mod guard { // stackaddr < stackaddr + stacksize, so if stackaddr is not // page-aligned, calculate the fix such that stackaddr < // new_page_aligned_stackaddr < stackaddr + stacksize - let remainder = (stackaddr as usize) % psize; - if remainder != 0 { - stackaddr = ((stackaddr as usize) + psize - remainder) - as *mut libc::c_void; - } + let remainder = (stackaddr as usize) % PAGE_SIZE; + Some(if remainder == 0 { + stackaddr + } else { + ((stackaddr as usize) + PAGE_SIZE - remainder) as *mut libc::c_void + }) + } + + pub unsafe fn init() -> Option<Guard> { + PAGE_SIZE = os::page_size(); + + let stackaddr = get_stack_start_aligned()?; if cfg!(target_os = "linux") { // Linux doesn't allocate the whole stack right away, and @@ -280,60 +321,71 @@ pub mod guard { // Instead, we'll just note where we expect rlimit to start // faulting, so our handler can report "stack overflow", and // trust that the kernel's own stack guard will work. - Some(stackaddr as usize) + let stackaddr = stackaddr as usize; + Some(stackaddr - PAGE_SIZE..stackaddr) } else { // Reallocate the last page of the stack. // This ensures SIGBUS will be raised on // stack overflow. - let result = mmap(stackaddr, psize, PROT_NONE, + // Systems which enforce strict PAX MPROTECT do not allow + // to mprotect() a mapping with less restrictive permissions + // than the initial mmap() used, so we mmap() here with + // read/write permissions and only then mprotect() it to + // no permissions at all. See issue #50313. + let result = mmap(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); - if result != stackaddr || result == MAP_FAILED { panic!("failed to allocate a guard page"); } + let result = mprotect(stackaddr, PAGE_SIZE, PROT_NONE); + if result != 0 { + panic!("failed to protect the guard page"); + } + + let guardaddr = stackaddr as usize; let offset = if cfg!(target_os = "freebsd") { 2 } else { 1 }; - Some(stackaddr as usize + offset * psize) + Some(guardaddr..guardaddr + offset * PAGE_SIZE) } } - #[cfg(target_os = "solaris")] - pub unsafe fn current() -> Option<usize> { - let mut current_stack: libc::stack_t = ::mem::zeroed(); - assert_eq!(libc::stack_getbounds(&mut current_stack), 0); - Some(current_stack.ss_sp as usize) - } - - #[cfg(target_os = "macos")] - pub unsafe fn current() -> Option<usize> { - Some((libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize - - libc::pthread_get_stacksize_np(libc::pthread_self()))) + pub unsafe fn deinit() { + if !cfg!(target_os = "linux") { + if let Some(stackaddr) = get_stack_start_aligned() { + // Remove the protection on the guard page. + // FIXME: we cannot unmap the page, because when we mmap() + // above it may be already mapped by the OS, which we can't + // detect from mmap()'s return value. If we unmap this page, + // it will lead to failure growing stack size on platforms like + // macOS. Instead, just restore the page to a writable state. + // This ain't Linux, so we probably don't need to care about + // execstack. + let result = mprotect(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE); + + if result != 0 { + panic!("unable to reset the guard page"); + } + } + } } - #[cfg(any(target_os = "openbsd", target_os = "bitrig"))] - pub unsafe fn current() -> Option<usize> { - let mut current_stack: libc::stack_t = ::mem::zeroed(); - assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(), - &mut current_stack), 0); - - let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size(); - Some(if libc::pthread_main_np() == 1 { - // main thread - current_stack.ss_sp as usize - current_stack.ss_size + extra - } else { - // new thread - current_stack.ss_sp as usize - current_stack.ss_size - }) + #[cfg(any(target_os = "macos", + target_os = "bitrig", + target_os = "openbsd", + target_os = "solaris"))] + pub unsafe fn current() -> Option<Guard> { + let stackaddr = get_stack_start()? as usize; + Some(stackaddr - PAGE_SIZE..stackaddr) } #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux", target_os = "netbsd", target_os = "l4re"))] - pub unsafe fn current() -> Option<usize> { + pub unsafe fn current() -> Option<Guard> { let mut ret = None; let mut attr: libc::pthread_attr_t = ::mem::zeroed(); assert_eq!(libc::pthread_attr_init(&mut attr), 0); @@ -352,12 +404,23 @@ pub mod guard { assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0); + let stackaddr = stackaddr as usize; ret = if cfg!(target_os = "freebsd") { - Some(stackaddr as usize - guardsize) + // FIXME does freebsd really fault *below* the guard addr? + let guardaddr = stackaddr - guardsize; + Some(guardaddr - PAGE_SIZE..guardaddr) } else if cfg!(target_os = "netbsd") { - Some(stackaddr as usize) + Some(stackaddr - guardsize..stackaddr) + } else if cfg!(all(target_os = "linux", target_env = "gnu")) { + // glibc used to include the guard area within the stack, as noted in the BUGS + // section of `man pthread_attr_getguardsize`. This has been corrected starting + // with glibc 2.27, and in some distro backports, so the guard is now placed at the + // end (below) the stack. There's no easy way for us to know which we have at + // runtime, so we'll just match any fault in the range right above or below the + // stack base to call that fault a stack overflow. + Some(stackaddr - guardsize..stackaddr + guardsize) } else { - Some(stackaddr as usize + guardsize) + Some(stackaddr..stackaddr + guardsize) }; } assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index 83127935909..0b1fb726357 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -289,7 +289,7 @@ mod inner { pub fn sub_instant(&self, other: &Instant) -> Duration { self.t.sub_timespec(&other.t).unwrap_or_else(|_| { - panic!("other was less than the current instant") + panic!("specified instant was later than self") }) } @@ -345,9 +345,9 @@ mod inner { } } - #[cfg(not(target_os = "dragonfly"))] + #[cfg(not(any(target_os = "dragonfly", target_os = "hermit")))] pub type clock_t = libc::c_int; - #[cfg(target_os = "dragonfly")] + #[cfg(any(target_os = "dragonfly", target_os = "hermit"))] pub type clock_t = libc::c_ulong; fn now(clock: clock_t) -> Timespec { diff --git a/src/libstd/sys/wasm/args.rs b/src/libstd/sys/wasm/args.rs index d2a4a7b19d5..b3c6b671e80 100644 --- a/src/libstd/sys/wasm/args.rs +++ b/src/libstd/sys/wasm/args.rs @@ -10,8 +10,8 @@ use ffi::OsString; use marker::PhantomData; -use mem; use vec; +use sys::ArgsSysCall; pub unsafe fn init(_argc: isize, _argv: *const *const u8) { // On wasm these should always be null, so there's nothing for us to do here @@ -21,38 +21,10 @@ pub unsafe fn cleanup() { } pub fn args() -> Args { - // When the runtime debugging is enabled we'll link to some extra runtime - // functions to actually implement this. These are for now just implemented - // in a node.js script but they're off by default as they're sort of weird - // in a web-wasm world. - if !super::DEBUG { - return Args { - iter: Vec::new().into_iter(), - _dont_send_or_sync_me: PhantomData, - } - } - - // You'll find the definitions of these in `src/etc/wasm32-shim.js`. These - // are just meant for debugging and should not be relied on. - extern { - fn rust_wasm_args_count() -> usize; - fn rust_wasm_args_arg_size(a: usize) -> usize; - fn rust_wasm_args_arg_fill(a: usize, ptr: *mut u8); - } - - unsafe { - let cnt = rust_wasm_args_count(); - let mut v = Vec::with_capacity(cnt); - for i in 0..cnt { - let n = rust_wasm_args_arg_size(i); - let mut data = vec![0; n]; - rust_wasm_args_arg_fill(i, data.as_mut_ptr()); - v.push(mem::transmute::<Vec<u8>, OsString>(data)); - } - Args { - iter: v.into_iter(), - _dont_send_or_sync_me: PhantomData, - } + let v = ArgsSysCall::perform(); + Args { + iter: v.into_iter(), + _dont_send_or_sync_me: PhantomData, } } diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs index ba3d6a2813a..c02e5e809c8 100644 --- a/src/libstd/sys/wasm/mod.rs +++ b/src/libstd/sys/wasm/mod.rs @@ -26,17 +26,11 @@ use io; use os::raw::c_char; - -// Right now the wasm backend doesn't even have the ability to print to the -// console by default. Wasm can't import anything from JS! (you have to -// explicitly provide it). -// -// Sometimes that's a real bummer, though, so this flag can be set to `true` to -// enable calling various shims defined in `src/etc/wasm32-shim.js` which should -// help receive debug output and see what's going on. In general this flag -// currently controls "will we call out to our own defined shims in node.js", -// and this flag should always be `false` for release builds. -const DEBUG: bool = false; +use ptr; +use sys::os_str::Buf; +use sys_common::{AsInner, FromInner}; +use ffi::{OsString, OsStr}; +use time::Duration; pub mod args; #[cfg(feature = "backtrace")] @@ -92,7 +86,7 @@ pub unsafe fn strlen(mut s: *const c_char) -> usize { } pub unsafe fn abort_internal() -> ! { - ::intrinsics::abort(); + ExitSysCall::perform(1) } // We don't have randomness yet, but I totally used a random number generator to @@ -103,3 +97,218 @@ pub unsafe fn abort_internal() -> ! { pub fn hashmap_random_keys() -> (u64, u64) { (1, 2) } + +// Implement a minimal set of system calls to enable basic IO +pub enum SysCallIndex { + Read = 0, + Write = 1, + Exit = 2, + Args = 3, + GetEnv = 4, + SetEnv = 5, + Time = 6, +} + +#[repr(C)] +pub struct ReadSysCall { + fd: usize, + ptr: *mut u8, + len: usize, + result: usize, +} + +impl ReadSysCall { + pub fn perform(fd: usize, buffer: &mut [u8]) -> usize { + let mut call_record = ReadSysCall { + fd, + len: buffer.len(), + ptr: buffer.as_mut_ptr(), + result: 0 + }; + if unsafe { syscall(SysCallIndex::Read, &mut call_record) } { + call_record.result + } else { + 0 + } + } +} + +#[repr(C)] +pub struct WriteSysCall { + fd: usize, + ptr: *const u8, + len: usize, +} + +impl WriteSysCall { + pub fn perform(fd: usize, buffer: &[u8]) { + let mut call_record = WriteSysCall { + fd, + len: buffer.len(), + ptr: buffer.as_ptr() + }; + unsafe { syscall(SysCallIndex::Write, &mut call_record); } + } +} + +#[repr(C)] +pub struct ExitSysCall { + code: usize, +} + +impl ExitSysCall { + pub fn perform(code: usize) -> ! { + let mut call_record = ExitSysCall { + code + }; + unsafe { + syscall(SysCallIndex::Exit, &mut call_record); + ::intrinsics::abort(); + } + } +} + +fn receive_buffer<E, F: FnMut(&mut [u8]) -> Result<usize, E>>(estimate: usize, mut f: F) + -> Result<Vec<u8>, E> +{ + let mut buffer = vec![0; estimate]; + loop { + let result = f(&mut buffer)?; + if result <= buffer.len() { + buffer.truncate(result); + break; + } + buffer.resize(result, 0); + } + Ok(buffer) +} + +#[repr(C)] +pub struct ArgsSysCall { + ptr: *mut u8, + len: usize, + result: usize +} + +impl ArgsSysCall { + pub fn perform() -> Vec<OsString> { + receive_buffer(1024, |buffer| -> Result<usize, !> { + let mut call_record = ArgsSysCall { + len: buffer.len(), + ptr: buffer.as_mut_ptr(), + result: 0 + }; + if unsafe { syscall(SysCallIndex::Args, &mut call_record) } { + Ok(call_record.result) + } else { + Ok(0) + } + }) + .unwrap() + .split(|b| *b == 0) + .map(|s| FromInner::from_inner(Buf { inner: s.to_owned() })) + .collect() + } +} + +#[repr(C)] +pub struct GetEnvSysCall { + key_ptr: *const u8, + key_len: usize, + value_ptr: *mut u8, + value_len: usize, + result: usize +} + +impl GetEnvSysCall { + pub fn perform(key: &OsStr) -> Option<OsString> { + let key_buf = &AsInner::as_inner(key).inner; + receive_buffer(64, |buffer| { + let mut call_record = GetEnvSysCall { + key_len: key_buf.len(), + key_ptr: key_buf.as_ptr(), + value_len: buffer.len(), + value_ptr: buffer.as_mut_ptr(), + result: !0usize + }; + if unsafe { syscall(SysCallIndex::GetEnv, &mut call_record) } { + if call_record.result == !0usize { + Err(()) + } else { + Ok(call_record.result) + } + } else { + Err(()) + } + }).ok().map(|s| { + FromInner::from_inner(Buf { inner: s }) + }) + } +} + +#[repr(C)] +pub struct SetEnvSysCall { + key_ptr: *const u8, + key_len: usize, + value_ptr: *const u8, + value_len: usize +} + +impl SetEnvSysCall { + pub fn perform(key: &OsStr, value: Option<&OsStr>) { + let key_buf = &AsInner::as_inner(key).inner; + let value_buf = value.map(|v| &AsInner::as_inner(v).inner); + let mut call_record = SetEnvSysCall { + key_len: key_buf.len(), + key_ptr: key_buf.as_ptr(), + value_len: value_buf.map(|v| v.len()).unwrap_or(!0usize), + value_ptr: value_buf.map(|v| v.as_ptr()).unwrap_or(ptr::null()) + }; + unsafe { syscall(SysCallIndex::SetEnv, &mut call_record); } + } +} + +pub enum TimeClock { + Monotonic = 0, + System = 1, +} + +#[repr(C)] +pub struct TimeSysCall { + clock: usize, + secs_hi: usize, + secs_lo: usize, + nanos: usize +} + +impl TimeSysCall { + pub fn perform(clock: TimeClock) -> Duration { + let mut call_record = TimeSysCall { + clock: clock as usize, + secs_hi: 0, + secs_lo: 0, + nanos: 0 + }; + if unsafe { syscall(SysCallIndex::Time, &mut call_record) } { + Duration::new( + ((call_record.secs_hi as u64) << 32) | (call_record.secs_lo as u64), + call_record.nanos as u32 + ) + } else { + panic!("Time system call is not implemented by WebAssembly host"); + } + } +} + +unsafe fn syscall<T>(index: SysCallIndex, data: &mut T) -> bool { + #[cfg(feature = "wasm_syscall")] + extern { + #[no_mangle] + fn rust_wasm_syscall(index: usize, data: *mut Void) -> usize; + } + + #[cfg(not(feature = "wasm_syscall"))] + unsafe fn rust_wasm_syscall(_index: usize, _data: *mut Void) -> usize { 0 } + + rust_wasm_syscall(index as usize, data as *mut T as *mut Void) != 0 +} diff --git a/src/libstd/sys/wasm/os.rs b/src/libstd/sys/wasm/os.rs index c98030f7ebf..0cb991e19b0 100644 --- a/src/libstd/sys/wasm/os.rs +++ b/src/libstd/sys/wasm/os.rs @@ -8,23 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::intrinsics; - use error::Error as StdError; use ffi::{OsString, OsStr}; use fmt; use io; -use mem; use path::{self, PathBuf}; use str; -use sys::{unsupported, Void}; +use sys::{unsupported, Void, ExitSysCall, GetEnvSysCall, SetEnvSysCall}; pub fn errno() -> i32 { 0 } pub fn error_string(_errno: i32) -> String { - format!("operation successful") + "operation successful".to_string() } pub fn getcwd() -> io::Result<PathBuf> { @@ -87,36 +84,15 @@ pub fn env() -> Env { } pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> { - // If we're debugging the runtime then we actually probe node.js to ask for - // the value of environment variables to help provide inputs to programs. - // The `extern` shims here are defined in `src/etc/wasm32-shim.js` and are - // intended for debugging only, you should not rely on them. - if !super::DEBUG { - return Ok(None) - } - - extern { - fn rust_wasm_getenv_len(k: *const u8, kl: usize) -> isize; - fn rust_wasm_getenv_data(k: *const u8, kl: usize, v: *mut u8); - } - unsafe { - let k: &[u8] = mem::transmute(k); - let n = rust_wasm_getenv_len(k.as_ptr(), k.len()); - if n == -1 { - return Ok(None) - } - let mut data = vec![0; n as usize]; - rust_wasm_getenv_data(k.as_ptr(), k.len(), data.as_mut_ptr()); - Ok(Some(mem::transmute(data))) - } + Ok(GetEnvSysCall::perform(k)) } -pub fn setenv(_k: &OsStr, _v: &OsStr) -> io::Result<()> { - unsupported() +pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + Ok(SetEnvSysCall::perform(k, Some(v))) } -pub fn unsetenv(_n: &OsStr) -> io::Result<()> { - unsupported() +pub fn unsetenv(k: &OsStr) -> io::Result<()> { + Ok(SetEnvSysCall::perform(k, None)) } pub fn temp_dir() -> PathBuf { @@ -128,7 +104,7 @@ pub fn home_dir() -> Option<PathBuf> { } pub fn exit(_code: i32) -> ! { - unsafe { intrinsics::abort() } + ExitSysCall::perform(_code as isize as usize) } pub fn getpid() -> u32 { diff --git a/src/libstd/sys/wasm/os_str.rs b/src/libstd/sys/wasm/os_str.rs index 543c22ebe18..e0da5bdf36c 100644 --- a/src/libstd/sys/wasm/os_str.rs +++ b/src/libstd/sys/wasm/os_str.rs @@ -19,7 +19,7 @@ use rc::Rc; use sync::Arc; use sys_common::{AsInner, IntoInner}; use sys_common::bytestring::debug_fmt_bytestring; -use std_unicode::lossy::Utf8Lossy; +use core::str::lossy::Utf8Lossy; #[derive(Clone, Hash)] pub struct Buf { @@ -104,6 +104,11 @@ impl Buf { self.inner.shrink_to_fit() } + #[inline] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.inner.shrink_to(min_capacity) + } + pub fn as_slice(&self) -> &Slice { unsafe { mem::transmute(&*self.inner) } } diff --git a/src/libstd/sys/wasm/process.rs b/src/libstd/sys/wasm/process.rs index f3f5de350f1..433e9cec7c8 100644 --- a/src/libstd/sys/wasm/process.rs +++ b/src/libstd/sys/wasm/process.rs @@ -129,6 +129,18 @@ impl fmt::Display for ExitStatus { } } +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitCode(bool); + +impl ExitCode { + pub const SUCCESS: ExitCode = ExitCode(false); + pub const FAILURE: ExitCode = ExitCode(true); + + pub fn as_i32(&self) -> i32 { + self.0 as i32 + } +} + pub struct Process(Void); impl Process { diff --git a/src/libstd/sys/wasm/rwlock.rs b/src/libstd/sys/wasm/rwlock.rs index 8b06f541674..6516010af47 100644 --- a/src/libstd/sys/wasm/rwlock.rs +++ b/src/libstd/sys/wasm/rwlock.rs @@ -30,7 +30,7 @@ impl RWLock { if *mode >= 0 { *mode += 1; } else { - panic!("rwlock locked for writing"); + rtabort!("rwlock locked for writing"); } } @@ -51,7 +51,7 @@ impl RWLock { if *mode == 0 { *mode = -1; } else { - panic!("rwlock locked for reading") + rtabort!("rwlock locked for reading") } } diff --git a/src/libstd/sys/wasm/stdio.rs b/src/libstd/sys/wasm/stdio.rs index 0f75f240251..023f29576a2 100644 --- a/src/libstd/sys/wasm/stdio.rs +++ b/src/libstd/sys/wasm/stdio.rs @@ -9,19 +9,19 @@ // except according to those terms. use io; -use sys::{Void, unsupported}; +use sys::{ReadSysCall, WriteSysCall}; -pub struct Stdin(Void); +pub struct Stdin; pub struct Stdout; pub struct Stderr; impl Stdin { pub fn new() -> io::Result<Stdin> { - unsupported() + Ok(Stdin) } - pub fn read(&self, _data: &mut [u8]) -> io::Result<usize> { - match self.0 {} + pub fn read(&self, data: &mut [u8]) -> io::Result<usize> { + Ok(ReadSysCall::perform(0, data)) } } @@ -31,19 +31,7 @@ impl Stdout { } pub fn write(&self, data: &[u8]) -> io::Result<usize> { - // If runtime debugging is enabled at compile time we'll invoke some - // runtime functions that are defined in our src/etc/wasm32-shim.js - // debugging script. Note that this ffi function call is intended - // *purely* for debugging only and should not be relied upon. - if !super::DEBUG { - return unsupported() - } - extern { - fn rust_wasm_write_stdout(data: *const u8, len: usize); - } - unsafe { - rust_wasm_write_stdout(data.as_ptr(), data.len()) - } + WriteSysCall::perform(1, data); Ok(data.len()) } @@ -58,16 +46,7 @@ impl Stderr { } pub fn write(&self, data: &[u8]) -> io::Result<usize> { - // See comments in stdout for what's going on here. - if !super::DEBUG { - return unsupported() - } - extern { - fn rust_wasm_write_stderr(data: *const u8, len: usize); - } - unsafe { - rust_wasm_write_stderr(data.as_ptr(), data.len()) - } + WriteSysCall::perform(2, data); Ok(data.len()) } @@ -90,3 +69,7 @@ pub const STDIN_BUF_SIZE: usize = 0; pub fn is_ebadf(_err: &io::Error) -> bool { true } + +pub fn stderr_prints_nothing() -> bool { + !cfg!(feature = "wasm_syscall") +} diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs index 13980e0cc19..8173a624211 100644 --- a/src/libstd/sys/wasm/thread.rs +++ b/src/libstd/sys/wasm/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::boxed::FnBox; +use boxed::FnBox; use ffi::CStr; use io; use sys::{unsupported, Void}; @@ -19,7 +19,7 @@ pub struct Thread(Void); pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; impl Thread { - pub unsafe fn new<'a>(_stack: usize, _p: Box<FnBox() + 'a>) + pub unsafe fn new<'a>(_stack: usize, _p: Box<dyn FnBox() + 'a>) -> io::Result<Thread> { unsupported() @@ -43,6 +43,8 @@ impl Thread { } pub mod guard { - pub unsafe fn current() -> Option<usize> { None } - pub unsafe fn init() -> Option<usize> { None } + pub type Guard = !; + pub unsafe fn current() -> Option<Guard> { None } + pub unsafe fn init() -> Option<Guard> { None } + pub unsafe fn deinit() {} } diff --git a/src/libstd/sys/wasm/time.rs b/src/libstd/sys/wasm/time.rs index c269def98f6..e52435e6339 100644 --- a/src/libstd/sys/wasm/time.rs +++ b/src/libstd/sys/wasm/time.rs @@ -8,56 +8,50 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use fmt; use time::Duration; +use sys::{TimeSysCall, TimeClock}; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct Instant; +pub struct Instant(Duration); -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct SystemTime; +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct SystemTime(Duration); -pub const UNIX_EPOCH: SystemTime = SystemTime; +pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); impl Instant { pub fn now() -> Instant { - panic!("not supported on web assembly"); + Instant(TimeSysCall::perform(TimeClock::Monotonic)) } - pub fn sub_instant(&self, _other: &Instant) -> Duration { - panic!("can't sub yet"); + pub fn sub_instant(&self, other: &Instant) -> Duration { + self.0 - other.0 } - pub fn add_duration(&self, _other: &Duration) -> Instant { - panic!("can't add yet"); + pub fn add_duration(&self, other: &Duration) -> Instant { + Instant(self.0 + *other) } - pub fn sub_duration(&self, _other: &Duration) -> Instant { - panic!("can't sub yet"); + pub fn sub_duration(&self, other: &Duration) -> Instant { + Instant(self.0 - *other) } } impl SystemTime { pub fn now() -> SystemTime { - panic!("not supported on web assembly"); + SystemTime(TimeSysCall::perform(TimeClock::System)) } - pub fn sub_time(&self, _other: &SystemTime) + pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { - panic!() - } - - pub fn add_duration(&self, _other: &Duration) -> SystemTime { - panic!() + self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) } - pub fn sub_duration(&self, _other: &Duration) -> SystemTime { - panic!() + pub fn add_duration(&self, other: &Duration) -> SystemTime { + SystemTime(self.0 + *other) } -} -impl fmt::Debug for SystemTime { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - panic!() + pub fn sub_duration(&self, other: &Duration) -> SystemTime { + SystemTime(self.0 - *other) } } diff --git a/src/libstd/sys/windows/backtrace/mod.rs b/src/libstd/sys/windows/backtrace/mod.rs index 176891fff23..f64cae810b9 100644 --- a/src/libstd/sys/windows/backtrace/mod.rs +++ b/src/libstd/sys/windows/backtrace/mod.rs @@ -46,111 +46,281 @@ mod printing; #[path = "backtrace_gnu.rs"] pub mod gnu; -pub use self::printing::{resolve_symname, foreach_symbol_fileline}; +pub use self::printing::{foreach_symbol_fileline, resolve_symname}; +use self::printing::{load_printing_fns_64, load_printing_fns_ex}; -pub fn unwind_backtrace(frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ +pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> { let dbghelp = DynamicLibrary::open("dbghelp.dll")?; // Fetch the symbols necessary from dbghelp.dll let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?; let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?; - let StackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn)?; + + // StackWalkEx might not be present and we'll fall back to StackWalk64 + let sw_var = match sym!(dbghelp, "StackWalkEx", StackWalkExFn) { + Ok(StackWalkEx) => { + StackWalkVariant::StackWalkEx(StackWalkEx, load_printing_fns_ex(&dbghelp)?) + } + Err(e) => match sym!(dbghelp, "StackWalk64", StackWalk64Fn) { + Ok(StackWalk64) => { + StackWalkVariant::StackWalk64(StackWalk64, load_printing_fns_64(&dbghelp)?) + } + Err(..) => return Err(e), + }, + }; // Allocate necessary structures for doing the stack walk let process = unsafe { c::GetCurrentProcess() }; - let thread = unsafe { c::GetCurrentThread() }; - let mut context: c::CONTEXT = unsafe { mem::zeroed() }; - unsafe { c::RtlCaptureContext(&mut context) }; - let mut frame: c::STACKFRAME64 = unsafe { mem::zeroed() }; - let image = init_frame(&mut frame, &context); let backtrace_context = BacktraceContext { handle: process, SymCleanup, + StackWalkVariant: sw_var, dbghelp, }; // Initialize this process's symbols let ret = unsafe { SymInitialize(process, ptr::null_mut(), c::TRUE) }; if ret != c::TRUE { - return Ok((0, backtrace_context)) + return Ok((0, backtrace_context)); } // And now that we're done with all the setup, do the stack walking! - // Start from -1 to avoid printing this stack frame, which will - // always be exactly the same. + match backtrace_context.StackWalkVariant { + StackWalkVariant::StackWalkEx(StackWalkEx, _) => { + set_frames(StackWalkEx, frames).map(|i| (i, backtrace_context)) + } + + StackWalkVariant::StackWalk64(StackWalk64, _) => { + set_frames(StackWalk64, frames).map(|i| (i, backtrace_context)) + } + } +} + +fn set_frames<W: StackWalker>(StackWalk: W, frames: &mut [Frame]) -> io::Result<usize> { + let process = unsafe { c::GetCurrentProcess() }; + let thread = unsafe { c::GetCurrentProcess() }; + let mut context: c::CONTEXT = unsafe { mem::zeroed() }; + unsafe { c::RtlCaptureContext(&mut context) }; + let mut frame = W::Item::new(); + let image = frame.init(&context); + let mut i = 0; - unsafe { - while i < frames.len() && - StackWalk64(image, process, thread, &mut frame, &mut context, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut()) == c::TRUE - { - let addr = frame.AddrPC.Offset; - if addr == frame.AddrReturn.Offset || addr == 0 || - frame.AddrReturn.Offset == 0 { break } - - frames[i] = Frame { - symbol_addr: (addr - 1) as *const u8, - exact_position: (addr - 1) as *const u8, - }; - i += 1; + while i < frames.len() + && StackWalk.walk(image, process, thread, &mut frame, &mut context) == c::TRUE + { + let addr = frame.get_addr(); + frames[i] = Frame { + symbol_addr: addr, + exact_position: addr, + inline_context: 0, + }; + + i += 1 + } + Ok(i) +} + +type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL; +type SymCleanupFn = unsafe extern "system" fn(c::HANDLE) -> c::BOOL; + +type StackWalkExFn = unsafe extern "system" fn( + c::DWORD, + c::HANDLE, + c::HANDLE, + *mut c::STACKFRAME_EX, + *mut c::CONTEXT, + *mut c_void, + *mut c_void, + *mut c_void, + *mut c_void, + c::DWORD, +) -> c::BOOL; + +type StackWalk64Fn = unsafe extern "system" fn( + c::DWORD, + c::HANDLE, + c::HANDLE, + *mut c::STACKFRAME64, + *mut c::CONTEXT, + *mut c_void, + *mut c_void, + *mut c_void, + *mut c_void, +) -> c::BOOL; + +trait StackWalker { + type Item: StackFrame; + + fn walk(&self, c::DWORD, c::HANDLE, c::HANDLE, &mut Self::Item, &mut c::CONTEXT) -> c::BOOL; +} + +impl StackWalker for StackWalkExFn { + type Item = c::STACKFRAME_EX; + fn walk( + &self, + image: c::DWORD, + process: c::HANDLE, + thread: c::HANDLE, + frame: &mut Self::Item, + context: &mut c::CONTEXT, + ) -> c::BOOL { + unsafe { + self( + image, + process, + thread, + frame, + context, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + 0, + ) + } + } +} + +impl StackWalker for StackWalk64Fn { + type Item = c::STACKFRAME64; + fn walk( + &self, + image: c::DWORD, + process: c::HANDLE, + thread: c::HANDLE, + frame: &mut Self::Item, + context: &mut c::CONTEXT, + ) -> c::BOOL { + unsafe { + self( + image, + process, + thread, + frame, + context, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ) } } +} + +trait StackFrame { + fn new() -> Self; + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD; + fn get_addr(&self) -> *const u8; +} + +impl StackFrame for c::STACKFRAME_EX { + fn new() -> c::STACKFRAME_EX { + unsafe { mem::zeroed() } + } + + #[cfg(target_arch = "x86")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Eip as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Esp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Ebp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_I386 + } + + #[cfg(target_arch = "x86_64")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Rip as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Rsp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Rbp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_AMD64 + } + + #[cfg(target_arch = "aarch64")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Pc as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Sp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Fp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_ARM64 + } - Ok((i, backtrace_context)) + fn get_addr(&self) -> *const u8 { + (self.AddrPC.Offset - 1) as *const u8 + } } -type SymInitializeFn = - unsafe extern "system" fn(c::HANDLE, *mut c_void, - c::BOOL) -> c::BOOL; -type SymCleanupFn = - unsafe extern "system" fn(c::HANDLE) -> c::BOOL; - -type StackWalk64Fn = - unsafe extern "system" fn(c::DWORD, c::HANDLE, c::HANDLE, - *mut c::STACKFRAME64, *mut c::CONTEXT, - *mut c_void, *mut c_void, - *mut c_void, *mut c_void) -> c::BOOL; - -#[cfg(target_arch = "x86")] -fn init_frame(frame: &mut c::STACKFRAME64, - ctx: &c::CONTEXT) -> c::DWORD { - frame.AddrPC.Offset = ctx.Eip as u64; - frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrStack.Offset = ctx.Esp as u64; - frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrFrame.Offset = ctx.Ebp as u64; - frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_I386 +impl StackFrame for c::STACKFRAME64 { + fn new() -> c::STACKFRAME64 { + unsafe { mem::zeroed() } + } + + #[cfg(target_arch = "x86")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Eip as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Esp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Ebp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_I386 + } + + #[cfg(target_arch = "x86_64")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Rip as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Rsp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Rbp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_AMD64 + } + + #[cfg(target_arch = "aarch64")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Pc as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Sp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Fp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_ARM64 + } + + fn get_addr(&self) -> *const u8 { + (self.AddrPC.Offset - 1) as *const u8 + } } -#[cfg(target_arch = "x86_64")] -fn init_frame(frame: &mut c::STACKFRAME64, - ctx: &c::CONTEXT) -> c::DWORD { - frame.AddrPC.Offset = ctx.Rip as u64; - frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrStack.Offset = ctx.Rsp as u64; - frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrFrame.Offset = ctx.Rbp as u64; - frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_AMD64 +enum StackWalkVariant { + StackWalkEx(StackWalkExFn, printing::PrintingFnsEx), + StackWalk64(StackWalk64Fn, printing::PrintingFns64), } pub struct BacktraceContext { handle: c::HANDLE, SymCleanup: SymCleanupFn, // Only used in printing for msvc and not gnu + // The gnu version is effectively a ZST dummy. + #[allow(dead_code)] + StackWalkVariant: StackWalkVariant, + // keeping DynamycLibrary loaded until its functions no longer needed #[allow(dead_code)] dbghelp: DynamicLibrary, } impl Drop for BacktraceContext { fn drop(&mut self) { - unsafe { (self.SymCleanup)(self.handle); } + unsafe { + (self.SymCleanup)(self.handle); + } } } diff --git a/src/libstd/sys/windows/backtrace/printing/mod.rs b/src/libstd/sys/windows/backtrace/printing/mod.rs index 3e566f6e2bd..251d5028aea 100644 --- a/src/libstd/sys/windows/backtrace/printing/mod.rs +++ b/src/libstd/sys/windows/backtrace/printing/mod.rs @@ -15,6 +15,20 @@ mod printing; #[cfg(target_env = "gnu")] mod printing { pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname}; + + // dummy functions to mirror those present in msvc version. + use sys::dynamic_lib::DynamicLibrary; + use io; + pub struct PrintingFnsEx {} + pub struct PrintingFns64 {} + pub fn load_printing_fns_ex(_: &DynamicLibrary) -> io::Result<PrintingFnsEx> { + Ok(PrintingFnsEx{}) + } + pub fn load_printing_fns_64(_: &DynamicLibrary) -> io::Result<PrintingFns64> { + Ok(PrintingFns64{}) + } } pub use self::printing::{foreach_symbol_fileline, resolve_symname}; +pub use self::printing::{load_printing_fns_ex, load_printing_fns_64, + PrintingFnsEx, PrintingFns64}; diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs index 5a49b77af8e..c8b946bf13a 100644 --- a/src/libstd/sys/windows/backtrace/printing/msvc.rs +++ b/src/libstd/sys/windows/backtrace/printing/msvc.rs @@ -10,27 +10,108 @@ use ffi::CStr; use io; -use libc::{c_ulong, c_char}; +use libc::{c_char, c_ulong}; use mem; -use sys::c; use sys::backtrace::BacktraceContext; +use sys::backtrace::StackWalkVariant; +use sys::c; +use sys::dynamic_lib::DynamicLibrary; use sys_common::backtrace::Frame; +// Structs holding printing functions and loaders for them +// Two versions depending on whether dbghelp.dll has StackWalkEx or not +// (the former being in newer Windows versions, the older being in Win7 and before) +pub struct PrintingFnsEx { + resolve_symname: SymFromInlineContextFn, + sym_get_line: SymGetLineFromInlineContextFn, +} +pub struct PrintingFns64 { + resolve_symname: SymFromAddrFn, + sym_get_line: SymGetLineFromAddr64Fn, +} + +pub fn load_printing_fns_ex(dbghelp: &DynamicLibrary) -> io::Result<PrintingFnsEx> { + Ok(PrintingFnsEx { + resolve_symname: sym!(dbghelp, "SymFromInlineContext", SymFromInlineContextFn)?, + sym_get_line: sym!( + dbghelp, + "SymGetLineFromInlineContext", + SymGetLineFromInlineContextFn + )?, + }) +} +pub fn load_printing_fns_64(dbghelp: &DynamicLibrary) -> io::Result<PrintingFns64> { + Ok(PrintingFns64 { + resolve_symname: sym!(dbghelp, "SymFromAddr", SymFromAddrFn)?, + sym_get_line: sym!(dbghelp, "SymGetLineFromAddr64", SymGetLineFromAddr64Fn)?, + }) +} + type SymFromAddrFn = - unsafe extern "system" fn(c::HANDLE, u64, *mut u64, - *mut c::SYMBOL_INFO) -> c::BOOL; + unsafe extern "system" fn(c::HANDLE, u64, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; +type SymFromInlineContextFn = + unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; + type SymGetLineFromAddr64Fn = - unsafe extern "system" fn(c::HANDLE, u64, *mut u32, - *mut c::IMAGEHLP_LINE64) -> c::BOOL; + unsafe extern "system" fn(c::HANDLE, u64, *mut u32, *mut c::IMAGEHLP_LINE64) -> c::BOOL; +type SymGetLineFromInlineContextFn = unsafe extern "system" fn( + c::HANDLE, + u64, + c::ULONG, + u64, + *mut c::DWORD, + *mut c::IMAGEHLP_LINE64, +) -> c::BOOL; /// Converts a pointer to symbol to its string value. -pub fn resolve_symname<F>(frame: Frame, - callback: F, - context: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> +pub fn resolve_symname<F>(frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()> +where + F: FnOnce(Option<&str>) -> io::Result<()>, { - let SymFromAddr = sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn)?; + match context.StackWalkVariant { + StackWalkVariant::StackWalkEx(_, ref fns) => resolve_symname_internal( + |process: c::HANDLE, + symbol_address: u64, + inline_context: c::ULONG, + info: *mut c::SYMBOL_INFO| unsafe { + let mut displacement = 0u64; + (fns.resolve_symname)( + process, + symbol_address, + inline_context, + &mut displacement, + info, + ) + }, + frame, + callback, + context, + ), + StackWalkVariant::StackWalk64(_, ref fns) => resolve_symname_internal( + |process: c::HANDLE, + symbol_address: u64, + _inline_context: c::ULONG, + info: *mut c::SYMBOL_INFO| unsafe { + let mut displacement = 0u64; + (fns.resolve_symname)(process, symbol_address, &mut displacement, info) + }, + frame, + callback, + context, + ), + } +} +fn resolve_symname_internal<F, R>( + mut symbol_resolver: R, + frame: Frame, + callback: F, + context: &BacktraceContext, +) -> io::Result<()> +where + F: FnOnce(Option<&str>) -> io::Result<()>, + R: FnMut(c::HANDLE, u64, c::ULONG, *mut c::SYMBOL_INFO) -> c::BOOL, +{ unsafe { let mut info: c::SYMBOL_INFO = mem::zeroed(); info.MaxNameLen = c::MAX_SYM_NAME as c_ulong; @@ -39,13 +120,22 @@ pub fn resolve_symname<F>(frame: Frame, // due to struct alignment. info.SizeOfStruct = 88; - let mut displacement = 0u64; - let ret = SymFromAddr(context.handle, - frame.symbol_addr as u64, - &mut displacement, - &mut info); - - let symname = if ret == c::TRUE { + let ret = symbol_resolver( + context.handle, + frame.symbol_addr as u64, + frame.inline_context, + &mut info, + ); + let valid_range = if ret == c::TRUE && frame.symbol_addr as usize >= info.Address as usize { + if info.Size != 0 { + (frame.symbol_addr as usize) < info.Address as usize + info.Size as usize + } else { + true + } + } else { + false + }; + let symname = if valid_range { let ptr = info.Name.as_ptr() as *const c_char; CStr::from_ptr(ptr).to_str().ok() } else { @@ -55,28 +145,72 @@ pub fn resolve_symname<F>(frame: Frame, } } -pub fn foreach_symbol_fileline<F>(frame: Frame, - mut f: F, - context: &BacktraceContext) - -> io::Result<bool> - where F: FnMut(&[u8], u32) -> io::Result<()> +pub fn foreach_symbol_fileline<F>( + frame: Frame, + callback: F, + context: &BacktraceContext, +) -> io::Result<bool> +where + F: FnMut(&[u8], u32) -> io::Result<()>, { - let SymGetLineFromAddr64 = sym!(&context.dbghelp, - "SymGetLineFromAddr64", - SymGetLineFromAddr64Fn)?; + match context.StackWalkVariant { + StackWalkVariant::StackWalkEx(_, ref fns) => foreach_symbol_fileline_iternal( + |process: c::HANDLE, + frame_address: u64, + inline_context: c::ULONG, + line: *mut c::IMAGEHLP_LINE64| unsafe { + let mut displacement = 0u32; + (fns.sym_get_line)( + process, + frame_address, + inline_context, + 0, + &mut displacement, + line, + ) + }, + frame, + callback, + context, + ), + StackWalkVariant::StackWalk64(_, ref fns) => foreach_symbol_fileline_iternal( + |process: c::HANDLE, + frame_address: u64, + _inline_context: c::ULONG, + line: *mut c::IMAGEHLP_LINE64| unsafe { + let mut displacement = 0u32; + (fns.sym_get_line)(process, frame_address, &mut displacement, line) + }, + frame, + callback, + context, + ), + } +} +fn foreach_symbol_fileline_iternal<F, G>( + mut line_getter: G, + frame: Frame, + mut callback: F, + context: &BacktraceContext, +) -> io::Result<bool> +where + F: FnMut(&[u8], u32) -> io::Result<()>, + G: FnMut(c::HANDLE, u64, c::ULONG, *mut c::IMAGEHLP_LINE64) -> c::BOOL, +{ unsafe { let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); line.SizeOfStruct = ::mem::size_of::<c::IMAGEHLP_LINE64>() as u32; - let mut displacement = 0u32; - let ret = SymGetLineFromAddr64(context.handle, - frame.exact_position as u64, - &mut displacement, - &mut line); + let ret = line_getter( + context.handle, + frame.exact_position as u64, + frame.inline_context, + &mut line, + ); if ret == c::TRUE { let name = CStr::from_ptr(line.Filename).to_bytes(); - f(name, line.LineNumber as u32)?; + callback(name, line.LineNumber as u32)?; } Ok(false) } diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 66b44f1402f..e514a56dcc4 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -280,6 +280,9 @@ pub const IMAGE_FILE_MACHINE_I386: DWORD = 0x014c; #[cfg(target_arch = "x86_64")] #[cfg(feature = "backtrace")] pub const IMAGE_FILE_MACHINE_AMD64: DWORD = 0x8664; +#[cfg(target_arch = "aarch64")] +#[cfg(feature = "backtrace")] +pub const IMAGE_FILE_MACHINE_ARM64: DWORD = 0xAA64; pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0; pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd; @@ -296,6 +299,8 @@ pub const PIPE_READMODE_BYTE: DWORD = 0x00000000; pub const FD_SETSIZE: usize = 64; +pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000; + #[repr(C)] #[cfg(not(target_pointer_width = "64"))] pub struct WSADATA { @@ -619,6 +624,24 @@ pub struct ADDRESS64 { #[repr(C)] #[cfg(feature = "backtrace")] +pub struct STACKFRAME_EX { + pub AddrPC: ADDRESS64, + pub AddrReturn: ADDRESS64, + pub AddrFrame: ADDRESS64, + pub AddrStack: ADDRESS64, + pub AddrBStore: ADDRESS64, + pub FuncTableEntry: *mut c_void, + pub Params: [u64; 4], + pub Far: BOOL, + pub Virtual: BOOL, + pub Reserved: [u64; 3], + pub KdHelp: KDHELP64, + pub StackFrameSize: DWORD, + pub InlineFrameContext: DWORD, +} + +#[repr(C)] +#[cfg(feature = "backtrace")] pub struct STACKFRAME64 { pub AddrPC: ADDRESS64, pub AddrReturn: ADDRESS64, @@ -771,9 +794,68 @@ pub struct FLOATING_SAVE_AREA { // will not appear in the final documentation. This should be also defined for // other architectures supported by Windows such as ARM, and for historical // interest, maybe MIPS and PowerPC as well. -#[cfg(all(dox, not(any(target_arch = "x86_64", target_arch = "x86"))))] +#[cfg(all(dox, not(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"))))] pub enum CONTEXT {} +#[cfg(target_arch = "aarch64")] +pub const ARM64_MAX_BREAKPOINTS: usize = 8; + +#[cfg(target_arch = "aarch64")] +pub const ARM64_MAX_WATCHPOINTS: usize = 2; + +#[cfg(target_arch = "aarch64")] +#[repr(C)] +pub struct ARM64_NT_NEON128 { + pub D: [f64; 2], +} + +#[cfg(target_arch = "aarch64")] +#[repr(C, align(16))] +pub struct CONTEXT { + pub ContextFlags: DWORD, + pub Cpsr: DWORD, + pub X0: u64, + pub X1: u64, + pub X2: u64, + pub X3: u64, + pub X4: u64, + pub X5: u64, + pub X6: u64, + pub X7: u64, + pub X8: u64, + pub X9: u64, + pub X10: u64, + pub X11: u64, + pub X12: u64, + pub X13: u64, + pub X14: u64, + pub X15: u64, + pub X16: u64, + pub X17: u64, + pub X18: u64, + pub X19: u64, + pub X20: u64, + pub X21: u64, + pub X22: u64, + pub X23: u64, + pub X24: u64, + pub X25: u64, + pub X26: u64, + pub X27: u64, + pub X28: u64, + pub Fp: u64, + pub Lr: u64, + pub Sp: u64, + pub Pc: u64, + pub V: [ARM64_NT_NEON128; 32], + pub Fpcr: DWORD, + pub Fpsr: DWORD, + pub Bcr: [DWORD; ARM64_MAX_BREAKPOINTS], + pub Bvr: [DWORD; ARM64_MAX_BREAKPOINTS], + pub Wcr: [DWORD; ARM64_MAX_WATCHPOINTS], + pub Wvr: [DWORD; ARM64_MAX_WATCHPOINTS], +} + #[repr(C)] pub struct SOCKADDR_STORAGE_LH { pub ss_family: ADDRESS_FAMILY, diff --git a/src/libstd/sys/windows/ext/ffi.rs b/src/libstd/sys/windows/ext/ffi.rs index d6b8896ac09..bae0d02786a 100644 --- a/src/libstd/sys/windows/ext/ffi.rs +++ b/src/libstd/sys/windows/ext/ffi.rs @@ -31,7 +31,7 @@ //! //! If Rust code *does* need to look into those strings, it can //! convert them to valid UTF-8, possibly lossily, by substituting -//! invalid sequences with U+FFFD REPLACEMENT CHARACTER, as is +//! invalid sequences with [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD], as is //! conventionally done in other Rust APIs that deal with string //! encodings. //! @@ -65,6 +65,7 @@ //! [`from_wide`]: trait.OsStringExt.html#tymethod.from_wide //! [`encode_wide`]: trait.OsStrExt.html#tymethod.encode_wide //! [`collect`]: ../../../iter/trait.Iterator.html#method.collect +//! [U+FFFD]: ../../../char/constant.REPLACEMENT_CHARACTER.html #![stable(feature = "rust1", since = "1.0.0")] @@ -76,7 +77,9 @@ use sys_common::{FromInner, AsInner}; #[stable(feature = "rust1", since = "1.0.0")] pub use sys_common::wtf8::EncodeWide; -/// Windows-specific extensions to `OsString`. +/// Windows-specific extensions to [`OsString`]. +/// +/// [`OsString`]: ../../../../std/ffi/struct.OsString.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStringExt { /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of @@ -109,7 +112,9 @@ impl OsStringExt for OsString { } } -/// Windows-specific extensions to `OsStr`. +/// Windows-specific extensions to [`OsStr`]. +/// +/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStrExt { /// Re-encodes an `OsStr` as a wide character sequence, i.e. potentially diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs index 24c41046f26..78c9e95a055 100644 --- a/src/libstd/sys/windows/ext/fs.rs +++ b/src/libstd/sys/windows/ext/fs.rs @@ -45,15 +45,15 @@ pub trait FileExt { /// 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(()) - /// # } + /// fn main() -> 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>; @@ -79,14 +79,14 @@ pub trait FileExt { /// use std::fs::File; /// use std::os::windows::prelude::*; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; + /// fn main() -> 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(()) - /// # } + /// // 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>; @@ -103,9 +103,9 @@ impl FileExt for fs::File { } } -/// Windows-specific extensions to [`OpenOptions`]. +/// Windows-specific extensions to [`fs::OpenOptions`]. /// -/// [`OpenOptions`]: ../../../fs/struct.OpenOptions.html +/// [`fs::OpenOptions`]: ../../../../std/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`] @@ -281,13 +281,12 @@ impl OpenOptionsExt for OpenOptions { } } -/// Extension methods for [`fs::Metadata`] to access the raw fields contained -/// within. +/// Windows-specific extensions to [`fs::Metadata`]. /// /// The data members that this trait exposes correspond to the members /// of the [`BY_HANDLE_FILE_INFORMATION`] structure. /// -/// [`fs::Metadata`]: ../../../fs/struct.Metadata.html +/// [`fs::Metadata`]: ../../../../std/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")] @@ -305,11 +304,11 @@ pub trait MetadataExt { /// use std::fs; /// use std::os::windows::prelude::*; /// - /// # fn foo() -> io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// let attributes = metadata.file_attributes(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; + /// let attributes = metadata.file_attributes(); + /// Ok(()) + /// } /// ``` /// /// [File Attribute Constants]: @@ -335,11 +334,11 @@ pub trait MetadataExt { /// 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(()) - /// # } + /// fn main() -> 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 @@ -370,11 +369,11 @@ pub trait MetadataExt { /// 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(()) - /// # } + /// fn main() -> 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 @@ -403,11 +402,11 @@ pub trait MetadataExt { /// 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(()) - /// # } + /// fn main() -> 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 @@ -426,11 +425,11 @@ pub trait MetadataExt { /// 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(()) - /// # } + /// fn main() -> 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; @@ -445,6 +444,27 @@ impl MetadataExt for Metadata { fn file_size(&self) -> u64 { self.as_inner().size() } } +/// Windows-specific extensions to [`FileType`]. +/// +/// On Windows, a symbolic link knows whether it is a file or directory. +/// +/// [`FileType`]: ../../../../std/fs/struct.FileType.html +#[unstable(feature = "windows_file_type_ext", issue = "0")] +pub trait FileTypeExt { + /// Returns whether this file type is a symbolic link that is also a directory. + #[unstable(feature = "windows_file_type_ext", issue = "0")] + fn is_symlink_dir(&self) -> bool; + /// Returns whether this file type is a symbolic link that is also a file. + #[unstable(feature = "windows_file_type_ext", issue = "0")] + fn is_symlink_file(&self) -> bool; +} + +#[unstable(feature = "windows_file_type_ext", issue = "0")] +impl FileTypeExt for fs::FileType { + fn is_symlink_dir(&self) -> bool { self.as_inner().is_symlink_dir() } + fn is_symlink_file(&self) -> bool { self.as_inner().is_symlink_file() } +} + /// Creates a new file symbolic link on the filesystem. /// /// The `dst` path will be a file symbolic link pointing to the `src` @@ -455,10 +475,10 @@ impl MetadataExt for Metadata { /// ```no_run /// use std::os::windows::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::symlink_file("a.txt", "b.txt")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::symlink_file("a.txt", "b.txt")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "symlink", since = "1.1.0")] pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) @@ -476,10 +496,10 @@ pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) /// ```no_run /// use std::os::windows::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::symlink_dir("a", "b")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::symlink_dir("a", "b")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "symlink", since = "1.1.0")] pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) diff --git a/src/libstd/sys/windows/ext/mod.rs b/src/libstd/sys/windows/ext/mod.rs index 4b458d293bc..1f10609f32c 100644 --- a/src/libstd/sys/windows/ext/mod.rs +++ b/src/libstd/sys/windows/ext/mod.rs @@ -18,6 +18,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(cfg(windows))] +#![allow(missing_docs)] pub mod ffi; pub mod fs; diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index 759f055c4b1..a02bcbe0c87 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -82,7 +82,9 @@ impl IntoRawHandle for process::ChildStderr { } } -/// Windows-specific extensions to `std::process::ExitStatus` +/// Windows-specific extensions to [`process::ExitStatus`]. +/// +/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html #[stable(feature = "exit_status_from", since = "1.12.0")] pub trait ExitStatusExt { /// Creates a new `ExitStatus` from the raw underlying `u32` return value of @@ -98,7 +100,9 @@ impl ExitStatusExt for process::ExitStatus { } } -/// Windows-specific extensions to the `std::process::Command` builder +/// Windows-specific extensions to the [`process::Command`] builder. +/// +/// [`process::Command`]: ../../../../std/process/struct.Command.html #[stable(feature = "windows_process_extensions", since = "1.16.0")] pub trait CommandExt { /// Sets the [process creation flags][1] to be passed to `CreateProcess`. diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 165e1b0609b..082d4689c7b 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -38,8 +38,9 @@ pub struct FileAttr { } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum FileType { - Dir, File, SymlinkFile, SymlinkDir, ReparsePoint, MountPoint, +pub struct FileType { + attributes: c::DWORD, + reparse_tag: c::DWORD, } pub struct ReadDir { @@ -516,30 +517,34 @@ impl FilePermissions { impl FileType { fn new(attrs: c::DWORD, reparse_tag: c::DWORD) -> FileType { - match (attrs & c::FILE_ATTRIBUTE_DIRECTORY != 0, - attrs & c::FILE_ATTRIBUTE_REPARSE_POINT != 0, - reparse_tag) { - (false, false, _) => FileType::File, - (true, false, _) => FileType::Dir, - (false, true, c::IO_REPARSE_TAG_SYMLINK) => FileType::SymlinkFile, - (true, true, c::IO_REPARSE_TAG_SYMLINK) => FileType::SymlinkDir, - (true, true, c::IO_REPARSE_TAG_MOUNT_POINT) => FileType::MountPoint, - (_, true, _) => FileType::ReparsePoint, - // Note: if a _file_ has a reparse tag of the type IO_REPARSE_TAG_MOUNT_POINT it is - // invalid, as junctions always have to be dirs. We set the filetype to ReparsePoint - // to indicate it is something symlink-like, but not something you can follow. + FileType { + attributes: attrs, + reparse_tag: reparse_tag, } } - - pub fn is_dir(&self) -> bool { *self == FileType::Dir } - pub fn is_file(&self) -> bool { *self == FileType::File } + pub fn is_dir(&self) -> bool { + !self.is_symlink() && self.is_directory() + } + pub fn is_file(&self) -> bool { + !self.is_symlink() && !self.is_directory() + } pub fn is_symlink(&self) -> bool { - *self == FileType::SymlinkFile || - *self == FileType::SymlinkDir || - *self == FileType::MountPoint + self.is_reparse_point() && self.is_reparse_tag_name_surrogate() } pub fn is_symlink_dir(&self) -> bool { - *self == FileType::SymlinkDir || *self == FileType::MountPoint + self.is_symlink() && self.is_directory() + } + pub fn is_symlink_file(&self) -> bool { + self.is_symlink() && !self.is_directory() + } + fn is_directory(&self) -> bool { + self.attributes & c::FILE_ATTRIBUTE_DIRECTORY != 0 + } + fn is_reparse_point(&self) -> bool { + self.attributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 + } + fn is_reparse_tag_name_surrogate(&self) -> bool { + self.reparse_tag & 0x20000000 != 0 } } diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 0d12ecf8fe3..ccf79de909f 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -266,8 +266,12 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD { // handlers. // // https://msdn.microsoft.com/en-us/library/dn774154.aspx -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#[allow(unreachable_code)] pub unsafe fn abort_internal() -> ! { - asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT - ::intrinsics::unreachable(); + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + { + asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT + ::intrinsics::unreachable(); + } + ::intrinsics::abort(); } diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs index 85560368590..9bf9f749d4d 100644 --- a/src/libstd/sys/windows/mutex.rs +++ b/src/libstd/sys/windows/mutex.rs @@ -117,7 +117,7 @@ impl Mutex { 0 => {} n => return n as *mut _, } - let mut re = Box::new(ReentrantMutex::uninitialized()); + let mut re = box ReentrantMutex::uninitialized(); re.init(); let re = Box::into_raw(re); match self.lock.compare_and_swap(0, re as usize, Ordering::SeqCst) { diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index 414c9c5418e..bcc66b9954b 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -114,6 +114,11 @@ impl Buf { } #[inline] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.inner.shrink_to(min_capacity) + } + + #[inline] pub fn into_box(self) -> Box<Slice> { unsafe { mem::transmute(self.inner.into_box()) } } diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index f3b1185c6ea..df1dd7401af 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -236,7 +236,7 @@ enum State { impl<'a> AsyncPipe<'a> { fn new(pipe: Handle, dst: &'a mut Vec<u8>) -> io::Result<AsyncPipe<'a>> { // Create an event which we'll use to coordinate our overlapped - // opreations, this event will be used in WaitForMultipleObjects + // operations, this event will be used in WaitForMultipleObjects // and passed as part of the OVERLAPPED handle. // // Note that we do a somewhat clever thing here by flagging the diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index c93179869a6..4974a8de89c 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -10,7 +10,6 @@ #![unstable(feature = "process_internals", issue = "0")] -use ascii::AsciiExt; use collections::BTreeMap; use env::split_paths; use env; @@ -18,7 +17,7 @@ use ffi::{OsString, OsStr}; use fmt; use fs; use io::{self, Error, ErrorKind}; -use libc::c_void; +use libc::{c_void, EXIT_SUCCESS, EXIT_FAILURE}; use mem; use os::windows::ffi::OsStrExt; use path::Path; @@ -32,7 +31,7 @@ use sys::stdio; use sys::cvt; use sys_common::{AsInner, FromInner, IntoInner}; use sys_common::process::{CommandEnv, EnvKey}; -use alloc::borrow::Borrow; +use borrow::Borrow; //////////////////////////////////////////////////////////////////////////////// // Command @@ -408,6 +407,19 @@ impl fmt::Display for ExitStatus { } } +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitCode(c::DWORD); + +impl ExitCode { + pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _); + pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _); + + #[inline] + pub fn as_i32(&self) -> i32 { + self.0 as i32 + } +} + fn zeroed_startupinfo() -> c::STARTUPINFO { c::STARTUPINFO { cb: 0, @@ -475,9 +487,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> { } else { if x == '"' as u16 { // Add n+1 backslashes to total 2n+1 before internal '"'. - for _ in 0..(backslashes+1) { - cmd.push('\\' as u16); - } + cmd.extend((0..(backslashes + 1)).map(|_| '\\' as u16)); } backslashes = 0; } @@ -486,9 +496,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> { if quote { // Add n backslashes to total 2n before ending '"'. - for _ in 0..backslashes { - cmd.push('\\' as u16); - } + cmd.extend((0..backslashes).map(|_| '\\' as u16)); cmd.push('"' as u16); } Ok(()) diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index b43df20bddd..81b89da21d3 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -227,3 +227,7 @@ pub fn is_ebadf(err: &io::Error) -> bool { // idea is that on windows we use a slightly smaller buffer that's // been seen to be acceptable. pub const STDIN_BUF_SIZE: usize = 8 * 1024; + +pub fn stderr_prints_nothing() -> bool { + false +} diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index 74786d09285..85588cc6c8e 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::boxed::FnBox; +use boxed::FnBox; use io; use ffi::CStr; use mem; @@ -28,7 +28,7 @@ pub struct Thread { } impl Thread { - pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>) + pub unsafe fn new<'a>(stack: usize, p: Box<dyn FnBox() + 'a>) -> io::Result<Thread> { let p = box p; @@ -42,7 +42,8 @@ impl Thread { let stack_size = (stack + 0xfffe) & (!0xfffe); let ret = c::CreateThread(ptr::null_mut(), stack_size, thread_start, &*p as *const _ as *mut _, - 0, ptr::null_mut()); + c::STACK_SIZE_PARAM_IS_A_RESERVATION, + ptr::null_mut()); return if ret as usize == 0 { Err(io::Error::last_os_error()) @@ -93,6 +94,8 @@ impl Thread { #[cfg_attr(test, allow(dead_code))] pub mod guard { - pub unsafe fn current() -> Option<usize> { None } - pub unsafe fn init() -> Option<usize> { None } + pub type Guard = !; + pub unsafe fn current() -> Option<Guard> { None } + pub unsafe fn init() -> Option<Guard> { None } + pub unsafe fn deinit() {} } diff --git a/src/libstd/sys_common/at_exit_imp.rs b/src/libstd/sys_common/at_exit_imp.rs index ce6fd4cb075..76e5df2c865 100644 --- a/src/libstd/sys_common/at_exit_imp.rs +++ b/src/libstd/sys_common/at_exit_imp.rs @@ -12,19 +12,24 @@ //! //! Documentation can be found on the `rt::at_exit` function. -use alloc::boxed::FnBox; +use boxed::FnBox; use ptr; +use mem; use sys_common::mutex::Mutex; -type Queue = Vec<Box<FnBox()>>; +type Queue = Vec<Box<dyn FnBox()>>; // 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). +// We never call `LOCK.init()`, so it is UB to attempt to +// acquire this mutex reentrantly! static LOCK: Mutex = Mutex::new(); static mut QUEUE: *mut Queue = ptr::null_mut(); +const DONE: *mut Queue = 1_usize as *mut _; + // The maximum number of times the cleanup routines will be run. While running // the at_exit closures new ones may be registered, and this count is the number // of times the new closures will be allowed to register successfully. After @@ -35,7 +40,7 @@ unsafe fn init() -> bool { if QUEUE.is_null() { let state: Box<Queue> = box Vec::new(); QUEUE = Box::into_raw(state); - } else if QUEUE as usize == 1 { + } else if QUEUE == DONE { // can't re-init after a cleanup return false } @@ -44,20 +49,21 @@ unsafe fn init() -> bool { } pub fn cleanup() { - for i in 0..ITERS { + for i in 1..=ITERS { unsafe { - LOCK.lock(); - let queue = QUEUE; - QUEUE = if i == ITERS - 1 {1} else {0} as *mut _; - LOCK.unlock(); + let queue = { + let _guard = LOCK.lock(); + mem::replace(&mut QUEUE, if i == ITERS { DONE } else { ptr::null_mut() }) + }; // make sure we're not recursively cleaning up - assert!(queue as usize != 1); + assert!(queue != DONE); // If we never called init, not need to cleanup! - if queue as usize != 0 { + if !queue.is_null() { let queue: Box<Queue> = Box::from_raw(queue); for to_run in *queue { + // We are not holding any lock, so reentrancy is fine. to_run(); } } @@ -65,16 +71,16 @@ pub fn cleanup() { } } -pub fn push(f: Box<FnBox()>) -> bool { - let mut ret = true; +pub fn push(f: Box<dyn FnBox()>) -> bool { unsafe { - LOCK.lock(); + let _guard = LOCK.lock(); if init() { + // We are just moving `f` around, not calling it. + // There is no possibility of reentrancy here. (*QUEUE).push(f); + true } else { - ret = false; + false } - LOCK.unlock(); } - ret } diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 36cbce2df75..77371782977 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -41,13 +41,15 @@ pub struct Frame { pub exact_position: *const u8, /// Address of the enclosing function. pub symbol_addr: *const u8, + /// Which inlined function is this frame referring to + pub inline_context: u32, } /// Max number of frames to print. const MAX_NB_FRAMES: usize = 100; /// Prints the current backtrace. -pub fn print(w: &mut Write, format: PrintFormat) -> io::Result<()> { +pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> { static LOCK: Mutex = Mutex::new(); // Use a lock to prevent mixed output in multithreading context. @@ -60,10 +62,11 @@ pub fn print(w: &mut Write, format: PrintFormat) -> io::Result<()> { } } -fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> { +fn _print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> { let mut frames = [Frame { exact_position: ptr::null(), symbol_addr: ptr::null(), + inline_context: 0, }; MAX_NB_FRAMES]; let (nb_frames, context) = unwind_backtrace(&mut frames)?; let (skipped_before, skipped_after) = @@ -133,13 +136,13 @@ pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T f() } -/// Controls how the backtrace should be formated. +/// Controls how the backtrace should be formatted. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum PrintFormat { - /// Show all the frames with absolute path for files. - Full = 2, /// Show only relevant data from the backtrace. - Short = 3, + Short = 2, + /// Show all the frames with absolute path for files. + Full = 3, } // For now logging is turned off by default, and this function checks to see @@ -147,23 +150,21 @@ pub enum PrintFormat { pub fn log_enabled() -> Option<PrintFormat> { static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0); match ENABLED.load(Ordering::SeqCst) { - 0 => {}, + 0 => {} 1 => return None, - 2 => return Some(PrintFormat::Full), - 3 => return Some(PrintFormat::Short), - _ => unreachable!(), + 2 => return Some(PrintFormat::Short), + _ => return Some(PrintFormat::Full), } - let val = match env::var_os("RUST_BACKTRACE") { - Some(x) => if &x == "0" { + let val = env::var_os("RUST_BACKTRACE").and_then(|x| + if &x == "0" { None } else if &x == "full" { Some(PrintFormat::Full) } else { Some(PrintFormat::Short) - }, - None => None, - }; + } + ); ENABLED.store(match val { Some(v) => v as isize, None => 1, @@ -175,7 +176,7 @@ pub fn log_enabled() -> Option<PrintFormat> { /// /// These output functions should now be used everywhere to ensure consistency. /// You may want to also use `output_fileline`. -fn output(w: &mut Write, idx: usize, frame: Frame, +fn output(w: &mut dyn Write, idx: usize, frame: Frame, s: Option<&str>, format: PrintFormat) -> io::Result<()> { // Remove the `17: 0x0 - <unknown>` line. if format == PrintFormat::Short && frame.exact_position == ptr::null() { @@ -200,7 +201,7 @@ fn output(w: &mut Write, idx: usize, frame: Frame, /// /// See also `output`. #[allow(dead_code)] -fn output_fileline(w: &mut Write, +fn output_fileline(w: &mut dyn Write, file: &[u8], line: u32, format: PrintFormat) -> io::Result<()> { @@ -252,7 +253,7 @@ fn output_fileline(w: &mut Write, // Note that this demangler isn't quite as fancy as it could be. We have lots // of other information in our symbols like hashes, version, type information, // etc. Additionally, this doesn't handle glue symbols at all. -pub fn demangle(writer: &mut Write, mut s: &str, format: PrintFormat) -> io::Result<()> { +pub fn demangle(writer: &mut dyn Write, mut s: &str, format: PrintFormat) -> io::Result<()> { // During ThinLTO LLVM may import and rename internal symbols, so strip out // those endings first as they're one of the last manglings applied to // symbol names. @@ -261,7 +262,7 @@ pub fn demangle(writer: &mut Write, mut s: &str, format: PrintFormat) -> io::Res let candidate = &s[i + llvm.len()..]; let all_hex = candidate.chars().all(|c| { match c { - 'A' ... 'F' | '0' ... '9' => true, + 'A' ..= 'F' | '0' ..= '9' => true, _ => false, } }); diff --git a/src/libstd/sys_common/bytestring.rs b/src/libstd/sys_common/bytestring.rs index eb9cad09915..971b83938c1 100644 --- a/src/libstd/sys_common/bytestring.rs +++ b/src/libstd/sys_common/bytestring.rs @@ -11,7 +11,7 @@ #![allow(dead_code)] use fmt::{Formatter, Result, Write}; -use std_unicode::lossy::{Utf8Lossy, Utf8LossyChunk}; +use core::str::lossy::{Utf8Lossy, Utf8LossyChunk}; pub fn debug_fmt_bytestring(slice: &[u8], f: &mut Formatter) -> Result { // Writes out a valid unicode string with the correct escape sequences diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs index 27504d374dd..d0c4d6a7737 100644 --- a/src/libstd/sys_common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -28,6 +28,16 @@ use sync::Once; use sys; +macro_rules! rtabort { + ($($t:tt)*) => (::sys_common::util::abort(format_args!($($t)*))) +} + +macro_rules! rtassert { + ($e:expr) => (if !$e { + rtabort!(concat!("assertion failed: ", stringify!($e))); + }) +} + pub mod at_exit_imp; #[cfg(feature = "backtrace")] pub mod backtrace; @@ -101,10 +111,6 @@ pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> { if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())} } -macro_rules! rtabort { - ($($t:tt)*) => (::sys_common::util::abort(format_args!($($t)*))) -} - /// One-time runtime cleanup. pub fn cleanup() { static CLEANUP: Once = Once::new(); diff --git a/src/libstd/sys_common/mutex.rs b/src/libstd/sys_common/mutex.rs index d1a738770d3..c6d531c7a1a 100644 --- a/src/libstd/sys_common/mutex.rs +++ b/src/libstd/sys_common/mutex.rs @@ -24,11 +24,17 @@ impl Mutex { /// /// Behavior is undefined if the mutex is moved after it is /// first used with any of the functions below. + /// Also, until `init` is called, behavior is undefined if this + /// mutex is ever used reentrantly, i.e., `raw_lock` or `try_lock` + /// are called by the thread currently holding the lock. pub const fn new() -> Mutex { Mutex(imp::Mutex::new()) } /// Prepare the mutex for use. /// /// This should be called once the mutex is at a stable memory address. + /// If called, this must be the very first thing that happens to the mutex. + /// Calling it in parallel with or after any operation (including another + /// `init()`) is undefined behavior. #[inline] pub unsafe fn init(&mut self) { self.0.init() } @@ -37,7 +43,15 @@ impl Mutex { /// Behavior is undefined if the mutex has been moved between this and any /// previous function call. #[inline] - pub unsafe fn lock(&self) { self.0.lock() } + pub unsafe fn raw_lock(&self) { self.0.lock() } + + /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex + /// will be unlocked. + #[inline] + pub unsafe fn lock(&self) -> MutexGuard { + self.raw_lock(); + MutexGuard(&self.0) + } /// Attempts to lock the mutex without blocking, returning whether it was /// successfully acquired or not. @@ -51,8 +65,11 @@ impl Mutex { /// /// Behavior is undefined if the current thread does not actually hold the /// mutex. + /// + /// Consider switching from the pair of raw_lock() and raw_unlock() to + /// lock() whenever possible. #[inline] - pub unsafe fn unlock(&self) { self.0.unlock() } + pub unsafe fn raw_unlock(&self) { self.0.unlock() } /// Deallocates all resources associated with this mutex. /// @@ -64,3 +81,14 @@ impl Mutex { // not meant to be exported to the outside world, just the containing module pub fn raw(mutex: &Mutex) -> &imp::Mutex { &mutex.0 } + +#[must_use] +/// A simple RAII utility for the above Mutex without the poisoning semantics. +pub struct MutexGuard<'a>(&'a imp::Mutex); + +impl<'a> Drop for MutexGuard<'a> { + #[inline] + fn drop(&mut self) { + unsafe { self.0.unlock(); } + } +} diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs index c70b39995eb..b841afe1a51 100644 --- a/src/libstd/sys_common/net.rs +++ b/src/libstd/sys_common/net.rs @@ -166,27 +166,9 @@ pub fn lookup_host(host: &str) -> io::Result<LookupHost> { hints.ai_socktype = c::SOCK_STREAM; let mut res = ptr::null_mut(); unsafe { - 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) => { - // If we're running glibc prior to version 2.26, the lookup - // failure could be caused by caching a stale /etc/resolv.conf. - // We need to call libc::res_init() to clear the cache. But we - // shouldn't call it in on any other platform, because other - // res_init implementations aren't thread-safe. See - // https://github.com/rust-lang/rust/issues/41570 and - // https://github.com/rust-lang/rust/issues/43592. - use sys::net::res_init_if_glibc_before_2_26; - let _ = res_init_if_glibc_before_2_26(); - Err(e) - }, - // the cfg is needed here to avoid an "unreachable pattern" warning - #[cfg(not(unix))] - Err(e) => Err(e), - } + cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)).map(|_| { + LookupHost { original: res, cur: res } + }) } } diff --git a/src/libstd/sys_common/poison.rs b/src/libstd/sys_common/poison.rs index 934ac3edbf1..1625efe4a2a 100644 --- a/src/libstd/sys_common/poison.rs +++ b/src/libstd/sys_common/poison.rs @@ -98,7 +98,7 @@ pub struct PoisonError<T> { } /// An enumeration of possible errors associated with a [`TryLockResult`] which -/// can occur while trying to aquire a lock, from the [`try_lock`] method on a +/// can occur while trying to acquire a lock, from the [`try_lock`] method on a /// [`Mutex`] or the [`try_read`] and [`try_write`] methods on an [`RwLock`]. /// /// [`Mutex`]: struct.Mutex.html @@ -251,7 +251,7 @@ impl<T> Error for TryLockError<T> { } } - fn cause(&self) -> Option<&Error> { + fn cause(&self) -> Option<&dyn Error> { match *self { TryLockError::Poisoned(ref p) => Some(p), _ => None diff --git a/src/libstd/sys_common/process.rs b/src/libstd/sys_common/process.rs index fd1a5fdb410..ddf0ebe603e 100644 --- a/src/libstd/sys_common/process.rs +++ b/src/libstd/sys_common/process.rs @@ -14,7 +14,7 @@ use ffi::{OsStr, OsString}; use env; use collections::BTreeMap; -use alloc::borrow::Borrow; +use borrow::Borrow; pub trait EnvKey: From<OsString> + Into<OsString> + @@ -47,6 +47,7 @@ impl EnvKey for DefaultEnvKey {} #[derive(Clone, Debug)] pub struct CommandEnv<K> { clear: bool, + saw_path: bool, vars: BTreeMap<K, Option<OsString>> } @@ -54,6 +55,7 @@ impl<K: EnvKey> Default for CommandEnv<K> { fn default() -> Self { CommandEnv { clear: false, + saw_path: false, vars: Default::default() } } @@ -108,9 +110,11 @@ impl<K: EnvKey> CommandEnv<K> { // The following functions build up changes pub fn set(&mut self, key: &OsStr, value: &OsStr) { + self.maybe_saw_path(&key); self.vars.insert(key.to_owned().into(), Some(value.to_owned())); } pub fn remove(&mut self, key: &OsStr) { + self.maybe_saw_path(&key); if self.clear { self.vars.remove(key); } else { @@ -121,4 +125,12 @@ impl<K: EnvKey> CommandEnv<K> { self.clear = true; self.vars.clear(); } + pub fn have_changed_path(&self) -> bool { + self.saw_path || self.clear + } + fn maybe_saw_path(&mut self, key: &OsStr) { + if !self.saw_path && key == "PATH" { + self.saw_path = true; + } + } } diff --git a/src/libstd/sys_common/remutex.rs b/src/libstd/sys_common/remutex.rs index ce43ec6d9ab..071a3a25c7a 100644 --- a/src/libstd/sys_common/remutex.rs +++ b/src/libstd/sys_common/remutex.rs @@ -13,6 +13,7 @@ use marker; use ops::Deref; use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; use sys::mutex as sys; +use panic::{UnwindSafe, RefUnwindSafe}; /// A re-entrant mutual exclusion /// @@ -28,6 +29,9 @@ pub struct ReentrantMutex<T> { unsafe impl<T: Send> Send for ReentrantMutex<T> {} unsafe impl<T: Send> Sync for ReentrantMutex<T> {} +impl<T> UnwindSafe for ReentrantMutex<T> {} +impl<T> RefUnwindSafe for ReentrantMutex<T> {} + /// An RAII implementation of a "scoped lock" of a mutex. When this structure is /// dropped (falls out of scope), the lock will be unlocked. @@ -41,7 +45,7 @@ unsafe impl<T: Send> Sync for ReentrantMutex<T> {} /// because implementation of the trait would violate Rust’s reference aliasing /// rules. Use interior mutability (usually `RefCell`) in order to mutate the /// guarded data. -#[must_use] +#[must_use = "if unused the ReentrantMutex will immediately unlock"] pub struct ReentrantMutexGuard<'a, T: 'a> { // funny underscores due to how Deref currently works (it disregards field // privacy). diff --git a/src/libstd/sys_common/thread.rs b/src/libstd/sys_common/thread.rs index f1379b6ec63..86a5e2b8694 100644 --- a/src/libstd/sys_common/thread.rs +++ b/src/libstd/sys_common/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::boxed::FnBox; +use boxed::FnBox; use env; use sync::atomic::{self, Ordering}; use sys::stack_overflow; @@ -21,7 +21,7 @@ pub unsafe fn start_thread(main: *mut u8) { let _handler = stack_overflow::Handler::new(); // Finally, let's run some code. - Box::from_raw(main as *mut Box<FnBox()>)() + Box::from_raw(main as *mut Box<dyn FnBox()>)() } pub fn min_stack() -> usize { diff --git a/src/libstd/sys_common/thread_info.rs b/src/libstd/sys_common/thread_info.rs index 7970042b1d6..d75cbded734 100644 --- a/src/libstd/sys_common/thread_info.rs +++ b/src/libstd/sys_common/thread_info.rs @@ -11,10 +11,11 @@ #![allow(dead_code)] // stack_guard isn't used right now on all platforms use cell::RefCell; +use sys::thread::guard::Guard; use thread::Thread; struct ThreadInfo { - stack_guard: Option<usize>, + stack_guard: Option<Guard>, thread: Thread, } @@ -38,14 +39,18 @@ pub fn current_thread() -> Option<Thread> { ThreadInfo::with(|info| info.thread.clone()) } -pub fn stack_guard() -> Option<usize> { - ThreadInfo::with(|info| info.stack_guard).and_then(|o| o) +pub fn stack_guard() -> Option<Guard> { + ThreadInfo::with(|info| info.stack_guard.clone()).and_then(|o| o) } -pub fn set(stack_guard: Option<usize>, thread: Thread) { +pub fn set(stack_guard: Option<Guard>, thread: Thread) { THREAD_INFO.with(|c| assert!(c.borrow().is_none())); THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{ stack_guard, thread, })); } + +pub fn reset_guard(stack_guard: Option<Guard>) { + THREAD_INFO.with(move |c| c.borrow_mut().as_mut().unwrap().stack_guard = stack_guard); +} diff --git a/src/libstd/sys_common/thread_local.rs b/src/libstd/sys_common/thread_local.rs index a4aa3d96d25..bb72cb0930a 100644 --- a/src/libstd/sys_common/thread_local.rs +++ b/src/libstd/sys_common/thread_local.rs @@ -161,15 +161,16 @@ impl StaticKey { // 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() { + // We never call `INIT_LOCK.init()`, so it is UB to attempt to + // acquire this mutex reentrantly! static INIT_LOCK: Mutex = Mutex::new(); - INIT_LOCK.lock(); + let _guard = 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); + rtassert!(key != 0); return key } @@ -190,7 +191,7 @@ impl StaticKey { imp::destroy(key1); key2 }; - assert!(key != 0); + rtassert!(key != 0); match self.key.compare_and_swap(0, key as usize, Ordering::SeqCst) { // The CAS succeeded, so we've created the actual key 0 => key as usize, diff --git a/src/libstd/sys_common/util.rs b/src/libstd/sys_common/util.rs index a391c7cc6ef..a373e980b97 100644 --- a/src/libstd/sys_common/util.rs +++ b/src/libstd/sys_common/util.rs @@ -10,10 +10,13 @@ use fmt; use io::prelude::*; -use sys::stdio::Stderr; +use sys::stdio::{Stderr, stderr_prints_nothing}; use thread; pub fn dumb_print(args: fmt::Arguments) { + if stderr_prints_nothing() { + return + } let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args)); } diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index 46d554d6411..45204b56ead 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -27,7 +27,6 @@ use core::str::next_code_point; -use ascii::*; use borrow::Cow; use char; use fmt; @@ -57,7 +56,7 @@ pub struct CodePoint { /// Example: `U+1F4A9` impl fmt::Debug for CodePoint { #[inline] - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!(formatter, "U+{:04X}", self.value) } } @@ -77,7 +76,7 @@ impl CodePoint { #[inline] pub fn from_u32(value: u32) -> Option<CodePoint> { match value { - 0 ... 0x10FFFF => Some(CodePoint { value: value }), + 0 ..= 0x10FFFF => Some(CodePoint { value: value }), _ => None } } @@ -102,7 +101,7 @@ impl CodePoint { #[inline] pub fn to_char(&self) -> Option<char> { match self.value { - 0xD800 ... 0xDFFF => None, + 0xD800 ..= 0xDFFF => None, _ => Some(unsafe { char::from_u32_unchecked(self.value) }) } } @@ -145,7 +144,7 @@ impl ops::DerefMut for Wtf8Buf { /// Example: `"a\u{D800}"` for a string with code points [U+0061, U+D800] impl fmt::Debug for Wtf8Buf { #[inline] - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, formatter) } } @@ -254,6 +253,11 @@ impl Wtf8Buf { self.bytes.shrink_to_fit() } + #[inline] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.bytes.shrink_to(min_capacity) + } + /// Returns the number of bytes that this string buffer can hold without reallocating. #[inline] pub fn capacity(&self) -> usize { @@ -301,7 +305,7 @@ impl Wtf8Buf { /// like concatenating ill-formed UTF-16 strings effectively would. #[inline] pub fn push(&mut self, code_point: CodePoint) { - if let trail @ 0xDC00...0xDFFF = code_point.to_u32() { + if let trail @ 0xDC00..=0xDFFF = code_point.to_u32() { if let Some(lead) = (&*self).final_lead_surrogate() { let len_without_lead_surrogate = self.len() - 3; self.bytes.truncate(len_without_lead_surrogate); @@ -428,20 +432,15 @@ impl fmt::Debug for Wtf8 { formatter.write_str("\"")?; let mut pos = 0; - loop { - match self.next_surrogate(pos) { - None => break, - Some((surrogate_pos, surrogate)) => { - write_str_escaped( - formatter, - unsafe { str::from_utf8_unchecked( - &self.bytes[pos .. surrogate_pos] - )}, - )?; - write!(formatter, "\\u{{{:x}}}", surrogate)?; - pos = surrogate_pos + 3; - } - } + while let Some((surrogate_pos, surrogate)) = self.next_surrogate(pos) { + write_str_escaped( + formatter, + unsafe { str::from_utf8_unchecked( + &self.bytes[pos .. surrogate_pos] + )}, + )?; + write!(formatter, "\\u{{{:x}}}", surrogate)?; + pos = surrogate_pos + 3; } write_str_escaped( formatter, @@ -526,7 +525,7 @@ impl Wtf8 { #[inline] pub fn ascii_byte_at(&self, position: usize) -> u8 { match self.bytes[position] { - ascii_byte @ 0x00 ... 0x7F => ascii_byte, + ascii_byte @ 0x00 ..= 0x7F => ascii_byte, _ => 0xFF } } @@ -631,7 +630,7 @@ impl Wtf8 { return None } match &self.bytes[(len - 3)..] { - &[0xED, b2 @ 0xA0...0xAF, b3] => Some(decode_surrogate(b2, b3)), + &[0xED, b2 @ 0xA0..=0xAF, b3] => Some(decode_surrogate(b2, b3)), _ => None } } @@ -643,7 +642,7 @@ impl Wtf8 { return None } match &self.bytes[..3] { - &[0xED, b2 @ 0xB0...0xBF, b3] => Some(decode_surrogate(b2, b3)), + &[0xED, b2 @ 0xB0..=0xBF, b3] => Some(decode_surrogate(b2, b3)), _ => None } } @@ -876,24 +875,8 @@ impl Hash for Wtf8 { } } -impl AsciiExt for Wtf8 { - type Owned = Wtf8Buf; - - fn is_ascii(&self) -> bool { - self.bytes.is_ascii() - } - fn to_ascii_uppercase(&self) -> Wtf8Buf { - Wtf8Buf { bytes: self.bytes.to_ascii_uppercase() } - } - fn to_ascii_lowercase(&self) -> Wtf8Buf { - Wtf8Buf { bytes: self.bytes.to_ascii_lowercase() } - } - fn eq_ignore_ascii_case(&self, other: &Wtf8) -> bool { - self.bytes.eq_ignore_ascii_case(&other.bytes) - } - - fn make_ascii_uppercase(&mut self) { self.bytes.make_ascii_uppercase() } - fn make_ascii_lowercase(&mut self) { self.bytes.make_ascii_lowercase() } +impl Wtf8 { + pub fn make_ascii_uppercase(&mut self) { self.bytes.make_ascii_uppercase() } } #[cfg(test)] @@ -1262,7 +1245,7 @@ mod tests { #[test] fn wtf8_display() { fn d(b: &[u8]) -> String { - format!("{}", &unsafe { Wtf8::from_bytes_unchecked(b) }) + (&unsafe { Wtf8::from_bytes_unchecked(b) }).to_string() } assert_eq!("", d("".as_bytes())); diff --git a/src/libstd/termination.rs b/src/libstd/termination.rs deleted file mode 100644 index 93a913bb540..00000000000 --- a/src/libstd/termination.rs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use error::Error; -#[cfg(target_arch = "wasm32")] -mod exit { - pub const SUCCESS: i32 = 0; - pub const FAILURE: i32 = 1; -} -#[cfg(not(target_arch = "wasm32"))] -mod exit { - use libc; - pub const SUCCESS: i32 = libc::EXIT_SUCCESS; - pub const FAILURE: i32 = libc::EXIT_FAILURE; -} - -/// A trait for implementing arbitrary return types in the `main` function. -/// -/// The c-main function only supports to return integers as return type. -/// So, every type implementing the `Termination` trait has to be converted -/// to an integer. -/// -/// The default implementations are returning `libc::EXIT_SUCCESS` to indicate -/// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned. -#[cfg_attr(not(test), lang = "termination")] -#[unstable(feature = "termination_trait", issue = "43301")] -#[rustc_on_unimplemented = - "`main` can only return types that implement {Termination}, not `{Self}`"] -pub trait Termination { - /// Is called to get the representation of the value as status code. - /// This status code is returned to the operating system. - fn report(self) -> i32; -} - -#[unstable(feature = "termination_trait", issue = "43301")] -impl Termination for () { - fn report(self) -> i32 { exit::SUCCESS } -} - -#[unstable(feature = "termination_trait", issue = "43301")] -impl<T: Termination, E: Error> Termination for Result<T, E> { - fn report(self) -> i32 { - match self { - Ok(val) => val.report(), - Err(err) => { - print_error(err); - exit::FAILURE - } - } - } -} - -#[unstable(feature = "termination_trait", issue = "43301")] -fn print_error<E: Error>(err: E) { - eprintln!("Error: {}", err.description()); - - if let Some(ref err) = err.cause() { - eprintln!("Caused by: {}", err.description()); - } -} - -#[unstable(feature = "termination_trait", issue = "43301")] -impl Termination for ! { - fn report(self) -> i32 { unreachable!(); } -} - -#[unstable(feature = "termination_trait", issue = "43301")] -impl Termination for bool { - fn report(self) -> i32 { - if self { exit::SUCCESS } else { exit::FAILURE } - } -} - -#[unstable(feature = "termination_trait", issue = "43301")] -impl Termination for i32 { - fn report(self) -> i32 { - self - } -} diff --git a/src/libstd/tests/env.rs b/src/libstd/tests/env.rs new file mode 100644 index 00000000000..8acb8a46d7b --- /dev/null +++ b/src/libstd/tests/env.rs @@ -0,0 +1,94 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate rand; + +use std::env::*; +use std::ffi::{OsString, OsStr}; + +use rand::Rng; + +fn make_rand_name() -> OsString { + let mut rng = rand::thread_rng(); + let n = format!("TEST{}", rng.gen_ascii_chars().take(10) + .collect::<String>()); + let n = OsString::from(n); + assert!(var_os(&n).is_none()); + n +} + +fn eq(a: Option<OsString>, b: Option<&str>) { + assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::new).map(|s| &*s)); +} + +#[test] +fn test_set_var() { + let n = make_rand_name(); + set_var(&n, "VALUE"); + eq(var_os(&n), Some("VALUE")); +} + +#[test] +fn test_remove_var() { + let n = make_rand_name(); + set_var(&n, "VALUE"); + remove_var(&n); + eq(var_os(&n), None); +} + +#[test] +fn test_set_var_overwrite() { + let n = make_rand_name(); + set_var(&n, "1"); + set_var(&n, "2"); + eq(var_os(&n), Some("2")); + set_var(&n, ""); + eq(var_os(&n), Some("")); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn test_var_big() { + let mut s = "".to_string(); + let mut i = 0; + while i < 100 { + s.push_str("aaaaaaaaaa"); + i += 1; + } + let n = make_rand_name(); + set_var(&n, &s); + eq(var_os(&n), Some(&s)); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn test_env_set_get_huge() { + let n = make_rand_name(); + let s = "x".repeat(10000); + set_var(&n, &s); + eq(var_os(&n), Some(&s)); + remove_var(&n); + eq(var_os(&n), None); +} + +#[test] +fn test_env_set_var() { + let n = make_rand_name(); + + let mut e = vars_os(); + set_var(&n, "VALUE"); + assert!(!e.any(|(k, v)| { + &*k == &*n && &*v == "VALUE" + })); + + assert!(vars_os().any(|(k, v)| { + &*k == &*n && &*v == "VALUE" + })); +} diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index fcbca38a98f..a170abb2628 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -172,12 +172,16 @@ macro_rules! __thread_local_inner { &'static $crate::cell::UnsafeCell< $crate::option::Option<$t>>> { + #[cfg(target_arch = "wasm32")] + static __KEY: $crate::thread::__StaticLocalKeyInner<$t> = + $crate::thread::__StaticLocalKeyInner::new(); + #[thread_local] - #[cfg(target_thread_local)] + #[cfg(all(target_thread_local, not(target_arch = "wasm32")))] static __KEY: $crate::thread::__FastLocalKeyInner<$t> = $crate::thread::__FastLocalKeyInner::new(); - #[cfg(not(target_thread_local))] + #[cfg(all(not(target_thread_local), not(target_arch = "wasm32")))] static __KEY: $crate::thread::__OsLocalKeyInner<$t> = $crate::thread::__OsLocalKeyInner::new(); @@ -195,64 +199,20 @@ macro_rules! __thread_local_inner { } } -/// Indicator of the state of a thread local storage key. -#[unstable(feature = "thread_local_state", - reason = "state querying was recently added", - issue = "27716")] -#[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 - /// 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. - /// - /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with - Uninitialized, - - /// Once a key has been accessed successfully, it will enter the `Valid` - /// state. Keys in the `Valid` state will remain so until the thread exits, - /// at which point the destructor will be run and the key will enter the - /// `Destroyed` state. - /// - /// Keys in the `Valid` state will be guaranteed to yield a reference to the - /// 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 - /// necessary). While a destructor is running, and possibly after a - /// destructor has run, a key is in the `Destroyed` state. - /// - /// Keys in the `Destroyed` states will trigger a panic when accessed via - /// [`with`]. - /// - /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with - Destroyed, -} - /// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with). -#[unstable(feature = "thread_local_state", - reason = "state querying was recently added", - issue = "27716")] +#[stable(feature = "thread_local_try_with", since = "1.26.0")] pub struct AccessError { _private: (), } -#[unstable(feature = "thread_local_state", - reason = "state querying was recently added", - issue = "27716")] +#[stable(feature = "thread_local_try_with", since = "1.26.0")] impl fmt::Debug for AccessError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("AccessError").finish() } } -#[unstable(feature = "thread_local_state", - reason = "state querying was recently added", - issue = "27716")] +#[stable(feature = "thread_local_try_with", since = "1.26.0")] impl fmt::Display for AccessError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt("already destroyed", f) @@ -312,64 +272,21 @@ impl<T: 'static> LocalKey<T> { (*ptr).as_ref().unwrap() } - /// 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`] - /// 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 - /// succeed within the thread. Some keys might skip the `Uninitialized` - /// state altogether and start in the `Valid` state as an optimization - /// (e.g. keys initialized with a constant expression), but no guarantees - /// are made. - /// - /// 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. - /// - /// 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`]. - /// - /// [`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")] - pub fn state(&'static self) -> LocalKeyState { - unsafe { - match (self.inner)() { - Some(cell) => { - match *cell.get() { - Some(..) => LocalKeyState::Valid, - None => LocalKeyState::Uninitialized, - } - } - None => LocalKeyState::Destroyed, - } - } - } - /// Acquires a reference to the value in this TLS key. /// /// This will lazily initialize the value if this thread has not referenced /// this key yet. If the key has been destroyed (which may happen if this is called - /// in a destructor), this function will return a ThreadLocalError. + /// in a destructor), this function will return an [`AccessError`](struct.AccessError.html). /// /// # Panics /// /// This function will still `panic!()` if the key is uninitialized and the /// key's initializer panics. - #[unstable(feature = "thread_local_state", - reason = "state querying was recently added", - issue = "27716")] + #[stable(feature = "thread_local_try_with", since = "1.26.0")] pub fn try_with<F, R>(&'static self, f: F) -> Result<R, AccessError> - where F: FnOnce(&T) -> R { + where + F: FnOnce(&T) -> R, + { unsafe { let slot = (self.inner)().ok_or(AccessError { _private: (), @@ -382,6 +299,39 @@ impl<T: 'static> LocalKey<T> { } } +/// On some platforms like wasm32 there's no threads, so no need to generate +/// thread locals and we can instead just use plain statics! +#[doc(hidden)] +#[cfg(target_arch = "wasm32")] +pub mod statik { + use cell::UnsafeCell; + use fmt; + + pub struct Key<T> { + inner: UnsafeCell<Option<T>>, + } + + unsafe impl<T> ::marker::Sync for Key<T> { } + + impl<T> fmt::Debug for Key<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Key { .. }") + } + } + + impl<T> Key<T> { + pub const fn new() -> Key<T> { + Key { + inner: UnsafeCell::new(None), + } + } + + pub unsafe fn get(&self) -> Option<&'static UnsafeCell<Option<T>>> { + Some(&*(&self.inner as *const _)) + } + } +} + #[doc(hidden)] #[cfg(target_thread_local)] pub mod fast { @@ -530,7 +480,6 @@ pub mod os { mod tests { use sync::mpsc::{channel, Sender}; use cell::{Cell, UnsafeCell}; - use super::LocalKeyState; use thread; struct Foo(Sender<()>); @@ -569,21 +518,13 @@ mod tests { struct Foo; impl Drop for Foo { fn drop(&mut self) { - assert!(FOO.state() == LocalKeyState::Destroyed); + assert!(FOO.try_with(|_| ()).is_err()); } } - fn foo() -> Foo { - assert!(FOO.state() == LocalKeyState::Uninitialized); - Foo - } - thread_local!(static FOO: Foo = foo()); + thread_local!(static FOO: Foo = Foo); thread::spawn(|| { - assert!(FOO.state() == LocalKeyState::Uninitialized); - FOO.with(|_| { - assert!(FOO.state() == LocalKeyState::Valid); - }); - assert!(FOO.state() == LocalKeyState::Valid); + assert!(FOO.try_with(|_| ()).is_ok()); }).join().ok().unwrap(); } @@ -613,7 +554,7 @@ mod tests { fn drop(&mut self) { unsafe { HITS += 1; - if K2.state() == LocalKeyState::Destroyed { + if K2.try_with(|_| ()).is_err() { assert_eq!(HITS, 3); } else { if HITS == 1 { @@ -629,7 +570,7 @@ mod tests { fn drop(&mut self) { unsafe { HITS += 1; - assert!(K1.state() != LocalKeyState::Destroyed); + assert!(K1.try_with(|_| ()).is_ok()); assert_eq!(HITS, 2); K1.with(|s| *s.get() = Some(S1)); } @@ -648,7 +589,7 @@ mod tests { impl Drop for S1 { fn drop(&mut self) { - assert!(K1.state() == LocalKeyState::Destroyed); + assert!(K1.try_with(|_| ()).is_err()); } } @@ -672,9 +613,7 @@ mod tests { fn drop(&mut self) { let S1(ref tx) = *self; unsafe { - if K2.state() != LocalKeyState::Destroyed { - K2.with(|s| *s.get() = Some(Foo(tx.clone()))); - } + let _ = K2.try_with(|s| *s.get() = Some(Foo(tx.clone()))); } } } diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index ee49bf796b8..61c6084a250 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -191,7 +191,7 @@ use time::Duration; #[macro_use] mod local; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::local::{LocalKey, LocalKeyState, AccessError}; +pub use self::local::{LocalKey, AccessError}; // The types used by the thread_local! macro to access TLS keys. Note that there // are two types, the "OS" type and the "fast" type. The OS thread local key @@ -203,6 +203,9 @@ pub use self::local::{LocalKey, LocalKeyState, AccessError}; // where available, but both are needed. #[unstable(feature = "libstd_thread_internals", issue = "0")] +#[cfg(target_arch = "wasm32")] +#[doc(hidden)] pub use self::local::statik::Key as __StaticLocalKeyInner; +#[unstable(feature = "libstd_thread_internals", issue = "0")] #[cfg(target_thread_local)] #[doc(hidden)] pub use self::local::fast::Key as __FastLocalKeyInner; #[unstable(feature = "libstd_thread_internals", issue = "0")] @@ -652,7 +655,7 @@ pub fn panicking() -> bool { /// The thread may sleep longer than the duration specified due to scheduling /// specifics or platform-dependent functionality. /// -/// # Platform behavior +/// # Platform-specific behavior /// /// On Unix platforms this function will not return early due to a /// signal being received or a spurious wakeup. @@ -676,7 +679,7 @@ pub fn sleep_ms(ms: u32) { /// The thread may sleep longer than the duration specified due to scheduling /// specifics or platform-dependent functionality. /// -/// # Platform behavior +/// # Platform-specific behavior /// /// On Unix platforms this function will not return early due to a /// signal being received or a spurious wakeup. Platforms which do not support @@ -728,7 +731,8 @@ const NOTIFIED: usize = 2; /// 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. +/// if it wasn't already. Because the token is initially absent, [`unpark`] +/// followed by [`park`] will result in the second call returning immediately. /// /// In other words, each [`Thread`] acts a bit like a spinlock that can be /// locked and unlocked using `park` and `unpark`. @@ -763,6 +767,8 @@ const NOTIFIED: usize = 2; /// // Let some time pass for the thread to be spawned. /// thread::sleep(Duration::from_millis(10)); /// +/// // There is no race condition here, if `unpark` +/// // happens first, `park` will return immediately. /// println!("Unpark the thread"); /// parked_thread.thread().unpark(); /// @@ -793,7 +799,10 @@ pub fn park() { let mut m = thread.inner.lock.lock().unwrap(); match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { Ok(_) => {} - Err(NOTIFIED) => return, // notified after we locked + Err(NOTIFIED) => { + thread.inner.state.store(EMPTY, SeqCst); + return; + } // should consume this notification, so prohibit spurious wakeups in next park. Err(_) => panic!("inconsistent park state"), } loop { @@ -837,7 +846,7 @@ pub fn park_timeout_ms(ms: u32) { /// /// See the [park documentation][park] for more details. /// -/// # Platform behavior +/// # Platform-specific behavior /// /// Platforms which do not support nanosecond precision for sleeping will have /// `dur` rounded up to the nearest granularity of time they can sleep for. @@ -879,7 +888,10 @@ pub fn park_timeout(dur: Duration) { let m = thread.inner.lock.lock().unwrap(); match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { Ok(_) => {} - Err(NOTIFIED) => return, // notified after we locked + Err(NOTIFIED) => { + thread.inner.state.store(EMPTY, SeqCst); + return; + } // should consume this notification, so prohibit spurious wakeups in next park. Err(_) => panic!("inconsistent park_timeout state"), } @@ -928,24 +940,23 @@ pub struct ThreadId(u64); impl ThreadId { // Generate a new unique thread ID. fn new() -> ThreadId { + // We never call `GUARD.init()`, so it is UB to attempt to + // acquire this mutex reentrantly! static GUARD: mutex::Mutex = mutex::Mutex::new(); static mut COUNTER: u64 = 0; unsafe { - GUARD.lock(); + let _guard = GUARD.lock(); // If we somehow use up all our bits, panic so that we're not // covering up subtle bugs of IDs being reused. if COUNTER == ::u64::MAX { - GUARD.unlock(); panic!("failed to generate unique thread ID: bitspace exhausted"); } let id = COUNTER; COUNTER += 1; - GUARD.unlock(); - ThreadId(id) } } @@ -1169,7 +1180,7 @@ impl fmt::Debug for Thread { /// /// [`Result`]: ../../std/result/enum.Result.html #[stable(feature = "rust1", since = "1.0.0")] -pub type Result<T> = ::result::Result<T, Box<Any + Send + 'static>>; +pub type Result<T> = ::result::Result<T, Box<dyn Any + Send + 'static>>; // This packet is used to communicate the return value between the child thread // and the parent thread. Memory is shared through the `Arc` within and there's @@ -1270,6 +1281,11 @@ impl<T> JoinInner<T> { #[stable(feature = "rust1", since = "1.0.0")] pub struct JoinHandle<T>(JoinInner<T>); +#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")] +unsafe impl<T> Send for JoinHandle<T> {} +#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")] +unsafe impl<T> Sync for JoinHandle<T> {} + impl<T> JoinHandle<T> { /// Extracts a handle to the underlying thread. /// @@ -1432,7 +1448,7 @@ mod tests { rx.recv().unwrap(); } - fn avoid_copying_the_body<F>(spawnfn: F) where F: FnOnce(Box<Fn() + Send>) { + fn avoid_copying_the_body<F>(spawnfn: F) where F: FnOnce(Box<dyn Fn() + Send>) { let (tx, rx) = channel(); let x: Box<_> = box 1; @@ -1479,7 +1495,7 @@ mod tests { // (well, it would if the constant were 8000+ - I lowered it to be more // valgrind-friendly. try this at home, instead..!) const GENERATIONS: u32 = 16; - fn child_no(x: u32) -> Box<Fn() + Send> { + fn child_no(x: u32) -> Box<dyn Fn() + Send> { return Box::new(move|| { if x < GENERATIONS { thread::spawn(move|| child_no(x+1)()); @@ -1525,10 +1541,10 @@ mod tests { #[test] fn test_try_panic_message_any() { match thread::spawn(move|| { - panic!(box 413u16 as Box<Any + Send>); + panic!(box 413u16 as Box<dyn Any + Send>); }).join() { Err(e) => { - type T = Box<Any + Send>; + type T = Box<dyn Any + Send>; assert!(e.is::<T>()); let any = e.downcast::<T>().unwrap(); assert!(any.is::<u16>()); diff --git a/src/libstd/time/mod.rs b/src/libstd/time.rs index 6ce3b3e8a00..90ab3491599 100644 --- a/src/libstd/time/mod.rs +++ b/src/libstd/time.rs @@ -29,9 +29,7 @@ use sys::time; use sys_common::FromInner; #[stable(feature = "time", since = "1.3.0")] -pub use self::duration::Duration; - -mod duration; +pub use core::time::Duration; /// A measurement of a monotonically nondecreasing clock. /// Opaque and useful only with `Duration`. @@ -51,6 +49,9 @@ mod duration; /// allows measuring the duration between two instants (or comparing two /// instants). /// +/// The size of an `Instant` struct may vary depending on the target operating +/// system. +/// /// Example: /// /// ```no_run @@ -90,6 +91,9 @@ pub struct Instant(time::Instant); /// fixed point in time, a `SystemTime` can be converted to a human-readable time, /// or perhaps some other string representation. /// +/// The size of a `SystemTime` struct may vary depending on the target operating +/// system. +/// /// [`Instant`]: ../../std/time/struct.Instant.html /// [`Result`]: ../../std/result/enum.Result.html /// [`Duration`]: ../../std/time/struct.Duration.html @@ -255,6 +259,28 @@ impl fmt::Debug for Instant { } impl SystemTime { + /// An anchor in time which can be used to create new `SystemTime` instances or + /// learn about where in time a `SystemTime` lies. + /// + /// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with + /// respect to the system clock. Using `duration_since` on an existing + /// `SystemTime` instance can tell how far away from this point in time a + /// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a + /// `SystemTime` instance to represent another fixed point in time. + /// + /// # Examples + /// + /// ```no_run + /// use std::time::SystemTime; + /// + /// match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) { + /// Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()), + /// Err(_) => panic!("SystemTime before UNIX EPOCH!"), + /// } + /// ``` + #[stable(feature = "assoc_unix_epoch", since = "1.28.0")] + pub const UNIX_EPOCH: SystemTime = UNIX_EPOCH; + /// Returns the system time corresponding to "now". /// /// # Examples diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs deleted file mode 100644 index cb5bfb9176e..00000000000 --- a/src/libstd/time/duration.rs +++ /dev/null @@ -1,587 +0,0 @@ -// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use iter::Sum; -use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign}; - -const NANOS_PER_SEC: u32 = 1_000_000_000; -const NANOS_PER_MILLI: u32 = 1_000_000; -const NANOS_PER_MICRO: u32 = 1_000; -const MILLIS_PER_SEC: u64 = 1_000; -const MICROS_PER_SEC: u64 = 1_000_000; - -/// A `Duration` type to represent a span of time, typically used for system -/// timeouts. -/// -/// Each `Duration` is composed of a whole number of seconds and a fractional part -/// represented in nanoseconds. If the underlying system does not support -/// nanosecond-level precision, APIs binding a system timeout will typically round up -/// the number of nanoseconds. -/// -/// `Duration`s implement many common traits, including [`Add`], [`Sub`], and other -/// [`ops`] traits. -/// -/// [`Add`]: ../../std/ops/trait.Add.html -/// [`Sub`]: ../../std/ops/trait.Sub.html -/// [`ops`]: ../../std/ops/index.html -/// -/// # Examples -/// -/// ``` -/// use std::time::Duration; -/// -/// let five_seconds = Duration::new(5, 0); -/// let five_seconds_and_five_nanos = five_seconds + Duration::new(0, 5); -/// -/// assert_eq!(five_seconds_and_five_nanos.as_secs(), 5); -/// assert_eq!(five_seconds_and_five_nanos.subsec_nanos(), 5); -/// -/// let ten_millis = Duration::from_millis(10); -/// ``` -#[stable(feature = "duration", since = "1.3.0")] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] -pub struct Duration { - secs: u64, - nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC -} - -impl Duration { - /// Creates a new `Duration` from the specified number of whole seconds and - /// additional nanoseconds. - /// - /// If the number of nanoseconds is greater than 1 billion (the number of - /// nanoseconds in a second), then it will carry over into the seconds provided. - /// - /// # Panics - /// - /// This constructor will panic if the carry from the nanoseconds overflows - /// the seconds counter. - /// - /// # Examples - /// - /// ``` - /// use std::time::Duration; - /// - /// let five_seconds = Duration::new(5, 0); - /// ``` - #[stable(feature = "duration", since = "1.3.0")] - #[inline] - pub fn new(secs: u64, nanos: u32) -> Duration { - let secs = secs.checked_add((nanos / NANOS_PER_SEC) as u64) - .expect("overflow in Duration::new"); - let nanos = nanos % NANOS_PER_SEC; - Duration { secs: secs, nanos: nanos } - } - - /// Creates a new `Duration` from the specified number of whole seconds. - /// - /// # Examples - /// - /// ``` - /// use std::time::Duration; - /// - /// 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] - pub fn from_secs(secs: u64) -> Duration { - Duration { secs: secs, nanos: 0 } - } - - /// Creates a new `Duration` from the specified number of milliseconds. - /// - /// # Examples - /// - /// ``` - /// use std::time::Duration; - /// - /// let duration = Duration::from_millis(2569); - /// - /// assert_eq!(2, duration.as_secs()); - /// assert_eq!(569_000_000, duration.subsec_nanos()); - /// ``` - #[stable(feature = "duration", since = "1.3.0")] - #[inline] - pub fn from_millis(millis: u64) -> Duration { - let secs = millis / MILLIS_PER_SEC; - let nanos = ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI; - Duration { secs: secs, nanos: nanos } - } - - /// Creates a new `Duration` from the specified number of microseconds. - /// - /// # Examples - /// - /// ``` - /// #![feature(duration_from_micros)] - /// use std::time::Duration; - /// - /// let duration = Duration::from_micros(1_000_002); - /// - /// assert_eq!(1, duration.as_secs()); - /// assert_eq!(2000, duration.subsec_nanos()); - /// ``` - #[unstable(feature = "duration_from_micros", issue = "44400")] - #[inline] - pub fn from_micros(micros: u64) -> Duration { - let secs = micros / MICROS_PER_SEC; - let nanos = ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO; - Duration { secs: secs, nanos: nanos } - } - - /// Creates a new `Duration` from the specified number of nanoseconds. - /// - /// # Examples - /// - /// ``` - /// #![feature(duration_extras)] - /// use std::time::Duration; - /// - /// let duration = Duration::from_nanos(1_000_000_123); - /// - /// assert_eq!(1, duration.as_secs()); - /// assert_eq!(123, duration.subsec_nanos()); - /// ``` - #[unstable(feature = "duration_extras", issue = "46507")] - #[inline] - pub fn from_nanos(nanos: u64) -> Duration { - let secs = nanos / (NANOS_PER_SEC as u64); - let nanos = (nanos % (NANOS_PER_SEC as u64)) as u32; - Duration { secs: secs, nanos: nanos } - } - - /// Returns the number of _whole_ seconds contained by this `Duration`. - /// - /// The returned value does not include the fractional (nanosecond) part of the - /// duration, which can be obtained using [`subsec_nanos`]. - /// - /// # Examples - /// - /// ``` - /// use std::time::Duration; - /// - /// 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 } - - /// Returns the fractional part of this `Duration`, in milliseconds. - /// - /// This method does **not** return the length of the duration when - /// represented by milliseconds. The returned number always represents a - /// fractional portion of a second (i.e. it is less than one thousand). - /// - /// # Examples - /// - /// ``` - /// #![feature(duration_extras)] - /// use std::time::Duration; - /// - /// let duration = Duration::from_millis(5432); - /// assert_eq!(duration.as_secs(), 5); - /// assert_eq!(duration.subsec_millis(), 432); - /// ``` - #[unstable(feature = "duration_extras", issue = "46507")] - #[inline] - pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI } - - /// Returns the fractional part of this `Duration`, in microseconds. - /// - /// This method does **not** return the length of the duration when - /// represented by microseconds. The returned number always represents a - /// fractional portion of a second (i.e. it is less than one million). - /// - /// # Examples - /// - /// ``` - /// #![feature(duration_extras, duration_from_micros)] - /// use std::time::Duration; - /// - /// let duration = Duration::from_micros(1_234_567); - /// assert_eq!(duration.as_secs(), 1); - /// assert_eq!(duration.subsec_micros(), 234_567); - /// ``` - #[unstable(feature = "duration_extras", issue = "46507")] - #[inline] - pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO } - - /// Returns the fractional part of this `Duration`, in nanoseconds. - /// - /// This method does **not** return the length of the duration when - /// represented by nanoseconds. The returned number always represents a - /// fractional portion of a second (i.e. it is less than one billion). - /// - /// # Examples - /// - /// ``` - /// use std::time::Duration; - /// - /// let duration = Duration::from_millis(5010); - /// assert_eq!(duration.as_secs(), 5); - /// assert_eq!(duration.subsec_nanos(), 10_000_000); - /// ``` - #[stable(feature = "duration", since = "1.3.0")] - #[inline] - pub fn subsec_nanos(&self) -> u32 { self.nanos } - - /// Checked `Duration` addition. Computes `self + other`, returning [`None`] - /// if overflow occurred. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::time::Duration; - /// - /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1))); - /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(std::u64::MAX, 0)), None); - /// ``` - #[stable(feature = "duration_checked_ops", since = "1.16.0")] - #[inline] - pub fn checked_add(self, rhs: Duration) -> Option<Duration> { - if let Some(mut secs) = self.secs.checked_add(rhs.secs) { - let mut nanos = self.nanos + rhs.nanos; - if nanos >= NANOS_PER_SEC { - nanos -= NANOS_PER_SEC; - if let Some(new_secs) = secs.checked_add(1) { - secs = new_secs; - } else { - return None; - } - } - debug_assert!(nanos < NANOS_PER_SEC); - Some(Duration { - secs, - nanos, - }) - } else { - None - } - } - - /// Checked `Duration` subtraction. Computes `self - other`, returning [`None`] - /// if the result would be negative or if overflow occurred. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::time::Duration; - /// - /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1))); - /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None); - /// ``` - #[stable(feature = "duration_checked_ops", since = "1.16.0")] - #[inline] - pub fn checked_sub(self, rhs: Duration) -> Option<Duration> { - if let Some(mut secs) = self.secs.checked_sub(rhs.secs) { - let nanos = if self.nanos >= rhs.nanos { - self.nanos - rhs.nanos - } else { - if let Some(sub_secs) = secs.checked_sub(1) { - secs = sub_secs; - self.nanos + NANOS_PER_SEC - rhs.nanos - } else { - return None; - } - }; - debug_assert!(nanos < NANOS_PER_SEC); - Some(Duration { secs: secs, nanos: nanos }) - } else { - None - } - } - - /// Checked `Duration` multiplication. Computes `self * other`, returning - /// [`None`] if overflow occurred. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::time::Duration; - /// - /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2))); - /// assert_eq!(Duration::new(std::u64::MAX - 1, 0).checked_mul(2), None); - /// ``` - #[stable(feature = "duration_checked_ops", since = "1.16.0")] - #[inline] - pub fn checked_mul(self, rhs: u32) -> Option<Duration> { - // Multiply nanoseconds as u64, because it cannot overflow that way. - let total_nanos = self.nanos as u64 * rhs as u64; - let extra_secs = total_nanos / (NANOS_PER_SEC as u64); - let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32; - if let Some(secs) = self.secs - .checked_mul(rhs as u64) - .and_then(|s| s.checked_add(extra_secs)) { - debug_assert!(nanos < NANOS_PER_SEC); - Some(Duration { - secs, - nanos, - }) - } else { - None - } - } - - /// Checked `Duration` division. Computes `self / other`, returning [`None`] - /// if `other == 0`. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::time::Duration; - /// - /// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); - /// assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); - /// assert_eq!(Duration::new(2, 0).checked_div(0), None); - /// ``` - #[stable(feature = "duration_checked_ops", since = "1.16.0")] - #[inline] - pub fn checked_div(self, rhs: u32) -> Option<Duration> { - if rhs != 0 { - let secs = self.secs / (rhs as u64); - let carry = self.secs - secs * (rhs as u64); - let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64); - let nanos = self.nanos / rhs + (extra_nanos as u32); - debug_assert!(nanos < NANOS_PER_SEC); - Some(Duration { secs: secs, nanos: nanos }) - } else { - None - } - } -} - -#[stable(feature = "duration", since = "1.3.0")] -impl Add for Duration { - type Output = Duration; - - fn add(self, rhs: Duration) -> Duration { - self.checked_add(rhs).expect("overflow when adding durations") - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl AddAssign for Duration { - fn add_assign(&mut self, rhs: Duration) { - *self = *self + rhs; - } -} - -#[stable(feature = "duration", since = "1.3.0")] -impl Sub for Duration { - type Output = Duration; - - fn sub(self, rhs: Duration) -> Duration { - self.checked_sub(rhs).expect("overflow when subtracting durations") - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl SubAssign for Duration { - fn sub_assign(&mut self, rhs: Duration) { - *self = *self - rhs; - } -} - -#[stable(feature = "duration", since = "1.3.0")] -impl Mul<u32> for Duration { - type Output = Duration; - - fn mul(self, rhs: u32) -> Duration { - self.checked_mul(rhs).expect("overflow when multiplying duration by scalar") - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl MulAssign<u32> for Duration { - fn mul_assign(&mut self, rhs: u32) { - *self = *self * rhs; - } -} - -#[stable(feature = "duration", since = "1.3.0")] -impl Div<u32> for Duration { - type Output = Duration; - - fn div(self, rhs: u32) -> Duration { - self.checked_div(rhs).expect("divide by zero error when dividing duration by scalar") - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl DivAssign<u32> for Duration { - fn div_assign(&mut self, rhs: u32) { - *self = *self / rhs; - } -} - -#[stable(feature = "duration_sum", since = "1.16.0")] -impl Sum for Duration { - fn sum<I: Iterator<Item=Duration>>(iter: I) -> Duration { - iter.fold(Duration::new(0, 0), |a, b| a + b) - } -} - -#[stable(feature = "duration_sum", since = "1.16.0")] -impl<'a> Sum<&'a Duration> for Duration { - fn sum<I: Iterator<Item=&'a Duration>>(iter: I) -> Duration { - iter.fold(Duration::new(0, 0), |a, b| a + *b) - } -} - -#[cfg(test)] -mod tests { - use super::Duration; - - #[test] - fn creation() { - assert!(Duration::from_secs(1) != Duration::from_secs(0)); - assert_eq!(Duration::from_secs(1) + Duration::from_secs(2), - Duration::from_secs(3)); - assert_eq!(Duration::from_millis(10) + Duration::from_secs(4), - Duration::new(4, 10 * 1_000_000)); - assert_eq!(Duration::from_millis(4000), Duration::new(4, 0)); - } - - #[test] - fn secs() { - assert_eq!(Duration::new(0, 0).as_secs(), 0); - assert_eq!(Duration::from_secs(1).as_secs(), 1); - assert_eq!(Duration::from_millis(999).as_secs(), 0); - assert_eq!(Duration::from_millis(1001).as_secs(), 1); - } - - #[test] - fn nanos() { - assert_eq!(Duration::new(0, 0).subsec_nanos(), 0); - assert_eq!(Duration::new(0, 5).subsec_nanos(), 5); - assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1); - assert_eq!(Duration::from_secs(1).subsec_nanos(), 0); - assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000); - assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000); - } - - #[test] - fn add() { - assert_eq!(Duration::new(0, 0) + Duration::new(0, 1), - Duration::new(0, 1)); - assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001), - Duration::new(1, 1)); - } - - #[test] - fn checked_add() { - assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), - Some(Duration::new(0, 1))); - assert_eq!(Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)), - Some(Duration::new(1, 1))); - assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::u64::MAX, 0)), None); - } - - #[test] - fn sub() { - assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), - Duration::new(0, 1)); - assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000), - Duration::new(0, 1)); - assert_eq!(Duration::new(1, 0) - Duration::new(0, 1), - Duration::new(0, 999_999_999)); - } - - #[test] - fn checked_sub() { - let zero = Duration::new(0, 0); - let one_nano = Duration::new(0, 1); - let one_sec = Duration::new(1, 0); - assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1))); - assert_eq!(one_sec.checked_sub(one_nano), - Some(Duration::new(0, 999_999_999))); - assert_eq!(zero.checked_sub(one_nano), None); - assert_eq!(zero.checked_sub(one_sec), None); - } - - #[test] #[should_panic] - fn sub_bad1() { - Duration::new(0, 0) - Duration::new(0, 1); - } - - #[test] #[should_panic] - fn sub_bad2() { - Duration::new(0, 0) - Duration::new(1, 0); - } - - #[test] - fn mul() { - assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2)); - assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3)); - assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4)); - assert_eq!(Duration::new(0, 500_000_001) * 4000, - Duration::new(2000, 4000)); - } - - #[test] - fn checked_mul() { - assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2))); - assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3))); - assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4))); - assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000), - Some(Duration::new(2000, 4000))); - assert_eq!(Duration::new(::u64::MAX - 1, 0).checked_mul(2), None); - } - - #[test] - fn div() { - assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); - assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333)); - assert_eq!(Duration::new(99, 999_999_000) / 100, - Duration::new(0, 999_999_990)); - } - - #[test] - fn checked_div() { - assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); - assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); - assert_eq!(Duration::new(2, 0).checked_div(0), None); - } -} |
