aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src
diff options
context:
space:
mode:
authorFenrir <[email protected]>2018-08-19 17:48:00 -0600
committerFenrir <[email protected]>2018-08-19 17:56:18 -0600
commit5d28bfcfd6086c3328837de9695099ea39048d0d (patch)
treea514fde042ff2a504a03305bfe0894ff8cd8d47e /ctr-std/src
parentUpdate for latest nightly 2018-06-09 (#70) (diff)
downloadctru-rs-5d28bfcfd6086c3328837de9695099ea39048d0d.tar.xz
ctru-rs-5d28bfcfd6086c3328837de9695099ea39048d0d.zip
Update for nightly-2018-08-18
Diffstat (limited to 'ctr-std/src')
-rw-r--r--ctr-std/src/alloc.rs121
-rw-r--r--ctr-std/src/ascii.rs290
-rw-r--r--ctr-std/src/build.rs11
-rw-r--r--ctr-std/src/collections/hash/map.rs38
-rw-r--r--ctr-std/src/collections/hash/set.rs24
-rw-r--r--ctr-std/src/collections/hash/table.rs7
-rw-r--r--ctr-std/src/collections/mod.rs10
-rw-r--r--ctr-std/src/env.rs25
-rw-r--r--ctr-std/src/error.rs93
-rw-r--r--ctr-std/src/f32.rs11
-rw-r--r--ctr-std/src/f64.rs11
-rw-r--r--ctr-std/src/ffi/c_str.rs43
-rw-r--r--ctr-std/src/ffi/os_str.rs48
-rw-r--r--ctr-std/src/fs.rs6
-rw-r--r--ctr-std/src/future.rs116
-rw-r--r--ctr-std/src/io/buffered.rs85
-rw-r--r--ctr-std/src/io/cursor.rs57
-rw-r--r--ctr-std/src/io/error.rs25
-rw-r--r--ctr-std/src/io/lazy.rs30
-rw-r--r--ctr-std/src/io/mod.rs171
-rw-r--r--ctr-std/src/io/stdio.rs40
-rw-r--r--ctr-std/src/io/util.rs2
-rw-r--r--ctr-std/src/keyword_docs.rs58
-rw-r--r--ctr-std/src/lib.rs76
-rw-r--r--ctr-std/src/macros.rs80
-rw-r--r--ctr-std/src/net/ip.rs218
-rw-r--r--ctr-std/src/net/parser.rs7
-rw-r--r--ctr-std/src/net/tcp.rs4
-rw-r--r--ctr-std/src/net/udp.rs2
-rw-r--r--ctr-std/src/os/hermit/fs.rs389
-rw-r--r--ctr-std/src/os/hermit/mod.rs16
-rw-r--r--ctr-std/src/os/hermit/raw.rs27
-rw-r--r--ctr-std/src/os/mod.rs1
-rw-r--r--ctr-std/src/os/raw/mod.rs6
-rw-r--r--ctr-std/src/panic.rs30
-rw-r--r--ctr-std/src/panicking.rs132
-rw-r--r--ctr-std/src/path.rs31
-rw-r--r--ctr-std/src/prelude/v1.rs58
-rw-r--r--ctr-std/src/process.rs37
-rw-r--r--ctr-std/src/rt.rs2
-rw-r--r--ctr-std/src/sync/mod.rs2
-rw-r--r--ctr-std/src/sync/mpsc/mod.rs40
-rw-r--r--ctr-std/src/sync/mpsc/select.rs2
-rw-r--r--ctr-std/src/sync/mutex.rs4
-rw-r--r--ctr-std/src/sync/once.rs40
-rw-r--r--ctr-std/src/sys/cloudabi/abi/cloudabi.rs18
-rw-r--r--ctr-std/src/sys/cloudabi/backtrace.rs18
-rw-r--r--ctr-std/src/sys/cloudabi/thread.rs2
-rw-r--r--ctr-std/src/sys/horizon/net.rs13
-rw-r--r--ctr-std/src/sys/mod.rs3
-rw-r--r--ctr-std/src/sys/redox/args.rs16
-rw-r--r--ctr-std/src/sys/redox/backtrace/tracing.rs18
-rw-r--r--ctr-std/src/sys/redox/ext/mod.rs1
-rw-r--r--ctr-std/src/sys/redox/ext/net.rs769
-rw-r--r--ctr-std/src/sys/redox/fd.rs5
-rw-r--r--ctr-std/src/sys/redox/net/mod.rs4
-rw-r--r--ctr-std/src/sys/redox/net/netc.rs2
-rw-r--r--ctr-std/src/sys/redox/net/udp.rs2
-rw-r--r--ctr-std/src/sys/redox/os.rs3
-rw-r--r--ctr-std/src/sys/redox/process.rs15
-rw-r--r--ctr-std/src/sys/redox/thread.rs2
-rw-r--r--ctr-std/src/sys/unix/args.rs19
-rw-r--r--ctr-std/src/sys/unix/backtrace/tracing/gcc_s.rs18
-rw-r--r--ctr-std/src/sys/unix/condvar.rs13
-rw-r--r--ctr-std/src/sys/unix/env.rs11
-rw-r--r--ctr-std/src/sys/unix/ext/fs.rs127
-rw-r--r--ctr-std/src/sys/unix/ext/mod.rs1
-rw-r--r--ctr-std/src/sys/unix/ext/net.rs6
-rw-r--r--ctr-std/src/sys/unix/fast_thread_local.rs7
-rw-r--r--ctr-std/src/sys/unix/fs.rs56
-rw-r--r--ctr-std/src/sys/unix/mod.rs1
-rw-r--r--ctr-std/src/sys/unix/mutex.rs9
-rw-r--r--ctr-std/src/sys/unix/os.rs39
-rw-r--r--ctr-std/src/sys/unix/process/process_common.rs6
-rw-r--r--ctr-std/src/sys/unix/rand.rs29
-rw-r--r--ctr-std/src/sys/unix/thread.rs5
-rw-r--r--ctr-std/src/sys/unix/time.rs4
-rw-r--r--ctr-std/src/sys/wasm/os.rs2
-rw-r--r--ctr-std/src/sys/wasm/thread.rs2
-rw-r--r--ctr-std/src/sys/windows/backtrace/mod.rs297
-rw-r--r--ctr-std/src/sys/windows/backtrace/printing/mod.rs14
-rw-r--r--ctr-std/src/sys/windows/backtrace/printing/msvc.rs196
-rw-r--r--ctr-std/src/sys/windows/c.rs82
-rw-r--r--ctr-std/src/sys/windows/ext/ffi.rs3
-rw-r--r--ctr-std/src/sys/windows/ext/mod.rs1
-rw-r--r--ctr-std/src/sys/windows/mod.rs10
-rw-r--r--ctr-std/src/sys/windows/process.rs8
-rw-r--r--ctr-std/src/sys/windows/thread.rs5
-rw-r--r--ctr-std/src/sys_common/at_exit_imp.rs36
-rw-r--r--ctr-std/src/sys_common/backtrace.rs21
-rw-r--r--ctr-std/src/sys_common/mutex.rs32
-rw-r--r--ctr-std/src/sys_common/poison.rs2
-rw-r--r--ctr-std/src/sys_common/remutex.rs4
-rw-r--r--ctr-std/src/sys_common/thread.rs2
-rw-r--r--ctr-std/src/sys_common/thread_local.rs5
-rw-r--r--ctr-std/src/sys_common/wtf8.rs14
-rw-r--r--ctr-std/src/tests/env.rs3
-rw-r--r--ctr-std/src/thread/local.rs2
-rw-r--r--ctr-std/src/thread/mod.rs37
99 files changed, 3170 insertions, 1376 deletions
diff --git a/ctr-std/src/alloc.rs b/ctr-std/src/alloc.rs
index 3b1a3a4..b9aba1e 100644
--- a/ctr-std/src/alloc.rs
+++ b/ctr-std/src/alloc.rs
@@ -8,61 +8,129 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! dox
+//! 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.
-#![unstable(issue = "32838", feature = "allocator_api")]
-
-#[doc(inline)] #[allow(deprecated)] pub use alloc_crate::alloc::Heap;
-#[doc(inline)] pub use alloc_crate::alloc::{Global, Layout, oom};
-#[doc(inline)] pub use alloc_system::System;
-#[doc(inline)] pub use core::alloc::*;
+#![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 OOM hook, replacing any that was previously registered.
+/// Registers a custom allocation error hook, replacing any that was previously registered.
///
-/// The OOM hook is invoked when an infallible memory allocation fails, before
+/// 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_oom_hook`] and
-/// [`take_oom_hook`] functions.
+/// 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 OOM hook is a global resource.
-pub fn set_oom_hook(hook: fn(Layout)) {
+/// 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 OOM hook, returning it.
+/// Unregisters the current allocation error hook, returning it.
///
-/// *See also the function [`set_oom_hook`].*
+/// *See also the function [`set_alloc_error_hook`].*
///
/// If no custom hook is registered, the default hook will be returned.
-pub fn take_oom_hook() -> fn(Layout) {
+#[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_oom_hook
+ default_alloc_error_hook
} else {
unsafe { mem::transmute(hook) }
}
}
-fn default_oom_hook(layout: Layout) {
+fn default_alloc_error_hook(layout: Layout) {
dumb_print(format_args!("memory allocation of {} bytes failed", layout.size()));
}
#[cfg(not(test))]
#[doc(hidden)]
-#[lang = "oom"]
-pub extern fn rust_oom(layout: Layout) -> ! {
+#[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_oom_hook
+ default_alloc_error_hook
} else {
unsafe { mem::transmute(hook) }
};
@@ -73,8 +141,9 @@ pub extern fn rust_oom(layout: Layout) -> ! {
#[cfg(not(test))]
#[doc(hidden)]
#[allow(unused_attributes)]
+#[unstable(feature = "alloc_internals", issue = "0")]
pub mod __default_lib_allocator {
- use super::{System, Layout, GlobalAlloc, Opaque};
+ use super::{System, Layout, GlobalAlloc};
// for symbol names src/librustc/middle/allocator.rs
// for signatures src/librustc_allocator/lib.rs
@@ -85,7 +154,7 @@ pub mod __default_lib_allocator {
#[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) as *mut u8
+ System.alloc(layout)
}
#[no_mangle]
@@ -93,7 +162,7 @@ pub mod __default_lib_allocator {
pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
size: usize,
align: usize) {
- System.dealloc(ptr as *mut Opaque, Layout::from_size_align_unchecked(size, align))
+ System.dealloc(ptr, Layout::from_size_align_unchecked(size, align))
}
#[no_mangle]
@@ -103,13 +172,13 @@ pub mod __default_lib_allocator {
align: usize,
new_size: usize) -> *mut u8 {
let old_layout = Layout::from_size_align_unchecked(old_size, align);
- System.realloc(ptr as *mut Opaque, old_layout, new_size) as *mut u8
+ 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) as *mut u8
+ System.alloc_zeroed(layout)
}
}
diff --git a/ctr-std/src/ascii.rs b/ctr-std/src/ascii.rs
index 6472edb..0c8e95a 100644
--- a/ctr-std/src/ascii.rs
+++ b/ctr-std/src/ascii.rs
@@ -154,160 +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")]
- #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
- 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")]
- #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
- 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")]
- #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
- 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")]
- #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
- 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")]
- #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
- 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")]
- #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
- 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")]
- #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
- 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")]
- #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
- 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")]
- #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
- 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")]
- #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
- fn is_ascii_control(&self) -> bool { unimplemented!(); }
}
macro_rules! delegating_ascii_methods {
@@ -332,47 +178,12 @@ 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")]
@@ -381,7 +192,6 @@ impl AsciiExt for char {
type Owned = char;
delegating_ascii_methods!();
- delegating_ascii_ctype_methods!();
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -390,56 +200,6 @@ 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")]
@@ -448,54 +208,4 @@ 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())
- }
}
diff --git a/ctr-std/src/build.rs b/ctr-std/src/build.rs
index c001e4e..016e7ad 100644
--- a/ctr-std/src/build.rs
+++ b/ctr-std/src/build.rs
@@ -22,7 +22,6 @@ fn main() {
if cfg!(feature = "backtrace") &&
!target.contains("cloudabi") &&
!target.contains("emscripten") &&
- !target.contains("fuchsia") &&
!target.contains("msvc") &&
!target.contains("wasm32")
{
@@ -68,10 +67,6 @@ 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");
} else if target.contains("cloudabi") {
@@ -109,7 +104,8 @@ fn build_libbacktrace(target: &str) -> Result<(), ()> {
} else {
build.file("../libbacktrace/elf.c");
- if target.contains("64") {
+ 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");
@@ -126,7 +122,8 @@ fn build_libbacktrace(target: &str) -> Result<(), ()> {
if !target.contains("apple-ios") &&
!target.contains("solaris") &&
!target.contains("redox") &&
- !target.contains("android") {
+ !target.contains("android") &&
+ !target.contains("haiku") {
build.define("HAVE_DL_ITERATE_PHDR", "1");
}
build.define("_GNU_SOURCE", "1");
diff --git a/ctr-std/src/collections/hash/map.rs b/ctr-std/src/collections/hash/map.rs
index 9c77acb..91912e5 100644
--- a/ctr-std/src/collections/hash/map.rs
+++ b/ctr-std/src/collections/hash/map.rs
@@ -11,7 +11,7 @@
use self::Entry::*;
use self::VacantEntryState::*;
-use alloc::CollectionAllocErr;
+use collections::CollectionAllocErr;
use cell::Cell;
use borrow::Borrow;
use cmp::max;
@@ -276,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());
@@ -295,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);
/// }
diff --git a/ctr-std/src/collections/hash/set.rs b/ctr-std/src/collections/hash/set.rs
index 855563a..5ac3e8f 100644
--- a/ctr-std/src/collections/hash/set.rs
+++ b/ctr-std/src/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
/// }
diff --git a/ctr-std/src/collections/hash/table.rs b/ctr-std/src/collections/hash/table.rs
index d997fb2..2b31918 100644
--- a/ctr-std/src/collections/hash/table.rs
+++ b/ctr-std/src/collections/hash/table.rs
@@ -8,7 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use alloc::{Global, Alloc, Layout, LayoutErr, CollectionAllocErr, oom};
+use alloc::{Global, Alloc, Layout, LayoutErr, handle_alloc_error};
+use collections::CollectionAllocErr;
use hash::{BuildHasher, Hash, Hasher};
use marker;
use mem::{size_of, needs_drop};
@@ -699,7 +700,7 @@ impl<K, V> RawTable<K, V> {
// point into it.
let (layout, _) = calculate_layout::<K, V>(capacity)?;
let buffer = Global.alloc(layout).map_err(|e| match fallibility {
- Infallible => oom(layout),
+ Infallible => handle_alloc_error(layout),
Fallible => e,
})?;
@@ -1124,7 +1125,7 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> {
let (layout, _) = calculate_layout::<K, V>(self.capacity())
.unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() });
unsafe {
- Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), layout);
+ 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/ctr-std/src/collections/mod.rs b/ctr-std/src/collections/mod.rs
index d8e79b9..8d2c82b 100644
--- a/ctr-std/src/collections/mod.rs
+++ b/ctr-std/src/collections/mod.rs
@@ -424,13 +424,13 @@
#[doc(hidden)]
pub use ops::Bound;
#[stable(feature = "rust1", since = "1.0.0")]
-pub use alloc_crate::{BinaryHeap, BTreeMap, BTreeSet};
+pub use alloc_crate::collections::{BinaryHeap, BTreeMap, BTreeSet};
#[stable(feature = "rust1", since = "1.0.0")]
-pub use alloc_crate::{LinkedList, VecDeque};
+pub use alloc_crate::collections::{LinkedList, VecDeque};
#[stable(feature = "rust1", since = "1.0.0")]
-pub use alloc_crate::{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_crate::{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;
@@ -438,7 +438,7 @@ pub use self::hash_map::HashMap;
pub use self::hash_set::HashSet;
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
-pub use heap::CollectionAllocErr;
+pub use alloc_crate::collections::CollectionAllocErr;
mod hash;
diff --git a/ctr-std/src/env.rs b/ctr-std/src/env.rs
index 91e417c..9066c0b 100644
--- a/ctr-std/src/env.rs
+++ b/ctr-std/src/env.rs
@@ -512,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
///
@@ -533,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()
diff --git a/ctr-std/src/error.rs b/ctr-std/src/error.rs
index 817eea5..2953469 100644
--- a/ctr-std/src/error.rs
+++ b/ctr-std/src/error.rs
@@ -23,13 +23,13 @@
// coherence challenge (e.g., specialization, neg impls, etc) we can
// reconsider what crate these items belong in.
+use alloc::{AllocErr, LayoutErr, CannotReallocInPlace};
use any::TypeId;
use borrow::Cow;
use cell;
use char;
use core::array;
use fmt::{self, Debug, Display};
-use heap::{AllocErr, LayoutErr, CannotReallocInPlace};
use mem::transmute;
use num;
use str;
@@ -49,6 +49,7 @@ use string;
///
/// [`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 {
@@ -137,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)]
@@ -150,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);
@@ -184,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))
}
}
@@ -326,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)
}
}
@@ -367,7 +368,7 @@ impl Error for char::ParseCharError {
}
// 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]
@@ -389,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
@@ -403,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
@@ -411,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 {
@@ -473,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)
})
}
}
@@ -532,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/ctr-std/src/f32.rs b/ctr-std/src/f32.rs
index ae30321..8e8340b 100644
--- a/ctr-std/src/f32.rs
+++ b/ctr-std/src/f32.rs
@@ -254,7 +254,14 @@ impl f32 {
/// Calculates the Euclidean modulo (self mod rhs), which is never negative.
///
- /// In particular, the result `n` satisfies `0 <= n < rhs.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
///
@@ -266,6 +273,8 @@ impl f32 {
/// 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]
#[unstable(feature = "euclidean_division", issue = "49048")]
diff --git a/ctr-std/src/f64.rs b/ctr-std/src/f64.rs
index 7950d43..6880294 100644
--- a/ctr-std/src/f64.rs
+++ b/ctr-std/src/f64.rs
@@ -230,7 +230,14 @@ impl f64 {
/// Calculates the Euclidean modulo (self mod rhs), which is never negative.
///
- /// In particular, the result `n` satisfies `0 <= n < rhs.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
///
@@ -242,6 +249,8 @@ impl f64 {
/// 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]
#[unstable(feature = "euclidean_division", issue = "49048")]
diff --git a/ctr-std/src/ffi/c_str.rs b/ctr-std/src/ffi/c_str.rs
index 52372df..06edd29 100644
--- a/ctr-std/src/ffi/c_str.rs
+++ b/ctr-std/src/ffi/c_str.rs
@@ -692,6 +692,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()
@@ -750,14 +756,30 @@ 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()
@@ -790,6 +812,10 @@ impl<'a> From<&'a CString> for Cow<'a, CStr> {
#[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());
@@ -808,6 +834,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());
@@ -881,6 +911,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")
@@ -933,7 +967,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)
}
}
@@ -1234,9 +1268,9 @@ 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 constant-time cast, but it is planned to alter its definition
@@ -1248,6 +1282,7 @@ impl CStr {
/// [`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/ctr-std/src/ffi/os_str.rs b/ctr-std/src/ffi/os_str.rs
index 0a31480..6bcd62d 100644
--- a/ctr-std/src/ffi/os_str.rs
+++ b/ctr-std/src/ffi/os_str.rs
@@ -348,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) }
}
@@ -417,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 {}
@@ -500,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
///
@@ -616,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()
}
@@ -623,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();
@@ -648,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();
diff --git a/ctr-std/src/fs.rs b/ctr-std/src/fs.rs
index 987687e..7632fbc 100644
--- a/ctr-std/src/fs.rs
+++ b/ctr-std/src/fs.rs
@@ -356,9 +356,9 @@ impl File {
/// use std::fs::File;
///
/// fn main() -> std::io::Result<()> {
- /// let mut f = File::open("foo.txt")?;
- /// # Ok(())
- /// # }
+ /// 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> {
diff --git a/ctr-std/src/future.rs b/ctr-std/src/future.rs
new file mode 100644
index 0000000..12ea1ea
--- /dev/null
+++ b/ctr-std/src/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/ctr-std/src/io/buffered.rs b/ctr-std/src/io/buffered.rs
index ee297d3..03c97de 100644
--- a/ctr-std/src/io/buffered.rs
+++ b/ctr-std/src/io/buffered.rs
@@ -61,7 +61,8 @@ 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
///
@@ -153,33 +154,6 @@ impl<R: Read> BufReader<R> {
#[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.
- ///
- /// # Examples
- //
- /// ```no_run
- /// # #![feature(bufreader_is_empty)]
- /// use std::io::BufReader;
- /// use std::io::BufRead;
- /// use std::fs::File;
- ///
- /// fn main() -> std::io::Result<()> {
- /// let f1 = File::open("log.txt")?;
- /// let mut reader = BufReader::new(f1);
- /// assert!(reader.is_empty());
- ///
- /// if reader.fill_buf()?.len() > 0 {
- /// assert!(!reader.is_empty());
- /// }
- /// Ok(())
- /// }
- /// ```
- #[unstable(feature = "bufreader_is_empty", issue = "45323", reason = "recently added")]
- #[rustc_deprecated(since = "1.26.0", reason = "use .buffer().is_empty() instead")]
- pub fn is_empty(&self) -> bool {
- self.buffer().is_empty()
- }
-
/// Returns a reference to the internally buffered data.
///
/// Unlike `fill_buf`, this will not attempt to fill the buffer if it is empty.
@@ -454,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
///
@@ -738,7 +713,7 @@ impl<W> fmt::Display for IntoInnerError<W> {
/// reducing the number of actual writes to the file.
///
/// ```no_run
-/// use std::fs::File;
+/// use std::fs::{self, File};
/// use std::io::prelude::*;
/// use std::io::LineWriter;
///
@@ -752,17 +727,30 @@ impl<W> fmt::Display for IntoInnerError<W> {
/// 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")?;
///
-/// // let's check we did the right thing.
-/// let mut file = File::open("poem.txt")?;
-/// let mut contents = String::new();
+/// // 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",
+/// );
///
-/// file.read_to_string(&mut contents)?;
+/// // 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.")?;
///
-/// assert_eq!(contents.as_bytes(), &road_not_taken[..]);
+/// // 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()?;
+///
+/// // Confirm the whole poem was written.
+/// assert_eq!(fs::read("poem.txt")?, &road_not_taken[..]);
/// Ok(())
/// }
/// ```
@@ -862,7 +850,7 @@ 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.
///
@@ -1251,25 +1239,6 @@ mod tests {
}
#[test]
- #[allow(deprecated)]
- fn read_char_buffered() {
- let buf = [195, 159];
- let reader = BufReader::with_capacity(1, &buf[..]);
- assert_eq!(reader.chars().next().unwrap().unwrap(), 'ß');
- }
-
- #[test]
- #[allow(deprecated)]
- 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/ctr-std/src/io/cursor.rs b/ctr-std/src/io/cursor.rs
index 8ac5257..14f2015 100644
--- a/ctr-std/src/io/cursor.rs
+++ b/ctr-std/src/io/cursor.rs
@@ -10,15 +10,17 @@
use io::prelude::*;
+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
@@ -86,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
///
@@ -259,26 +261,9 @@ fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<us
Ok(amt)
}
-/// Compensate removal of some impls per
-/// https://github.com/rust-lang/rust/pull/49305#issuecomment-376293243
-#[cfg(any(target_pointer_width = "16",
- target_pointer_width = "32"))]
-fn try_into(n: u64) -> Result<usize, ()> {
- if n <= (<usize>::max_value() as u64) {
- Ok(n as usize)
- } else {
- Err(())
- }
-}
-
-#[cfg(any(target_pointer_width = "64"))]
-fn try_into(n: u64) -> Result<usize, ()> {
- Ok(n as usize)
-}
-
// Resizing write implementation
fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> {
- let pos: usize = try_into(*pos_mut).map_err(|_| {
+ let pos: usize = (*pos_mut).try_into().map_err(|_| {
Error::new(ErrorKind::InvalidInput,
"cursor position exceeds maximum possible vector length")
})?;
@@ -566,26 +551,6 @@ mod tests {
}
#[test]
- #[allow(deprecated)]
- 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]
- #[allow(deprecated)]
- 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/ctr-std/src/io/error.rs b/ctr-std/src/io/error.rs
index bdd675e..3e50988 100644
--- a/ctr-std/src/io/error.rs
+++ b/ctr-std/src/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,
@@ -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/ctr-std/src/io/lazy.rs b/ctr-std/src/io/lazy.rs
index 9cef4e3..4fb367f 100644
--- a/ctr-std/src/io/lazy.rs
+++ b/ctr-std/src/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/ctr-std/src/io/mod.rs b/ctr-std/src/io/mod.rs
index eba4e9f..b83f3fb 100644
--- a/ctr-std/src/io/mod.rs
+++ b/ctr-std/src/io/mod.rs
@@ -147,7 +147,7 @@
//! ```
//!
//! 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
@@ -270,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;
@@ -357,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..]);
@@ -800,53 +804,6 @@ pub trait Read {
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
- ///
- /// ```no_run
- /// #![feature(io)]
- /// use std::io;
- /// use std::io::prelude::*;
- /// use std::fs::File;
- ///
- /// fn main() -> 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")]
- #[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead:
- https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")]
- #[allow(deprecated)]
- 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
@@ -1949,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")]
@@ -1972,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) {
@@ -2005,104 +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")]
-#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead:
- https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")]
-#[derive(Debug)]
-#[allow(deprecated)]
-pub struct Chars<R> {
- inner: R,
-}
-
-/// An enumeration of possible errors that can be generated from the `Chars`
-/// adapter.
-#[unstable(feature = "io", reason = "awaiting stability of Read::chars",
- issue = "27802")]
-#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead:
- https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")]
-#[derive(Debug)]
-#[allow(deprecated)]
-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")]
-#[allow(deprecated)]
-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")]
-#[allow(deprecated)]
-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")]
-#[allow(deprecated)]
-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/ctr-std/src/io/stdio.rs b/ctr-std/src/io/stdio.rs
index 2472bed..1f256f5 100644
--- a/ctr-std/src/io/stdio.rs
+++ b/ctr-std/src/io/stdio.rs
@@ -21,7 +21,7 @@ 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)
}
}
@@ -197,12 +197,13 @@ pub struct StdinLock<'a> {
/// ```
#[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
@@ -396,12 +397,13 @@ pub struct StdoutLock<'a> {
#[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,
@@ -531,12 +533,14 @@ pub struct StderrLock<'a> {
/// ```
#[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)
@@ -670,7 +674,7 @@ pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
/// 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>>>>,
+ local_s: &'static LocalKey<RefCell<Option<Box<dyn Write+Send>>>>,
global_s: fn() -> T,
label: &str,
)
@@ -712,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/ctr-std/src/io/util.rs b/ctr-std/src/io/util.rs
index 195310a..33f741d 100644
--- a/ctr-std/src/io/util.rs
+++ b/ctr-std/src/io/util.rs
@@ -223,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/ctr-std/src/keyword_docs.rs b/ctr-std/src/keyword_docs.rs
new file mode 100644
index 0000000..4f6bda6
--- /dev/null
+++ b/ctr-std/src/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/ctr-std/src/lib.rs b/ctr-std/src/lib.rs
index 7248a10..19ea930 100644
--- a/ctr-std/src/lib.rs
+++ b/ctr-std/src/lib.rs
@@ -232,15 +232,16 @@
// 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(alloc_error_handler)]
#![feature(allocator_api)]
-#![feature(alloc_system)]
#![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)]
@@ -248,25 +249,22 @@
#![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(const_int_ops)]
+#![feature(const_ip)]
#![feature(core_intrinsics)]
#![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)]
#![feature(external_doc)]
-#![feature(fs_read_write)]
#![feature(fixed_size_array)]
-#![feature(float_from_str_radix)]
#![feature(fn_traits)]
#![feature(fnbox)]
#![feature(futures_api)]
+#![feature(generator_trait)]
#![feature(hashmap_internals)]
-#![feature(heap_api)]
#![feature(int_error_internals)]
#![feature(integer_atomics)]
-#![feature(into_cow)]
#![feature(lang_items)]
#![feature(libc)]
#![feature(link_args)]
@@ -274,35 +272,28 @@
#![feature(macro_vis_matcher)]
#![feature(needs_panic_runtime)]
#![feature(never_type)]
+#![cfg_attr(not(stage0), feature(nll))]
#![feature(exhaustive_patterns)]
-#![feature(num_bits_bytes)]
-#![feature(old_wrapping)]
#![feature(on_unimplemented)]
-#![feature(oom)]
#![feature(optin_builtin_traits)]
#![feature(panic_internals)]
#![feature(panic_unwind)]
-#![feature(peek)]
#![feature(pin)]
-#![feature(placement_new_protocol)]
#![feature(prelude_import)]
#![feature(ptr_internals)]
-#![feature(rand)]
#![feature(raw)]
#![feature(rustc_attrs)]
+#![feature(rustc_const_unstable)]
#![feature(std_internals)]
#![feature(stdsimd)]
#![feature(shrink_to)]
-#![feature(slice_bytes)]
#![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(test, rustc_private)]
+#![feature(rustc_private)]
#![feature(thread_local)]
#![feature(toowned_clone_into)]
#![feature(try_from)]
@@ -310,18 +301,16 @@
#![feature(unboxed_closures)]
#![feature(untagged_unions)]
#![feature(unwind_attributes)]
-#![feature(use_extern_macros)]
-#![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(float_internals)]
#![feature(panic_info_message)]
-#![cfg_attr(not(stage0), feature(panic_implementation))]
+#![feature(panic_implementation)]
+#![feature(non_exhaustive)]
#![default_lib_allocator]
@@ -331,9 +320,6 @@
// `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(all(stage0, not(test)), feature = "force_alloc_system")),
- feature(global_allocator))]
#[cfg(all(not(target_env = "msvc"),
any(all(stage0, not(test)), feature = "force_alloc_system")))]
#[global_allocator]
@@ -465,20 +451,6 @@ pub use core::u128;
#[stable(feature = "core_hint", since = "1.27.0")]
pub use core::hint;
-#[unstable(feature = "futures_api",
- reason = "futures in libcore are unstable",
- issue = "50547")]
-pub mod task {
- //! Types and Traits for working with asynchronous tasks.
- pub use core::task::*;
- pub use alloc_crate::task::*;
-}
-
-#[unstable(feature = "futures_api",
- reason = "futures in libcore are unstable",
- issue = "50547")]
-pub use core::future;
-
pub mod f32;
pub mod f64;
@@ -500,13 +472,22 @@ pub mod process;
pub mod sync;
pub mod time;
-#[unstable(feature = "allocator_api", issue = "32838")]
-#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")]
-/// Use the `alloc` module instead.
-pub mod heap {
- pub use alloc::*;
+#[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;
@@ -526,3 +507,8 @@ pub mod rt;
// 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/ctr-std/src/macros.rs b/ctr-std/src/macros.rs
index 8da70f5..f15494c 100644
--- a/ctr-std/src/macros.rs
+++ b/ctr-std/src/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
@@ -150,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.
@@ -207,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.
@@ -281,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 {
@@ -313,8 +345,10 @@ 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]
+ #[rustc_doc_only_macro]
macro_rules! compile_error {
($msg:expr) => ({ /* compiler built-in */ });
($msg:expr,) => ({ /* compiler built-in */ });
@@ -366,7 +400,7 @@ pub mod builtin {
/// 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 */ });
@@ -404,7 +438,7 @@ pub mod builtin {
/// 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 */ });
@@ -430,7 +464,7 @@ pub mod builtin {
/// println!("the secret key might be: {:?}", key);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[macro_export]
+ #[rustc_doc_only_macro]
macro_rules! option_env {
($name:expr) => ({ /* compiler built-in */ });
($name:expr,) => ({ /* compiler built-in */ });
@@ -461,7 +495,7 @@ 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 */ });
@@ -483,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 */ });
@@ -511,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.
@@ -536,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.
@@ -560,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.
@@ -579,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.
@@ -613,7 +647,7 @@ pub mod builtin {
///
/// Compiling 'main.rs' and running the resulting binary will print "adiós".
#[stable(feature = "rust1", since = "1.0.0")]
- #[macro_export]
+ #[rustc_doc_only_macro]
macro_rules! include_str {
($file:expr) => ({ /* compiler built-in */ });
($file:expr,) => ({ /* compiler built-in */ });
@@ -650,7 +684,7 @@ pub mod builtin {
///
/// Compiling 'main.rs' and running the resulting binary will print "adiós".
#[stable(feature = "rust1", since = "1.0.0")]
- #[macro_export]
+ #[rustc_doc_only_macro]
macro_rules! include_bytes {
($file:expr) => ({ /* compiler built-in */ });
($file:expr,) => ({ /* compiler built-in */ });
@@ -674,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.
@@ -696,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.
@@ -739,7 +773,7 @@ pub mod builtin {
/// Compiling 'main.rs' and running the resulting binary will print
/// "🙈🙊🙉🙈🙊🙉".
#[stable(feature = "rust1", since = "1.0.0")]
- #[macro_export]
+ #[rustc_doc_only_macro]
macro_rules! include {
($file:expr) => ({ /* compiler built-in */ });
($file:expr,) => ({ /* compiler built-in */ });
@@ -792,7 +826,7 @@ pub mod builtin {
/// assert!(a + b == 30, "a = {}, b = {}", a, b);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[macro_export]
+ #[rustc_doc_only_macro]
macro_rules! assert {
($cond:expr) => ({ /* compiler built-in */ });
($cond:expr,) => ({ /* compiler built-in */ });
diff --git a/ctr-std/src/net/ip.rs b/ctr-std/src/net/ip.rs
index fcec8d0..9a610cd 100644
--- a/ctr-std/src/net/ip.rs
+++ b/ctr-std/src/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};
@@ -162,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(),
}
}
@@ -187,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(),
}
}
@@ -216,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(),
}
}
@@ -241,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(),
}
}
@@ -270,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(),
}
}
@@ -295,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,
}
@@ -320,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,
}
@@ -340,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
///
@@ -359,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
///
@@ -377,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.
///
@@ -399,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]
}
@@ -470,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,
}
}
@@ -496,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.
@@ -573,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.
@@ -600,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,
}
}
@@ -654,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),
}
}
}
@@ -705,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,
}
}
@@ -715,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,
}
}
@@ -743,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),
}
}
@@ -753,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),
}
}
@@ -763,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))
}
}
@@ -856,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
///
@@ -878,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
///
@@ -896,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.
///
@@ -1321,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,
}
}
}
@@ -1331,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,
}
}
}
@@ -1358,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),
}
}
}
@@ -1368,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),
}
}
}
@@ -1414,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)
}
}
@@ -1846,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/ctr-std/src/net/parser.rs b/ctr-std/src/net/parser.rs
index ae5037c..cf3e535 100644
--- a/ctr-std/src/net/parser.rs
+++ b/ctr-std/src/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)) {
diff --git a/ctr-std/src/net/tcp.rs b/ctr-std/src/net/tcp.rs
index 0f60b5b..75c7a3d 100644
--- a/ctr-std/src/net/tcp.rs
+++ b/ctr-std/src/net/tcp.rs
@@ -81,7 +81,7 @@ pub struct TcpStream(net_imp::TcpStream);
/// }
///
/// fn main() -> io::Result<()> {
-/// let listener = TcpListener::bind("127.0.0.1:80").unwrap();
+/// let listener = TcpListener::bind("127.0.0.1:80")?;
///
/// // accept connections and process them serially
/// for stream in listener.incoming() {
@@ -927,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());
}
diff --git a/ctr-std/src/net/udp.rs b/ctr-std/src/net/udp.rs
index d25e299..0ebe328 100644
--- a/ctr-std/src/net/udp.rs
+++ b/ctr-std/src/net/udp.rs
@@ -826,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());
}
diff --git a/ctr-std/src/os/hermit/fs.rs b/ctr-std/src/os/hermit/fs.rs
new file mode 100644
index 0000000..d2e7516
--- /dev/null
+++ b/ctr-std/src/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/ctr-std/src/os/hermit/mod.rs b/ctr-std/src/os/hermit/mod.rs
new file mode 100644
index 0000000..fcb22cd
--- /dev/null
+++ b/ctr-std/src/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/ctr-std/src/os/hermit/raw.rs b/ctr-std/src/os/hermit/raw.rs
new file mode 100644
index 0000000..282afe0
--- /dev/null
+++ b/ctr-std/src/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/ctr-std/src/os/mod.rs b/ctr-std/src/os/mod.rs
index 0bf1b0d..ff4dd4f 100644
--- a/ctr-std/src/os/mod.rs
+++ b/ctr-std/src/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(target_os = "horizon")] pub mod horizon;
#[cfg(any(target_os = "redox", unix))]
diff --git a/ctr-std/src/os/raw/mod.rs b/ctr-std/src/os/raw/mod.rs
index d5eeb52..dc33747 100644
--- a/ctr-std/src/os/raw/mod.rs
+++ b/ctr-std/src/os/raw/mod.rs
@@ -29,6 +29,9 @@ 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;
@@ -41,6 +44,9 @@ 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;
diff --git a/ctr-std/src/panic.rs b/ctr-std/src/panic.rs
index 229034e..b8c1c4f 100644
--- a/ctr-std/src/panic.rs
+++ b/ctr-std/src/panic.rs
@@ -15,11 +15,14 @@
use any::Any;
use cell::UnsafeCell;
use fmt;
+use future::Future;
+use mem::PinMut;
use ops::{Deref, DerefMut};
use panicking;
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")]
@@ -107,8 +110,10 @@ pub use core::panic::{PanicInfo, Location};
///
/// [`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
@@ -123,9 +128,12 @@ pub auto trait UnwindSafe {}
/// [`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.
@@ -315,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
@@ -403,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/ctr-std/src/panicking.rs b/ctr-std/src/panicking.rs
index 321d634..4cdde2b 100644
--- a/ctr-std/src/panicking.rs
+++ b/ctr-std/src/panicking.rs
@@ -36,7 +36,7 @@ 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)
}
}
@@ -64,7 +64,7 @@ extern {
#[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();
@@ -104,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");
}
@@ -149,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");
}
@@ -222,7 +222,7 @@ fn default_hook(info: &PanicInfo) {
consoleDebugInit(debugDevice_SVC);
}
- let write = |err: &mut ::io::Write| {
+ let write = |err: &mut dyn (::io::Write)| {
let _ = writeln!(err, "thread '{}' panicked at '{}', {}",
name, msg, location);
@@ -273,7 +273,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,
@@ -344,18 +344,6 @@ pub fn panicking() -> bool {
/// Entry point of panic from the libcore crate.
#[cfg(not(test))]
-#[cfg(stage0)]
-#[lang = "panic_fmt"]
-pub extern fn rust_begin_panic(msg: fmt::Arguments,
- file: &'static str,
- line: u32,
- col: u32) -> ! {
- begin_panic_fmt(&msg, &(file, line, col))
-}
-
-/// Entry point of panic from the libcore crate.
-#[cfg(not(test))]
-#[cfg(not(stage0))]
#[panic_implementation]
#[unwind(allowed)]
pub fn rust_begin_panic(info: &PanicInfo) -> ! {
@@ -368,78 +356,54 @@ pub fn rust_begin_panic(info: &PanicInfo) -> ! {
/// site as much as possible (so that `panic!()` has as low an impact
/// on (e.g.) the inlining of other functions as possible), by moving
/// the actual formatting into this shared place.
-#[cfg(stage0)]
#[unstable(feature = "libstd_sys_internals",
reason = "used by the panic! macro",
issue = "0")]
#[inline(never)] #[cold]
pub fn begin_panic_fmt(msg: &fmt::Arguments,
file_line_col: &(&'static str, u32, u32)) -> ! {
- // 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).
-
- rust_panic_with_hook(&mut PanicPayload::new(msg), Some(msg), file_line_col);
-}
-
-// NOTE(stage0) move into `continue_panic_fmt` on next stage0 update
-struct PanicPayload<'a> {
- inner: &'a fmt::Arguments<'a>,
- string: Option<String>,
+ let (file, line, col) = *file_line_col;
+ let info = PanicInfo::internal_constructor(
+ Some(msg),
+ Location::internal_constructor(file, line, col),
+ );
+ continue_panic_fmt(&info)
}
-impl<'a> PanicPayload<'a> {
- fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> {
- PanicPayload { inner, string: None }
+fn continue_panic_fmt(info: &PanicInfo) -> ! {
+ struct PanicPayload<'a> {
+ inner: &'a fmt::Arguments<'a>,
+ string: Option<String>,
}
- fn fill(&mut self) -> &mut String {
- use fmt::Write;
+ impl<'a> PanicPayload<'a> {
+ fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> {
+ PanicPayload { inner, string: None }
+ }
- let inner = self.inner;
- self.string.get_or_insert_with(|| {
- let mut s = String::new();
- drop(s.write_fmt(*inner));
- s
- })
- }
-}
+ fn fill(&mut self) -> &mut String {
+ use fmt::Write;
-unsafe impl<'a> BoxMeUp for PanicPayload<'a> {
- fn box_me_up(&mut self) -> *mut (Any + Send) {
- let contents = mem::replace(self.fill(), String::new());
- Box::into_raw(Box::new(contents))
+ let inner = self.inner;
+ self.string.get_or_insert_with(|| {
+ let mut s = String::new();
+ drop(s.write_fmt(*inner));
+ s
+ })
+ }
}
- fn get(&mut self) -> &(Any + Send) {
- self.fill()
- }
-}
+ 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))
+ }
-/// The entry point for panicking with a formatted message.
-///
-/// This is designed to reduce the amount of code required at the call
-/// site as much as possible (so that `panic!()` has as low an impact
-/// on (e.g.) the inlining of other functions as possible), by moving
-/// the actual formatting into this shared place.
-#[cfg(not(stage0))]
-#[unstable(feature = "libstd_sys_internals",
- reason = "used by the panic! macro",
- issue = "0")]
-#[inline(never)] #[cold]
-pub fn begin_panic_fmt(msg: &fmt::Arguments,
- file_line_col: &(&'static str, u32, u32)) -> ! {
- 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 get(&mut self) -> &(dyn Any + Send) {
+ self.fill()
+ }
+ }
-#[cfg(not(stage0))]
-fn continue_panic_fmt(info: &PanicInfo) -> ! {
// 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
@@ -480,15 +444,15 @@ pub fn begin_panic<M: Any + Send>(msg: M, file_line_col: &(&'static str, u32, u3
}
unsafe impl<A: Send + 'static> BoxMeUp for PanicPayload<A> {
- fn box_me_up(&mut self) -> *mut (Any + Send) {
+ fn box_me_up(&mut self) -> *mut (dyn Any + Send) {
let data = match self.inner.take() {
- Some(a) => Box::new(a) as Box<Any + Send>,
+ Some(a) => Box::new(a) as Box<dyn Any + Send>,
None => Box::new(()),
};
Box::into_raw(data)
}
- fn get(&mut self) -> &(Any + Send) {
+ fn get(&mut self) -> &(dyn Any + Send) {
match self.inner {
Some(ref a) => a,
None => &(),
@@ -502,7 +466,7 @@ pub fn begin_panic<M: Any + Send>(msg: M, file_line_col: &(&'static str, u32, u3
/// 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 BoxMeUp,
+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;
@@ -557,17 +521,17 @@ fn rust_panic_with_hook(payload: &mut BoxMeUp,
}
/// 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);
- struct RewrapBox(Box<Any + Send>);
+ struct RewrapBox(Box<dyn Any + Send>);
unsafe impl BoxMeUp for RewrapBox {
- fn box_me_up(&mut self) -> *mut (Any + Send) {
+ fn box_me_up(&mut self) -> *mut (dyn Any + Send) {
Box::into_raw(mem::replace(&mut self.0, Box::new(())))
}
- fn get(&mut self) -> &(Any + Send) {
+ fn get(&mut self) -> &(dyn Any + Send) {
&*self.0
}
}
@@ -578,9 +542,9 @@ pub fn update_count_then_panic(msg: Box<Any + Send>) -> ! {
/// 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(mut msg: &mut BoxMeUp) -> ! {
+pub fn rust_panic(mut msg: &mut dyn BoxMeUp) -> ! {
let code = unsafe {
- let obj = &mut msg as *mut &mut BoxMeUp;
+ 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/ctr-std/src/path.rs b/ctr-std/src/path.rs
index 27f57bd..ae7b632 100644
--- a/ctr-std/src/path.rs
+++ b/ctr-std/src/path.rs
@@ -1045,8 +1045,6 @@ impl<'a> cmp::Ord for Components<'a> {
/// # Examples
///
/// ```
-/// #![feature(path_ancestors)]
-///
/// use std::path::Path;
///
/// let path = Path::new("/foo/bar");
@@ -1059,26 +1057,23 @@ impl<'a> cmp::Ord for Components<'a> {
/// [`ancestors`]: struct.Path.html#method.ancestors
/// [`Path`]: struct.Path.html
#[derive(Copy, Clone, Debug)]
-#[unstable(feature = "path_ancestors", issue = "48581")]
+#[stable(feature = "path_ancestors", since = "1.28.0")]
pub struct Ancestors<'a> {
next: Option<&'a Path>,
}
-#[unstable(feature = "path_ancestors", issue = "48581")]
+#[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 = match next {
- Some(path) => path.parent(),
- None => None,
- };
+ self.next = next.and_then(Path::parent);
next
}
}
-#[unstable(feature = "path_ancestors", issue = "48581")]
+#[stable(feature = "path_ancestors", since = "1.28.0")]
impl<'a> FusedIterator for Ancestors<'a> {}
////////////////////////////////////////////////////////////////////////////////
@@ -1415,6 +1410,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 {
@@ -1737,9 +1740,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
///
@@ -1833,7 +1838,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`
///
@@ -1893,8 +1898,6 @@ impl Path {
/// # Examples
///
/// ```
- /// #![feature(path_ancestors)]
- ///
/// use std::path::Path;
///
/// let mut ancestors = Path::new("/foo/bar").ancestors();
@@ -1906,7 +1909,7 @@ impl Path {
///
/// [`None`]: ../../std/option/enum.Option.html#variant.None
/// [`parent`]: struct.Path.html#method.parent
- #[unstable(feature = "path_ancestors", issue = "48581")]
+ #[stable(feature = "path_ancestors", since = "1.28.0")]
pub fn ancestors(&self) -> Ancestors {
Ancestors {
next: Some(&self),
diff --git a/ctr-std/src/prelude/v1.rs b/ctr-std/src/prelude/v1.rs
index feedd4e..53763da 100644
--- a/ctr-std/src/prelude/v1.rs
+++ b/ctr-std/src/prelude/v1.rs
@@ -12,42 +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;
+#[doc(no_inline)]
+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/ctr-std/src/process.rs b/ctr-std/src/process.rs
index 732f43c..9dd0767 100644
--- a/ctr-std/src/process.rs
+++ b/ctr-std/src/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
};
diff --git a/ctr-std/src/rt.rs b/ctr-std/src/rt.rs
index e139276..fdaf2a8 100644
--- a/ctr-std/src/rt.rs
+++ b/ctr-std/src/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;
diff --git a/ctr-std/src/sync/mod.rs b/ctr-std/src/sync/mod.rs
index 642b284..e12ef8d 100644
--- a/ctr-std/src/sync/mod.rs
+++ b/ctr-std/src/sync/mod.rs
@@ -18,7 +18,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
-pub use alloc_crate::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/ctr-std/src/sync/mpsc/mod.rs b/ctr-std/src/sync/mpsc/mod.rs
index 2dd3aeb..59cf741 100644
--- a/ctr-std/src/sync/mpsc/mod.rs
+++ b/ctr-std/src/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/ctr-std/src/sync/mpsc/select.rs b/ctr-std/src/sync/mpsc/select.rs
index 9310dad..a7a284c 100644
--- a/ctr-std/src/sync/mpsc/select.rs
+++ b/ctr-std/src/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)
diff --git a/ctr-std/src/sync/mutex.rs b/ctr-std/src/sync/mutex.rs
index f3503b0..e5a4106 100644
--- a/ctr-std/src/sync/mutex.rs
+++ b/ctr-std/src/sync/mutex.rs
@@ -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/ctr-std/src/sync/once.rs b/ctr-std/src/sync/once.rs
index 7eb7be2..f6cb8be 100644
--- a/ctr-std/src/sync/once.rs
+++ b/ctr-std/src/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
@@ -149,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 {
@@ -178,6 +176,10 @@ 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
///
/// ```
@@ -218,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
}
@@ -275,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
}
@@ -299,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 {
@@ -390,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.
diff --git a/ctr-std/src/sys/cloudabi/abi/cloudabi.rs b/ctr-std/src/sys/cloudabi/abi/cloudabi.rs
index 2909db5..cd9a5ad 100644
--- a/ctr-std/src/sys/cloudabi/abi/cloudabi.rs
+++ b/ctr-std/src/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/ctr-std/src/sys/cloudabi/backtrace.rs b/ctr-std/src/sys/cloudabi/backtrace.rs
index 1b97018..2c43b59 100644
--- a/ctr-std/src/sys/cloudabi/backtrace.rs
+++ b/ctr-std/src/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,14 +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,
- inline_context: 0,
- };
- 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/ctr-std/src/sys/cloudabi/thread.rs b/ctr-std/src/sys/cloudabi/thread.rs
index 5d66936..8cca47e 100644
--- a/ctr-std/src/sys/cloudabi/thread.rs
+++ b/ctr-std/src/sys/cloudabi/thread.rs
@@ -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();
diff --git a/ctr-std/src/sys/horizon/net.rs b/ctr-std/src/sys/horizon/net.rs
index b6af433..14c58eb 100644
--- a/ctr-std/src/sys/horizon/net.rs
+++ b/ctr-std/src/sys/horizon/net.rs
@@ -148,7 +148,9 @@ impl Socket {
let mut pollfd = libc::pollfd {
fd: self.0.raw(),
- events: libc::POLLOUT,
+ // supposed to be `libc::POLLOUT`, but the value in the `libc` crate is currently
+ // incorrect for the 3DS
+ events: 0x10,
revents: 0,
};
@@ -184,9 +186,9 @@ impl Socket {
}
0 => {}
_ => {
- // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
- // for POLLHUP rather than read readiness
- if pollfd.revents & libc::POLLHUP != 0 {
+ // `libc::POLLHUP` should be 0x4, but the constant is currently defined
+ // incorrectly for 3DS. So we just specifiy it manually for now.
+ if pollfd.revents & 0x4 != 0 {
let e = self.take_error()?
.unwrap_or_else(|| {
io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP")
@@ -343,8 +345,7 @@ impl Socket {
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
- let mut nonblocking = nonblocking as libc::c_int;
- cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO as u32, &mut nonblocking) }).map(|_| ())
+ self.0.set_nonblocking(nonblocking)
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
diff --git a/ctr-std/src/sys/mod.rs b/ctr-std/src/sys/mod.rs
index d0ed80e..9aa6662 100644
--- a/ctr-std/src/sys/mod.rs
+++ b/ctr-std/src/sys/mod.rs
@@ -70,6 +70,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
@@ -83,11 +84,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/ctr-std/src/sys/redox/args.rs b/ctr-std/src/sys/redox/args.rs
index 59ae2a7..556ed77 100644
--- a/ctr-std/src/sys/redox/args.rs
+++ b/ctr-std/src/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/ctr-std/src/sys/redox/backtrace/tracing.rs b/ctr-std/src/sys/redox/backtrace/tracing.rs
index bb70ca3..c0414b7 100644
--- a/ctr-std/src/sys/redox/backtrace/tracing.rs
+++ b/ctr-std/src/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,14 +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,
- inline_context: 0,
- };
- 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/ctr-std/src/sys/redox/ext/mod.rs b/ctr-std/src/sys/redox/ext/mod.rs
index 9fd8d6c..cb2c75a 100644
--- a/ctr-std/src/sys/redox/ext/mod.rs
+++ b/ctr-std/src/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/ctr-std/src/sys/redox/ext/net.rs b/ctr-std/src/sys/redox/ext/net.rs
new file mode 100644
index 0000000..2ab7770
--- /dev/null
+++ b/ctr-std/src/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/ctr-std/src/sys/redox/fd.rs b/ctr-std/src/sys/redox/fd.rs
index ba7bbdc..e04e279 100644
--- a/ctr-std/src/sys/redox/fd.rs
+++ b/ctr-std/src/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/ctr-std/src/sys/redox/net/mod.rs b/ctr-std/src/sys/redox/net/mod.rs
index 0291d7f..67f2223 100644
--- a/ctr-std/src/sys/redox/net/mod.rs
+++ b/ctr-std/src/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/ctr-std/src/sys/redox/net/netc.rs b/ctr-std/src/sys/redox/net/netc.rs
index d443a4d..b6d9f45 100644
--- a/ctr-std/src/sys/redox/net/netc.rs
+++ b/ctr-std/src/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/ctr-std/src/sys/redox/net/udp.rs b/ctr-std/src/sys/redox/net/udp.rs
index 2ed67bd..22af020 100644
--- a/ctr-std/src/sys/redox/net/udp.rs
+++ b/ctr-std/src/sys/redox/net/udp.rs
@@ -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"))
diff --git a/ctr-std/src/sys/redox/os.rs b/ctr-std/src/sys/redox/os.rs
index 480765b..5822216 100644
--- a/ctr-std/src/sys/redox/os.rs
+++ b/ctr-std/src/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/ctr-std/src/sys/redox/process.rs b/ctr-std/src/sys/redox/process.rs
index d0b94e1..2037616 100644
--- a/ctr-std/src/sys/redox/process.rs
+++ b/ctr-std/src/sys/redox/process.rs
@@ -13,6 +13,7 @@ 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;
@@ -51,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>,
@@ -122,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);
}
@@ -296,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();
diff --git a/ctr-std/src/sys/redox/thread.rs b/ctr-std/src/sys/redox/thread.rs
index 110d46c..f417708 100644
--- a/ctr-std/src/sys/redox/thread.rs
+++ b/ctr-std/src/sys/redox/thread.rs
@@ -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))?;
diff --git a/ctr-std/src/sys/unix/args.rs b/ctr-std/src/sys/unix/args.rs
index e1c7ffc..c3c033d 100644
--- a/ctr-std/src/sys/unix/args.rs
+++ b/ctr-std/src/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/ctr-std/src/sys/unix/backtrace/tracing/gcc_s.rs b/ctr-std/src/sys/unix/backtrace/tracing/gcc_s.rs
index 1b92fc0..6e84156 100644
--- a/ctr-std/src/sys/unix/backtrace/tracing/gcc_s.rs
+++ b/ctr-std/src/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,14 +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,
- inline_context: 0,
- };
- 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/ctr-std/src/sys/unix/condvar.rs b/ctr-std/src/sys/unix/condvar.rs
index 4f878d8..2007da7 100644
--- a/ctr-std/src/sys/unix/condvar.rs
+++ b/ctr-std/src/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/ctr-std/src/sys/unix/env.rs b/ctr-std/src/sys/unix/env.rs
index 00cf7ec..ad116c5 100644
--- a/ctr-std/src/sys/unix/env.rs
+++ b/ctr-std/src/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/ctr-std/src/sys/unix/ext/fs.rs b/ctr-std/src/sys/unix/ext/fs.rs
index 4e98101..507e9d8 100644
--- a/ctr-std/src/sys/unix/ext/fs.rs
+++ b/ctr-std/src/sys/unix/ext/fs.rs
@@ -59,6 +59,78 @@ pub trait FileExt {
#[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.
@@ -93,6 +165,61 @@ pub trait FileExt {
/// ```
#[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")]
diff --git a/ctr-std/src/sys/unix/ext/mod.rs b/ctr-std/src/sys/unix/ext/mod.rs
index c221f7c..88e4237 100644
--- a/ctr-std/src/sys/unix/ext/mod.rs
+++ b/ctr-std/src/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/ctr-std/src/sys/unix/ext/net.rs b/ctr-std/src/sys/unix/ext/net.rs
index e277b1a..55f43cc 100644
--- a/ctr-std/src/sys/unix/ext/net.rs
+++ b/ctr-std/src/sys/unix/ext/net.rs
@@ -524,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()
@@ -846,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()
diff --git a/ctr-std/src/sys/unix/fast_thread_local.rs b/ctr-std/src/sys/unix/fast_thread_local.rs
index 6cdbe5d..c13a0fe 100644
--- a/ctr-std/src/sys/unix/fast_thread_local.rs
+++ b/ctr-std/src/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/ctr-std/src/sys/unix/fs.rs b/ctr-std/src/sys/unix/fs.rs
index 7743403..7a89d98 100644
--- a/ctr-std/src/sys/unix/fs.rs
+++ b/ctr-std/src/sys/unix/fs.rs
@@ -25,10 +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::{fstatat, dirfd};
+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",
@@ -57,7 +59,10 @@ struct InnerReadDir {
}
#[derive(Clone)]
-pub struct ReadDir(Arc<InnerReadDir>);
+pub struct ReadDir {
+ inner: Arc<InnerReadDir>,
+ end_of_stream: bool,
+}
struct Dir(*mut libc::DIR);
@@ -213,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.0.root, f)
+ fmt::Debug::fmt(&*self.inner.root, f)
}
}
@@ -229,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.0.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.
@@ -257,6 +262,10 @@ 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(),
@@ -264,7 +273,14 @@ impl Iterator for ReadDir {
};
let mut entry_ptr = ptr::null_mut();
loop {
- if readdir64_r(self.0.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() {
@@ -287,7 +303,7 @@ impl Drop for Dir {
impl DirEntry {
pub fn path(&self) -> PathBuf {
- self.dir.0.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 {
@@ -296,13 +312,10 @@ impl DirEntry {
#[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.0.dirp.0)})?;
+ let fd = cvt(unsafe {dirfd(self.dir.inner.dirp.0)})?;
let mut stat: stat64 = unsafe { mem::zeroed() };
cvt(unsafe {
- fstatat(fd,
- self.entry.d_name.as_ptr(),
- &mut stat as *mut _ as *mut _,
- libc::AT_SYMLINK_NOFOLLOW)
+ fstatat64(fd, self.entry.d_name.as_ptr(), &mut stat, libc::AT_SYMLINK_NOFOLLOW)
})?;
Ok(FileAttr { stat: stat })
}
@@ -312,12 +325,12 @@ impl DirEntry {
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 }),
@@ -339,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
}
@@ -370,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()
@@ -692,7 +707,10 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
Err(Error::last_os_error())
} else {
let inner = InnerReadDir { dirp: Dir(ptr), root };
- Ok(ReadDir(Arc::new(inner)))
+ Ok(ReadDir{
+ inner: Arc::new(inner),
+ end_of_stream: false,
+ })
}
}
}
@@ -787,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 })
}
@@ -796,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 })
}
diff --git a/ctr-std/src/sys/unix/mod.rs b/ctr-std/src/sys/unix/mod.rs
index c1298e5..c738003 100644
--- a/ctr-std/src/sys/unix/mod.rs
+++ b/ctr-std/src/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;
diff --git a/ctr-std/src/sys/unix/mutex.rs b/ctr-std/src/sys/unix/mutex.rs
index 52cf3f9..1d447de 100644
--- a/ctr-std/src/sys/unix/mutex.rs
+++ b/ctr-std/src/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/ctr-std/src/sys/unix/os.rs b/ctr-std/src/sys/unix/os.rs
index 4c86fdd..f8f0bbd 100644
--- a/ctr-std/src/sys/unix/os.rs
+++ b/ctr-std/src/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(|_| ())
}
}
@@ -572,7 +563,7 @@ fn glibc_version_cstr() -> Option<&'static CStr> {
// 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();
+ 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/ctr-std/src/sys/unix/process/process_common.rs b/ctr-std/src/sys/unix/process/process_common.rs
index 6396bb3..77f125f 100644
--- a/ctr-std/src/sys/unix/process/process_common.rs
+++ b/ctr-std/src/sys/unix/process/process_common.rs
@@ -52,7 +52,7 @@ pub struct Command {
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>,
@@ -155,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);
}
diff --git a/ctr-std/src/sys/unix/rand.rs b/ctr-std/src/sys/unix/rand.rs
index caa1894..01c0ada 100644
--- a/ctr-std/src/sys/unix/rand.rs
+++ b/ctr-std/src/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/ctr-std/src/sys/unix/thread.rs b/ctr-std/src/sys/unix/thread.rs
index 7fdecc9..f3a45d2 100644
--- a/ctr-std/src/sys/unix/thread.rs
+++ b/ctr-std/src/sys/unix/thread.rs
@@ -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.
}
diff --git a/ctr-std/src/sys/unix/time.rs b/ctr-std/src/sys/unix/time.rs
index 89786eb..0b1fb72 100644
--- a/ctr-std/src/sys/unix/time.rs
+++ b/ctr-std/src/sys/unix/time.rs
@@ -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/ctr-std/src/sys/wasm/os.rs b/ctr-std/src/sys/wasm/os.rs
index 23ca175..0cb991e 100644
--- a/ctr-std/src/sys/wasm/os.rs
+++ b/ctr-std/src/sys/wasm/os.rs
@@ -21,7 +21,7 @@ pub fn errno() -> i32 {
}
pub fn error_string(_errno: i32) -> String {
- format!("operation successful")
+ "operation successful".to_string()
}
pub fn getcwd() -> io::Result<PathBuf> {
diff --git a/ctr-std/src/sys/wasm/thread.rs b/ctr-std/src/sys/wasm/thread.rs
index 728e678..8173a62 100644
--- a/ctr-std/src/sys/wasm/thread.rs
+++ b/ctr-std/src/sys/wasm/thread.rs
@@ -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()
diff --git a/ctr-std/src/sys/windows/backtrace/mod.rs b/ctr-std/src/sys/windows/backtrace/mod.rs
index 82498ad..f64cae8 100644
--- a/ctr-std/src/sys/windows/backtrace/mod.rs
+++ b/ctr-std/src/sys/windows/backtrace/mod.rs
@@ -46,110 +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 StackWalkEx = sym!(dbghelp, "StackWalkEx", StackWalkExFn)?;
+
+ // 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::STACKFRAME_EX = unsafe { mem::zeroed() };
- frame.StackFrameSize = mem::size_of_val(&frame) as c::DWORD;
- 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!
+ 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() &&
- StackWalkEx(image, process, thread, &mut frame, &mut context,
- ptr::null_mut(),
- ptr::null_mut(),
- ptr::null_mut(),
- ptr::null_mut(),
- 0) == c::TRUE
- {
- let addr = (frame.AddrPC.Offset - 1) as *const u8;
-
- frames[i] = Frame {
- symbol_addr: addr,
- exact_position: addr,
- inline_context: frame.InlineFrameContext,
- };
- 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 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;
-
-#[cfg(target_arch = "x86")]
-fn init_frame(frame: &mut c::STACKFRAME_EX,
- 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::STACKFRAME_EX,
- 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/ctr-std/src/sys/windows/backtrace/printing/mod.rs b/ctr-std/src/sys/windows/backtrace/printing/mod.rs
index 3e566f6..251d502 100644
--- a/ctr-std/src/sys/windows/backtrace/printing/mod.rs
+++ b/ctr-std/src/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/ctr-std/src/sys/windows/backtrace/printing/msvc.rs b/ctr-std/src/sys/windows/backtrace/printing/msvc.rs
index 967df1c..c8b946b 100644
--- a/ctr-std/src/sys/windows/backtrace/printing/msvc.rs
+++ b/ctr-std/src/sys/windows/backtrace/printing/msvc.rs
@@ -10,29 +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;
type SymFromInlineContextFn =
- unsafe extern "system" fn(c::HANDLE, u64, c::ULONG,
- *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
-type SymGetLineFromInlineContextFn =
- unsafe extern "system" fn(c::HANDLE, u64, c::ULONG,
- u64, *mut c::DWORD, *mut c::IMAGEHLP_LINE64) -> c::BOOL;
+ 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;
+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 SymFromInlineContext = sym!(&context.dbghelp,
- "SymFromInlineContext",
- SymFromInlineContextFn)?;
+ 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;
@@ -41,14 +120,13 @@ pub fn resolve_symname<F>(frame: Frame,
// due to struct alignment.
info.SizeOfStruct = 88;
- let mut displacement = 0u64;
- let ret = SymFromInlineContext(context.handle,
- frame.symbol_addr as u64,
- frame.inline_context,
- &mut displacement,
- &mut info);
- let valid_range = if ret == c::TRUE &&
- frame.symbol_addr as usize >= info.Address as usize {
+ 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 {
@@ -67,30 +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 SymGetLineFromInlineContext = sym!(&context.dbghelp,
- "SymGetLineFromInlineContext",
- SymGetLineFromInlineContextFn)?;
+ 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 = SymGetLineFromInlineContext(context.handle,
- frame.exact_position as u64,
- frame.inline_context,
- 0,
- &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/ctr-std/src/sys/windows/c.rs b/ctr-std/src/sys/windows/c.rs
index 6d929f2..e514a56 100644
--- a/ctr-std/src/sys/windows/c.rs
+++ b/ctr-std/src/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 {
@@ -637,6 +642,22 @@ pub struct STACKFRAME_EX {
#[repr(C)]
#[cfg(feature = "backtrace")]
+pub struct STACKFRAME64 {
+ 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,
+}
+
+#[repr(C)]
+#[cfg(feature = "backtrace")]
pub struct KDHELP64 {
pub Thread: u64,
pub ThCallbackStack: DWORD,
@@ -773,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/ctr-std/src/sys/windows/ext/ffi.rs b/ctr-std/src/sys/windows/ext/ffi.rs
index 98d4355..bae0d02 100644
--- a/ctr-std/src/sys/windows/ext/ffi.rs
+++ b/ctr-std/src/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")]
diff --git a/ctr-std/src/sys/windows/ext/mod.rs b/ctr-std/src/sys/windows/ext/mod.rs
index 4b458d2..1f10609 100644
--- a/ctr-std/src/sys/windows/ext/mod.rs
+++ b/ctr-std/src/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/ctr-std/src/sys/windows/mod.rs b/ctr-std/src/sys/windows/mod.rs
index 0d12ecf..ccf79de 100644
--- a/ctr-std/src/sys/windows/mod.rs
+++ b/ctr-std/src/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/ctr-std/src/sys/windows/process.rs b/ctr-std/src/sys/windows/process.rs
index be442f4..4974a8d 100644
--- a/ctr-std/src/sys/windows/process.rs
+++ b/ctr-std/src/sys/windows/process.rs
@@ -487,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;
}
@@ -498,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/ctr-std/src/sys/windows/thread.rs b/ctr-std/src/sys/windows/thread.rs
index b6f6330..85588cc 100644
--- a/ctr-std/src/sys/windows/thread.rs
+++ b/ctr-std/src/sys/windows/thread.rs
@@ -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())
diff --git a/ctr-std/src/sys_common/at_exit_imp.rs b/ctr-std/src/sys_common/at_exit_imp.rs
index 26da51c..76e5df2 100644
--- a/ctr-std/src/sys_common/at_exit_imp.rs
+++ b/ctr-std/src/sys_common/at_exit_imp.rs
@@ -14,17 +14,22 @@
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/ctr-std/src/sys_common/backtrace.rs b/ctr-std/src/sys_common/backtrace.rs
index 20109d2..7737178 100644
--- a/ctr-std/src/sys_common/backtrace.rs
+++ b/ctr-std/src/sys_common/backtrace.rs
@@ -49,7 +49,7 @@ pub struct Frame {
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.
@@ -62,7 +62,7 @@ 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(),
@@ -156,16 +156,15 @@ pub fn log_enabled() -> Option<PrintFormat> {
_ => 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,
@@ -177,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() {
@@ -202,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<()> {
@@ -254,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.
@@ -263,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/ctr-std/src/sys_common/mutex.rs b/ctr-std/src/sys_common/mutex.rs
index d1a7387..c6d531c 100644
--- a/ctr-std/src/sys_common/mutex.rs
+++ b/ctr-std/src/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/ctr-std/src/sys_common/poison.rs b/ctr-std/src/sys_common/poison.rs
index e74c40a..1625efe 100644
--- a/ctr-std/src/sys_common/poison.rs
+++ b/ctr-std/src/sys_common/poison.rs
@@ -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/ctr-std/src/sys_common/remutex.rs b/ctr-std/src/sys_common/remutex.rs
index 022056f..071a3a2 100644
--- a/ctr-std/src/sys_common/remutex.rs
+++ b/ctr-std/src/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.
diff --git a/ctr-std/src/sys_common/thread.rs b/ctr-std/src/sys_common/thread.rs
index da6f58e..86a5e2b 100644
--- a/ctr-std/src/sys_common/thread.rs
+++ b/ctr-std/src/sys_common/thread.rs
@@ -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/ctr-std/src/sys_common/thread_local.rs b/ctr-std/src/sys_common/thread_local.rs
index d0d6224..bb72cb0 100644
--- a/ctr-std/src/sys_common/thread_local.rs
+++ b/ctr-std/src/sys_common/thread_local.rs
@@ -161,14 +161,15 @@ 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();
rtassert!(key != 0);
return key
}
diff --git a/ctr-std/src/sys_common/wtf8.rs b/ctr-std/src/sys_common/wtf8.rs
index 14a2555..45204b5 100644
--- a/ctr-std/src/sys_common/wtf8.rs
+++ b/ctr-std/src/sys_common/wtf8.rs
@@ -76,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
}
}
@@ -101,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) })
}
}
@@ -305,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);
@@ -525,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
}
}
@@ -630,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
}
}
@@ -642,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
}
}
@@ -1245,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/ctr-std/src/tests/env.rs b/ctr-std/src/tests/env.rs
index d437652..8acb8a4 100644
--- a/ctr-std/src/tests/env.rs
+++ b/ctr-std/src/tests/env.rs
@@ -11,7 +11,6 @@
extern crate rand;
use std::env::*;
-use std::iter::repeat;
use std::ffi::{OsString, OsStr};
use rand::Rng;
@@ -72,7 +71,7 @@ fn test_var_big() {
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_env_set_get_huge() {
let n = make_rand_name();
- let s = repeat("x").take(10000).collect::<String>();
+ let s = "x".repeat(10000);
set_var(&n, &s);
eq(var_os(&n), Some(&s));
remove_var(&n);
diff --git a/ctr-std/src/thread/local.rs b/ctr-std/src/thread/local.rs
index 40d3280..a170abb 100644
--- a/ctr-std/src/thread/local.rs
+++ b/ctr-std/src/thread/local.rs
@@ -276,7 +276,7 @@ impl<T: 'static> LocalKey<T> {
///
/// 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
///
diff --git a/ctr-std/src/thread/mod.rs b/ctr-std/src/thread/mod.rs
index 1b976b7..61c6084 100644
--- a/ctr-std/src/thread/mod.rs
+++ b/ctr-std/src/thread/mod.rs
@@ -731,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`.
@@ -766,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();
///
@@ -796,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 {
@@ -882,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"),
}
@@ -931,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)
}
}
@@ -1172,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
@@ -1273,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.
///
@@ -1435,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;
@@ -1482,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)());
@@ -1528,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>());