Browse Source

Merge pull request #73 from FenrirWolf/update-2018-08-18

Update for nightly-2018-08-18
pull/10/head
FenrirWolf 6 years ago committed by GitHub
parent
commit
15cb3c1e91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      .travis.yml
  2. 121
      ctr-std/src/alloc.rs
  3. 290
      ctr-std/src/ascii.rs
  4. 11
      ctr-std/src/build.rs
  5. 38
      ctr-std/src/collections/hash/map.rs
  6. 24
      ctr-std/src/collections/hash/set.rs
  7. 7
      ctr-std/src/collections/hash/table.rs
  8. 10
      ctr-std/src/collections/mod.rs
  9. 25
      ctr-std/src/env.rs
  10. 93
      ctr-std/src/error.rs
  11. 11
      ctr-std/src/f32.rs
  12. 11
      ctr-std/src/f64.rs
  13. 43
      ctr-std/src/ffi/c_str.rs
  14. 48
      ctr-std/src/ffi/os_str.rs
  15. 6
      ctr-std/src/fs.rs
  16. 116
      ctr-std/src/future.rs
  17. 85
      ctr-std/src/io/buffered.rs
  18. 57
      ctr-std/src/io/cursor.rs
  19. 25
      ctr-std/src/io/error.rs
  20. 30
      ctr-std/src/io/lazy.rs
  21. 171
      ctr-std/src/io/mod.rs
  22. 40
      ctr-std/src/io/stdio.rs
  23. 2
      ctr-std/src/io/util.rs
  24. 58
      ctr-std/src/keyword_docs.rs
  25. 76
      ctr-std/src/lib.rs
  26. 80
      ctr-std/src/macros.rs
  27. 218
      ctr-std/src/net/ip.rs
  28. 7
      ctr-std/src/net/parser.rs
  29. 4
      ctr-std/src/net/tcp.rs
  30. 2
      ctr-std/src/net/udp.rs
  31. 389
      ctr-std/src/os/hermit/fs.rs
  32. 16
      ctr-std/src/os/hermit/mod.rs
  33. 27
      ctr-std/src/os/hermit/raw.rs
  34. 1
      ctr-std/src/os/mod.rs
  35. 6
      ctr-std/src/os/raw/mod.rs
  36. 30
      ctr-std/src/panic.rs
  37. 132
      ctr-std/src/panicking.rs
  38. 31
      ctr-std/src/path.rs
  39. 58
      ctr-std/src/prelude/v1.rs
  40. 37
      ctr-std/src/process.rs
  41. 2
      ctr-std/src/rt.rs
  42. 2
      ctr-std/src/sync/mod.rs
  43. 40
      ctr-std/src/sync/mpsc/mod.rs
  44. 2
      ctr-std/src/sync/mpsc/select.rs
  45. 4
      ctr-std/src/sync/mutex.rs
  46. 40
      ctr-std/src/sync/once.rs
  47. 18
      ctr-std/src/sys/cloudabi/abi/cloudabi.rs
  48. 18
      ctr-std/src/sys/cloudabi/backtrace.rs
  49. 2
      ctr-std/src/sys/cloudabi/thread.rs
  50. 13
      ctr-std/src/sys/horizon/net.rs
  51. 3
      ctr-std/src/sys/mod.rs
  52. 16
      ctr-std/src/sys/redox/args.rs
  53. 18
      ctr-std/src/sys/redox/backtrace/tracing.rs
  54. 1
      ctr-std/src/sys/redox/ext/mod.rs
  55. 769
      ctr-std/src/sys/redox/ext/net.rs
  56. 5
      ctr-std/src/sys/redox/fd.rs
  57. 4
      ctr-std/src/sys/redox/net/mod.rs
  58. 2
      ctr-std/src/sys/redox/net/netc.rs
  59. 2
      ctr-std/src/sys/redox/net/udp.rs
  60. 3
      ctr-std/src/sys/redox/os.rs
  61. 15
      ctr-std/src/sys/redox/process.rs
  62. 2
      ctr-std/src/sys/redox/thread.rs
  63. 19
      ctr-std/src/sys/unix/args.rs
  64. 18
      ctr-std/src/sys/unix/backtrace/tracing/gcc_s.rs
  65. 13
      ctr-std/src/sys/unix/condvar.rs
  66. 11
      ctr-std/src/sys/unix/env.rs
  67. 127
      ctr-std/src/sys/unix/ext/fs.rs
  68. 1
      ctr-std/src/sys/unix/ext/mod.rs
  69. 6
      ctr-std/src/sys/unix/ext/net.rs
  70. 7
      ctr-std/src/sys/unix/fast_thread_local.rs
  71. 56
      ctr-std/src/sys/unix/fs.rs
  72. 1
      ctr-std/src/sys/unix/mod.rs
  73. 9
      ctr-std/src/sys/unix/mutex.rs
  74. 39
      ctr-std/src/sys/unix/os.rs
  75. 6
      ctr-std/src/sys/unix/process/process_common.rs
  76. 29
      ctr-std/src/sys/unix/rand.rs
  77. 5
      ctr-std/src/sys/unix/thread.rs
  78. 4
      ctr-std/src/sys/unix/time.rs
  79. 2
      ctr-std/src/sys/wasm/os.rs
  80. 2
      ctr-std/src/sys/wasm/thread.rs
  81. 297
      ctr-std/src/sys/windows/backtrace/mod.rs
  82. 14
      ctr-std/src/sys/windows/backtrace/printing/mod.rs
  83. 196
      ctr-std/src/sys/windows/backtrace/printing/msvc.rs
  84. 82
      ctr-std/src/sys/windows/c.rs
  85. 3
      ctr-std/src/sys/windows/ext/ffi.rs
  86. 1
      ctr-std/src/sys/windows/ext/mod.rs
  87. 10
      ctr-std/src/sys/windows/mod.rs
  88. 8
      ctr-std/src/sys/windows/process.rs
  89. 5
      ctr-std/src/sys/windows/thread.rs
  90. 36
      ctr-std/src/sys_common/at_exit_imp.rs
  91. 21
      ctr-std/src/sys_common/backtrace.rs
  92. 32
      ctr-std/src/sys_common/mutex.rs
  93. 2
      ctr-std/src/sys_common/poison.rs
  94. 4
      ctr-std/src/sys_common/remutex.rs
  95. 2
      ctr-std/src/sys_common/thread.rs
  96. 5
      ctr-std/src/sys_common/thread_local.rs
  97. 14
      ctr-std/src/sys_common/wtf8.rs
  98. 3
      ctr-std/src/tests/env.rs
  99. 2
      ctr-std/src/thread/local.rs
  100. 37
      ctr-std/src/thread/mod.rs
  101. Some files were not shown because too many files have changed in this diff Show More

7
.travis.yml

@ -1,12 +1,7 @@
language: rust language: rust
rust: rust:
- nightly-2018-06-09 - nightly-2018-08-18
- nightly
matrix:
allow_failures:
- rust: nightly
install: install:
- set -eo pipefail - set -eo pipefail

121
ctr-std/src/alloc.rs

@ -8,61 +8,129 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // 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")] #![stable(feature = "alloc_module", since = "1.28.0")]
#[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::*;
use core::sync::atomic::{AtomicPtr, Ordering}; use core::sync::atomic::{AtomicPtr, Ordering};
use core::{mem, ptr}; use core::{mem, ptr};
use sys_common::util::dumb_print; 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()); 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, /// the runtime aborts. The default hook prints a message to standard error,
/// but this behavior can be customized with the [`set_oom_hook`] and /// but this behavior can be customized with the [`set_alloc_error_hook`] and
/// [`take_oom_hook`] functions. /// [`take_alloc_error_hook`] functions.
/// ///
/// The hook is provided with a `Layout` struct which contains information /// The hook is provided with a `Layout` struct which contains information
/// about the allocation that failed. /// about the allocation that failed.
/// ///
/// The OOM hook is a global resource. /// The allocation error hook is a global resource.
pub fn set_oom_hook(hook: fn(Layout)) { #[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn set_alloc_error_hook(hook: fn(Layout)) {
HOOK.store(hook as *mut (), Ordering::SeqCst); 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. /// 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); let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
if hook.is_null() { if hook.is_null() {
default_oom_hook default_alloc_error_hook
} else { } else {
unsafe { mem::transmute(hook) } 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())); dumb_print(format_args!("memory allocation of {} bytes failed", layout.size()));
} }
#[cfg(not(test))] #[cfg(not(test))]
#[doc(hidden)] #[doc(hidden)]
#[lang = "oom"] #[alloc_error_handler]
pub extern fn rust_oom(layout: Layout) -> ! { #[unstable(feature = "alloc_internals", issue = "0")]
pub fn rust_oom(layout: Layout) -> ! {
let hook = HOOK.load(Ordering::SeqCst); let hook = HOOK.load(Ordering::SeqCst);
let hook: fn(Layout) = if hook.is_null() { let hook: fn(Layout) = if hook.is_null() {
default_oom_hook default_alloc_error_hook
} else { } else {
unsafe { mem::transmute(hook) } unsafe { mem::transmute(hook) }
}; };
@ -73,8 +141,9 @@ pub extern fn rust_oom(layout: Layout) -> ! {
#[cfg(not(test))] #[cfg(not(test))]
#[doc(hidden)] #[doc(hidden)]
#[allow(unused_attributes)] #[allow(unused_attributes)]
#[unstable(feature = "alloc_internals", issue = "0")]
pub mod __default_lib_allocator { 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 symbol names src/librustc/middle/allocator.rs
// for signatures src/librustc_allocator/lib.rs // for signatures src/librustc_allocator/lib.rs
@ -85,7 +154,7 @@ pub mod __default_lib_allocator {
#[rustc_std_internal_symbol] #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 { pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
let layout = Layout::from_size_align_unchecked(size, align); let layout = Layout::from_size_align_unchecked(size, align);
System.alloc(layout) as *mut u8 System.alloc(layout)
} }
#[no_mangle] #[no_mangle]
@ -93,7 +162,7 @@ pub mod __default_lib_allocator {
pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
size: usize, size: usize,
align: 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] #[no_mangle]
@ -103,13 +172,13 @@ pub mod __default_lib_allocator {
align: usize, align: usize,
new_size: usize) -> *mut u8 { new_size: usize) -> *mut u8 {
let old_layout = Layout::from_size_align_unchecked(old_size, align); 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] #[no_mangle]
#[rustc_std_internal_symbol] #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 { pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
let layout = Layout::from_size_align_unchecked(size, align); let layout = Layout::from_size_align_unchecked(size, align);
System.alloc_zeroed(layout) as *mut u8 System.alloc_zeroed(layout)
} }
} }

290
ctr-std/src/ascii.rs

@ -154,160 +154,6 @@ pub trait AsciiExt {
/// [`to_ascii_lowercase`]: #tymethod.to_ascii_lowercase /// [`to_ascii_lowercase`]: #tymethod.to_ascii_lowercase
#[stable(feature = "ascii", since = "1.9.0")] #[stable(feature = "ascii", since = "1.9.0")]
fn make_ascii_lowercase(&mut self); 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 { 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")] #[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)] #[allow(deprecated)]
impl AsciiExt for u8 { impl AsciiExt for u8 {
type Owned = u8; type Owned = u8;
delegating_ascii_methods!(); delegating_ascii_methods!();
delegating_ascii_ctype_methods!();
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
@ -381,7 +192,6 @@ impl AsciiExt for char {
type Owned = char; type Owned = char;
delegating_ascii_methods!(); delegating_ascii_methods!();
delegating_ascii_ctype_methods!();
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
@ -390,56 +200,6 @@ impl AsciiExt for [u8] {
type Owned = Vec<u8>; type Owned = Vec<u8>;
delegating_ascii_methods!(); 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")] #[stable(feature = "rust1", since = "1.0.0")]
@ -448,54 +208,4 @@ impl AsciiExt for str {
type Owned = String; type Owned = String;
delegating_ascii_methods!(); 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())
}
} }

11
ctr-std/src/build.rs

@ -22,7 +22,6 @@ fn main() {
if cfg!(feature = "backtrace") && if cfg!(feature = "backtrace") &&
!target.contains("cloudabi") && !target.contains("cloudabi") &&
!target.contains("emscripten") && !target.contains("emscripten") &&
!target.contains("fuchsia") &&
!target.contains("msvc") && !target.contains("msvc") &&
!target.contains("wasm32") !target.contains("wasm32")
{ {
@ -68,10 +67,6 @@ fn main() {
println!("cargo:rustc-link-lib=userenv"); println!("cargo:rustc-link-lib=userenv");
println!("cargo:rustc-link-lib=shell32"); println!("cargo:rustc-link-lib=shell32");
} else if target.contains("fuchsia") { } 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=zircon");
println!("cargo:rustc-link-lib=fdio"); println!("cargo:rustc-link-lib=fdio");
} else if target.contains("cloudabi") { } else if target.contains("cloudabi") {
@ -109,7 +104,8 @@ fn build_libbacktrace(target: &str) -> Result<(), ()> {
} else { } else {
build.file("../libbacktrace/elf.c"); 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"); build.define("BACKTRACE_ELF_SIZE", "64");
} else { } else {
build.define("BACKTRACE_ELF_SIZE", "32"); build.define("BACKTRACE_ELF_SIZE", "32");
@ -126,7 +122,8 @@ fn build_libbacktrace(target: &str) -> Result<(), ()> {
if !target.contains("apple-ios") && if !target.contains("apple-ios") &&
!target.contains("solaris") && !target.contains("solaris") &&
!target.contains("redox") && !target.contains("redox") &&
!target.contains("android") { !target.contains("android") &&
!target.contains("haiku") {
build.define("HAVE_DL_ITERATE_PHDR", "1"); build.define("HAVE_DL_ITERATE_PHDR", "1");
} }
build.define("_GNU_SOURCE", "1"); build.define("_GNU_SOURCE", "1");

38
ctr-std/src/collections/hash/map.rs

@ -11,7 +11,7 @@
use self::Entry::*; use self::Entry::*;
use self::VacantEntryState::*; use self::VacantEntryState::*;
use alloc::CollectionAllocErr; use collections::CollectionAllocErr;
use cell::Cell; use cell::Cell;
use borrow::Borrow; use borrow::Borrow;
use cmp::max; use cmp::max;
@ -276,17 +276,31 @@ const DISPLACEMENT_THRESHOLD: usize = 128;
/// ``` /// ```
/// use std::collections::HashMap; /// use std::collections::HashMap;
/// ///
/// // type inference lets us omit an explicit type signature (which /// // Type inference lets us omit an explicit type signature (which
/// // would be `HashMap<&str, &str>` in this example). /// // would be `HashMap<String, String>` in this example).
/// let mut book_reviews = HashMap::new(); /// let mut book_reviews = HashMap::new();
/// ///
/// // review some books. /// // Review some books.
/// book_reviews.insert("Adventures of Huckleberry Finn", "My favorite book."); /// book_reviews.insert(
/// book_reviews.insert("Grimms' Fairy Tales", "Masterpiece."); /// "Adventures of Huckleberry Finn".to_string(),
/// book_reviews.insert("Pride and Prejudice", "Very enjoyable."); /// "My favorite book.".to_string(),
/// book_reviews.insert("The Adventures of Sherlock Holmes", "Eye lyked it alot."); /// );
/// 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") { /// if !book_reviews.contains_key("Les Misérables") {
/// println!("We've got {} reviews, but Les Misérables ain't one.", /// println!("We've got {} reviews, but Les Misérables ain't one.",
/// book_reviews.len()); /// 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. /// // oops, this review has a lot of spelling mistakes, let's delete it.
/// book_reviews.remove("The Adventures of Sherlock Holmes"); /// 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"]; /// 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) { /// match book_reviews.get(book) {
/// Some(review) => println!("{}: {}", book, review), /// Some(review) => println!("{}: {}", book, review),
/// None => println!("{} is unreviewed.", book) /// None => println!("{} is unreviewed.", book)
/// } /// }
/// } /// }
/// ///
/// // iterate over everything. /// // Iterate over everything.
/// for (book, review) in &book_reviews { /// for (book, review) in &book_reviews {
/// println!("{}: \"{}\"", book, review); /// println!("{}: \"{}\"", book, review);
/// } /// }

24
ctr-std/src/collections/hash/set.rs

@ -49,14 +49,14 @@ use super::map::{self, HashMap, Keys, RandomState};
/// ``` /// ```
/// use std::collections::HashSet; /// use std::collections::HashSet;
/// // Type inference lets us omit an explicit type signature (which /// // 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(); /// let mut books = HashSet::new();
/// ///
/// // Add some books. /// // Add some books.
/// books.insert("A Dance With Dragons"); /// books.insert("A Dance With Dragons".to_string());
/// books.insert("To Kill a Mockingbird"); /// books.insert("To Kill a Mockingbird".to_string());
/// books.insert("The Odyssey"); /// books.insert("The Odyssey".to_string());
/// books.insert("The Great Gatsby"); /// books.insert("The Great Gatsby".to_string());
/// ///
/// // Check for a specific one. /// // Check for a specific one.
/// if !books.contains("The Winds of Winter") { /// if !books.contains("The Winds of Winter") {
@ -80,17 +80,17 @@ use super::map::{self, HashMap, Keys, RandomState};
/// ``` /// ```
/// use std::collections::HashSet; /// use std::collections::HashSet;
/// #[derive(Hash, Eq, PartialEq, Debug)] /// #[derive(Hash, Eq, PartialEq, Debug)]
/// struct Viking<'a> { /// struct Viking {
/// name: &'a str, /// name: String,
/// power: usize, /// power: usize,
/// } /// }
/// ///
/// let mut vikings = HashSet::new(); /// let mut vikings = HashSet::new();
/// ///
/// vikings.insert(Viking { name: "Einar", power: 9 }); /// vikings.insert(Viking { name: "Einar".to_string(), power: 9 });
/// vikings.insert(Viking { name: "Einar", power: 9 }); /// vikings.insert(Viking { name: "Einar".to_string(), power: 9 });
/// vikings.insert(Viking { name: "Olaf", power: 4 }); /// vikings.insert(Viking { name: "Olaf".to_string(), power: 4 });
/// vikings.insert(Viking { name: "Harald", power: 8 }); /// vikings.insert(Viking { name: "Harald".to_string(), power: 8 });
/// ///
/// // Use derived implementation to print the vikings. /// // Use derived implementation to print the vikings.
/// for x in &vikings { /// for x in &vikings {
@ -104,7 +104,7 @@ use super::map::{self, HashMap, Keys, RandomState};
/// use std::collections::HashSet; /// use std::collections::HashSet;
/// ///
/// fn main() { /// fn main() {
/// let viking_names: HashSet<&str> = /// let viking_names: HashSet<&'static str> =
/// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect(); /// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect();
/// // use the values stored in the set /// // use the values stored in the set
/// } /// }

7
ctr-std/src/collections/hash/table.rs

@ -8,7 +8,8 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // 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 hash::{BuildHasher, Hash, Hasher};
use marker; use marker;
use mem::{size_of, needs_drop}; use mem::{size_of, needs_drop};
@ -699,7 +700,7 @@ impl<K, V> RawTable<K, V> {
// point into it. // point into it.
let (layout, _) = calculate_layout::<K, V>(capacity)?; let (layout, _) = calculate_layout::<K, V>(capacity)?;
let buffer = Global.alloc(layout).map_err(|e| match fallibility { let buffer = Global.alloc(layout).map_err(|e| match fallibility {
Infallible => oom(layout), Infallible => handle_alloc_error(layout),
Fallible => e, 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()) let (layout, _) = calculate_layout::<K, V>(self.capacity())
.unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() }); .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() });
unsafe { 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 // Remember how everything was allocated out of one buffer
// during initialization? We only need one call to free here. // during initialization? We only need one call to free here.
} }

10
ctr-std/src/collections/mod.rs

@ -424,13 +424,13 @@
#[doc(hidden)] #[doc(hidden)]
pub use ops::Bound; pub use ops::Bound;
#[stable(feature = "rust1", since = "1.0.0")] #[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")] #[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")] #[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")] #[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")] #[stable(feature = "rust1", since = "1.0.0")]
pub use self::hash_map::HashMap; pub use self::hash_map::HashMap;
@ -438,7 +438,7 @@ pub use self::hash_map::HashMap;
pub use self::hash_set::HashSet; pub use self::hash_set::HashSet;
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] #[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
pub use heap::CollectionAllocErr; pub use alloc_crate::collections::CollectionAllocErr;
mod hash; mod hash;

25
ctr-std/src/env.rs

@ -512,18 +512,20 @@ impl Error for JoinPathsError {
/// ///
/// # Unix /// # Unix
/// ///
/// Returns the value of the 'HOME' environment variable if it is set /// - 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 /// (including to an empty string).
/// home directory by invoking the `getpwuid_r` function on the UID of the /// - Otherwise, it tries to determine the home directory by invoking the `getpwuid_r` function
/// current user. /// 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 /// # Windows
/// ///
/// Returns the value of the 'HOME' environment variable if it is /// - Returns the value of the 'HOME' environment variable if it is set
/// set and not equal to the empty string. Otherwise, returns the value of the /// (including to an empty string).
/// 'USERPROFILE' environment variable if it is set and not equal to the empty /// - Otherwise, returns the value of the 'USERPROFILE' environment variable if it is set
/// string. If both do not exist, [`GetUserProfileDirectory`][msdn] is used to /// (including to an empty string).
/// return the appropriate path. /// - 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 /// [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; /// use std::env;
/// ///
/// match env::home_dir() { /// 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!"), /// 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")] #[stable(feature = "env", since = "1.0.0")]
pub fn home_dir() -> Option<PathBuf> { pub fn home_dir() -> Option<PathBuf> {
os_imp::home_dir() os_imp::home_dir()

93
ctr-std/src/error.rs

@ -23,13 +23,13 @@
// coherence challenge (e.g., specialization, neg impls, etc) we can // coherence challenge (e.g., specialization, neg impls, etc) we can
// reconsider what crate these items belong in. // reconsider what crate these items belong in.
use alloc::{AllocErr, LayoutErr, CannotReallocInPlace};
use any::TypeId; use any::TypeId;
use borrow::Cow; use borrow::Cow;
use cell; use cell;
use char; use char;
use core::array; use core::array;
use fmt::{self, Debug, Display}; use fmt::{self, Debug, Display};
use heap::{AllocErr, LayoutErr, CannotReallocInPlace};
use mem::transmute; use mem::transmute;
use num; use num;
use str; use str;
@ -49,6 +49,7 @@ use string;
/// ///
/// [`Result<T, E>`]: ../result/enum.Result.html /// [`Result<T, E>`]: ../result/enum.Result.html
/// [`Display`]: ../fmt/trait.Display.html /// [`Display`]: ../fmt/trait.Display.html
/// [`Debug`]: ../fmt/trait.Debug.html
/// [`cause`]: trait.Error.html#method.cause /// [`cause`]: trait.Error.html#method.cause
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub trait Error: Debug + Display { pub trait Error: Debug + Display {
@ -137,7 +138,7 @@ pub trait Error: Debug + Display {
/// } /// }
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[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` /// Get the `TypeId` of `self`
#[doc(hidden)] #[doc(hidden)]
@ -150,22 +151,22 @@ pub trait Error: Debug + Display {
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<'a, E: Error + 'a> From<E> for Box<Error + 'a> { impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
fn from(err: E) -> Box<Error + 'a> { fn from(err: E) -> Box<dyn Error + 'a> {
Box::new(err) Box::new(err)
} }
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<'a, E: Error + Send + Sync + 'a> From<E> for 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<Error + Send + Sync + 'a> { fn from(err: E) -> Box<dyn Error + Send + Sync + 'a> {
Box::new(err) Box::new(err)
} }
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl From<String> for Box<Error + Send + Sync> { impl From<String> for Box<dyn Error + Send + Sync> {
fn from(err: String) -> Box<Error + Send + Sync> { fn from(err: String) -> Box<dyn Error + Send + Sync> {
#[derive(Debug)] #[derive(Debug)]
struct StringError(String); struct StringError(String);
@ -184,38 +185,38 @@ impl From<String> for Box<Error + Send + Sync> {
} }
#[stable(feature = "string_box_error", since = "1.6.0")] #[stable(feature = "string_box_error", since = "1.6.0")]
impl From<String> for Box<Error> { impl From<String> for Box<dyn Error> {
fn from(str_err: String) -> Box<Error> { fn from(str_err: String) -> Box<dyn Error> {
let err1: Box<Error + Send + Sync> = From::from(str_err); let err1: Box<dyn Error + Send + Sync> = From::from(str_err);
let err2: Box<Error> = err1; let err2: Box<dyn Error> = err1;
err2 err2
} }
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b> From<&'b str> for Box<Error + Send + Sync + 'a> { impl<'a, 'b> From<&'b str> for Box<dyn Error + Send + Sync + 'a> {
fn from(err: &'b str) -> Box<Error + Send + Sync + 'a> { fn from(err: &'b str) -> Box<dyn Error + Send + Sync + 'a> {
From::from(String::from(err)) From::from(String::from(err))
} }
} }
#[stable(feature = "string_box_error", since = "1.6.0")] #[stable(feature = "string_box_error", since = "1.6.0")]
impl<'a> From<&'a str> for Box<Error> { impl<'a> From<&'a str> for Box<dyn Error> {
fn from(err: &'a str) -> Box<Error> { fn from(err: &'a str) -> Box<dyn Error> {
From::from(String::from(err)) From::from(String::from(err))
} }
} }
#[stable(feature = "cow_box_error", since = "1.22.0")] #[stable(feature = "cow_box_error", since = "1.22.0")]
impl<'a, 'b> From<Cow<'b, str>> for 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<Error + Send + Sync + 'a> { fn from(err: Cow<'b, str>) -> Box<dyn Error + Send + Sync + 'a> {
From::from(String::from(err)) From::from(String::from(err))
} }
} }
#[stable(feature = "cow_box_error", since = "1.22.0")] #[stable(feature = "cow_box_error", since = "1.22.0")]
impl<'a> From<Cow<'a, str>> for Box<Error> { impl<'a> From<Cow<'a, str>> for Box<dyn Error> {
fn from(err: Cow<'a, str>) -> Box<Error> { fn from(err: Cow<'a, str>) -> Box<dyn Error> {
From::from(String::from(err)) From::from(String::from(err))
} }
} }
@ -326,7 +327,7 @@ impl<T: Error> Error for Box<T> {
Error::description(&**self) Error::description(&**self)
} }
fn cause(&self) -> Option<&Error> { fn cause(&self) -> Option<&dyn Error> {
Error::cause(&**self) Error::cause(&**self)
} }
} }
@ -367,7 +368,7 @@ impl Error for char::ParseCharError {
} }
// copied from any.rs // copied from any.rs
impl Error + 'static { impl dyn Error + 'static {
/// Returns true if the boxed type is the same as `T` /// Returns true if the boxed type is the same as `T`
#[stable(feature = "error_downcast", since = "1.3.0")] #[stable(feature = "error_downcast", since = "1.3.0")]
#[inline] #[inline]
@ -389,7 +390,7 @@ impl Error + 'static {
pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> { pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
if self.is::<T>() { if self.is::<T>() {
unsafe { unsafe {
Some(&*(self as *const Error as *const T)) Some(&*(self as *const dyn Error as *const T))
} }
} else { } else {
None None
@ -403,7 +404,7 @@ impl Error + 'static {
pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> { pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
if self.is::<T>() { if self.is::<T>() {
unsafe { unsafe {
Some(&mut *(self as *mut Error as *mut T)) Some(&mut *(self as *mut dyn Error as *mut T))
} }
} else { } else {
None 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`. /// Forwards to the method defined on the type `Any`.
#[stable(feature = "error_downcast", since = "1.3.0")] #[stable(feature = "error_downcast", since = "1.3.0")]
#[inline] #[inline]
pub fn is<T: Error + 'static>(&self) -> bool { 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`. /// Forwards to the method defined on the type `Any`.
#[stable(feature = "error_downcast", since = "1.3.0")] #[stable(feature = "error_downcast", since = "1.3.0")]
#[inline] #[inline]
pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> { 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`. /// Forwards to the method defined on the type `Any`.
#[stable(feature = "error_downcast", since = "1.3.0")] #[stable(feature = "error_downcast", since = "1.3.0")]
#[inline] #[inline]
pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> { 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`. /// Forwards to the method defined on the type `Any`.
#[stable(feature = "error_downcast", since = "1.3.0")] #[stable(feature = "error_downcast", since = "1.3.0")]
#[inline] #[inline]
pub fn is<T: Error + 'static>(&self) -> bool { 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`. /// Forwards to the method defined on the type `Any`.
#[stable(feature = "error_downcast", since = "1.3.0")] #[stable(feature = "error_downcast", since = "1.3.0")]
#[inline] #[inline]
pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> { 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`. /// Forwards to the method defined on the type `Any`.
#[stable(feature = "error_downcast", since = "1.3.0")] #[stable(feature = "error_downcast", since = "1.3.0")]
#[inline] #[inline]
pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> { 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] #[inline]
#[stable(feature = "error_downcast", since = "1.3.0")] #[stable(feature = "error_downcast", since = "1.3.0")]
/// Attempt to downcast the box to a concrete type. /// 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>() { if self.is::<T>() {
unsafe { 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)) Ok(Box::from_raw(raw as *mut T))
} }
} else { } else {
@ -473,30 +474,30 @@ impl Error {
} }
} }
impl Error + Send { impl dyn Error + Send {
#[inline] #[inline]
#[stable(feature = "error_downcast", since = "1.3.0")] #[stable(feature = "error_downcast", since = "1.3.0")]
/// Attempt to downcast the box to a concrete type. /// Attempt to downcast the box to a concrete type.
pub fn downcast<T: Error + 'static>(self: Box<Self>) pub fn downcast<T: Error + 'static>(self: Box<Self>)
-> Result<Box<T>, Box<Error + Send>> { -> Result<Box<T>, Box<dyn Error + Send>> {
let err: Box<Error> = self; let err: Box<dyn Error> = self;
<Error>::downcast(err).map_err(|s| unsafe { <dyn Error>::downcast(err).map_err(|s| unsafe {
// reapply the Send marker // 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] #[inline]
#[stable(feature = "error_downcast", since = "1.3.0")] #[stable(feature = "error_downcast", since = "1.3.0")]
/// Attempt to downcast the box to a concrete type. /// Attempt to downcast the box to a concrete type.
pub fn downcast<T: Error + 'static>(self: Box<Self>) pub fn downcast<T: Error + 'static>(self: Box<Self>)
-> Result<Box<T>, Box<Self>> { -> Result<Box<T>, Box<Self>> {
let err: Box<Error> = self; let err: Box<dyn Error> = self;
<Error>::downcast(err).map_err(|s| unsafe { <dyn Error>::downcast(err).map_err(|s| unsafe {
// reapply the Send+Sync marker // 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] #[test]
fn downcasting() { fn downcasting() {
let mut a = A; 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::<A>(), Some(&A));
assert_eq!(a.downcast_ref::<B>(), None); assert_eq!(a.downcast_ref::<B>(), None);
assert_eq!(a.downcast_mut::<A>(), Some(&mut A)); assert_eq!(a.downcast_mut::<A>(), Some(&mut A));
assert_eq!(a.downcast_mut::<B>(), None); 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>() { match a.downcast::<B>() {
Ok(..) => panic!("expected error"), Ok(..) => panic!("expected error"),
Err(e) => assert_eq!(*e.downcast::<A>().unwrap(), A), Err(e) => assert_eq!(*e.downcast::<A>().unwrap(), A),

11
ctr-std/src/f32.rs

@ -254,7 +254,14 @@ impl f32 {
/// Calculates the Euclidean modulo (self mod rhs), which is never negative. /// 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 /// # Examples
/// ///
@ -266,6 +273,8 @@ impl f32 {
/// assert_eq!((-a).mod_euc(b), 1.0); /// assert_eq!((-a).mod_euc(b), 1.0);
/// assert_eq!(a.mod_euc(-b), 3.0); /// assert_eq!(a.mod_euc(-b), 3.0);
/// assert_eq!((-a).mod_euc(-b), 1.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] #[inline]
#[unstable(feature = "euclidean_division", issue = "49048")] #[unstable(feature = "euclidean_division", issue = "49048")]

11
ctr-std/src/f64.rs

@ -230,7 +230,14 @@ impl f64 {
/// Calculates the Euclidean modulo (self mod rhs), which is never negative. /// 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 /// # Examples
/// ///
@ -242,6 +249,8 @@ impl f64 {
/// assert_eq!((-a).mod_euc(b), 1.0); /// assert_eq!((-a).mod_euc(b), 1.0);
/// assert_eq!(a.mod_euc(-b), 3.0); /// assert_eq!(a.mod_euc(-b), 3.0);
/// assert_eq!((-a).mod_euc(-b), 1.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] #[inline]
#[unstable(feature = "euclidean_division", issue = "49048")] #[unstable(feature = "euclidean_division", issue = "49048")]

43
ctr-std/src/ffi/c_str.rs

@ -692,6 +692,12 @@ impl fmt::Debug for CString {
#[stable(feature = "cstring_into", since = "1.7.0")] #[stable(feature = "cstring_into", since = "1.7.0")]
impl From<CString> for Vec<u8> { 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] #[inline]
fn from(s: CString) -> Vec<u8> { fn from(s: CString) -> Vec<u8> {
s.into_bytes() 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")] #[stable(feature = "c_string_from_box", since = "1.18.0")]
impl From<Box<CStr>> for CString { 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] #[inline]
fn from(s: Box<CStr>) -> CString { fn from(s: Box<CStr>) -> CString {
s.into_c_string() 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")] #[stable(feature = "box_from_c_string", since = "1.20.0")]
impl From<CString> for Box<CStr> { 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] #[inline]
fn from(s: CString) -> Box<CStr> { fn from(s: CString) -> Box<CStr> {
s.into_boxed_c_str() 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")] #[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<CString> for Arc<CStr> { 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] #[inline]
fn from(s: CString) -> Arc<CStr> { fn from(s: CString) -> Arc<CStr> {
let arc: Arc<[u8]> = Arc::from(s.into_inner()); 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")] #[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<CString> for Rc<CStr> { 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] #[inline]
fn from(s: CString) -> Rc<CStr> { fn from(s: CString) -> Rc<CStr> {
let rc: Rc<[u8]> = Rc::from(s.into_inner()); 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")] #[stable(feature = "rust1", since = "1.0.0")]
impl From<NulError> for io::Error { 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 { fn from(_: NulError) -> io::Error {
io::Error::new(io::ErrorKind::InvalidInput, io::Error::new(io::ErrorKind::InvalidInput,
"data provided contains a nul byte") "data provided contains a nul byte")
@ -933,7 +967,7 @@ impl Error for IntoStringError {
"C string contained non-utf8 bytes" "C string contained non-utf8 bytes"
} }
fn cause(&self) -> Option<&Error> { fn cause(&self) -> Option<&dyn Error> {
Some(&self.error) Some(&self.error)
} }
} }
@ -1234,9 +1268,9 @@ impl CStr {
/// If the contents of the `CStr` are valid UTF-8 data, this /// If the contents of the `CStr` are valid UTF-8 data, this
/// function will return a [`Cow`]`::`[`Borrowed`]`(`[`&str`]`)` /// function will return a [`Cow`]`::`[`Borrowed`]`(`[`&str`]`)`
/// with the the corresponding [`&str`] slice. Otherwise, it will /// with the the corresponding [`&str`] slice. Otherwise, it will
/// replace any invalid UTF-8 sequences with `U+FFFD REPLACEMENT /// replace any invalid UTF-8 sequences with
/// CHARACTER` and return a [`Cow`]`::`[`Owned`]`(`[`String`]`)` /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a
/// with the result. /// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result.
/// ///
/// > **Note**: This method is currently implemented to check for validity /// > **Note**: This method is currently implemented to check for validity
/// > after a constant-time cast, but it is planned to alter its definition /// > 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 /// [`Owned`]: ../borrow/enum.Cow.html#variant.Owned
/// [`str`]: ../primitive.str.html /// [`str`]: ../primitive.str.html
/// [`String`]: ../string/struct.String.html /// [`String`]: ../string/struct.String.html
/// [U+FFFD]: ../char/constant.REPLACEMENT_CHARACTER.html
/// ///
/// # Examples /// # Examples
/// ///

48
ctr-std/src/ffi/os_str.rs

@ -348,6 +348,12 @@ impl OsString {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl From<String> for OsString { 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 { fn from(s: String) -> OsString {
OsString { inner: Buf::from_string(s) } 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")] #[stable(feature = "rust1", since = "1.0.0")]
impl Eq for OsString {} impl Eq for OsString {}
@ -500,10 +520,12 @@ impl OsStr {
/// Converts an `OsStr` to a [`Cow`]`<`[`str`]`>`. /// 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 /// [`Cow`]: ../../std/borrow/enum.Cow.html
/// [`str`]: ../../std/primitive.str.html /// [`str`]: ../../std/primitive.str.html
/// [U+FFFD]: ../../std/char/constant.REPLACEMENT_CHARACTER.html
/// ///
/// # Examples /// # Examples
/// ///
@ -616,6 +638,10 @@ impl<'a> From<&'a OsStr> for Box<OsStr> {
#[stable(feature = "os_string_from_box", since = "1.18.0")] #[stable(feature = "os_string_from_box", since = "1.18.0")]
impl From<Box<OsStr>> for OsString { 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 { fn from(boxed: Box<OsStr>) -> OsString {
boxed.into_os_string() boxed.into_os_string()
} }
@ -623,13 +649,29 @@ impl From<Box<OsStr>> for OsString {
#[stable(feature = "box_from_os_string", since = "1.20.0")] #[stable(feature = "box_from_os_string", since = "1.20.0")]
impl From<OsString> for Box<OsStr> { 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> { fn from(s: OsString) -> Box<OsStr> {
s.into_boxed_os_str() 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")] #[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<OsString> for Arc<OsStr> { 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] #[inline]
fn from(s: OsString) -> Arc<OsStr> { fn from(s: OsString) -> Arc<OsStr> {
let arc = s.inner.into_arc(); 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")] #[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<OsString> for Rc<OsStr> { 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] #[inline]
fn from(s: OsString) -> Rc<OsStr> { fn from(s: OsString) -> Rc<OsStr> {
let rc = s.inner.into_rc(); let rc = s.inner.into_rc();

6
ctr-std/src/fs.rs

@ -356,9 +356,9 @@ impl File {
/// use std::fs::File; /// use std::fs::File;
/// ///
/// fn main() -> std::io::Result<()> { /// fn main() -> std::io::Result<()> {
/// let mut f = File::open("foo.txt")?; /// let mut f = File::open("foo.txt")?;
/// # Ok(()) /// Ok(())
/// # } /// }
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> { pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {

116
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))
}

85
ctr-std/src/io/buffered.rs

@ -61,7 +61,8 @@ pub struct BufReader<R> {
} }
impl<R: Read> 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 /// # Examples
/// ///
@ -153,33 +154,6 @@ impl<R: Read> BufReader<R> {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn get_mut(&mut self) -> &mut R { &mut self.inner } 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. /// Returns a reference to the internally buffered data.
/// ///
/// Unlike `fill_buf`, this will not attempt to fill the buffer if it is empty. /// 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); pub struct IntoInnerError<W>(W, Error);
impl<W: Write> BufWriter<W> { 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 /// # Examples
/// ///
@ -738,7 +713,7 @@ impl<W> fmt::Display for IntoInnerError<W> {
/// reducing the number of actual writes to the file. /// reducing the number of actual writes to the file.
/// ///
/// ```no_run /// ```no_run
/// use std::fs::File; /// use std::fs::{self, File};
/// use std::io::prelude::*; /// use std::io::prelude::*;
/// use std::io::LineWriter; /// use std::io::LineWriter;
/// ///
@ -752,17 +727,30 @@ impl<W> fmt::Display for IntoInnerError<W> {
/// let file = File::create("poem.txt")?; /// let file = File::create("poem.txt")?;
/// let mut file = LineWriter::new(file); /// let mut file = LineWriter::new(file);
/// ///
/// for &byte in road_not_taken.iter() { /// file.write_all(b"I shall be telling this with a sigh")?;
/// file.write(&[byte]).unwrap();
/// }
/// ///
/// // let's check we did the right thing. /// // No bytes are written until a newline is encountered (or
/// let mut file = File::open("poem.txt")?; /// // the internal buffer is filled).
/// let mut contents = String::new(); /// 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(()) /// Ok(())
/// } /// }
/// ``` /// ```
@ -862,7 +850,7 @@ impl<W: Write> LineWriter<W> {
/// ///
/// The internal buffer is written out before returning the writer. /// 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. /// An `Err` will be returned if an error occurs while flushing the buffer.
/// ///
@ -1250,25 +1238,6 @@ mod tests {
assert_eq!(reader.read(&mut buf).unwrap(), 0); assert_eq!(reader.read(&mut buf).unwrap(), 0);
} }
#[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] #[test]
#[should_panic] #[should_panic]
fn dont_panic_in_drop_on_panicked_flush() { fn dont_panic_in_drop_on_panicked_flush() {

57
ctr-std/src/io/cursor.rs

@ -10,15 +10,17 @@
use io::prelude::*; use io::prelude::*;
use core::convert::TryInto;
use cmp; use cmp;
use io::{self, Initializer, SeekFrom, Error, ErrorKind}; 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. /// [`Seek`] implementation.
/// ///
/// `Cursor`s are typically used with in-memory buffers to allow them to /// `Cursor`s are used with in-memory buffers, anything implementing
/// implement [`Read`] and/or [`Write`], allowing these buffers to be used /// `AsRef<[u8]>`, to allow them to implement [`Read`] and/or [`Write`],
/// anywhere you might use a reader or writer that does actual I/O. /// 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 /// The standard library implements some I/O traits on various types which
/// are commonly used as a buffer, like `Cursor<`[`Vec`]`<u8>>` and /// are commonly used as a buffer, like `Cursor<`[`Vec`]`<u8>>` and
@ -86,11 +88,11 @@ pub struct Cursor<T> {
} }
impl<T> 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. /// Cursor initial position is `0` even if underlying buffer (e.g. `Vec`)
/// g. `Vec`) is not empty. So writing to cursor starts with /// is not empty. So writing to cursor starts with overwriting `Vec`
/// overwriting `Vec` content, not with appending to it. /// content, not with appending to it.
/// ///
/// # Examples /// # Examples
/// ///
@ -259,26 +261,9 @@ fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<us
Ok(amt) 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 // Resizing write implementation
fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> { 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, Error::new(ErrorKind::InvalidInput,
"cursor position exceeds maximum possible vector length") "cursor position exceeds maximum possible vector length")
})?; })?;
@ -565,26 +550,6 @@ mod tests {
assert_eq!(reader.read(&mut buf).unwrap(), 0); assert_eq!(reader.read(&mut buf).unwrap(), 0);
} }
#[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] #[test]
fn seek_past_end() { fn seek_past_end() {
let buf = [0xff]; let buf = [0xff];

25
ctr-std/src/io/error.rs

@ -83,7 +83,7 @@ enum Repr {
#[derive(Debug)] #[derive(Debug)]
struct Custom { struct Custom {
kind: ErrorKind, kind: ErrorKind,
error: Box<error::Error+Send+Sync>, error: Box<dyn error::Error+Send+Sync>,
} }
/// A list specifying general categories of I/O error. /// A list specifying general categories of I/O error.
@ -97,6 +97,7 @@ struct Custom {
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)] #[allow(deprecated)]
#[non_exhaustive]
pub enum ErrorKind { pub enum ErrorKind {
/// An entity was not found, often a file. /// An entity was not found, often a file.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
@ -180,15 +181,6 @@ pub enum ErrorKind {
/// read. /// read.
#[stable(feature = "read_exact", since = "1.6.0")] #[stable(feature = "read_exact", since = "1.6.0")]
UnexpectedEof, 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 { impl ErrorKind {
@ -212,7 +204,6 @@ impl ErrorKind {
ErrorKind::Interrupted => "operation interrupted", ErrorKind::Interrupted => "operation interrupted",
ErrorKind::Other => "other os error", ErrorKind::Other => "other os error",
ErrorKind::UnexpectedEof => "unexpected end of file", ErrorKind::UnexpectedEof => "unexpected end of file",
ErrorKind::__Nonexhaustive => unreachable!()
} }
} }
} }
@ -250,12 +241,12 @@ impl Error {
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn new<E>(kind: ErrorKind, error: E) -> Error 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()) 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 { Error {
repr: Repr::Custom(Box::new(Custom { repr: Repr::Custom(Box::new(Custom {
kind, kind,
@ -373,7 +364,7 @@ impl Error {
/// } /// }
/// ``` /// ```
#[stable(feature = "io_error_inner", since = "1.3.0")] #[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 { match self.repr {
Repr::Os(..) => None, Repr::Os(..) => None,
Repr::Simple(..) => None, Repr::Simple(..) => None,
@ -444,7 +435,7 @@ impl Error {
/// } /// }
/// ``` /// ```
#[stable(feature = "io_error_inner", since = "1.3.0")] #[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 { match self.repr {
Repr::Os(..) => None, Repr::Os(..) => None,
Repr::Simple(..) => None, Repr::Simple(..) => None,
@ -478,7 +469,7 @@ impl Error {
/// } /// }
/// ``` /// ```
#[stable(feature = "io_error_inner", since = "1.3.0")] #[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 { match self.repr {
Repr::Os(..) => None, Repr::Os(..) => None,
Repr::Simple(..) => 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 { match self.repr {
Repr::Os(..) => None, Repr::Os(..) => None,
Repr::Simple(..) => None, Repr::Simple(..) => None,

30
ctr-std/src/io/lazy.rs

@ -15,15 +15,21 @@ use sys_common;
use sys_common::mutex::Mutex; use sys_common::mutex::Mutex;
pub struct Lazy<T> { pub struct Lazy<T> {
// We never call `lock.init()`, so it is UB to attempt to acquire this mutex reentrantly!
lock: Mutex, lock: Mutex,
ptr: Cell<*mut Arc<T>>, ptr: Cell<*mut Arc<T>>,
init: fn() -> 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> {} unsafe impl<T> Sync for Lazy<T> {}
impl<T: Send + Sync + 'static> 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 { Lazy {
lock: Mutex::new(), lock: Mutex::new(),
ptr: Cell::new(ptr::null_mut()), 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>> { pub fn get(&'static self) -> Option<Arc<T>> {
unsafe { unsafe {
self.lock.lock(); let _guard = self.lock.lock();
let ptr = self.ptr.get(); let ptr = self.ptr.get();
let ret = if ptr.is_null() { if ptr.is_null() {
Some(self.init()) Some(self.init())
} else if ptr as usize == 1 { } else if ptr == done() {
None None
} else { } else {
Some((*ptr).clone()) Some((*ptr).clone())
}; }
self.lock.unlock();
return ret
} }
} }
// Must only be called with `lock` held
unsafe fn init(&'static self) -> Arc<T> { unsafe fn init(&'static self) -> Arc<T> {
// If we successfully register an at exit handler, then we cache the // If we successfully register an at exit handler, then we cache the
// `Arc` allocation in our own internal box (it will get deallocated by // `Arc` allocation in our own internal box (it will get deallocated by
// the at exit handler). Otherwise we just return the freshly allocated // the at exit handler). Otherwise we just return the freshly allocated
// `Arc`. // `Arc`.
let registered = sys_common::at_exit(move || { let registered = sys_common::at_exit(move || {
self.lock.lock(); let ptr = {
let ptr = self.ptr.get(); let _guard = self.lock.lock();
self.ptr.set(1 as *mut _); self.ptr.replace(done())
self.lock.unlock(); };
drop(Box::from_raw(ptr)) 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)(); let ret = (self.init)();
if registered.is_ok() { if registered.is_ok() {
self.ptr.set(Box::into_raw(Box::new(ret.clone()))); self.ptr.set(Box::into_raw(Box::new(ret.clone())));

171
ctr-std/src/io/mod.rs

@ -147,7 +147,7 @@
//! ``` //! ```
//! //!
//! Note that you cannot use the [`?` operator] in functions that do not return //! 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: //! or `match` on the return value to catch any possible errors:
//! //!
//! ```no_run //! ```no_run
@ -270,10 +270,7 @@
#![stable(feature = "rust1", since = "1.0.0")] #![stable(feature = "rust1", since = "1.0.0")]
use cmp; use cmp;
use core::str as core_str;
use error as std_error;
use fmt; use fmt;
use result;
use str; use str;
use memchr; use memchr;
use ptr; 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 // 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 // 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 // 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 // time is 4,500 times (!) slower than a default reservation size of 32 if the
// amount of data to return. // reader has a very small amount of data to return.
// //
// Because we're extending the buffer with uninitialized data for trusted // 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. // 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> { 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 start_len = buf.len();
let mut g = Guard { len: buf.len(), buf: buf }; let mut g = Guard { len: buf.len(), buf: buf };
let ret; let ret;
loop { loop {
if g.len == g.buf.len() { if g.len == g.buf.len() {
unsafe { unsafe {
g.buf.reserve(32); g.buf.reserve(reservation_size);
let capacity = g.buf.capacity(); let capacity = g.buf.capacity();
g.buf.set_len(capacity); g.buf.set_len(capacity);
r.initializer().initialize(&mut g.buf[g.len..]); r.initializer().initialize(&mut g.buf[g.len..]);
@ -800,53 +804,6 @@ pub trait Read {
Bytes { inner: self } 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. /// Creates an adaptor which will chain this stream with another.
/// ///
/// The returned `Read` instance will first read all bytes from this object /// 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 { unsafe fn initializer(&self) -> Initializer {
self.inner.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")] #[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]; let mut buf = [0];
loop { loop {
return match reader.read(&mut buf) { 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 /// An iterator over the contents of an instance of `BufRead` split on a
/// particular byte. /// particular byte.
/// ///

40
ctr-std/src/io/stdio.rs

@ -21,7 +21,7 @@ use thread::LocalKey;
/// Stdout used by print! and println! macros /// Stdout used by print! and println! macros
thread_local! { thread_local! {
static LOCAL_STDOUT: RefCell<Option<Box<Write + Send>>> = { static LOCAL_STDOUT: RefCell<Option<Box<dyn Write + Send>>> = {
RefCell::new(None) RefCell::new(None)
} }
} }
@ -197,12 +197,13 @@ pub struct StdinLock<'a> {
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn stdin() -> Stdin { 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 { return Stdin {
inner: INSTANCE.get().expect("cannot access stdin during shutdown"), inner: INSTANCE.get().expect("cannot access stdin during shutdown"),
}; };
fn stdin_init() -> Arc<Mutex<BufReader<Maybe<StdinRaw>>>> { fn stdin_init() -> Arc<Mutex<BufReader<Maybe<StdinRaw>>>> {
// This must not reentrantly access `INSTANCE`
let stdin = match stdin_raw() { let stdin = match stdin_raw() {
Ok(stdin) => Maybe::Real(stdin), Ok(stdin) => Maybe::Real(stdin),
_ => Maybe::Fake _ => Maybe::Fake
@ -396,12 +397,13 @@ pub struct StdoutLock<'a> {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn stdout() -> Stdout { pub fn stdout() -> Stdout {
static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>>
= Lazy::new(stdout_init); = unsafe { Lazy::new(stdout_init) };
return Stdout { return Stdout {
inner: INSTANCE.get().expect("cannot access stdout during shutdown"), inner: INSTANCE.get().expect("cannot access stdout during shutdown"),
}; };
fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> { fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> {
// This must not reentrantly access `INSTANCE`
let stdout = match stdout_raw() { let stdout = match stdout_raw() {
Ok(stdout) => Maybe::Real(stdout), Ok(stdout) => Maybe::Real(stdout),
_ => Maybe::Fake, _ => Maybe::Fake,
@ -531,12 +533,14 @@ pub struct StderrLock<'a> {
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn stderr() -> Stderr { 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 { return Stderr {
inner: INSTANCE.get().expect("cannot access stderr during shutdown"), inner: INSTANCE.get().expect("cannot access stderr during shutdown"),
}; };
fn stderr_init() -> Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> { fn stderr_init() -> Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> {
// This must not reentrantly access `INSTANCE`
let stderr = match stderr_raw() { let stderr = match stderr_raw() {
Ok(stderr) => Maybe::Real(stderr), Ok(stderr) => Maybe::Real(stderr),
_ => Maybe::Fake, _ => Maybe::Fake,
@ -624,7 +628,7 @@ impl<'a> fmt::Debug for StderrLock<'a> {
with a more general mechanism", with a more general mechanism",
issue = "0")] issue = "0")]
#[doc(hidden)] #[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 panicking::LOCAL_STDERR;
use mem; use mem;
LOCAL_STDERR.with(move |slot| { 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", with a more general mechanism",
issue = "0")] issue = "0")]
#[doc(hidden)] #[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; use mem;
LOCAL_STDOUT.with(move |slot| { LOCAL_STDOUT.with(move |slot| {
mem::replace(&mut *slot.borrow_mut(), sink) 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. /// However, if the actual I/O causes an error, this function does panic.
fn print_to<T>( fn print_to<T>(
args: fmt::Arguments, 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, global_s: fn() -> T,
label: &str, label: &str,
) )
@ -712,9 +716,31 @@ pub fn _eprint(args: fmt::Arguments) {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use panic::{UnwindSafe, RefUnwindSafe};
use thread; use thread;
use super::*; 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] #[test]
#[cfg_attr(target_os = "emscripten", ignore)] #[cfg_attr(target_os = "emscripten", ignore)]
fn panic_doesnt_poison() { fn panic_doesnt_poison() {

2
ctr-std/src/io/util.rs

@ -223,7 +223,7 @@ mod tests {
assert_eq!(copy(&mut r, &mut w).unwrap(), 4); assert_eq!(copy(&mut r, &mut w).unwrap(), 4);
let mut r = repeat(0).take(1 << 17); 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] #[test]

58
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 { }

76
ctr-std/src/lib.rs

@ -232,15 +232,16 @@
// std is implemented with unstable features, many of which are internal // std is implemented with unstable features, many of which are internal
// compiler details that will never be stable // compiler details that will never be stable
#![cfg_attr(test, feature(test, update_panic_count))]
#![feature(alloc)] #![feature(alloc)]
#![feature(alloc_error_handler)]
#![feature(allocator_api)] #![feature(allocator_api)]
#![feature(alloc_system)]
#![feature(allocator_internals)] #![feature(allocator_internals)]
#![feature(allow_internal_unsafe)] #![feature(allow_internal_unsafe)]
#![feature(allow_internal_unstable)] #![feature(allow_internal_unstable)]
#![feature(align_offset)] #![feature(align_offset)]
#![feature(arbitrary_self_types)]
#![feature(array_error_internals)] #![feature(array_error_internals)]
#![feature(ascii_ctype)]
#![feature(asm)] #![feature(asm)]
#![feature(attr_literals)] #![feature(attr_literals)]
#![feature(box_syntax)] #![feature(box_syntax)]
@ -248,25 +249,22 @@
#![feature(cfg_target_thread_local)] #![feature(cfg_target_thread_local)]
#![feature(cfg_target_vendor)] #![feature(cfg_target_vendor)]
#![feature(char_error_internals)] #![feature(char_error_internals)]
#![feature(char_internals)]
#![feature(collections_range)]
#![feature(compiler_builtins_lib)] #![feature(compiler_builtins_lib)]
#![feature(const_fn)] #![feature(const_fn)]
#![feature(const_int_ops)]
#![feature(const_ip)]
#![feature(core_intrinsics)] #![feature(core_intrinsics)]
#![feature(dropck_eyepatch)] #![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)] #![feature(exact_size_is_empty)]
#![feature(external_doc)] #![feature(external_doc)]
#![feature(fs_read_write)]
#![feature(fixed_size_array)] #![feature(fixed_size_array)]
#![feature(float_from_str_radix)]
#![feature(fn_traits)] #![feature(fn_traits)]
#![feature(fnbox)] #![feature(fnbox)]
#![feature(futures_api)] #![feature(futures_api)]
#![feature(generator_trait)]
#![feature(hashmap_internals)] #![feature(hashmap_internals)]
#![feature(heap_api)]
#![feature(int_error_internals)] #![feature(int_error_internals)]
#![feature(integer_atomics)] #![feature(integer_atomics)]
#![feature(into_cow)]
#![feature(lang_items)] #![feature(lang_items)]
#![feature(libc)] #![feature(libc)]
#![feature(link_args)] #![feature(link_args)]
@ -274,35 +272,28 @@
#![feature(macro_vis_matcher)] #![feature(macro_vis_matcher)]
#![feature(needs_panic_runtime)] #![feature(needs_panic_runtime)]
#![feature(never_type)] #![feature(never_type)]
#![cfg_attr(not(stage0), feature(nll))]
#![feature(exhaustive_patterns)] #![feature(exhaustive_patterns)]
#![feature(num_bits_bytes)]
#![feature(old_wrapping)]
#![feature(on_unimplemented)] #![feature(on_unimplemented)]
#![feature(oom)]
#![feature(optin_builtin_traits)] #![feature(optin_builtin_traits)]
#![feature(panic_internals)] #![feature(panic_internals)]
#![feature(panic_unwind)] #![feature(panic_unwind)]
#![feature(peek)]
#![feature(pin)] #![feature(pin)]
#![feature(placement_new_protocol)]
#![feature(prelude_import)] #![feature(prelude_import)]
#![feature(ptr_internals)] #![feature(ptr_internals)]
#![feature(rand)]
#![feature(raw)] #![feature(raw)]
#![feature(rustc_attrs)] #![feature(rustc_attrs)]
#![feature(rustc_const_unstable)]
#![feature(std_internals)] #![feature(std_internals)]
#![feature(stdsimd)] #![feature(stdsimd)]
#![feature(shrink_to)] #![feature(shrink_to)]
#![feature(slice_bytes)]
#![feature(slice_concat_ext)] #![feature(slice_concat_ext)]
#![feature(slice_internals)] #![feature(slice_internals)]
#![feature(slice_patterns)] #![feature(slice_patterns)]
#![feature(staged_api)] #![feature(staged_api)]
#![feature(stmt_expr_attributes)] #![feature(stmt_expr_attributes)]
#![feature(str_char)]
#![feature(str_internals)] #![feature(str_internals)]
#![feature(str_utf16)] #![feature(rustc_private)]
#![feature(test, rustc_private)]
#![feature(thread_local)] #![feature(thread_local)]
#![feature(toowned_clone_into)] #![feature(toowned_clone_into)]
#![feature(try_from)] #![feature(try_from)]
@ -310,18 +301,16 @@
#![feature(unboxed_closures)] #![feature(unboxed_closures)]
#![feature(untagged_unions)] #![feature(untagged_unions)]
#![feature(unwind_attributes)] #![feature(unwind_attributes)]
#![feature(use_extern_macros)] #![cfg_attr(stage0, feature(use_extern_macros))]
#![feature(vec_push_all)]
#![feature(doc_cfg)] #![feature(doc_cfg)]
#![feature(doc_masked)] #![feature(doc_masked)]
#![feature(doc_spotlight)] #![feature(doc_spotlight)]
#![cfg_attr(test, feature(update_panic_count))]
#![cfg_attr(windows, feature(used))] #![cfg_attr(windows, feature(used))]
#![feature(doc_alias)] #![feature(doc_alias)]
#![feature(doc_keyword)] #![feature(doc_keyword)]
#![feature(float_internals)]
#![feature(panic_info_message)] #![feature(panic_info_message)]
#![cfg_attr(not(stage0), feature(panic_implementation))] #![feature(panic_implementation)]
#![feature(non_exhaustive)]
#![default_lib_allocator] #![default_lib_allocator]
@ -331,9 +320,6 @@
// `force_alloc_system` is *only* intended as a workaround for local rebuilds // `force_alloc_system` is *only* intended as a workaround for local rebuilds
// with a rustc without jemalloc. // with a rustc without jemalloc.
// FIXME(#44236) shouldn't need MSVC logic // 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"), #[cfg(all(not(target_env = "msvc"),
any(all(stage0, not(test)), feature = "force_alloc_system")))] any(all(stage0, not(test)), feature = "force_alloc_system")))]
#[global_allocator] #[global_allocator]
@ -465,20 +451,6 @@ pub use core::u128;
#[stable(feature = "core_hint", since = "1.27.0")] #[stable(feature = "core_hint", since = "1.27.0")]
pub use core::hint; 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 f32;
pub mod f64; pub mod f64;
@ -500,13 +472,22 @@ pub mod process;
pub mod sync; pub mod sync;
pub mod time; pub mod time;
#[unstable(feature = "allocator_api", issue = "32838")] #[unstable(feature = "futures_api",
#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] reason = "futures in libcore are unstable",
/// Use the `alloc` module instead. issue = "50547")]
pub mod heap { pub mod task {
pub use alloc::*; //! 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 // Platform-abstraction modules
#[macro_use] #[macro_use]
mod sys_common; mod sys_common;
@ -526,3 +507,8 @@ pub mod rt;
// the rustdoc documentation for primitive types. Using `include!` // the rustdoc documentation for primitive types. Using `include!`
// because rustdoc only looks for these modules at the crate level. // because rustdoc only looks for these modules at the crate level.
include!("primitive_docs.rs"); 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");

80
ctr-std/src/macros.rs

@ -38,10 +38,13 @@
/// The multi-argument form of this macro panics with a string and has the /// The multi-argument form of this macro panics with a string and has the
/// [`format!`] syntax for building a string. /// [`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 /// [runwrap]: ../std/result/enum.Result.html#method.unwrap
/// [`Option`]: ../std/option/enum.Option.html#method.unwrap /// [`Option`]: ../std/option/enum.Option.html#method.unwrap
/// [`Result`]: ../std/result/enum.Result.html /// [`Result`]: ../std/result/enum.Result.html
/// [`format!`]: ../std/macro.format.html /// [`format!`]: ../std/macro.format.html
/// [`compile_error!`]: ../std/macro.compile_error.html
/// [book]: ../book/second-edition/ch09-01-unrecoverable-errors-with-panic.html /// [book]: ../book/second-edition/ch09-01-unrecoverable-errors-with-panic.html
/// ///
/// # Current implementation /// # Current implementation
@ -150,10 +153,12 @@ macro_rules! print {
/// ``` /// ```
#[macro_export] #[macro_export]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable]
macro_rules! println { macro_rules! println {
() => (print!("\n")); () => (print!("\n"));
($fmt:expr) => (print!(concat!($fmt, "\n"))); ($($arg:tt)*) => ({
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); $crate::io::_print(format_args_nl!($($arg)*));
})
} }
/// Macro for printing to the standard error. /// Macro for printing to the standard error.
@ -207,10 +212,34 @@ macro_rules! eprint {
/// ``` /// ```
#[macro_export] #[macro_export]
#[stable(feature = "eprint", since = "1.19.0")] #[stable(feature = "eprint", since = "1.19.0")]
#[allow_internal_unstable]
macro_rules! eprintln { macro_rules! eprintln {
() => (eprint!("\n")); () => (eprint!("\n"));
($fmt:expr) => (eprint!(concat!($fmt, "\n"))); ($($arg:tt)*) => ({
($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*)); $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. /// 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 /// macro, but are documented here. Their implementations can be found hardcoded
/// into libsyntax itself. /// into libsyntax itself.
#[cfg(dox)] #[cfg(dox)]
pub mod builtin { mod builtin {
/// Unconditionally causes compilation to fail with the given error message when encountered. /// 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 /// 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 /// # Examples
/// ///
/// Two such examples are macros and `#[cfg]` environments. /// 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 /// ```compile_fail
/// macro_rules! give_me_foo_or_bar { /// macro_rules! give_me_foo_or_bar {
@ -313,8 +345,10 @@ pub mod builtin {
/// #[cfg(not(any(feature = "foo", feature = "bar")))] /// #[cfg(not(any(feature = "foo", feature = "bar")))]
/// compile_error!("Either feature \"foo\" or \"bar\" must be enabled for this crate.") /// 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")] #[stable(feature = "compile_error_macro", since = "1.20.0")]
#[macro_export] #[rustc_doc_only_macro]
macro_rules! compile_error { macro_rules! compile_error {
($msg:expr) => ({ /* compiler built-in */ }); ($msg:expr) => ({ /* compiler built-in */ });
($msg:expr,) => ({ /* compiler built-in */ }); ($msg:expr,) => ({ /* compiler built-in */ });
@ -366,7 +400,7 @@ pub mod builtin {
/// assert_eq!(s, format!("hello {}", "world")); /// assert_eq!(s, format!("hello {}", "world"));
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[macro_export] #[rustc_doc_only_macro]
macro_rules! format_args { macro_rules! format_args {
($fmt:expr) => ({ /* compiler built-in */ }); ($fmt:expr) => ({ /* compiler built-in */ });
($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }); ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ });
@ -404,7 +438,7 @@ pub mod builtin {
/// error: what's that?! /// error: what's that?!
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[macro_export] #[rustc_doc_only_macro]
macro_rules! env { macro_rules! env {
($name:expr) => ({ /* compiler built-in */ }); ($name:expr) => ({ /* compiler built-in */ });
($name:expr,) => ({ /* compiler built-in */ }); ($name:expr,) => ({ /* compiler built-in */ });
@ -430,7 +464,7 @@ pub mod builtin {
/// println!("the secret key might be: {:?}", key); /// println!("the secret key might be: {:?}", key);
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[macro_export] #[rustc_doc_only_macro]
macro_rules! option_env { macro_rules! option_env {
($name:expr) => ({ /* compiler built-in */ }); ($name:expr) => ({ /* compiler built-in */ });
($name:expr,) => ({ /* compiler built-in */ }); ($name:expr,) => ({ /* compiler built-in */ });
@ -461,7 +495,7 @@ pub mod builtin {
/// # } /// # }
/// ``` /// ```
#[unstable(feature = "concat_idents_macro", issue = "29599")] #[unstable(feature = "concat_idents_macro", issue = "29599")]
#[macro_export] #[rustc_doc_only_macro]
macro_rules! concat_idents { macro_rules! concat_idents {
($($e:ident),+) => ({ /* compiler built-in */ }); ($($e:ident),+) => ({ /* compiler built-in */ });
($($e:ident,)+) => ({ /* compiler built-in */ }); ($($e:ident,)+) => ({ /* compiler built-in */ });
@ -483,7 +517,7 @@ pub mod builtin {
/// assert_eq!(s, "test10btrue"); /// assert_eq!(s, "test10btrue");
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[macro_export] #[rustc_doc_only_macro]
macro_rules! concat { macro_rules! concat {
($($e:expr),*) => ({ /* compiler built-in */ }); ($($e:expr),*) => ({ /* compiler built-in */ });
($($e:expr,)*) => ({ /* compiler built-in */ }); ($($e:expr,)*) => ({ /* compiler built-in */ });
@ -511,7 +545,7 @@ pub mod builtin {
/// println!("defined on line: {}", current_line); /// println!("defined on line: {}", current_line);
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[macro_export] #[rustc_doc_only_macro]
macro_rules! line { () => ({ /* compiler built-in */ }) } macro_rules! line { () => ({ /* compiler built-in */ }) }
/// A macro which expands to the column number on which it was invoked. /// 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); /// println!("defined on column: {}", current_col);
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[macro_export] #[rustc_doc_only_macro]
macro_rules! column { () => ({ /* compiler built-in */ }) } macro_rules! column { () => ({ /* compiler built-in */ }) }
/// A macro which expands to the file name from which it was invoked. /// 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); /// println!("defined in file: {}", this_file);
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[macro_export] #[rustc_doc_only_macro]
macro_rules! file { () => ({ /* compiler built-in */ }) } macro_rules! file { () => ({ /* compiler built-in */ }) }
/// A macro which stringifies its arguments. /// A macro which stringifies its arguments.
@ -579,7 +613,7 @@ pub mod builtin {
/// assert_eq!(one_plus_one, "1 + 1"); /// assert_eq!(one_plus_one, "1 + 1");
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[macro_export] #[rustc_doc_only_macro]
macro_rules! stringify { ($($t:tt)*) => ({ /* compiler built-in */ }) } macro_rules! stringify { ($($t:tt)*) => ({ /* compiler built-in */ }) }
/// Includes a utf8-encoded file as a string. /// 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". /// Compiling 'main.rs' and running the resulting binary will print "adiós".
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[macro_export] #[rustc_doc_only_macro]
macro_rules! include_str { macro_rules! include_str {
($file:expr) => ({ /* compiler built-in */ }); ($file:expr) => ({ /* compiler built-in */ });
($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". /// Compiling 'main.rs' and running the resulting binary will print "adiós".
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[macro_export] #[rustc_doc_only_macro]
macro_rules! include_bytes { macro_rules! include_bytes {
($file:expr) => ({ /* compiler built-in */ }); ($file:expr) => ({ /* compiler built-in */ });
($file:expr,) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ });
@ -674,7 +708,7 @@ pub mod builtin {
/// test::foo(); /// test::foo();
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[macro_export] #[rustc_doc_only_macro]
macro_rules! module_path { () => ({ /* compiler built-in */ }) } macro_rules! module_path { () => ({ /* compiler built-in */ }) }
/// Boolean evaluation of configuration flags, at compile-time. /// Boolean evaluation of configuration flags, at compile-time.
@ -696,7 +730,7 @@ pub mod builtin {
/// }; /// };
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[macro_export] #[rustc_doc_only_macro]
macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) } macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) }
/// Parse a file as an expression or an item according to the context. /// 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 /// Compiling 'main.rs' and running the resulting binary will print
/// "🙈🙊🙉🙈🙊🙉". /// "🙈🙊🙉🙈🙊🙉".
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[macro_export] #[rustc_doc_only_macro]
macro_rules! include { macro_rules! include {
($file:expr) => ({ /* compiler built-in */ }); ($file:expr) => ({ /* compiler built-in */ });
($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); /// assert!(a + b == 30, "a = {}, b = {}", a, b);
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[macro_export] #[rustc_doc_only_macro]
macro_rules! assert { macro_rules! assert {
($cond:expr) => ({ /* compiler built-in */ }); ($cond:expr) => ({ /* compiler built-in */ });
($cond:expr,) => ({ /* compiler built-in */ }); ($cond:expr,) => ({ /* compiler built-in */ });

218
ctr-std/src/net/ip.rs

@ -16,8 +16,6 @@
use cmp::Ordering; use cmp::Ordering;
use fmt; use fmt;
use hash; use hash;
use mem;
use net::{hton, ntoh};
use sys::net::netc as c; use sys::net::netc as c;
use sys_common::{AsInner, FromInner}; use sys_common::{AsInner, FromInner};
@ -162,9 +160,9 @@ impl IpAddr {
/// ``` /// ```
#[stable(feature = "ip_shared", since = "1.12.0")] #[stable(feature = "ip_shared", since = "1.12.0")]
pub fn is_unspecified(&self) -> bool { pub fn is_unspecified(&self) -> bool {
match *self { match self {
IpAddr::V4(ref a) => a.is_unspecified(), IpAddr::V4(ip) => ip.is_unspecified(),
IpAddr::V6(ref a) => a.is_unspecified(), IpAddr::V6(ip) => ip.is_unspecified(),
} }
} }
@ -187,9 +185,9 @@ impl IpAddr {
/// ``` /// ```
#[stable(feature = "ip_shared", since = "1.12.0")] #[stable(feature = "ip_shared", since = "1.12.0")]
pub fn is_loopback(&self) -> bool { pub fn is_loopback(&self) -> bool {
match *self { match self {
IpAddr::V4(ref a) => a.is_loopback(), IpAddr::V4(ip) => ip.is_loopback(),
IpAddr::V6(ref a) => a.is_loopback(), IpAddr::V6(ip) => ip.is_loopback(),
} }
} }
@ -216,9 +214,9 @@ impl IpAddr {
/// } /// }
/// ``` /// ```
pub fn is_global(&self) -> bool { pub fn is_global(&self) -> bool {
match *self { match self {
IpAddr::V4(ref a) => a.is_global(), IpAddr::V4(ip) => ip.is_global(),
IpAddr::V6(ref a) => a.is_global(), IpAddr::V6(ip) => ip.is_global(),
} }
} }
@ -241,9 +239,9 @@ impl IpAddr {
/// ``` /// ```
#[stable(feature = "ip_shared", since = "1.12.0")] #[stable(feature = "ip_shared", since = "1.12.0")]
pub fn is_multicast(&self) -> bool { pub fn is_multicast(&self) -> bool {
match *self { match self {
IpAddr::V4(ref a) => a.is_multicast(), IpAddr::V4(ip) => ip.is_multicast(),
IpAddr::V6(ref a) => a.is_multicast(), IpAddr::V6(ip) => ip.is_multicast(),
} }
} }
@ -270,9 +268,9 @@ impl IpAddr {
/// } /// }
/// ``` /// ```
pub fn is_documentation(&self) -> bool { pub fn is_documentation(&self) -> bool {
match *self { match self {
IpAddr::V4(ref a) => a.is_documentation(), IpAddr::V4(ip) => ip.is_documentation(),
IpAddr::V6(ref a) => a.is_documentation(), IpAddr::V6(ip) => ip.is_documentation(),
} }
} }
@ -295,7 +293,7 @@ impl IpAddr {
/// ``` /// ```
#[stable(feature = "ipaddr_checker", since = "1.16.0")] #[stable(feature = "ipaddr_checker", since = "1.16.0")]
pub fn is_ipv4(&self) -> bool { pub fn is_ipv4(&self) -> bool {
match *self { match self {
IpAddr::V4(_) => true, IpAddr::V4(_) => true,
IpAddr::V6(_) => false, IpAddr::V6(_) => false,
} }
@ -320,7 +318,7 @@ impl IpAddr {
/// ``` /// ```
#[stable(feature = "ipaddr_checker", since = "1.16.0")] #[stable(feature = "ipaddr_checker", since = "1.16.0")]
pub fn is_ipv6(&self) -> bool { pub fn is_ipv6(&self) -> bool {
match *self { match self {
IpAddr::V4(_) => false, IpAddr::V4(_) => false,
IpAddr::V6(_) => true, IpAddr::V6(_) => true,
} }
@ -340,18 +338,21 @@ impl Ipv4Addr {
/// let addr = Ipv4Addr::new(127, 0, 0, 1); /// let addr = Ipv4Addr::new(127, 0, 0, 1);
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[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 { Ipv4Addr {
inner: c::in_addr { inner: c::in_addr {
s_addr: hton(((a as u32) << 24) | s_addr: u32::to_be(
((b as u32) << 16) | ((a as u32) << 24) |
((c as u32) << 8) | ((b as u32) << 16) |
(d as u32)), ((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 /// # Examples
/// ///
@ -359,17 +360,15 @@ impl Ipv4Addr {
/// #![feature(ip_constructors)] /// #![feature(ip_constructors)]
/// use std::net::Ipv4Addr; /// use std::net::Ipv4Addr;
/// ///
/// let addr = Ipv4Addr::localhost(); /// let addr = Ipv4Addr::LOCALHOST;
/// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1)); /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1));
/// ``` /// ```
#[unstable(feature = "ip_constructors", #[unstable(feature = "ip_constructors",
reason = "requires greater scrutiny before stabilization", reason = "requires greater scrutiny before stabilization",
issue = "44582")] issue = "44582")]
pub fn localhost() -> Ipv4Addr { pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1);
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 /// # Examples
/// ///
@ -377,15 +376,29 @@ impl Ipv4Addr {
/// #![feature(ip_constructors)] /// #![feature(ip_constructors)]
/// use std::net::Ipv4Addr; /// use std::net::Ipv4Addr;
/// ///
/// let addr = Ipv4Addr::unspecified(); /// let addr = Ipv4Addr::UNSPECIFIED;
/// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0)); /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0));
/// ``` /// ```
#[unstable(feature = "ip_constructors", #[unstable(feature = "ip_constructors",
reason = "requires greater scrutiny before stabilization", reason = "requires greater scrutiny before stabilization",
issue = "44582")] issue = "44582")]
pub fn unspecified() -> Ipv4Addr { pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0);
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. /// Returns the four eight-bit integers that make up this address.
/// ///
@ -399,7 +412,7 @@ impl Ipv4Addr {
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn octets(&self) -> [u8; 4] { 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] [(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")] #[stable(since = "1.7.0", feature = "ip_17")]
pub fn is_private(&self) -> bool { pub fn is_private(&self) -> bool {
match (self.octets()[0], self.octets()[1]) { match self.octets() {
(10, _) => true, [10, ..] => true,
(172, b) if b >= 16 && b <= 31 => true, [172, b, ..] if b >= 16 && b <= 31 => true,
(192, 168) => true, [192, 168, ..] => true,
_ => false _ => false,
} }
} }
@ -496,7 +509,10 @@ impl Ipv4Addr {
/// ``` /// ```
#[stable(since = "1.7.0", feature = "ip_17")] #[stable(since = "1.7.0", feature = "ip_17")]
pub fn is_link_local(&self) -> bool { 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. /// Returns [`true`] if the address appears to be globally routable.
@ -573,8 +589,7 @@ impl Ipv4Addr {
/// ``` /// ```
#[stable(since = "1.7.0", feature = "ip_17")] #[stable(since = "1.7.0", feature = "ip_17")]
pub fn is_broadcast(&self) -> bool { pub fn is_broadcast(&self) -> bool {
self.octets()[0] == 255 && self.octets()[1] == 255 && self == &Self::BROADCAST
self.octets()[2] == 255 && self.octets()[3] == 255
} }
/// Returns [`true`] if this address is in a range designated for documentation. /// Returns [`true`] if this address is in a range designated for documentation.
@ -600,11 +615,11 @@ impl Ipv4Addr {
/// ``` /// ```
#[stable(since = "1.7.0", feature = "ip_17")] #[stable(since = "1.7.0", feature = "ip_17")]
pub fn is_documentation(&self) -> bool { pub fn is_documentation(&self) -> bool {
match(self.octets()[0], self.octets()[1], self.octets()[2], self.octets()[3]) { match self.octets() {
(192, 0, 2, _) => true, [192, 0, 2, _] => true,
(198, 51, 100, _) => true, [198, 51, 100, _] => true,
(203, 0, 113, _) => true, [203, 0, 113, _] => true,
_ => false _ => false,
} }
} }
@ -654,9 +669,9 @@ impl Ipv4Addr {
#[stable(feature = "ip_addr", since = "1.7.0")] #[stable(feature = "ip_addr", since = "1.7.0")]
impl fmt::Display for IpAddr { impl fmt::Display for IpAddr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self { match self {
IpAddr::V4(ref a) => a.fmt(fmt), IpAddr::V4(ip) => ip.fmt(fmt),
IpAddr::V6(ref a) => a.fmt(fmt), IpAddr::V6(ip) => ip.fmt(fmt),
} }
} }
} }
@ -705,8 +720,8 @@ impl PartialEq for Ipv4Addr {
#[stable(feature = "ip_cmp", since = "1.16.0")] #[stable(feature = "ip_cmp", since = "1.16.0")]
impl PartialEq<Ipv4Addr> for IpAddr { impl PartialEq<Ipv4Addr> for IpAddr {
fn eq(&self, other: &Ipv4Addr) -> bool { fn eq(&self, other: &Ipv4Addr) -> bool {
match *self { match self {
IpAddr::V4(ref v4) => v4 == other, IpAddr::V4(v4) => v4 == other,
IpAddr::V6(_) => false, IpAddr::V6(_) => false,
} }
} }
@ -715,8 +730,8 @@ impl PartialEq<Ipv4Addr> for IpAddr {
#[stable(feature = "ip_cmp", since = "1.16.0")] #[stable(feature = "ip_cmp", since = "1.16.0")]
impl PartialEq<IpAddr> for Ipv4Addr { impl PartialEq<IpAddr> for Ipv4Addr {
fn eq(&self, other: &IpAddr) -> bool { fn eq(&self, other: &IpAddr) -> bool {
match *other { match other {
IpAddr::V4(ref v4) => self == v4, IpAddr::V4(v4) => self == v4,
IpAddr::V6(_) => false, IpAddr::V6(_) => false,
} }
} }
@ -743,8 +758,8 @@ impl PartialOrd for Ipv4Addr {
#[stable(feature = "ip_cmp", since = "1.16.0")] #[stable(feature = "ip_cmp", since = "1.16.0")]
impl PartialOrd<Ipv4Addr> for IpAddr { impl PartialOrd<Ipv4Addr> for IpAddr {
fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> { fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
match *self { match self {
IpAddr::V4(ref v4) => v4.partial_cmp(other), IpAddr::V4(v4) => v4.partial_cmp(other),
IpAddr::V6(_) => Some(Ordering::Greater), IpAddr::V6(_) => Some(Ordering::Greater),
} }
} }
@ -753,8 +768,8 @@ impl PartialOrd<Ipv4Addr> for IpAddr {
#[stable(feature = "ip_cmp", since = "1.16.0")] #[stable(feature = "ip_cmp", since = "1.16.0")]
impl PartialOrd<IpAddr> for Ipv4Addr { impl PartialOrd<IpAddr> for Ipv4Addr {
fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> { fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
match *other { match other {
IpAddr::V4(ref v4) => self.partial_cmp(v4), IpAddr::V4(v4) => self.partial_cmp(v4),
IpAddr::V6(_) => Some(Ordering::Less), IpAddr::V6(_) => Some(Ordering::Less),
} }
} }
@ -763,7 +778,7 @@ impl PartialOrd<IpAddr> for Ipv4Addr {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl Ord for Ipv4Addr { impl Ord for Ipv4Addr {
fn cmp(&self, other: &Ipv4Addr) -> Ordering { 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); /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff);
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, #[rustc_const_unstable(feature = "const_ip")]
h: u16) -> Ipv6Addr { pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16,
let mut addr: c::in6_addr = unsafe { mem::zeroed() }; g: u16, h: u16) -> Ipv6Addr {
addr.s6_addr = [(a >> 8) as u8, a as u8, Ipv6Addr {
(b >> 8) as u8, b as u8, inner: c::in6_addr {
(c >> 8) as u8, c as u8, s6_addr: [
(d >> 8) as u8, d as u8, (a >> 8) as u8, a as u8,
(e >> 8) as u8, e as u8, (b >> 8) as u8, b as u8,
(f >> 8) as u8, f as u8, (c >> 8) as u8, c as u8,
(g >> 8) as u8, g as u8, (d >> 8) as u8, d as u8,
(h >> 8) as u8, h as u8]; (e >> 8) as u8, e as u8,
Ipv6Addr { inner: addr } (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 /// # Examples
/// ///
@ -878,17 +899,15 @@ impl Ipv6Addr {
/// #![feature(ip_constructors)] /// #![feature(ip_constructors)]
/// use std::net::Ipv6Addr; /// 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)); /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
/// ``` /// ```
#[unstable(feature = "ip_constructors", #[unstable(feature = "ip_constructors",
reason = "requires greater scrutiny before stabilization", reason = "requires greater scrutiny before stabilization",
issue = "44582")] issue = "44582")]
pub fn localhost() -> Ipv6Addr { pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
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 /// # Examples
/// ///
@ -896,15 +915,13 @@ impl Ipv6Addr {
/// #![feature(ip_constructors)] /// #![feature(ip_constructors)]
/// use std::net::Ipv6Addr; /// 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)); /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
/// ``` /// ```
#[unstable(feature = "ip_constructors", #[unstable(feature = "ip_constructors",
reason = "requires greater scrutiny before stabilization", reason = "requires greater scrutiny before stabilization",
issue = "44582")] issue = "44582")]
pub fn unspecified() -> Ipv6Addr { pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)
}
/// Returns the eight 16-bit segments that make up this address. /// 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")] #[stable(feature = "ip_cmp", since = "1.16.0")]
impl PartialEq<IpAddr> for Ipv6Addr { impl PartialEq<IpAddr> for Ipv6Addr {
fn eq(&self, other: &IpAddr) -> bool { fn eq(&self, other: &IpAddr) -> bool {
match *other { match other {
IpAddr::V4(_) => false, 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")] #[stable(feature = "ip_cmp", since = "1.16.0")]
impl PartialEq<Ipv6Addr> for IpAddr { impl PartialEq<Ipv6Addr> for IpAddr {
fn eq(&self, other: &Ipv6Addr) -> bool { fn eq(&self, other: &Ipv6Addr) -> bool {
match *self { match self {
IpAddr::V4(_) => false, 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")] #[stable(feature = "ip_cmp", since = "1.16.0")]
impl PartialOrd<Ipv6Addr> for IpAddr { impl PartialOrd<Ipv6Addr> for IpAddr {
fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> { fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
match *self { match self {
IpAddr::V4(_) => Some(Ordering::Less), 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")] #[stable(feature = "ip_cmp", since = "1.16.0")]
impl PartialOrd<IpAddr> for Ipv6Addr { impl PartialOrd<IpAddr> for Ipv6Addr {
fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> { fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
match *other { match other {
IpAddr::V4(_) => Some(Ordering::Greater), 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")] #[stable(feature = "ipv6_from_octets", since = "1.9.0")]
impl From<[u8; 16]> for Ipv6Addr { impl From<[u8; 16]> for Ipv6Addr {
fn from(octets: [u8; 16]) -> Ipv6Addr { fn from(octets: [u8; 16]) -> Ipv6Addr {
let mut inner: c::in6_addr = unsafe { mem::zeroed() }; let inner = c::in6_addr { s6_addr: octets };
inner.s6_addr = octets;
Ipv6Addr::from_inner(inner) Ipv6Addr::from_inner(inner)
} }
} }
@ -1846,18 +1862,20 @@ mod tests {
#[test] #[test]
fn ipv4_from_constructors() { fn ipv4_from_constructors() {
assert_eq!(Ipv4Addr::localhost(), Ipv4Addr::new(127, 0, 0, 1)); assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1));
assert!(Ipv4Addr::localhost().is_loopback()); assert!(Ipv4Addr::LOCALHOST.is_loopback());
assert_eq!(Ipv4Addr::unspecified(), Ipv4Addr::new(0, 0, 0, 0)); assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0));
assert!(Ipv4Addr::unspecified().is_unspecified()); assert!(Ipv4Addr::UNSPECIFIED.is_unspecified());
assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255));
assert!(Ipv4Addr::BROADCAST.is_broadcast());
} }
#[test] #[test]
fn ipv6_from_contructors() { fn ipv6_from_contructors() {
assert_eq!(Ipv6Addr::localhost(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
assert!(Ipv6Addr::localhost().is_loopback()); assert!(Ipv6Addr::LOCALHOST.is_loopback());
assert_eq!(Ipv6Addr::unspecified(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
assert!(Ipv6Addr::unspecified().is_unspecified()); assert!(Ipv6Addr::UNSPECIFIED.is_unspecified());
} }
#[test] #[test]

7
ctr-std/src/net/parser.rs

@ -53,15 +53,12 @@ impl<'a> Parser<'a> {
F: FnOnce(&mut Parser) -> Option<T>, F: FnOnce(&mut Parser) -> Option<T>,
{ {
self.read_atomically(move |p| { self.read_atomically(move |p| {
match cb(p) { cb(p).filter(|_| p.is_eof())
Some(x) => if p.is_eof() {Some(x)} else {None},
None => None,
}
}) })
} }
// Return result of first successful parser // 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> { -> Option<T> {
for pf in parsers { for pf in parsers {
if let Some(r) = self.read_atomically(|p: &mut Parser| pf(p)) { if let Some(r) = self.read_atomically(|p: &mut Parser| pf(p)) {

4
ctr-std/src/net/tcp.rs

@ -81,7 +81,7 @@ pub struct TcpStream(net_imp::TcpStream);
/// } /// }
/// ///
/// fn main() -> io::Result<()> { /// 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 /// // accept connections and process them serially
/// for stream in listener.incoming() { /// for stream in listener.incoming() {
@ -927,7 +927,7 @@ mod tests {
use time::{Instant, Duration}; use time::{Instant, Duration};
use thread; use thread;
fn each_ip(f: &mut FnMut(SocketAddr)) { fn each_ip(f: &mut dyn FnMut(SocketAddr)) {
f(next_test_ip4()); f(next_test_ip4());
f(next_test_ip6()); f(next_test_ip6());
} }

2
ctr-std/src/net/udp.rs

@ -826,7 +826,7 @@ mod tests {
use time::{Instant, Duration}; use time::{Instant, Duration};
use thread; 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_ip4(), next_test_ip4());
f(next_test_ip6(), next_test_ip6()); f(next_test_ip6(), next_test_ip6());
} }

389
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
}
}

16
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;

27
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};

1
ctr-std/src/os/mod.rs

@ -47,6 +47,7 @@ cfg_if! {
#[cfg(target_os = "solaris")] pub mod solaris; #[cfg(target_os = "solaris")] pub mod solaris;
#[cfg(target_os = "emscripten")] pub mod emscripten; #[cfg(target_os = "emscripten")] pub mod emscripten;
#[cfg(target_os = "fuchsia")] pub mod fuchsia; #[cfg(target_os = "fuchsia")] pub mod fuchsia;
#[cfg(target_os = "hermit")] pub mod hermit;
#[cfg(target_os = "horizon")] pub mod horizon; #[cfg(target_os = "horizon")] pub mod horizon;
#[cfg(any(target_os = "redox", unix))] #[cfg(any(target_os = "redox", unix))]

6
ctr-std/src/os/raw/mod.rs

@ -29,6 +29,9 @@ use fmt;
all(target_os = "android", any(target_arch = "aarch64", all(target_os = "android", any(target_arch = "aarch64",
target_arch = "arm")), target_arch = "arm")),
all(target_os = "l4re", target_arch = "x86_64"), 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 = "openbsd", target_arch = "aarch64"),
all(target_os = "fuchsia", target_arch = "aarch64")))] all(target_os = "fuchsia", target_arch = "aarch64")))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8; #[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", all(target_os = "android", any(target_arch = "aarch64",
target_arch = "arm")), target_arch = "arm")),
all(target_os = "l4re", target_arch = "x86_64"), 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 = "openbsd", target_arch = "aarch64"),
all(target_os = "fuchsia", target_arch = "aarch64"))))] all(target_os = "fuchsia", target_arch = "aarch64"))))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8; #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8;

30
ctr-std/src/panic.rs

@ -15,11 +15,14 @@
use any::Any; use any::Any;
use cell::UnsafeCell; use cell::UnsafeCell;
use fmt; use fmt;
use future::Future;
use mem::PinMut;
use ops::{Deref, DerefMut}; use ops::{Deref, DerefMut};
use panicking; use panicking;
use ptr::{Unique, NonNull}; use ptr::{Unique, NonNull};
use rc::Rc; use rc::Rc;
use sync::{Arc, Mutex, RwLock, atomic}; use sync::{Arc, Mutex, RwLock, atomic};
use task::{self, Poll};
use thread::Result; use thread::Result;
#[stable(feature = "panic_hooks", since = "1.10.0")] #[stable(feature = "panic_hooks", since = "1.10.0")]
@ -107,8 +110,10 @@ pub use core::panic::{PanicInfo, Location};
/// ///
/// [`AssertUnwindSafe`]: ./struct.AssertUnwindSafe.html /// [`AssertUnwindSafe`]: ./struct.AssertUnwindSafe.html
#[stable(feature = "catch_unwind", since = "1.9.0")] #[stable(feature = "catch_unwind", since = "1.9.0")]
#[rustc_on_unimplemented = "the type {Self} may not be safely transferred \ #[rustc_on_unimplemented(
across an unwind boundary"] 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 {} pub auto trait UnwindSafe {}
/// A marker trait representing types where a shared reference is considered /// A marker trait representing types where a shared reference is considered
@ -123,9 +128,12 @@ pub auto trait UnwindSafe {}
/// [`UnsafeCell`]: ../cell/struct.UnsafeCell.html /// [`UnsafeCell`]: ../cell/struct.UnsafeCell.html
/// [`UnwindSafe`]: ./trait.UnwindSafe.html /// [`UnwindSafe`]: ./trait.UnwindSafe.html
#[stable(feature = "catch_unwind", since = "1.9.0")] #[stable(feature = "catch_unwind", since = "1.9.0")]
#[rustc_on_unimplemented = "the type {Self} may contain interior mutability \ #[rustc_on_unimplemented(
and a reference may not be safely transferrable \ message="the type `{Self}` may contain interior mutability and a reference may not be safely \
across a catch_unwind boundary"] 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 {} pub auto trait RefUnwindSafe {}
/// A simple wrapper around a type to assert that it is unwind safe. /// 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. /// 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 /// 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")] #[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) panicking::update_count_then_panic(payload)
} }

132
ctr-std/src/panicking.rs

@ -36,7 +36,7 @@ use sys_common::util;
use thread; use thread;
thread_local! { thread_local! {
pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = { pub static LOCAL_STDERR: RefCell<Option<Box<dyn Write + Send>>> = {
RefCell::new(None) RefCell::new(None)
} }
} }
@ -64,7 +64,7 @@ extern {
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
enum Hook { enum Hook {
Default, Default,
Custom(*mut (Fn(&PanicInfo) + 'static + Sync + Send)), Custom(*mut (dyn Fn(&PanicInfo) + 'static + Sync + Send)),
} }
static HOOK_LOCK: RWLock = RWLock::new(); static HOOK_LOCK: RWLock = RWLock::new();
@ -104,7 +104,7 @@ static mut HOOK: Hook = Hook::Default;
/// panic!("Normal panic"); /// panic!("Normal panic");
/// ``` /// ```
#[stable(feature = "panic_hooks", since = "1.10.0")] #[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() { if thread::panicking() {
panic!("cannot modify the panic hook from a panicking thread"); 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"); /// panic!("Normal panic");
/// ``` /// ```
#[stable(feature = "panic_hooks", since = "1.10.0")] #[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() { if thread::panicking() {
panic!("cannot modify the panic hook from a panicking thread"); panic!("cannot modify the panic hook from a panicking thread");
} }
@ -222,7 +222,7 @@ fn default_hook(info: &PanicInfo) {
consoleDebugInit(debugDevice_SVC); consoleDebugInit(debugDevice_SVC);
} }
let write = |err: &mut ::io::Write| { let write = |err: &mut dyn (::io::Write)| {
let _ = writeln!(err, "thread '{}' panicked at '{}', {}", let _ = writeln!(err, "thread '{}' panicked at '{}', {}",
name, msg, location); name, msg, location);
@ -273,7 +273,7 @@ pub fn update_panic_count(amt: isize) -> usize {
pub use realstd::rt::update_panic_count; pub use realstd::rt::update_panic_count;
/// Invoke a closure, capturing the cause of an unwinding panic if one occurs. /// 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)] #[allow(unions_with_drop_fields)]
union Data<F, R> { union Data<F, R> {
f: F, f: F,
@ -344,18 +344,6 @@ pub fn panicking() -> bool {
/// Entry point of panic from the libcore crate. /// Entry point of panic from the libcore crate.
#[cfg(not(test))] #[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] #[panic_implementation]
#[unwind(allowed)] #[unwind(allowed)]
pub fn rust_begin_panic(info: &PanicInfo) -> ! { 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 /// 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 /// on (e.g.) the inlining of other functions as possible), by moving
/// the actual formatting into this shared place. /// the actual formatting into this shared place.
#[cfg(stage0)]
#[unstable(feature = "libstd_sys_internals", #[unstable(feature = "libstd_sys_internals",
reason = "used by the panic! macro", reason = "used by the panic! macro",
issue = "0")] issue = "0")]
#[inline(never)] #[cold] #[inline(never)] #[cold]
pub fn begin_panic_fmt(msg: &fmt::Arguments, pub fn begin_panic_fmt(msg: &fmt::Arguments,
file_line_col: &(&'static str, u32, u32)) -> ! { file_line_col: &(&'static str, u32, u32)) -> ! {
// We do two allocations here, unfortunately. But (a) they're let (file, line, col) = *file_line_col;
// required with the current scheme, and (b) we don't handle let info = PanicInfo::internal_constructor(
// panic + OOM properly anyway (see comment in begin_panic Some(msg),
// below). Location::internal_constructor(file, line, col),
);
rust_panic_with_hook(&mut PanicPayload::new(msg), Some(msg), file_line_col); continue_panic_fmt(&info)
}
// NOTE(stage0) move into `continue_panic_fmt` on next stage0 update
struct PanicPayload<'a> {
inner: &'a fmt::Arguments<'a>,
string: Option<String>,
} }
impl<'a> PanicPayload<'a> { fn continue_panic_fmt(info: &PanicInfo) -> ! {
fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> { struct PanicPayload<'a> {
PanicPayload { inner, string: None } inner: &'a fmt::Arguments<'a>,
string: Option<String>,
} }
fn fill(&mut self) -> &mut String { impl<'a> PanicPayload<'a> {
use fmt::Write; fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> {
PanicPayload { inner, string: None }
}
let inner = self.inner; fn fill(&mut self) -> &mut String {
self.string.get_or_insert_with(|| { use fmt::Write;
let mut s = String::new();
drop(s.write_fmt(*inner));
s
})
}
}
unsafe impl<'a> BoxMeUp for PanicPayload<'a> { let inner = self.inner;
fn box_me_up(&mut self) -> *mut (Any + Send) { self.string.get_or_insert_with(|| {
let contents = mem::replace(self.fill(), String::new()); let mut s = String::new();
Box::into_raw(Box::new(contents)) drop(s.write_fmt(*inner));
s
})
}
} }
fn get(&mut self) -> &(Any + Send) { unsafe impl<'a> BoxMeUp for PanicPayload<'a> {
self.fill() 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. fn get(&mut self) -> &(dyn Any + Send) {
/// self.fill()
/// 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)
}
#[cfg(not(stage0))]
fn continue_panic_fmt(info: &PanicInfo) -> ! {
// We do two allocations here, unfortunately. But (a) they're // We do two allocations here, unfortunately. But (a) they're
// required with the current scheme, and (b) we don't handle // required with the current scheme, and (b) we don't handle
// panic + OOM properly anyway (see comment in begin_panic // 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> { 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() { 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(()), None => Box::new(()),
}; };
Box::into_raw(data) Box::into_raw(data)
} }
fn get(&mut self) -> &(Any + Send) { fn get(&mut self) -> &(dyn Any + Send) {
match self.inner { match self.inner {
Some(ref a) => a, Some(ref a) => a,
None => &(), 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 /// Executes the primary logic for a panic, including checking for recursive
/// panics, panic hooks, and finally dispatching to the panic runtime to either /// panics, panic hooks, and finally dispatching to the panic runtime to either
/// abort or unwind. /// abort or unwind.
fn rust_panic_with_hook(payload: &mut BoxMeUp, fn rust_panic_with_hook(payload: &mut dyn BoxMeUp,
message: Option<&fmt::Arguments>, message: Option<&fmt::Arguments>,
file_line_col: &(&str, u32, u32)) -> ! { file_line_col: &(&str, u32, u32)) -> ! {
let (file, line, col) = *file_line_col; 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. /// 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); update_panic_count(1);
struct RewrapBox(Box<Any + Send>); struct RewrapBox(Box<dyn Any + Send>);
unsafe impl BoxMeUp for RewrapBox { 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(()))) 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 &*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. /// A private no-mangle function on which to slap yer breakpoints.
#[no_mangle] #[no_mangle]
#[allow(private_no_mangle_fns)] // yes we get it, but we like breakpoints #[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 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) __rust_start_panic(obj as usize)
}; };
rtabort!("failed to initiate panic, error {}", code) rtabort!("failed to initiate panic, error {}", code)

31
ctr-std/src/path.rs

@ -1045,8 +1045,6 @@ impl<'a> cmp::Ord for Components<'a> {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// #![feature(path_ancestors)]
///
/// use std::path::Path; /// use std::path::Path;
/// ///
/// let path = Path::new("/foo/bar"); /// let path = Path::new("/foo/bar");
@ -1059,26 +1057,23 @@ impl<'a> cmp::Ord for Components<'a> {
/// [`ancestors`]: struct.Path.html#method.ancestors /// [`ancestors`]: struct.Path.html#method.ancestors
/// [`Path`]: struct.Path.html /// [`Path`]: struct.Path.html
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[unstable(feature = "path_ancestors", issue = "48581")] #[stable(feature = "path_ancestors", since = "1.28.0")]
pub struct Ancestors<'a> { pub struct Ancestors<'a> {
next: Option<&'a Path>, next: Option<&'a Path>,
} }
#[unstable(feature = "path_ancestors", issue = "48581")] #[stable(feature = "path_ancestors", since = "1.28.0")]
impl<'a> Iterator for Ancestors<'a> { impl<'a> Iterator for Ancestors<'a> {
type Item = &'a Path; type Item = &'a Path;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let next = self.next; let next = self.next;
self.next = match next { self.next = next.and_then(Path::parent);
Some(path) => path.parent(),
None => None,
};
next next
} }
} }
#[unstable(feature = "path_ancestors", issue = "48581")] #[stable(feature = "path_ancestors", since = "1.28.0")]
impl<'a> FusedIterator for Ancestors<'a> {} 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")] #[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized + AsRef<OsStr>> From<&'a T> for PathBuf { impl<'a, T: ?Sized + AsRef<OsStr>> From<&'a T> for PathBuf {
fn from(s: &'a T) -> PathBuf { fn from(s: &'a T) -> PathBuf {
@ -1737,9 +1740,11 @@ impl Path {
/// Converts a `Path` to a [`Cow<str>`]. /// 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 /// [`Cow<str>`]: ../borrow/enum.Cow.html
/// [U+FFFD]: ../char/constant.REPLACEMENT_CHARACTER.html
/// ///
/// # Examples /// # Examples
/// ///
@ -1833,7 +1838,7 @@ impl Path {
/// * On Unix, a path has a root if it begins with `/`. /// * On Unix, a path has a root if it begins with `/`.
/// ///
/// * On Windows, a path has a root if it: /// * 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 a prefix followed by a separator, e.g. `c:\windows` but not `c:windows`
/// * has any non-disk prefix, e.g. `\\server\share` /// * has any non-disk prefix, e.g. `\\server\share`
/// ///
@ -1893,8 +1898,6 @@ impl Path {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// #![feature(path_ancestors)]
///
/// use std::path::Path; /// use std::path::Path;
/// ///
/// let mut ancestors = Path::new("/foo/bar").ancestors(); /// let mut ancestors = Path::new("/foo/bar").ancestors();
@ -1906,7 +1909,7 @@ impl Path {
/// ///
/// [`None`]: ../../std/option/enum.Option.html#variant.None /// [`None`]: ../../std/option/enum.Option.html#variant.None
/// [`parent`]: struct.Path.html#method.parent /// [`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 { pub fn ancestors(&self) -> Ancestors {
Ancestors { Ancestors {
next: Some(&self), next: Some(&self),

58
ctr-std/src/prelude/v1.rs

@ -12,42 +12,68 @@
//! //!
//! See the [module-level documentation](../index.html) for more. //! See the [module-level documentation](../index.html) for more.
#![stable(feature = "rust1", since = "1.0.0")] #![stable(feature = "rust1", since = "1.0.0")]
// Re-exported core operators // Re-exported core operators
#[stable(feature = "rust1", since = "1.0.0")] #[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")] #[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 // Re-exported functions
#[stable(feature = "rust1", since = "1.0.0")] #[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 // Re-exported types and traits
#[stable(feature = "rust1", since = "1.0.0")] #[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")] #[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")] #[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")] #[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")] #[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")] #[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")] #[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")] #[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")] #[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")] #[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")] #[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")] #[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")] #[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use vec::Vec; #[doc(no_inline)]
pub use vec::Vec;

37
ctr-std/src/process.rs

@ -381,6 +381,39 @@ impl fmt::Debug for ChildStderr {
/// ///
/// let hello = output.stdout; /// 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")] #[stable(feature = "process", since = "1.0.0")]
pub struct Command { pub struct Command {
inner: imp::Command, inner: imp::Command,
@ -813,13 +846,13 @@ impl fmt::Debug for Output {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let stdout_utf8 = str::from_utf8(&self.stdout); 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, Ok(ref str) => str,
Err(_) => &self.stdout Err(_) => &self.stdout
}; };
let stderr_utf8 = str::from_utf8(&self.stderr); 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, Ok(ref str) => str,
Err(_) => &self.stderr Err(_) => &self.stderr
}; };

2
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 // To reduce the generated code of the new `lang_start`, this function is doing
// the real work. // the real work.
#[cfg(not(test))] #[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 { argc: isize, argv: *const *const u8) -> isize {
use panic; use panic;
use sys; use sys;

2
ctr-std/src/sync/mod.rs

@ -18,7 +18,7 @@
#![stable(feature = "rust1", since = "1.0.0")] #![stable(feature = "rust1", since = "1.0.0")]
#[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")] #[stable(feature = "rust1", since = "1.0.0")]
pub use core::sync::atomic; pub use core::sync::atomic;

40
ctr-std/src/sync/mpsc/mod.rs

@ -689,7 +689,7 @@ impl<T> UnsafeFlavor<T> for Receiver<T> {
/// only one [`Receiver`] is supported. /// only one [`Receiver`] is supported.
/// ///
/// If the [`Receiver`] is disconnected while trying to [`send`] with the /// 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 /// [`Sender`] is disconnected while trying to [`recv`], the [`recv`] method will
/// return a [`RecvError`]. /// return a [`RecvError`].
/// ///
@ -1247,6 +1247,34 @@ impl<T> Receiver<T> {
/// [`SyncSender`]: struct.SyncSender.html /// [`SyncSender`]: struct.SyncSender.html
/// [`Err`]: ../../../std/result/enum.Result.html#variant.Err /// [`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 /// # Examples
/// ///
/// Successfully receiving value before encountering timeout: /// Successfully receiving value before encountering timeout:
@ -1638,7 +1666,7 @@ impl<T: Send> error::Error for SendError<T> {
"sending on a closed channel" "sending on a closed channel"
} }
fn cause(&self) -> Option<&error::Error> { fn cause(&self) -> Option<&dyn error::Error> {
None 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 None
} }
} }
@ -1709,7 +1737,7 @@ impl error::Error for RecvError {
"receiving on a closed channel" "receiving on a closed channel"
} }
fn cause(&self) -> Option<&error::Error> { fn cause(&self) -> Option<&dyn error::Error> {
None None
} }
} }
@ -1742,7 +1770,7 @@ impl error::Error for TryRecvError {
} }
} }
fn cause(&self) -> Option<&error::Error> { fn cause(&self) -> Option<&dyn error::Error> {
None None
} }
} }
@ -1783,7 +1811,7 @@ impl error::Error for RecvTimeoutError {
} }
} }
fn cause(&self) -> Option<&error::Error> { fn cause(&self) -> Option<&dyn error::Error> {
None None
} }
} }

2
ctr-std/src/sync/mpsc/select.rs

@ -93,7 +93,7 @@ pub struct Handle<'rx, T:Send+'rx> {
next: *mut Handle<'static, ()>, next: *mut Handle<'static, ()>,
prev: *mut Handle<'static, ()>, prev: *mut Handle<'static, ()>,
added: bool, 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 // due to our fun transmutes, we be sure to place this at the end. (nothing
// previous relies on T) // previous relies on T)

4
ctr-std/src/sync/mutex.rs

@ -227,7 +227,7 @@ impl<T: ?Sized> Mutex<T> {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn lock(&self) -> LockResult<MutexGuard<T>> { pub fn lock(&self) -> LockResult<MutexGuard<T>> {
unsafe { unsafe {
self.inner.lock(); self.inner.raw_lock();
MutexGuard::new(self) MutexGuard::new(self)
} }
} }
@ -454,7 +454,7 @@ impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
self.__lock.poison.done(&self.__poison); self.__lock.poison.done(&self.__poison);
self.__lock.inner.unlock(); self.__lock.inner.raw_unlock();
} }
} }
} }

40
ctr-std/src/sync/once.rs

@ -31,12 +31,10 @@
// initialization closure panics, the Once enters a "poisoned" state which means // initialization closure panics, the Once enters a "poisoned" state which means
// that all future calls will immediately panic as well. // that all future calls will immediately panic as well.
// //
// So to implement this, one might first reach for a `StaticMutex`, but those // So to implement this, one might first reach for a `Mutex`, but those cannot
// unfortunately need to be deallocated (e.g. call `destroy()`) to free memory // be put into a `static`. It also gets a lot harder with poisoning to figure
// on all OSes (some of the BSDs allocate memory for mutexes). It also gets a // out when the mutex needs to be deallocated because it's not after the closure
// lot harder with poisoning to figure out when the mutex needs to be // finishes, but after the first successful closure finishes.
// 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 // 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 // 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` // Helper struct used to clean up after a closure call with a `Drop`
// implementation to also run on panic. // implementation to also run on panic.
struct Finish { struct Finish<'a> {
panicked: bool, panicked: bool,
me: &'static Once, me: &'a Once,
} }
impl Once { impl Once {
@ -178,6 +176,10 @@ impl Once {
/// happens-before relation between the closure and code executing after the /// happens-before relation between the closure and code executing after the
/// return). /// 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 /// # Examples
/// ///
/// ``` /// ```
@ -218,9 +220,13 @@ impl Once {
/// ///
/// [poison]: struct.Mutex.html#poisoning /// [poison]: struct.Mutex.html#poisoning
#[stable(feature = "rust1", since = "1.0.0")] #[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. // 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 return
} }
@ -275,9 +281,13 @@ impl Once {
/// INIT.call_once(|| {}); /// INIT.call_once(|| {});
/// ``` /// ```
#[unstable(feature = "once_poison", issue = "33577")] #[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`. // 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 return
} }
@ -299,9 +309,9 @@ impl Once {
// currently no way to take an `FnOnce` and call it via virtual dispatch // currently no way to take an `FnOnce` and call it via virtual dispatch
// without some allocation overhead. // without some allocation overhead.
#[cold] #[cold]
fn call_inner(&'static self, fn call_inner(&self,
ignore_poisoning: bool, ignore_poisoning: bool,
init: &mut FnMut(bool)) { init: &mut dyn FnMut(bool)) {
let mut state = self.state.load(Ordering::SeqCst); let mut state = self.state.load(Ordering::SeqCst);
'outer: loop { '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) { fn drop(&mut self) {
// Swap out our state with however we finished. We should only ever see // Swap out our state with however we finished. We should only ever see
// an old state which was RUNNING. // an old state which was RUNNING.

18
ctr-std/src/sys/cloudabi/abi/cloudabi.rs

@ -121,6 +121,7 @@ include!("bitflags.rs");
/// File or memory access pattern advisory information. /// File or memory access pattern advisory information.
#[repr(u8)] #[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub enum advice { pub enum advice {
/// The application expects that it will not access the /// The application expects that it will not access the
/// specified data in the near future. /// specified data in the near future.
@ -140,12 +141,12 @@ pub enum advice {
/// The application expects to access the specified data /// The application expects to access the specified data
/// in the near future. /// in the near future.
WILLNEED = 6, WILLNEED = 6,
#[doc(hidden)] _NonExhaustive = -1 as isize as u8,
} }
/// Enumeration describing the kind of value stored in [`auxv`](struct.auxv.html). /// Enumeration describing the kind of value stored in [`auxv`](struct.auxv.html).
#[repr(u32)] #[repr(u32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub enum auxtype { pub enum auxtype {
/// Base address of the binary argument data provided to /// Base address of the binary argument data provided to
/// [`proc_exec()`](fn.proc_exec.html). /// [`proc_exec()`](fn.proc_exec.html).
@ -210,12 +211,12 @@ pub enum auxtype {
SYSINFO_EHDR = 262, SYSINFO_EHDR = 262,
/// Thread ID of the initial thread of the process. /// Thread ID of the initial thread of the process.
TID = 261, TID = 261,
#[doc(hidden)] _NonExhaustive = -1 as isize as u32,
} }
/// Identifiers for clocks. /// Identifiers for clocks.
#[repr(u32)] #[repr(u32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub enum clockid { pub enum clockid {
/// The system-wide monotonic clock, which is defined as a /// The system-wide monotonic clock, which is defined as a
/// clock measuring real time, whose value cannot be /// clock measuring real time, whose value cannot be
@ -232,7 +233,6 @@ pub enum clockid {
REALTIME = 3, REALTIME = 3,
/// The CPU-time clock associated with the current thread. /// The CPU-time clock associated with the current thread.
THREAD_CPUTIME_ID = 4, THREAD_CPUTIME_ID = 4,
#[doc(hidden)] _NonExhaustive = -1 as isize as u32,
} }
/// A userspace condition variable. /// A userspace condition variable.
@ -267,6 +267,7 @@ pub const DIRCOOKIE_START: dircookie = dircookie(0);
/// exclusively or merely provided for alignment with POSIX. /// exclusively or merely provided for alignment with POSIX.
#[repr(u16)] #[repr(u16)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub enum errno { pub enum errno {
/// No error occurred. System call completed successfully. /// No error occurred. System call completed successfully.
SUCCESS = 0, SUCCESS = 0,
@ -422,7 +423,6 @@ pub enum errno {
XDEV = 75, XDEV = 75,
/// Extension: Capabilities insufficient. /// Extension: Capabilities insufficient.
NOTCAPABLE = 76, NOTCAPABLE = 76,
#[doc(hidden)] _NonExhaustive = -1 as isize as u16,
} }
bitflags! { bitflags! {
@ -438,6 +438,7 @@ bitflags! {
/// Type of a subscription to an event or its occurrence. /// Type of a subscription to an event or its occurrence.
#[repr(u8)] #[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub enum eventtype { pub enum eventtype {
/// The time value of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id) /// 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). /// 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 /// The process associated with process descriptor
/// [`subscription.union.proc_terminate.fd`](struct.subscription_proc_terminate.html#structfield.fd) has terminated. /// [`subscription.union.proc_terminate.fd`](struct.subscription_proc_terminate.html#structfield.fd) has terminated.
PROC_TERMINATE = 7, PROC_TERMINATE = 7,
#[doc(hidden)] _NonExhaustive = -1 as isize as u8,
} }
/// Exit code generated by a process when exiting. /// Exit code generated by a process when exiting.
@ -530,6 +530,7 @@ pub type filesize = u64;
/// The type of a file descriptor or file. /// The type of a file descriptor or file.
#[repr(u8)] #[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub enum filetype { pub enum filetype {
/// The type of the file descriptor or file is unknown or /// The type of the file descriptor or file is unknown or
/// is different from any of the other types specified. /// is different from any of the other types specified.
@ -558,7 +559,6 @@ pub enum filetype {
SOCKET_STREAM = 130, SOCKET_STREAM = 130,
/// The file refers to a symbolic link inode. /// The file refers to a symbolic link inode.
SYMBOLIC_LINK = 144, SYMBOLIC_LINK = 144,
#[doc(hidden)] _NonExhaustive = -1 as isize as u8,
} }
bitflags! { bitflags! {
@ -847,12 +847,12 @@ bitflags! {
/// memory. /// memory.
#[repr(u8)] #[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub enum scope { pub enum scope {
/// The object is stored in private memory. /// The object is stored in private memory.
PRIVATE = 4, PRIVATE = 4,
/// The object is stored in shared memory. /// The object is stored in shared memory.
SHARED = 8, SHARED = 8,
#[doc(hidden)] _NonExhaustive = -1 as isize as u8,
} }
bitflags! { bitflags! {
@ -878,6 +878,7 @@ bitflags! {
/// Signal condition. /// Signal condition.
#[repr(u8)] #[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub enum signal { pub enum signal {
/// Process abort signal. /// Process abort signal.
/// ///
@ -983,7 +984,6 @@ pub enum signal {
/// ///
/// Action: Terminates the process. /// Action: Terminates the process.
XFSZ = 26, XFSZ = 26,
#[doc(hidden)] _NonExhaustive = -1 as isize as u8,
} }
bitflags! { bitflags! {
@ -1049,6 +1049,7 @@ pub type userdata = u64;
/// should be set. /// should be set.
#[repr(u8)] #[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub enum whence { pub enum whence {
/// Seek relative to current position. /// Seek relative to current position.
CUR = 1, CUR = 1,
@ -1056,7 +1057,6 @@ pub enum whence {
END = 2, END = 2,
/// Seek relative to start-of-file. /// Seek relative to start-of-file.
SET = 3, SET = 3,
#[doc(hidden)] _NonExhaustive = -1 as isize as u8,
} }
/// Auxiliary vector entry. /// Auxiliary vector entry.

18
ctr-std/src/sys/cloudabi/backtrace.rs

@ -64,6 +64,10 @@ extern "C" fn trace_fn(
arg: *mut libc::c_void, arg: *mut libc::c_void,
) -> uw::_Unwind_Reason_Code { ) -> uw::_Unwind_Reason_Code {
let cx = unsafe { &mut *(arg as *mut Context) }; 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_before_insn = 0;
let mut ip = unsafe { uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void }; 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 { if !ip.is_null() && ip_before_insn == 0 {
@ -73,14 +77,12 @@ extern "C" fn trace_fn(
} }
let symaddr = unsafe { uw::_Unwind_FindEnclosingFunction(ip) }; let symaddr = unsafe { uw::_Unwind_FindEnclosingFunction(ip) };
if cx.idx < cx.frames.len() { cx.frames[cx.idx] = Frame {
cx.frames[cx.idx] = Frame { symbol_addr: symaddr as *mut u8,
symbol_addr: symaddr as *mut u8, exact_position: ip as *mut u8,
exact_position: ip as *mut u8, inline_context: 0,
inline_context: 0, };
}; cx.idx += 1;
cx.idx += 1;
}
uw::_URC_NO_REASON uw::_URC_NO_REASON
} }

2
ctr-std/src/sys/cloudabi/thread.rs

@ -32,7 +32,7 @@ unsafe impl Send for Thread {}
unsafe impl Sync for Thread {} unsafe impl Sync for Thread {}
impl 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 p = box p;
let mut native: libc::pthread_t = mem::zeroed(); let mut native: libc::pthread_t = mem::zeroed();
let mut attr: libc::pthread_attr_t = mem::zeroed(); let mut attr: libc::pthread_attr_t = mem::zeroed();

13
ctr-std/src/sys/horizon/net.rs

@ -148,7 +148,9 @@ impl Socket {
let mut pollfd = libc::pollfd { let mut pollfd = libc::pollfd {
fd: self.0.raw(), 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, revents: 0,
}; };
@ -184,9 +186,9 @@ impl Socket {
} }
0 => {} 0 => {}
_ => { _ => {
// linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look // `libc::POLLHUP` should be 0x4, but the constant is currently defined
// for POLLHUP rather than read readiness // incorrectly for 3DS. So we just specifiy it manually for now.
if pollfd.revents & libc::POLLHUP != 0 { if pollfd.revents & 0x4 != 0 {
let e = self.take_error()? let e = self.take_error()?
.unwrap_or_else(|| { .unwrap_or_else(|| {
io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP") 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<()> { pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
let mut nonblocking = nonblocking as libc::c_int; self.0.set_nonblocking(nonblocking)
cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO as u32, &mut nonblocking) }).map(|_| ())
} }
pub fn take_error(&self) -> io::Result<Option<io::Error>> { pub fn take_error(&self) -> io::Result<Option<io::Error>> {

3
ctr-std/src/sys/mod.rs

@ -70,6 +70,7 @@ cfg_if! {
// (missing things in `libc` which is empty) so just omit everything // (missing things in `libc` which is empty) so just omit everything
// with an empty module // with an empty module
#[unstable(issue = "0", feature = "std_internals")] #[unstable(issue = "0", feature = "std_internals")]
#[allow(missing_docs)]
pub mod unix_ext {} pub mod unix_ext {}
} else { } else {
// On other platforms like Windows document the bare bones of unix // On other platforms like Windows document the bare bones of unix
@ -83,11 +84,13 @@ cfg_if! {
cfg_if! { cfg_if! {
if #[cfg(windows)] { if #[cfg(windows)] {
// On windows we'll just be documenting what's already available // On windows we'll just be documenting what's already available
#[allow(missing_docs)]
pub use self::ext as windows_ext; pub use self::ext as windows_ext;
} else if #[cfg(any(target_os = "cloudabi", target_arch = "wasm32"))] { } else if #[cfg(any(target_os = "cloudabi", target_arch = "wasm32"))] {
// On CloudABI and wasm right now the shim below doesn't compile, so // On CloudABI and wasm right now the shim below doesn't compile, so
// just omit it // just omit it
#[unstable(issue = "0", feature = "std_internals")] #[unstable(issue = "0", feature = "std_internals")]
#[allow(missing_docs)]
pub mod windows_ext {} pub mod windows_ext {}
} else { } else {
// On all other platforms (aka linux/osx/etc) then pull in a "minimal" // On all other platforms (aka linux/osx/etc) then pull in a "minimal"

16
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() CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec()
}).collect(); }).collect();
LOCK.lock(); let _guard = LOCK.lock();
let ptr = get_global_ptr(); let ptr = get_global_ptr();
assert!((*ptr).is_none()); assert!((*ptr).is_none());
(*ptr) = Some(box args); (*ptr) = Some(box args);
LOCK.unlock();
} }
pub unsafe fn cleanup() { pub unsafe fn cleanup() {
LOCK.lock(); let _guard = LOCK.lock();
*get_global_ptr() = None; *get_global_ptr() = None;
LOCK.unlock();
} }
pub fn args() -> Args { pub fn args() -> Args {
@ -96,16 +94,14 @@ mod imp {
fn clone() -> Option<Vec<Vec<u8>>> { fn clone() -> Option<Vec<Vec<u8>>> {
unsafe { unsafe {
LOCK.lock(); let _guard = LOCK.lock();
let ptr = get_global_ptr(); let ptr = get_global_ptr();
let ret = (*ptr).as_ref().map(|s| (**s).clone()); (*ptr).as_ref().map(|s| (**s).clone())
LOCK.unlock();
return ret
} }
} }
fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> { unsafe fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
unsafe { mem::transmute(&GLOBAL_ARGS_PTR) } mem::transmute(&GLOBAL_ARGS_PTR)
} }
} }

18
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, extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
let cx = unsafe { &mut *(arg as *mut Context) }; 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_before_insn = 0;
let mut ip = unsafe { let mut ip = unsafe {
uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void 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) } unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
}; };
if cx.idx < cx.frames.len() { cx.frames[cx.idx] = Frame {
cx.frames[cx.idx] = Frame { symbol_addr: symaddr as *mut u8,
symbol_addr: symaddr as *mut u8, exact_position: ip as *mut u8,
exact_position: ip as *mut u8, inline_context: 0,
inline_context: 0, };
}; cx.idx += 1;
cx.idx += 1;
}
uw::_URC_NO_REASON uw::_URC_NO_REASON
} }

1
ctr-std/src/sys/redox/ext/mod.rs

@ -33,6 +33,7 @@
pub mod ffi; pub mod ffi;
pub mod fs; pub mod fs;
pub mod io; pub mod io;
pub mod net;
pub mod process; pub mod process;
pub mod thread; pub mod thread;

769
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)
}
}

5
ctr-std/src/sys/redox/fd.rs

@ -47,7 +47,10 @@ impl FileDesc {
} }
pub fn duplicate(&self) -> io::Result<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)) Ok(FileDesc::new(new_fd))
} }

4
ctr-std/src/sys/redox/net/mod.rs

@ -41,12 +41,12 @@ impl Iterator for LookupHost {
pub fn lookup_host(host: &str) -> Result<LookupHost> { pub fn lookup_host(host: &str) -> Result<LookupHost> {
let mut ip_string = String::new(); let mut ip_string = String::new();
File::open("/etc/net/ip")?.read_to_string(&mut ip_string)?; 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(); .unwrap_or(0)).collect();
let mut dns_string = String::new(); let mut dns_string = String::new();
File::open("/etc/net/dns")?.read_to_string(&mut dns_string)?; 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(); .unwrap_or(0)).collect();
if ip.len() == 4 && dns.len() == 4 { if ip.len() == 4 && dns.len() == 4 {

2
ctr-std/src/sys/redox/net/netc.rs

@ -24,10 +24,10 @@ pub struct in_addr {
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
#[repr(align(4))]
#[repr(C)] #[repr(C)]
pub struct in6_addr { pub struct in6_addr {
pub s6_addr: [u8; 16], pub s6_addr: [u8; 16],
__align: [u32; 0],
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]

2
ctr-std/src/sys/redox/net/udp.rs

@ -58,7 +58,7 @@ impl UdpSocket {
pub fn recv(&self, buf: &mut [u8]) -> Result<usize> { pub fn recv(&self, buf: &mut [u8]) -> Result<usize> {
if let Some(addr) = *self.get_conn() { 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) from.read(buf)
} else { } else {
Err(Error::new(ErrorKind::Other, "UdpSocket::recv not connected")) Err(Error::new(ErrorKind::Other, "UdpSocket::recv not connected"))

3
ctr-std/src/sys/redox/os.rs

@ -30,9 +30,6 @@ use sys_common::mutex::Mutex;
use sys::{cvt, fd, syscall}; use sys::{cvt, fd, syscall};
use vec; use vec;
const TMPBUF_SZ: usize = 128;
static ENV_LOCK: Mutex = Mutex::new();
extern { extern {
#[link_name = "__errno_location"] #[link_name = "__errno_location"]
fn errno_location() -> *mut i32; fn errno_location() -> *mut i32;

15
ctr-std/src/sys/redox/process.rs

@ -13,6 +13,7 @@ use ffi::OsStr;
use os::unix::ffi::OsStrExt; use os::unix::ffi::OsStrExt;
use fmt; use fmt;
use io::{self, Error, ErrorKind}; use io::{self, Error, ErrorKind};
use iter;
use libc::{EXIT_SUCCESS, EXIT_FAILURE}; use libc::{EXIT_SUCCESS, EXIT_FAILURE};
use path::{Path, PathBuf}; use path::{Path, PathBuf};
use sys::fd::FileDesc; use sys::fd::FileDesc;
@ -51,7 +52,7 @@ pub struct Command {
uid: Option<u32>, uid: Option<u32>,
gid: Option<u32>, gid: Option<u32>,
saw_nul: bool, saw_nul: bool,
closures: Vec<Box<FnMut() -> io::Result<()> + Send + Sync>>, closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
stdin: Option<Stdio>, stdin: Option<Stdio>,
stdout: Option<Stdio>, stdout: Option<Stdio>,
stderr: Option<Stdio>, stderr: Option<Stdio>,
@ -122,7 +123,7 @@ impl Command {
} }
pub fn before_exec(&mut self, 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); self.closures.push(f);
} }
@ -296,11 +297,11 @@ impl Command {
t!(callback()); t!(callback());
} }
let mut args: Vec<[usize; 2]> = Vec::new(); let args: Vec<[usize; 2]> = iter::once(
args.push([self.program.as_ptr() as usize, self.program.len()]); [self.program.as_ptr() as usize, self.program.len()]
for arg in self.args.iter() { ).chain(
args.push([arg.as_ptr() as usize, arg.len()]); self.args.iter().map(|arg| [arg.as_ptr() as usize, arg.len()])
} ).collect();
self.env.apply(); self.env.apply();

2
ctr-std/src/sys/redox/thread.rs

@ -28,7 +28,7 @@ unsafe impl Send for Thread {}
unsafe impl Sync for Thread {} unsafe impl Sync for Thread {}
impl 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 p = box p;
let id = cvt(syscall::clone(syscall::CLONE_VM | syscall::CLONE_FS | syscall::CLONE_FILES))?; let id = cvt(syscall::clone(syscall::CLONE_VM | syscall::CLONE_FS | syscall::CLONE_FILES))?;

19
ctr-std/src/sys/unix/args.rs

@ -66,7 +66,8 @@ impl DoubleEndedIterator for Args {
target_os = "emscripten", target_os = "emscripten",
target_os = "haiku", target_os = "haiku",
target_os = "l4re", target_os = "l4re",
target_os = "fuchsia"))] target_os = "fuchsia",
target_os = "hermit"))]
mod imp { mod imp {
use os::unix::prelude::*; use os::unix::prelude::*;
use ptr; use ptr;
@ -79,20 +80,20 @@ mod imp {
static mut ARGC: isize = 0; static mut ARGC: isize = 0;
static mut ARGV: *const *const u8 = ptr::null(); 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(); static LOCK: Mutex = Mutex::new();
pub unsafe fn init(argc: isize, argv: *const *const u8) { pub unsafe fn init(argc: isize, argv: *const *const u8) {
LOCK.lock(); let _guard = LOCK.lock();
ARGC = argc; ARGC = argc;
ARGV = argv; ARGV = argv;
LOCK.unlock();
} }
pub unsafe fn cleanup() { pub unsafe fn cleanup() {
LOCK.lock(); let _guard = LOCK.lock();
ARGC = 0; ARGC = 0;
ARGV = ptr::null(); ARGV = ptr::null();
LOCK.unlock();
} }
pub fn args() -> Args { pub fn args() -> Args {
@ -104,13 +105,11 @@ mod imp {
fn clone() -> Vec<OsString> { fn clone() -> Vec<OsString> {
unsafe { unsafe {
LOCK.lock(); let _guard = LOCK.lock();
let ret = (0..ARGC).map(|i| { (0..ARGC).map(|i| {
let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char); let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char);
OsStringExt::from_vec(cstr.to_bytes().to_vec()) OsStringExt::from_vec(cstr.to_bytes().to_vec())
}).collect(); }).collect()
LOCK.unlock();
return ret
} }
} }
} }

18
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, extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
let cx = unsafe { &mut *(arg as *mut Context) }; 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_before_insn = 0;
let mut ip = unsafe { let mut ip = unsafe {
uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void 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) } unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
}; };
if cx.idx < cx.frames.len() { cx.frames[cx.idx] = Frame {
cx.frames[cx.idx] = Frame { symbol_addr: symaddr as *mut u8,
symbol_addr: symaddr as *mut u8, exact_position: ip as *mut u8,
exact_position: ip as *mut u8, inline_context: 0,
inline_context: 0, };
}; cx.idx += 1;
cx.idx += 1;
}
uw::_URC_NO_REASON uw::_URC_NO_REASON
} }

13
ctr-std/src/sys/unix/condvar.rs

@ -41,13 +41,15 @@ impl Condvar {
#[cfg(any(target_os = "macos", #[cfg(any(target_os = "macos",
target_os = "ios", target_os = "ios",
target_os = "l4re", target_os = "l4re",
target_os = "android"))] target_os = "android",
target_os = "hermit"))]
pub unsafe fn init(&mut self) {} pub unsafe fn init(&mut self) {}
#[cfg(not(any(target_os = "macos", #[cfg(not(any(target_os = "macos",
target_os = "ios", target_os = "ios",
target_os = "l4re", target_os = "l4re",
target_os = "android")))] target_os = "android",
target_os = "hermit")))]
pub unsafe fn init(&mut self) { pub unsafe fn init(&mut self) {
use mem; use mem;
let mut attr: libc::pthread_condattr_t = mem::uninitialized(); 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 // where we configure condition variable to use monotonic clock (instead of
// default system clock). This approach avoids all problems that result // default system clock). This approach avoids all problems that result
// from changes made to the system time. // 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 { pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
use mem; use mem;
@ -113,7 +118,7 @@ impl Condvar {
// This implementation is modeled after libcxx's condition_variable // 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/src/condition_variable.cpp#L46
// https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367 // 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 { pub unsafe fn wait_timeout(&self, mutex: &Mutex, mut dur: Duration) -> bool {
use ptr; use ptr;
use time::Instant; use time::Instant;

11
ctr-std/src/sys/unix/env.rs

@ -172,3 +172,14 @@ pub mod os {
pub const EXE_SUFFIX: &'static str = ""; pub const EXE_SUFFIX: &'static str = "";
pub const EXE_EXTENSION: &'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 = "";
}

127
ctr-std/src/sys/unix/ext/fs.rs

@ -59,6 +59,78 @@ pub trait FileExt {
#[stable(feature = "file_offset", since = "1.15.0")] #[stable(feature = "file_offset", since = "1.15.0")]
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>; 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. /// Writes a number of bytes starting from a given offset.
/// ///
/// Returns the number of bytes written. /// Returns the number of bytes written.
@ -93,6 +165,61 @@ pub trait FileExt {
/// ``` /// ```
#[stable(feature = "file_offset", since = "1.15.0")] #[stable(feature = "file_offset", since = "1.15.0")]
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>; 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")] #[stable(feature = "file_offset", since = "1.15.0")]

1
ctr-std/src/sys/unix/ext/mod.rs

@ -35,6 +35,7 @@
#![stable(feature = "rust1", since = "1.0.0")] #![stable(feature = "rust1", since = "1.0.0")]
#![doc(cfg(unix))] #![doc(cfg(unix))]
#![allow(missing_docs)]
pub mod io; pub mod io;
pub mod ffi; pub mod ffi;

6
ctr-std/src/sys/unix/ext/net.rs

@ -524,6 +524,9 @@ impl UnixStream {
/// println!("Got error: {:?}", err); /// println!("Got error: {:?}", err);
/// } /// }
/// ``` /// ```
///
/// # Platform specific
/// On Redox this always returns None.
#[stable(feature = "unix_socket", since = "1.10.0")] #[stable(feature = "unix_socket", since = "1.10.0")]
pub fn take_error(&self) -> io::Result<Option<io::Error>> { pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.0.take_error() self.0.take_error()
@ -846,6 +849,9 @@ impl UnixListener {
/// println!("Got error: {:?}", err); /// println!("Got error: {:?}", err);
/// } /// }
/// ``` /// ```
///
/// # Platform specific
/// On Redox this always returns None.
#[stable(feature = "unix_socket", since = "1.10.0")] #[stable(feature = "unix_socket", since = "1.10.0")]
pub fn take_error(&self) -> io::Result<Option<io::Error>> { pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.0.take_error() self.0.take_error()

7
ctr-std/src/sys/unix/fast_thread_local.rs

@ -20,7 +20,7 @@
// fallback implementation to use as well. // fallback implementation to use as well.
// //
// Due to rust-lang/rust#18804, make sure this is not generic! // 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)) { pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
use libc; use libc;
use mem; use mem;
@ -55,11 +55,6 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
_tlv_atexit(dtor, t); _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 { pub fn requires_move_before_drop() -> bool {
// The macOS implementation of TLS apparently had an odd aspect to it // The macOS implementation of TLS apparently had an odd aspect to it
// where the pointer we have may be overwritten while this destructor // where the pointer we have may be overwritten while this destructor

56
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"))] #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))]
use libc::{stat64, fstat64, lstat64, off64_t, ftruncate64, lseek64, dirent64, readdir64_r, open64}; 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"))] #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))]
use libc::{fstatat, dirfd}; use libc::dirfd;
#[cfg(target_os = "android")] #[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}; dirent as dirent64, open as open64};
#[cfg(not(any(target_os = "linux", #[cfg(not(any(target_os = "linux",
target_os = "emscripten", target_os = "emscripten",
@ -57,7 +59,10 @@ struct InnerReadDir {
} }
#[derive(Clone)] #[derive(Clone)]
pub struct ReadDir(Arc<InnerReadDir>); pub struct ReadDir {
inner: Arc<InnerReadDir>,
end_of_stream: bool,
}
struct Dir(*mut libc::DIR); struct Dir(*mut libc::DIR);
@ -213,7 +218,7 @@ impl fmt::Debug for ReadDir {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
// Thus the result will be e g 'ReadDir("/home")' // 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 // is safe to use in threaded applications and it is generally preferred
// over the readdir_r(3C) function. // over the readdir_r(3C) function.
super::os::set_errno(0); 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() { if entry_ptr.is_null() {
// NULL can mean either the end is reached or an error occurred. // 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. // 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")))] #[cfg(not(any(target_os = "solaris", target_os = "fuchsia")))]
fn next(&mut self) -> Option<io::Result<DirEntry>> { fn next(&mut self) -> Option<io::Result<DirEntry>> {
if self.end_of_stream {
return None;
}
unsafe { unsafe {
let mut ret = DirEntry { let mut ret = DirEntry {
entry: mem::zeroed(), entry: mem::zeroed(),
@ -264,7 +273,14 @@ impl Iterator for ReadDir {
}; };
let mut entry_ptr = ptr::null_mut(); let mut entry_ptr = ptr::null_mut();
loop { 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())) return Some(Err(Error::last_os_error()))
} }
if entry_ptr.is_null() { if entry_ptr.is_null() {
@ -287,7 +303,7 @@ impl Drop for Dir {
impl DirEntry { impl DirEntry {
pub fn path(&self) -> PathBuf { 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 { pub fn file_name(&self) -> OsString {
@ -296,13 +312,10 @@ impl DirEntry {
#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))]
pub fn metadata(&self) -> io::Result<FileAttr> { 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() }; let mut stat: stat64 = unsafe { mem::zeroed() };
cvt(unsafe { cvt(unsafe {
fstatat(fd, fstatat64(fd, self.entry.d_name.as_ptr(), &mut stat, libc::AT_SYMLINK_NOFOLLOW)
self.entry.d_name.as_ptr(),
&mut stat as *mut _ as *mut _,
libc::AT_SYMLINK_NOFOLLOW)
})?; })?;
Ok(FileAttr { stat: stat }) Ok(FileAttr { stat: stat })
} }
@ -312,12 +325,12 @@ impl DirEntry {
lstat(&self.path()) 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> { pub fn file_type(&self) -> io::Result<FileType> {
lstat(&self.path()).map(|m| m.file_type()) 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> { pub fn file_type(&self) -> io::Result<FileType> {
match self.entry.d_type { match self.entry.d_type {
libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }), libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }),
@ -339,7 +352,8 @@ impl DirEntry {
target_os = "solaris", target_os = "solaris",
target_os = "haiku", target_os = "haiku",
target_os = "l4re", target_os = "l4re",
target_os = "fuchsia"))] target_os = "fuchsia",
target_os = "hermit"))]
pub fn ino(&self) -> u64 { pub fn ino(&self) -> u64 {
self.entry.d_ino as u64 self.entry.d_ino as u64
} }
@ -370,7 +384,8 @@ impl DirEntry {
target_os = "linux", target_os = "linux",
target_os = "emscripten", target_os = "emscripten",
target_os = "l4re", target_os = "l4re",
target_os = "haiku"))] target_os = "haiku",
target_os = "hermit"))]
fn name_bytes(&self) -> &[u8] { fn name_bytes(&self) -> &[u8] {
unsafe { unsafe {
CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() 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()) Err(Error::last_os_error())
} else { } else {
let inner = InnerReadDir { dirp: Dir(ptr), root }; 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 p = cstr(p)?;
let mut stat: stat64 = unsafe { mem::zeroed() }; let mut stat: stat64 = unsafe { mem::zeroed() };
cvt(unsafe { cvt(unsafe {
stat64(p.as_ptr(), &mut stat as *mut _ as *mut _) stat64(p.as_ptr(), &mut stat)
})?; })?;
Ok(FileAttr { stat: stat }) Ok(FileAttr { stat: stat })
} }
@ -796,7 +814,7 @@ pub fn lstat(p: &Path) -> io::Result<FileAttr> {
let p = cstr(p)?; let p = cstr(p)?;
let mut stat: stat64 = unsafe { mem::zeroed() }; let mut stat: stat64 = unsafe { mem::zeroed() };
cvt(unsafe { cvt(unsafe {
lstat64(p.as_ptr(), &mut stat as *mut _ as *mut _) lstat64(p.as_ptr(), &mut stat)
})?; })?;
Ok(FileAttr { stat: stat }) Ok(FileAttr { stat: stat })
} }

1
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 = "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 = "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 = "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 self::rand::hashmap_random_keys;
pub use libc::strlen; pub use libc::strlen;

9
ctr-std/src/sys/unix/mutex.rs

@ -25,8 +25,10 @@ unsafe impl Sync for Mutex {}
#[allow(dead_code)] // sys isn't exported yet #[allow(dead_code)] // sys isn't exported yet
impl Mutex { impl Mutex {
pub const fn new() -> Mutex { pub const fn new() -> Mutex {
// Might be moved and address is changing it is better to avoid // Might be moved to a different address, so it is better to avoid
// initialization of potentially opaque OS data before it landed // 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) } Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) }
} }
#[inline] #[inline]
@ -49,9 +51,6 @@ impl Mutex {
// references, we instead create the mutex with type // references, we instead create the mutex with type
// PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to // PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to
// re-lock it from the same thread, thus avoiding undefined behavior. // 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 mut attr: libc::pthread_mutexattr_t = mem::uninitialized();
let r = libc::pthread_mutexattr_init(&mut attr); let r = libc::pthread_mutexattr_init(&mut attr);
debug_assert_eq!(r, 0); debug_assert_eq!(r, 0);

39
ctr-std/src/sys/unix/os.rs

@ -33,6 +33,8 @@ use sys::fd;
use vec; use vec;
const TMPBUF_SZ: usize = 128; 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(); static ENV_LOCK: Mutex = Mutex::new();
@ -47,6 +49,7 @@ extern {
target_os = "netbsd", target_os = "netbsd",
target_os = "openbsd", target_os = "openbsd",
target_os = "android", target_os = "android",
target_os = "hermit",
target_env = "newlib"), target_env = "newlib"),
link_name = "__errno")] link_name = "__errno")]
#[cfg_attr(target_os = "solaris", 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> { pub fn current_exe() -> io::Result<PathBuf> {
use io::ErrorKind; use io::ErrorKind;
Err(io::Error::new(ErrorKind::Other, "Not yet implemented!")) 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. /// environment variables of the current process.
pub fn env() -> Env { pub fn env() -> Env {
unsafe { unsafe {
ENV_LOCK.lock(); let _guard = ENV_LOCK.lock();
let mut environ = *environ(); 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(); 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()) { if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
result.push(key_value); result.push(key_value);
} }
environ = environ.offset(1); environ = environ.offset(1);
} }
let ret = Env { return Env {
iter: result.into_iter(), iter: result.into_iter(),
_dont_send_or_sync_me: PhantomData, _dont_send_or_sync_me: PhantomData,
}; }
ENV_LOCK.unlock();
return ret
} }
fn parse(input: &[u8]) -> Option<(OsString, OsString)> { fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
@ -452,15 +448,14 @@ pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
// always None as well // always None as well
let k = CString::new(k.as_bytes())?; let k = CString::new(k.as_bytes())?;
unsafe { unsafe {
ENV_LOCK.lock(); let _guard = ENV_LOCK.lock();
let s = libc::getenv(k.as_ptr()) as *const libc::c_char; let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
let ret = if s.is_null() { let ret = if s.is_null() {
None None
} else { } else {
Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
}; };
ENV_LOCK.unlock(); Ok(ret)
return Ok(ret)
} }
} }
@ -469,10 +464,8 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
let v = CString::new(v.as_bytes())?; let v = CString::new(v.as_bytes())?;
unsafe { unsafe {
ENV_LOCK.lock(); let _guard = ENV_LOCK.lock();
let ret = cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ()); cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ())
ENV_LOCK.unlock();
return ret
} }
} }
@ -480,10 +473,8 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> {
let nbuf = CString::new(n.as_bytes())?; let nbuf = CString::new(n.as_bytes())?;
unsafe { unsafe {
ENV_LOCK.lock(); let _guard = ENV_LOCK.lock();
let ret = cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ()); cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ())
ENV_LOCK.unlock();
return ret
} }
} }
@ -572,7 +563,7 @@ fn glibc_version_cstr() -> Option<&'static CStr> {
// ignoring any extra dot-separated parts. Otherwise return None. // ignoring any extra dot-separated parts. Otherwise return None.
#[cfg(target_env = "gnu")] #[cfg(target_env = "gnu")]
fn parse_glibc_version(version: &str) -> Option<(usize, usize)> { 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()) { match (parsed_ints.next(), parsed_ints.next()) {
(Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)), (Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)),
_ => None _ => None

6
ctr-std/src/sys/unix/process/process_common.rs

@ -52,7 +52,7 @@ pub struct Command {
uid: Option<uid_t>, uid: Option<uid_t>,
gid: Option<gid_t>, gid: Option<gid_t>,
saw_nul: bool, saw_nul: bool,
closures: Vec<Box<FnMut() -> io::Result<()> + Send + Sync>>, closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
stdin: Option<Stdio>, stdin: Option<Stdio>,
stdout: Option<Stdio>, stdout: Option<Stdio>,
stderr: Option<Stdio>, stderr: Option<Stdio>,
@ -155,12 +155,12 @@ impl Command {
self.gid 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 &mut self.closures
} }
pub fn before_exec(&mut self, 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); self.closures.push(f);
} }

29
ctr-std/src/sys/unix/rand.rs

@ -183,35 +183,10 @@ mod imp {
mod imp { mod imp {
#[link(name = "zircon")] #[link(name = "zircon")]
extern { extern {
fn zx_cprng_draw(buffer: *mut u8, len: usize, actual: *mut usize) -> i32; fn zx_cprng_draw(buffer: *mut u8, len: usize);
}
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)
}
}
} }
pub fn fill_bytes(v: &mut [u8]) { pub fn fill_bytes(v: &mut [u8]) {
let mut buf = v; unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) }
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)..];
}
}
}
} }
} }

5
ctr-std/src/sys/unix/thread.rs

@ -49,7 +49,7 @@ unsafe fn pthread_attr_setstacksize(_attr: *mut libc::pthread_attr_t,
} }
impl 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> { -> io::Result<Thread> {
let p = box p; let p = box p;
let mut native: libc::pthread_t = mem::zeroed(); let mut native: libc::pthread_t = mem::zeroed();
@ -138,7 +138,8 @@ impl Thread {
target_os = "solaris", target_os = "solaris",
target_os = "haiku", target_os = "haiku",
target_os = "l4re", target_os = "l4re",
target_os = "emscripten"))] target_os = "emscripten",
target_os = "hermit"))]
pub fn set_name(_name: &CStr) { pub fn set_name(_name: &CStr) {
// Newlib, Illumos, Haiku, and Emscripten have no way to set a thread name. // Newlib, Illumos, Haiku, and Emscripten have no way to set a thread name.
} }

4
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; 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; pub type clock_t = libc::c_ulong;
fn now(clock: clock_t) -> Timespec { fn now(clock: clock_t) -> Timespec {

2
ctr-std/src/sys/wasm/os.rs

@ -21,7 +21,7 @@ pub fn errno() -> i32 {
} }
pub fn error_string(_errno: i32) -> String { pub fn error_string(_errno: i32) -> String {
format!("operation successful") "operation successful".to_string()
} }
pub fn getcwd() -> io::Result<PathBuf> { pub fn getcwd() -> io::Result<PathBuf> {

2
ctr-std/src/sys/wasm/thread.rs

@ -19,7 +19,7 @@ pub struct Thread(Void);
pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
impl 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> -> io::Result<Thread>
{ {
unsupported() unsupported()

297
ctr-std/src/sys/windows/backtrace/mod.rs

@ -46,110 +46,281 @@ mod printing;
#[path = "backtrace_gnu.rs"] #[path = "backtrace_gnu.rs"]
pub mod gnu; 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]) pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> {
-> io::Result<(usize, BacktraceContext)>
{
let dbghelp = DynamicLibrary::open("dbghelp.dll")?; let dbghelp = DynamicLibrary::open("dbghelp.dll")?;
// Fetch the symbols necessary from dbghelp.dll // Fetch the symbols necessary from dbghelp.dll
let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?; let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?;
let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?; 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 // Allocate necessary structures for doing the stack walk
let process = unsafe { c::GetCurrentProcess() }; 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 { let backtrace_context = BacktraceContext {
handle: process, handle: process,
SymCleanup, SymCleanup,
StackWalkVariant: sw_var,
dbghelp, dbghelp,
}; };
// Initialize this process's symbols // Initialize this process's symbols
let ret = unsafe { SymInitialize(process, ptr::null_mut(), c::TRUE) }; let ret = unsafe { SymInitialize(process, ptr::null_mut(), c::TRUE) };
if ret != 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! // 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; let mut i = 0;
unsafe { while i < frames.len()
while i < frames.len() && && StackWalk.walk(image, process, thread, &mut frame, &mut context) == c::TRUE
StackWalkEx(image, process, thread, &mut frame, &mut context, {
ptr::null_mut(), let addr = frame.get_addr();
ptr::null_mut(), frames[i] = Frame {
ptr::null_mut(), symbol_addr: addr,
ptr::null_mut(), exact_position: addr,
0) == c::TRUE inline_context: 0,
{ };
let addr = (frame.AddrPC.Offset - 1) as *const u8;
i += 1
frames[i] = Frame { }
symbol_addr: addr, Ok(i)
exact_position: addr, }
inline_context: frame.InlineFrameContext,
}; type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL;
i += 1; 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 = impl StackFrame for c::STACKFRAME64 {
unsafe extern "system" fn(c::HANDLE, *mut c_void, fn new() -> c::STACKFRAME64 {
c::BOOL) -> c::BOOL; unsafe { mem::zeroed() }
type SymCleanupFn = }
unsafe extern "system" fn(c::HANDLE) -> c::BOOL;
#[cfg(target_arch = "x86")]
type StackWalkExFn = fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
unsafe extern "system" fn(c::DWORD, c::HANDLE, c::HANDLE, self.AddrPC.Offset = ctx.Eip as u64;
*mut c::STACKFRAME_EX, *mut c::CONTEXT, self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
*mut c_void, *mut c_void, self.AddrStack.Offset = ctx.Esp as u64;
*mut c_void, *mut c_void, c::DWORD) -> c::BOOL; self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
self.AddrFrame.Offset = ctx.Ebp as u64;
#[cfg(target_arch = "x86")] self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
fn init_frame(frame: &mut c::STACKFRAME_EX, c::IMAGE_FILE_MACHINE_I386
ctx: &c::CONTEXT) -> c::DWORD { }
frame.AddrPC.Offset = ctx.Eip as u64;
frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; #[cfg(target_arch = "x86_64")]
frame.AddrStack.Offset = ctx.Esp as u64; fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; self.AddrPC.Offset = ctx.Rip as u64;
frame.AddrFrame.Offset = ctx.Ebp as u64; self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; self.AddrStack.Offset = ctx.Rsp as u64;
c::IMAGE_FILE_MACHINE_I386 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")] enum StackWalkVariant {
fn init_frame(frame: &mut c::STACKFRAME_EX, StackWalkEx(StackWalkExFn, printing::PrintingFnsEx),
ctx: &c::CONTEXT) -> c::DWORD { StackWalk64(StackWalk64Fn, printing::PrintingFns64),
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
} }
pub struct BacktraceContext { pub struct BacktraceContext {
handle: c::HANDLE, handle: c::HANDLE,
SymCleanup: SymCleanupFn, SymCleanup: SymCleanupFn,
// Only used in printing for msvc and not gnu // 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)] #[allow(dead_code)]
dbghelp: DynamicLibrary, dbghelp: DynamicLibrary,
} }
impl Drop for BacktraceContext { impl Drop for BacktraceContext {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { (self.SymCleanup)(self.handle); } unsafe {
(self.SymCleanup)(self.handle);
}
} }
} }

14
ctr-std/src/sys/windows/backtrace/printing/mod.rs

@ -15,6 +15,20 @@ mod printing;
#[cfg(target_env = "gnu")] #[cfg(target_env = "gnu")]
mod printing { mod printing {
pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname}; 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::{foreach_symbol_fileline, resolve_symname};
pub use self::printing::{load_printing_fns_ex, load_printing_fns_64,
PrintingFnsEx, PrintingFns64};

196
ctr-std/src/sys/windows/backtrace/printing/msvc.rs

@ -10,29 +10,108 @@
use ffi::CStr; use ffi::CStr;
use io; use io;
use libc::{c_ulong, c_char}; use libc::{c_char, c_ulong};
use mem; use mem;
use sys::c;
use sys::backtrace::BacktraceContext; use sys::backtrace::BacktraceContext;
use sys::backtrace::StackWalkVariant;
use sys::c;
use sys::dynamic_lib::DynamicLibrary;
use sys_common::backtrace::Frame; 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 = type SymFromInlineContextFn =
unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
*mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
type SymGetLineFromInlineContextFn = type SymGetLineFromAddr64Fn =
unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, unsafe extern "system" fn(c::HANDLE, u64, *mut u32, *mut c::IMAGEHLP_LINE64) -> c::BOOL;
u64, *mut c::DWORD, *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. /// Converts a pointer to symbol to its string value.
pub fn resolve_symname<F>(frame: Frame, pub fn resolve_symname<F>(frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()>
callback: F, where
context: &BacktraceContext) -> io::Result<()> F: FnOnce(Option<&str>) -> io::Result<()>,
where F: FnOnce(Option<&str>) -> io::Result<()>
{ {
let SymFromInlineContext = sym!(&context.dbghelp, match context.StackWalkVariant {
"SymFromInlineContext", StackWalkVariant::StackWalkEx(_, ref fns) => resolve_symname_internal(
SymFromInlineContextFn)?; |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 { unsafe {
let mut info: c::SYMBOL_INFO = mem::zeroed(); let mut info: c::SYMBOL_INFO = mem::zeroed();
info.MaxNameLen = c::MAX_SYM_NAME as c_ulong; info.MaxNameLen = c::MAX_SYM_NAME as c_ulong;
@ -41,14 +120,13 @@ pub fn resolve_symname<F>(frame: Frame,
// due to struct alignment. // due to struct alignment.
info.SizeOfStruct = 88; info.SizeOfStruct = 88;
let mut displacement = 0u64; let ret = symbol_resolver(
let ret = SymFromInlineContext(context.handle, context.handle,
frame.symbol_addr as u64, frame.symbol_addr as u64,
frame.inline_context, frame.inline_context,
&mut displacement, &mut info,
&mut info); );
let valid_range = if ret == c::TRUE && let valid_range = if ret == c::TRUE && frame.symbol_addr as usize >= info.Address as usize {
frame.symbol_addr as usize >= info.Address as usize {
if info.Size != 0 { if info.Size != 0 {
(frame.symbol_addr as usize) < info.Address as usize + info.Size as usize (frame.symbol_addr as usize) < info.Address as usize + info.Size as usize
} else { } else {
@ -67,30 +145,72 @@ pub fn resolve_symname<F>(frame: Frame,
} }
} }
pub fn foreach_symbol_fileline<F>(frame: Frame, pub fn foreach_symbol_fileline<F>(
mut f: F, frame: Frame,
context: &BacktraceContext) callback: F,
-> io::Result<bool> context: &BacktraceContext,
where F: FnMut(&[u8], u32) -> io::Result<()> ) -> io::Result<bool>
where
F: FnMut(&[u8], u32) -> io::Result<()>,
{ {
let SymGetLineFromInlineContext = sym!(&context.dbghelp, match context.StackWalkVariant {
"SymGetLineFromInlineContext", StackWalkVariant::StackWalkEx(_, ref fns) => foreach_symbol_fileline_iternal(
SymGetLineFromInlineContextFn)?; |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 { unsafe {
let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); let mut line: c::IMAGEHLP_LINE64 = mem::zeroed();
line.SizeOfStruct = ::mem::size_of::<c::IMAGEHLP_LINE64>() as u32; line.SizeOfStruct = ::mem::size_of::<c::IMAGEHLP_LINE64>() as u32;
let mut displacement = 0u32; let ret = line_getter(
let ret = SymGetLineFromInlineContext(context.handle, context.handle,
frame.exact_position as u64, frame.exact_position as u64,
frame.inline_context, frame.inline_context,
0, &mut line,
&mut displacement, );
&mut line);
if ret == c::TRUE { if ret == c::TRUE {
let name = CStr::from_ptr(line.Filename).to_bytes(); let name = CStr::from_ptr(line.Filename).to_bytes();
f(name, line.LineNumber as u32)?; callback(name, line.LineNumber as u32)?;
} }
Ok(false) Ok(false)
} }

82
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(target_arch = "x86_64")]
#[cfg(feature = "backtrace")] #[cfg(feature = "backtrace")]
pub const IMAGE_FILE_MACHINE_AMD64: DWORD = 0x8664; 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_CONTINUE_SEARCH: LONG = 0;
pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd; 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 FD_SETSIZE: usize = 64;
pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000;
#[repr(C)] #[repr(C)]
#[cfg(not(target_pointer_width = "64"))] #[cfg(not(target_pointer_width = "64"))]
pub struct WSADATA { pub struct WSADATA {
@ -635,6 +640,22 @@ pub struct STACKFRAME_EX {
pub InlineFrameContext: DWORD, pub InlineFrameContext: DWORD,
} }
#[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)] #[repr(C)]
#[cfg(feature = "backtrace")] #[cfg(feature = "backtrace")]
pub struct KDHELP64 { pub struct KDHELP64 {
@ -773,9 +794,68 @@ pub struct FLOATING_SAVE_AREA {
// will not appear in the final documentation. This should be also defined for // will not appear in the final documentation. This should be also defined for
// other architectures supported by Windows such as ARM, and for historical // other architectures supported by Windows such as ARM, and for historical
// interest, maybe MIPS and PowerPC as well. // 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 {} 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)] #[repr(C)]
pub struct SOCKADDR_STORAGE_LH { pub struct SOCKADDR_STORAGE_LH {
pub ss_family: ADDRESS_FAMILY, pub ss_family: ADDRESS_FAMILY,

3
ctr-std/src/sys/windows/ext/ffi.rs

@ -31,7 +31,7 @@
//! //!
//! If Rust code *does* need to look into those strings, it can //! If Rust code *does* need to look into those strings, it can
//! convert them to valid UTF-8, possibly lossily, by substituting //! 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 //! conventionally done in other Rust APIs that deal with string
//! encodings. //! encodings.
//! //!
@ -65,6 +65,7 @@
//! [`from_wide`]: trait.OsStringExt.html#tymethod.from_wide //! [`from_wide`]: trait.OsStringExt.html#tymethod.from_wide
//! [`encode_wide`]: trait.OsStrExt.html#tymethod.encode_wide //! [`encode_wide`]: trait.OsStrExt.html#tymethod.encode_wide
//! [`collect`]: ../../../iter/trait.Iterator.html#method.collect //! [`collect`]: ../../../iter/trait.Iterator.html#method.collect
//! [U+FFFD]: ../../../char/constant.REPLACEMENT_CHARACTER.html
#![stable(feature = "rust1", since = "1.0.0")] #![stable(feature = "rust1", since = "1.0.0")]

1
ctr-std/src/sys/windows/ext/mod.rs

@ -18,6 +18,7 @@
#![stable(feature = "rust1", since = "1.0.0")] #![stable(feature = "rust1", since = "1.0.0")]
#![doc(cfg(windows))] #![doc(cfg(windows))]
#![allow(missing_docs)]
pub mod ffi; pub mod ffi;
pub mod fs; pub mod fs;

10
ctr-std/src/sys/windows/mod.rs

@ -266,8 +266,12 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD {
// handlers. // handlers.
// //
// https://msdn.microsoft.com/en-us/library/dn774154.aspx // 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() -> ! { pub unsafe fn abort_internal() -> ! {
asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
::intrinsics::unreachable(); {
asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT
::intrinsics::unreachable();
}
::intrinsics::abort();
} }

8
ctr-std/src/sys/windows/process.rs

@ -487,9 +487,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
} else { } else {
if x == '"' as u16 { if x == '"' as u16 {
// Add n+1 backslashes to total 2n+1 before internal '"'. // Add n+1 backslashes to total 2n+1 before internal '"'.
for _ in 0..(backslashes+1) { cmd.extend((0..(backslashes + 1)).map(|_| '\\' as u16));
cmd.push('\\' as u16);
}
} }
backslashes = 0; backslashes = 0;
} }
@ -498,9 +496,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
if quote { if quote {
// Add n backslashes to total 2n before ending '"'. // Add n backslashes to total 2n before ending '"'.
for _ in 0..backslashes { cmd.extend((0..backslashes).map(|_| '\\' as u16));
cmd.push('\\' as u16);
}
cmd.push('"' as u16); cmd.push('"' as u16);
} }
Ok(()) Ok(())

5
ctr-std/src/sys/windows/thread.rs

@ -28,7 +28,7 @@ pub struct Thread {
} }
impl 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> { -> io::Result<Thread> {
let p = box p; let p = box p;
@ -42,7 +42,8 @@ impl Thread {
let stack_size = (stack + 0xfffe) & (!0xfffe); let stack_size = (stack + 0xfffe) & (!0xfffe);
let ret = c::CreateThread(ptr::null_mut(), stack_size, let ret = c::CreateThread(ptr::null_mut(), stack_size,
thread_start, &*p as *const _ as *mut _, 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 { return if ret as usize == 0 {
Err(io::Error::last_os_error()) Err(io::Error::last_os_error())

36
ctr-std/src/sys_common/at_exit_imp.rs

@ -14,17 +14,22 @@
use boxed::FnBox; use boxed::FnBox;
use ptr; use ptr;
use mem;
use sys_common::mutex::Mutex; 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 // 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 // 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 // the thread infrastructure to be in place (useful on the borders of
// initialization/destruction). // initialization/destruction).
// We never call `LOCK.init()`, so it is UB to attempt to
// acquire this mutex reentrantly!
static LOCK: Mutex = Mutex::new(); static LOCK: Mutex = Mutex::new();
static mut QUEUE: *mut Queue = ptr::null_mut(); 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 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 // 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 // of times the new closures will be allowed to register successfully. After
@ -35,7 +40,7 @@ unsafe fn init() -> bool {
if QUEUE.is_null() { if QUEUE.is_null() {
let state: Box<Queue> = box Vec::new(); let state: Box<Queue> = box Vec::new();
QUEUE = Box::into_raw(state); QUEUE = Box::into_raw(state);
} else if QUEUE as usize == 1 { } else if QUEUE == DONE {
// can't re-init after a cleanup // can't re-init after a cleanup
return false return false
} }
@ -44,20 +49,21 @@ unsafe fn init() -> bool {
} }
pub fn cleanup() { pub fn cleanup() {
for i in 0..ITERS { for i in 1..=ITERS {
unsafe { unsafe {
LOCK.lock(); let queue = {
let queue = QUEUE; let _guard = LOCK.lock();
QUEUE = if i == ITERS - 1 {1} else {0} as *mut _; mem::replace(&mut QUEUE, if i == ITERS { DONE } else { ptr::null_mut() })
LOCK.unlock(); };
// make sure we're not recursively cleaning up // 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 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); let queue: Box<Queue> = Box::from_raw(queue);
for to_run in *queue { for to_run in *queue {
// We are not holding any lock, so reentrancy is fine.
to_run(); to_run();
} }
} }
@ -65,16 +71,16 @@ pub fn cleanup() {
} }
} }
pub fn push(f: Box<FnBox()>) -> bool { pub fn push(f: Box<dyn FnBox()>) -> bool {
let mut ret = true;
unsafe { unsafe {
LOCK.lock(); let _guard = LOCK.lock();
if init() { if init() {
// We are just moving `f` around, not calling it.
// There is no possibility of reentrancy here.
(*QUEUE).push(f); (*QUEUE).push(f);
true
} else { } else {
ret = false; false
} }
LOCK.unlock();
} }
ret
} }

21
ctr-std/src/sys_common/backtrace.rs

@ -49,7 +49,7 @@ pub struct Frame {
const MAX_NB_FRAMES: usize = 100; const MAX_NB_FRAMES: usize = 100;
/// Prints the current backtrace. /// 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(); static LOCK: Mutex = Mutex::new();
// Use a lock to prevent mixed output in multithreading context. // 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 { let mut frames = [Frame {
exact_position: ptr::null(), exact_position: ptr::null(),
symbol_addr: ptr::null(), symbol_addr: ptr::null(),
@ -156,16 +156,15 @@ pub fn log_enabled() -> Option<PrintFormat> {
_ => return Some(PrintFormat::Full), _ => return Some(PrintFormat::Full),
} }
let val = match env::var_os("RUST_BACKTRACE") { let val = env::var_os("RUST_BACKTRACE").and_then(|x|
Some(x) => if &x == "0" { if &x == "0" {
None None
} else if &x == "full" { } else if &x == "full" {
Some(PrintFormat::Full) Some(PrintFormat::Full)
} else { } else {
Some(PrintFormat::Short) Some(PrintFormat::Short)
}, }
None => None, );
};
ENABLED.store(match val { ENABLED.store(match val {
Some(v) => v as isize, Some(v) => v as isize,
None => 1, None => 1,
@ -177,7 +176,7 @@ pub fn log_enabled() -> Option<PrintFormat> {
/// ///
/// These output functions should now be used everywhere to ensure consistency. /// These output functions should now be used everywhere to ensure consistency.
/// You may want to also use `output_fileline`. /// 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<()> { s: Option<&str>, format: PrintFormat) -> io::Result<()> {
// Remove the `17: 0x0 - <unknown>` line. // Remove the `17: 0x0 - <unknown>` line.
if format == PrintFormat::Short && frame.exact_position == ptr::null() { 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`. /// See also `output`.
#[allow(dead_code)] #[allow(dead_code)]
fn output_fileline(w: &mut Write, fn output_fileline(w: &mut dyn Write,
file: &[u8], file: &[u8],
line: u32, line: u32,
format: PrintFormat) -> io::Result<()> { 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 // 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, // of other information in our symbols like hashes, version, type information,
// etc. Additionally, this doesn't handle glue symbols at all. // 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 // 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 // those endings first as they're one of the last manglings applied to
// symbol names. // 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 candidate = &s[i + llvm.len()..];
let all_hex = candidate.chars().all(|c| { let all_hex = candidate.chars().all(|c| {
match c { match c {
'A' ... 'F' | '0' ... '9' => true, 'A' ..= 'F' | '0' ..= '9' => true,
_ => false, _ => false,
} }
}); });

32
ctr-std/src/sys_common/mutex.rs

@ -24,11 +24,17 @@ impl Mutex {
/// ///
/// Behavior is undefined if the mutex is moved after it is /// Behavior is undefined if the mutex is moved after it is
/// first used with any of the functions below. /// 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()) } pub const fn new() -> Mutex { Mutex(imp::Mutex::new()) }
/// Prepare the mutex for use. /// Prepare the mutex for use.
/// ///
/// This should be called once the mutex is at a stable memory address. /// 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] #[inline]
pub unsafe fn init(&mut self) { self.0.init() } 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 /// Behavior is undefined if the mutex has been moved between this and any
/// previous function call. /// previous function call.
#[inline] #[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 /// Attempts to lock the mutex without blocking, returning whether it was
/// successfully acquired or not. /// successfully acquired or not.
@ -51,8 +65,11 @@ impl Mutex {
/// ///
/// Behavior is undefined if the current thread does not actually hold the /// Behavior is undefined if the current thread does not actually hold the
/// mutex. /// mutex.
///
/// Consider switching from the pair of raw_lock() and raw_unlock() to
/// lock() whenever possible.
#[inline] #[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. /// 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 // not meant to be exported to the outside world, just the containing module
pub fn raw(mutex: &Mutex) -> &imp::Mutex { &mutex.0 } 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(); }
}
}

2
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 { match *self {
TryLockError::Poisoned(ref p) => Some(p), TryLockError::Poisoned(ref p) => Some(p),
_ => None _ => None

4
ctr-std/src/sys_common/remutex.rs

@ -13,6 +13,7 @@ use marker;
use ops::Deref; use ops::Deref;
use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; use sys_common::poison::{self, TryLockError, TryLockResult, LockResult};
use sys::mutex as sys; use sys::mutex as sys;
use panic::{UnwindSafe, RefUnwindSafe};
/// A re-entrant mutual exclusion /// 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> Send for ReentrantMutex<T> {}
unsafe impl<T: Send> Sync 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 /// An RAII implementation of a "scoped lock" of a mutex. When this structure is
/// dropped (falls out of scope), the lock will be unlocked. /// dropped (falls out of scope), the lock will be unlocked.

2
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(); let _handler = stack_overflow::Handler::new();
// Finally, let's run some code. // 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 { pub fn min_stack() -> usize {

5
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 // Additionally a 0-index of a tls key hasn't been seen on windows, so
// we just simplify the whole branch. // we just simplify the whole branch.
if imp::requires_synchronized_create() { 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(); static INIT_LOCK: Mutex = Mutex::new();
INIT_LOCK.lock(); let _guard = INIT_LOCK.lock();
let mut key = self.key.load(Ordering::SeqCst); let mut key = self.key.load(Ordering::SeqCst);
if key == 0 { if key == 0 {
key = imp::create(self.dtor) as usize; key = imp::create(self.dtor) as usize;
self.key.store(key, Ordering::SeqCst); self.key.store(key, Ordering::SeqCst);
} }
INIT_LOCK.unlock();
rtassert!(key != 0); rtassert!(key != 0);
return key return key
} }

14
ctr-std/src/sys_common/wtf8.rs

@ -76,7 +76,7 @@ impl CodePoint {
#[inline] #[inline]
pub fn from_u32(value: u32) -> Option<CodePoint> { pub fn from_u32(value: u32) -> Option<CodePoint> {
match value { match value {
0 ... 0x10FFFF => Some(CodePoint { value: value }), 0 ..= 0x10FFFF => Some(CodePoint { value: value }),
_ => None _ => None
} }
} }
@ -101,7 +101,7 @@ impl CodePoint {
#[inline] #[inline]
pub fn to_char(&self) -> Option<char> { pub fn to_char(&self) -> Option<char> {
match self.value { match self.value {
0xD800 ... 0xDFFF => None, 0xD800 ..= 0xDFFF => None,
_ => Some(unsafe { char::from_u32_unchecked(self.value) }) _ => Some(unsafe { char::from_u32_unchecked(self.value) })
} }
} }
@ -305,7 +305,7 @@ impl Wtf8Buf {
/// like concatenating ill-formed UTF-16 strings effectively would. /// like concatenating ill-formed UTF-16 strings effectively would.
#[inline] #[inline]
pub fn push(&mut self, code_point: CodePoint) { 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() { if let Some(lead) = (&*self).final_lead_surrogate() {
let len_without_lead_surrogate = self.len() - 3; let len_without_lead_surrogate = self.len() - 3;
self.bytes.truncate(len_without_lead_surrogate); self.bytes.truncate(len_without_lead_surrogate);
@ -525,7 +525,7 @@ impl Wtf8 {
#[inline] #[inline]
pub fn ascii_byte_at(&self, position: usize) -> u8 { pub fn ascii_byte_at(&self, position: usize) -> u8 {
match self.bytes[position] { match self.bytes[position] {
ascii_byte @ 0x00 ... 0x7F => ascii_byte, ascii_byte @ 0x00 ..= 0x7F => ascii_byte,
_ => 0xFF _ => 0xFF
} }
} }
@ -630,7 +630,7 @@ impl Wtf8 {
return None return None
} }
match &self.bytes[(len - 3)..] { 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 _ => None
} }
} }
@ -642,7 +642,7 @@ impl Wtf8 {
return None return None
} }
match &self.bytes[..3] { 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 _ => None
} }
} }
@ -1245,7 +1245,7 @@ mod tests {
#[test] #[test]
fn wtf8_display() { fn wtf8_display() {
fn d(b: &[u8]) -> String { 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())); assert_eq!("", d("".as_bytes()));

3
ctr-std/src/tests/env.rs

@ -11,7 +11,6 @@
extern crate rand; extern crate rand;
use std::env::*; use std::env::*;
use std::iter::repeat;
use std::ffi::{OsString, OsStr}; use std::ffi::{OsString, OsStr};
use rand::Rng; use rand::Rng;
@ -72,7 +71,7 @@ fn test_var_big() {
#[cfg_attr(target_os = "emscripten", ignore)] #[cfg_attr(target_os = "emscripten", ignore)]
fn test_env_set_get_huge() { fn test_env_set_get_huge() {
let n = make_rand_name(); let n = make_rand_name();
let s = repeat("x").take(10000).collect::<String>(); let s = "x".repeat(10000);
set_var(&n, &s); set_var(&n, &s);
eq(var_os(&n), Some(&s)); eq(var_os(&n), Some(&s));
remove_var(&n); remove_var(&n);

2
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 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 /// 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 /// # Panics
/// ///

37
ctr-std/src/thread/mod.rs

@ -731,7 +731,8 @@ const NOTIFIED: usize = 2;
/// specifying a maximum time to block the thread for. /// specifying a maximum time to block the thread for.
/// ///
/// * The [`unpark`] method on a [`Thread`] atomically makes the token available /// * 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 /// In other words, each [`Thread`] acts a bit like a spinlock that can be
/// locked and unlocked using `park` and `unpark`. /// 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. /// // Let some time pass for the thread to be spawned.
/// thread::sleep(Duration::from_millis(10)); /// thread::sleep(Duration::from_millis(10));
/// ///
/// // There is no race condition here, if `unpark`
/// // happens first, `park` will return immediately.
/// println!("Unpark the thread"); /// println!("Unpark the thread");
/// parked_thread.thread().unpark(); /// parked_thread.thread().unpark();
/// ///
@ -796,7 +799,10 @@ pub fn park() {
let mut m = thread.inner.lock.lock().unwrap(); let mut m = thread.inner.lock.lock().unwrap();
match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
Ok(_) => {} 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"), Err(_) => panic!("inconsistent park state"),
} }
loop { loop {
@ -882,7 +888,10 @@ pub fn park_timeout(dur: Duration) {
let m = thread.inner.lock.lock().unwrap(); let m = thread.inner.lock.lock().unwrap();
match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
Ok(_) => {} 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"), Err(_) => panic!("inconsistent park_timeout state"),
} }
@ -931,24 +940,23 @@ pub struct ThreadId(u64);
impl ThreadId { impl ThreadId {
// Generate a new unique thread ID. // Generate a new unique thread ID.
fn new() -> ThreadId { 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 GUARD: mutex::Mutex = mutex::Mutex::new();
static mut COUNTER: u64 = 0; static mut COUNTER: u64 = 0;
unsafe { unsafe {
GUARD.lock(); let _guard = GUARD.lock();
// If we somehow use up all our bits, panic so that we're not // If we somehow use up all our bits, panic so that we're not
// covering up subtle bugs of IDs being reused. // covering up subtle bugs of IDs being reused.
if COUNTER == ::u64::MAX { if COUNTER == ::u64::MAX {
GUARD.unlock();
panic!("failed to generate unique thread ID: bitspace exhausted"); panic!("failed to generate unique thread ID: bitspace exhausted");
} }
let id = COUNTER; let id = COUNTER;
COUNTER += 1; COUNTER += 1;
GUARD.unlock();
ThreadId(id) ThreadId(id)
} }
} }
@ -1172,7 +1180,7 @@ impl fmt::Debug for Thread {
/// ///
/// [`Result`]: ../../std/result/enum.Result.html /// [`Result`]: ../../std/result/enum.Result.html
#[stable(feature = "rust1", since = "1.0.0")] #[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 // 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 // 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")] #[stable(feature = "rust1", since = "1.0.0")]
pub struct JoinHandle<T>(JoinInner<T>); 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> { impl<T> JoinHandle<T> {
/// Extracts a handle to the underlying thread. /// Extracts a handle to the underlying thread.
/// ///
@ -1435,7 +1448,7 @@ mod tests {
rx.recv().unwrap(); 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 (tx, rx) = channel();
let x: Box<_> = box 1; 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 // (well, it would if the constant were 8000+ - I lowered it to be more
// valgrind-friendly. try this at home, instead..!) // valgrind-friendly. try this at home, instead..!)
const GENERATIONS: u32 = 16; 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|| { return Box::new(move|| {
if x < GENERATIONS { if x < GENERATIONS {
thread::spawn(move|| child_no(x+1)()); thread::spawn(move|| child_no(x+1)());
@ -1528,10 +1541,10 @@ mod tests {
#[test] #[test]
fn test_try_panic_message_any() { fn test_try_panic_message_any() {
match thread::spawn(move|| { match thread::spawn(move|| {
panic!(box 413u16 as Box<Any + Send>); panic!(box 413u16 as Box<dyn Any + Send>);
}).join() { }).join() {
Err(e) => { Err(e) => {
type T = Box<Any + Send>; type T = Box<dyn Any + Send>;
assert!(e.is::<T>()); assert!(e.is::<T>());
let any = e.downcast::<T>().unwrap(); let any = e.downcast::<T>().unwrap();
assert!(any.is::<u16>()); assert!(any.is::<u16>());

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save